@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.cjs
CHANGED
|
@@ -570,7 +570,7 @@ var init_wire = __esm({
|
|
|
570
570
|
init_cjs_shims();
|
|
571
571
|
var import_config = require("dotenv/config");
|
|
572
572
|
var fs34 = __toESM(require("fs"), 1);
|
|
573
|
-
var
|
|
573
|
+
var readline3 = __toESM(require("readline"), 1);
|
|
574
574
|
var path42 = __toESM(require("path"), 1);
|
|
575
575
|
var import_child_process = require("child_process");
|
|
576
576
|
var import_util = require("util");
|
|
@@ -10094,6 +10094,38 @@ function countRawEscapes(chunk) {
|
|
|
10094
10094
|
for (const ch of cleaned) if (ch === "\x1B") escCount++;
|
|
10095
10095
|
return escCount;
|
|
10096
10096
|
}
|
|
10097
|
+
function patchReadlineHistoryNav(rl2) {
|
|
10098
|
+
const iface = rl2;
|
|
10099
|
+
const orig = iface._ttyWrite;
|
|
10100
|
+
let draft = null;
|
|
10101
|
+
iface._ttyWrite = function(s, key) {
|
|
10102
|
+
const k = key;
|
|
10103
|
+
const name = k?.name;
|
|
10104
|
+
const plainArrow = (name === "up" || name === "down") && !k?.ctrl && !k?.meta && !k?.shift;
|
|
10105
|
+
if (plainArrow) {
|
|
10106
|
+
if (name === "up" && iface.historyIndex === -1) {
|
|
10107
|
+
draft = { line: iface.line, cursor: iface.cursor };
|
|
10108
|
+
}
|
|
10109
|
+
if (iface.cursor > 0) {
|
|
10110
|
+
iface._moveCursor(-iface.cursor);
|
|
10111
|
+
}
|
|
10112
|
+
}
|
|
10113
|
+
const prevHistoryIndex = iface.historyIndex;
|
|
10114
|
+
orig.call(rl2, s, key);
|
|
10115
|
+
if (plainArrow && name === "down" && prevHistoryIndex >= 0 && iface.historyIndex === -1) {
|
|
10116
|
+
const saved = draft;
|
|
10117
|
+
draft = null;
|
|
10118
|
+
if (saved) {
|
|
10119
|
+
iface.line = saved.line;
|
|
10120
|
+
iface.cursor = Math.min(saved.cursor, saved.line.length);
|
|
10121
|
+
iface._refreshLine?.();
|
|
10122
|
+
}
|
|
10123
|
+
}
|
|
10124
|
+
};
|
|
10125
|
+
rl2.on("line", () => {
|
|
10126
|
+
draft = null;
|
|
10127
|
+
});
|
|
10128
|
+
}
|
|
10097
10129
|
var PASTE_PLACEHOLDER_PREFIX = "\u7C98\u8D34\u6587\u672C #";
|
|
10098
10130
|
var InputRouter = class {
|
|
10099
10131
|
rl;
|
|
@@ -10481,7 +10513,8 @@ function renderTerminalTutorial() {
|
|
|
10481
10513
|
|
|
10482
10514
|
// src/cli/link.ts
|
|
10483
10515
|
init_cjs_shims();
|
|
10484
|
-
var
|
|
10516
|
+
var path27 = __toESM(require("path"), 1);
|
|
10517
|
+
var readline2 = __toESM(require("readline"), 1);
|
|
10485
10518
|
|
|
10486
10519
|
// src/server/store.ts
|
|
10487
10520
|
init_cjs_shims();
|
|
@@ -10889,858 +10922,500 @@ async function hubEnrollByAccount(baseUrl, input) {
|
|
|
10889
10922
|
return { hubUrl: baseUrl.replace(/\/$/, ""), ...data };
|
|
10890
10923
|
}
|
|
10891
10924
|
|
|
10892
|
-
// src/cli/
|
|
10925
|
+
// src/cli/account-enroll.ts
|
|
10893
10926
|
init_cjs_shims();
|
|
10894
|
-
var
|
|
10895
|
-
var
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
for (let i = at + 1; i < argv.length; i++) {
|
|
10913
|
-
const arg = argv[i];
|
|
10914
|
-
if (arg === "--data-dir" && argv[i + 1]) {
|
|
10915
|
-
dataDir = argv[++i];
|
|
10916
|
-
} else if (arg.startsWith("--data-dir=")) {
|
|
10917
|
-
dataDir = arg.slice("--data-dir=".length);
|
|
10918
|
-
} else if (arg === "--host" && argv[i + 1]) {
|
|
10919
|
-
host = argv[++i];
|
|
10920
|
-
} else if (arg.startsWith("--host=")) {
|
|
10921
|
-
host = arg.slice("--host=".length);
|
|
10922
|
-
} else if (arg === "--port" && argv[i + 1]) {
|
|
10923
|
-
port = Number(argv[++i]);
|
|
10924
|
-
} else if (arg.startsWith("--port=")) {
|
|
10925
|
-
port = Number(arg.slice("--port=".length));
|
|
10926
|
-
}
|
|
10927
|
-
}
|
|
10928
|
-
if (!Number.isFinite(port) || port <= 0) port = DEFAULT_SERVE_PORT;
|
|
10929
|
-
if (host === "0.0.0.0" || host === "::" || host === "") host = DEFAULT_SERVE_HOST;
|
|
10930
|
-
return { dataDir, host, port };
|
|
10927
|
+
var path24 = __toESM(require("path"), 1);
|
|
10928
|
+
var readline = __toESM(require("readline/promises"), 1);
|
|
10929
|
+
|
|
10930
|
+
// src/server/projects.ts
|
|
10931
|
+
init_cjs_shims();
|
|
10932
|
+
var path23 = __toESM(require("path"), 1);
|
|
10933
|
+
|
|
10934
|
+
// src/server/session.ts
|
|
10935
|
+
init_cjs_shims();
|
|
10936
|
+
var path22 = __toESM(require("path"), 1);
|
|
10937
|
+
var import_async_hooks = require("async_hooks");
|
|
10938
|
+
|
|
10939
|
+
// src/server/mcpConfig.ts
|
|
10940
|
+
init_cjs_shims();
|
|
10941
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
10942
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
10943
|
+
function isValidMcpConfig(v) {
|
|
10944
|
+
return !!v && typeof v === "object" && typeof v.name === "string" && (v.type === "stdio" || v.type === "http");
|
|
10931
10945
|
}
|
|
10932
|
-
function
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
if (!
|
|
10946
|
+
function readConfigFile(file) {
|
|
10947
|
+
if (!file) return [];
|
|
10948
|
+
try {
|
|
10949
|
+
if (!import_node_fs.default.existsSync(file)) return [];
|
|
10950
|
+
const raw = JSON.parse(import_node_fs.default.readFileSync(file, "utf8"));
|
|
10951
|
+
const list = Array.isArray(raw) ? raw : raw && typeof raw === "object" && Array.isArray(raw.servers) ? raw.servers : [];
|
|
10952
|
+
return list.filter(isValidMcpConfig);
|
|
10953
|
+
} catch (err) {
|
|
10954
|
+
console.error(`[mcp] \u8BFB\u53D6\u914D\u7F6E\u5931\u8D25 ${file}: ${err.message}`);
|
|
10955
|
+
return [];
|
|
10936
10956
|
}
|
|
10937
|
-
return out;
|
|
10938
|
-
}
|
|
10939
|
-
function isWindowsAbsolute(p) {
|
|
10940
|
-
return /^[A-Za-z]:[\\/]/.test(p) || /^\\\\/.test(p);
|
|
10941
10957
|
}
|
|
10942
|
-
function
|
|
10943
|
-
|
|
10958
|
+
function hasServerMcpConfig() {
|
|
10959
|
+
if (readConfigFile(process.env.MCP_CONFIG_PATH).length > 0) return true;
|
|
10960
|
+
const workspace = process.env.WORKSPACE;
|
|
10961
|
+
if (!workspace) return false;
|
|
10962
|
+
return readConfigFile(import_node_path.default.join(workspace, ".agent", "mcp.json")).length > 0;
|
|
10944
10963
|
}
|
|
10945
|
-
function
|
|
10946
|
-
|
|
10964
|
+
function loadServerMcpConfigs(tenant) {
|
|
10965
|
+
const fromEnv = readConfigFile(process.env.MCP_CONFIG_PATH);
|
|
10966
|
+
if (fromEnv.length > 0) return fromEnv;
|
|
10967
|
+
if (Array.isArray(tenant.mcpServers) && tenant.mcpServers.length > 0) {
|
|
10968
|
+
return tenant.mcpServers.filter(isValidMcpConfig);
|
|
10969
|
+
}
|
|
10970
|
+
const workspace = tenant.workspaceRoot ?? process.env.WORKSPACE;
|
|
10971
|
+
if (workspace)
|
|
10972
|
+
return readConfigFile(import_node_path.default.join(workspace, ".agent", "mcp.json"));
|
|
10973
|
+
return [];
|
|
10947
10974
|
}
|
|
10948
|
-
|
|
10949
|
-
|
|
10950
|
-
|
|
10951
|
-
|
|
10952
|
-
|
|
10953
|
-
const
|
|
10954
|
-
|
|
10955
|
-
const portMatch = /--port(?:=|\s+)(\d+)/.exec(line);
|
|
10956
|
-
const port = Number(portMatch?.[1] ?? DEFAULT_SERVE_PORT);
|
|
10975
|
+
|
|
10976
|
+
// src/server/nodeLlm.ts
|
|
10977
|
+
init_cjs_shims();
|
|
10978
|
+
var GLOBAL_PROVIDER_ID = "__env__";
|
|
10979
|
+
function envProvider() {
|
|
10980
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
10981
|
+
if (!apiKey) return null;
|
|
10957
10982
|
return {
|
|
10958
|
-
|
|
10959
|
-
|
|
10960
|
-
|
|
10983
|
+
id: GLOBAL_PROVIDER_ID,
|
|
10984
|
+
name: process.env.OPENAI_MODEL || process.env.MODEL || "\u5168\u5C40 LLM",
|
|
10985
|
+
type: "env",
|
|
10986
|
+
baseURL: process.env.OPENAI_BASE_URL ?? "",
|
|
10987
|
+
model: process.env.OPENAI_MODEL || process.env.MODEL || "",
|
|
10988
|
+
apiKey
|
|
10961
10989
|
};
|
|
10962
10990
|
}
|
|
10963
|
-
function
|
|
10964
|
-
|
|
10965
|
-
return fs18.readlinkSync(`/proc/${pid}/cwd`);
|
|
10966
|
-
} catch {
|
|
10967
|
-
return null;
|
|
10968
|
-
}
|
|
10991
|
+
function normReasoningEffort(v) {
|
|
10992
|
+
return v === "low" || v === "medium" || v === "high" ? v : null;
|
|
10969
10993
|
}
|
|
10970
|
-
function
|
|
10971
|
-
|
|
10972
|
-
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
|
|
10977
|
-
|
|
10978
|
-
|
|
10994
|
+
function normalizeModelList(v) {
|
|
10995
|
+
if (!Array.isArray(v)) return void 0;
|
|
10996
|
+
const out = [];
|
|
10997
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10998
|
+
for (const x of v) {
|
|
10999
|
+
const s = String(x ?? "").trim();
|
|
11000
|
+
if (!s || seen.has(s)) continue;
|
|
11001
|
+
seen.add(s);
|
|
11002
|
+
out.push(s);
|
|
11003
|
+
if (out.length >= 500) break;
|
|
10979
11004
|
}
|
|
10980
11005
|
return out;
|
|
10981
11006
|
}
|
|
10982
|
-
function
|
|
10983
|
-
const
|
|
10984
|
-
|
|
10985
|
-
|
|
11007
|
+
function nodeLlmView(cfg) {
|
|
11008
|
+
const g = envProvider();
|
|
11009
|
+
const providers = [
|
|
11010
|
+
...g ? [
|
|
11011
|
+
{
|
|
11012
|
+
id: g.id,
|
|
11013
|
+
name: g.name,
|
|
11014
|
+
type: g.type,
|
|
11015
|
+
baseURL: g.baseURL,
|
|
11016
|
+
model: g.model,
|
|
11017
|
+
hasApiKey: true,
|
|
11018
|
+
global: true
|
|
11019
|
+
}
|
|
11020
|
+
] : [],
|
|
11021
|
+
...cfg.providers.map((p) => ({
|
|
11022
|
+
id: p.id,
|
|
11023
|
+
name: p.name,
|
|
11024
|
+
type: p.type ?? "",
|
|
11025
|
+
baseURL: p.baseURL,
|
|
11026
|
+
model: p.model,
|
|
11027
|
+
hasApiKey: Boolean(p.apiKey),
|
|
11028
|
+
models: p.models ?? [],
|
|
11029
|
+
nonChat: p.nonChat ?? [],
|
|
11030
|
+
modelMeta: p.modelMeta ?? [],
|
|
11031
|
+
reasoningEffort: p.reasoningEffort ?? null,
|
|
11032
|
+
global: false
|
|
11033
|
+
}))
|
|
11034
|
+
];
|
|
11035
|
+
return {
|
|
11036
|
+
defaultProviderId: cfg.defaultProviderId ?? null,
|
|
11037
|
+
providers,
|
|
11038
|
+
/** 未显式设置默认时,是否由环境变量全局配置兜底 */
|
|
11039
|
+
globalIsDefault: !cfg.defaultProviderId && Boolean(g)
|
|
11040
|
+
};
|
|
10986
11041
|
}
|
|
10987
|
-
function
|
|
10988
|
-
const
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
|
|
10992
|
-
|
|
10993
|
-
|
|
11042
|
+
function applyNodeLlmPatch(cfg, raw) {
|
|
11043
|
+
const next = { providers: cfg.providers, defaultProviderId: cfg.defaultProviderId };
|
|
11044
|
+
if (Array.isArray(raw?.providers)) {
|
|
11045
|
+
const old = new Map(cfg.providers.map((p) => [p.id, p]));
|
|
11046
|
+
next.providers = raw.providers.filter((x) => Boolean(x) && typeof x === "object").filter((x) => x.global !== true && String(x.id ?? "") !== GLOBAL_PROVIDER_ID).map((x) => {
|
|
11047
|
+
const id = String(x.id ?? "").trim();
|
|
11048
|
+
if (!id) throw new ApiError(400, "bad_request", "\u4F9B\u5E94\u5546 id \u4E0D\u80FD\u4E3A\u7A7A");
|
|
11049
|
+
const prev = old.get(id);
|
|
11050
|
+
const apiKey = String(x.apiKey ?? "").trim();
|
|
11051
|
+
const models = normalizeModelList(x.models) ?? prev?.models;
|
|
11052
|
+
const nonChat = normalizeModelList(x.nonChat) ?? prev?.nonChat;
|
|
11053
|
+
const modelMeta = normalizeModelMeta(x.modelMeta) ?? prev?.modelMeta;
|
|
11054
|
+
return {
|
|
11055
|
+
id,
|
|
11056
|
+
name: String(x.name ?? prev?.name ?? id).trim(),
|
|
11057
|
+
type: x.type == null ? prev?.type : String(x.type),
|
|
11058
|
+
baseURL: String(x.baseURL ?? prev?.baseURL ?? "").trim(),
|
|
11059
|
+
model: String(x.model ?? prev?.model ?? "").trim(),
|
|
11060
|
+
apiKey: apiKey || prev?.apiKey,
|
|
11061
|
+
reasoningEffort: x.reasoningEffort === void 0 ? prev?.reasoningEffort ?? null : normReasoningEffort(x.reasoningEffort),
|
|
11062
|
+
...models ? { models } : {},
|
|
11063
|
+
...nonChat ? { nonChat } : {},
|
|
11064
|
+
...modelMeta ? { modelMeta } : {}
|
|
11065
|
+
};
|
|
11066
|
+
});
|
|
10994
11067
|
}
|
|
10995
|
-
|
|
10996
|
-
|
|
10997
|
-
|
|
10998
|
-
|
|
10999
|
-
|
|
11000
|
-
try {
|
|
11001
|
-
argv = fs18.readFileSync(`/proc/${pid}/cmdline`, "utf-8").split("\0").filter(Boolean);
|
|
11002
|
-
} catch {
|
|
11003
|
-
continue;
|
|
11004
|
-
}
|
|
11005
|
-
const parsed = parseServeArgs(argv);
|
|
11006
|
-
if (!parsed) continue;
|
|
11007
|
-
const dataDir = resolveDataDir(parsed.dataDir, processCwd(pid), processEnv(pid));
|
|
11008
|
-
if (!dataDir) continue;
|
|
11009
|
-
out.push({ dataDir, host: parsed.host, port: parsed.port });
|
|
11068
|
+
if (typeof raw?.defaultProviderId === "string") {
|
|
11069
|
+
const id = raw.defaultProviderId.trim();
|
|
11070
|
+
next.defaultProviderId = id || void 0;
|
|
11071
|
+
} else if (raw?.defaultProviderId === null) {
|
|
11072
|
+
next.defaultProviderId = void 0;
|
|
11010
11073
|
}
|
|
11011
|
-
return
|
|
11074
|
+
return next;
|
|
11012
11075
|
}
|
|
11013
|
-
function
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
for (const line of res.stdout.split("\n")) {
|
|
11018
|
-
const inst = parseServeCommandLine(line);
|
|
11019
|
-
if (inst) out.push(inst);
|
|
11020
|
-
}
|
|
11021
|
-
return out;
|
|
11076
|
+
function findNodeProvider(store, id) {
|
|
11077
|
+
if (!id) return null;
|
|
11078
|
+
if (id === GLOBAL_PROVIDER_ID) return envProvider();
|
|
11079
|
+
return store.loadNodeLlm().providers.find((p) => p.id === id) ?? null;
|
|
11022
11080
|
}
|
|
11023
|
-
function
|
|
11024
|
-
const
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
"powershell.exe",
|
|
11028
|
-
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
11029
|
-
{ encoding: "utf-8", timeout: 15e3, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
|
|
11030
|
-
);
|
|
11031
|
-
if (res.status !== 0 || !res.stdout) return out;
|
|
11032
|
-
for (const line of res.stdout.replace(/^\uFEFF/, "").split(/\r?\n/)) {
|
|
11033
|
-
const inst = parseServeCommandLine(line);
|
|
11034
|
-
if (inst) out.push(inst);
|
|
11035
|
-
}
|
|
11036
|
-
return out;
|
|
11081
|
+
function nodeDefaultProvider(store) {
|
|
11082
|
+
const cfg = store.loadNodeLlm();
|
|
11083
|
+
if (cfg.providers.length === 0) return null;
|
|
11084
|
+
return cfg.providers.find((p) => p.id === cfg.defaultProviderId) ?? cfg.providers[0] ?? null;
|
|
11037
11085
|
}
|
|
11038
|
-
function
|
|
11039
|
-
const
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
if (
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
|
|
11086
|
+
function resolveSessionProvider(store, tenant, providerId) {
|
|
11087
|
+
const own = tenant.provider ?? {};
|
|
11088
|
+
if (providerId) {
|
|
11089
|
+
const picked = findNodeProvider(store, providerId);
|
|
11090
|
+
if (picked) {
|
|
11091
|
+
return {
|
|
11092
|
+
apiKey: picked.apiKey || own.apiKey,
|
|
11093
|
+
baseURL: picked.baseURL || own.baseURL,
|
|
11094
|
+
model: picked.model,
|
|
11095
|
+
providerId,
|
|
11096
|
+
reasoningEffort: picked.reasoningEffort ?? null,
|
|
11097
|
+
...picked.modelMeta ? { modelMeta: picked.modelMeta } : {}
|
|
11098
|
+
};
|
|
11099
|
+
}
|
|
11100
|
+
}
|
|
11101
|
+
if (own.apiKey) return { ...own, model: tenant.model };
|
|
11102
|
+
const def = nodeDefaultProvider(store);
|
|
11103
|
+
if (def?.apiKey) {
|
|
11104
|
+
return {
|
|
11105
|
+
apiKey: def.apiKey,
|
|
11106
|
+
baseURL: own.baseURL || def.baseURL,
|
|
11107
|
+
model: def.model || tenant.model,
|
|
11108
|
+
reasoningEffort: def.reasoningEffort ?? null,
|
|
11109
|
+
...def.modelMeta ? { modelMeta: def.modelMeta } : {}
|
|
11110
|
+
};
|
|
11111
|
+
}
|
|
11112
|
+
return { ...own, model: tenant.model };
|
|
11046
11113
|
}
|
|
11047
11114
|
|
|
11048
|
-
// src/
|
|
11049
|
-
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
|
|
11115
|
+
// src/server/usage.ts
|
|
11116
|
+
init_cjs_shims();
|
|
11117
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
11118
|
+
var path21 = __toESM(require("path"), 1);
|
|
11119
|
+
var LEDGER_RETENTION_MONTHS = 12;
|
|
11120
|
+
var USAGE_SCHEMA = 1;
|
|
11121
|
+
var DEFAULT_PRICING = {
|
|
11122
|
+
schema: USAGE_SCHEMA,
|
|
11123
|
+
base: "USD",
|
|
11124
|
+
rate: { CNY: 7.2 },
|
|
11125
|
+
vendors: {
|
|
11126
|
+
openai: {
|
|
11127
|
+
"gpt-4o": { input: 2.5, output: 10, cacheRead: 1.25 },
|
|
11128
|
+
"gpt-4o-mini": { input: 0.15, output: 0.6, cacheRead: 0.075 },
|
|
11129
|
+
"gpt-4.1": { input: 2, output: 8, cacheRead: 0.5 }
|
|
11130
|
+
},
|
|
11131
|
+
deepseek: {
|
|
11132
|
+
"deepseek-flash": {
|
|
11133
|
+
input: 0.27,
|
|
11134
|
+
output: 1.1,
|
|
11135
|
+
cacheRead: 0.027,
|
|
11136
|
+
cacheWrite: 0.27
|
|
11137
|
+
},
|
|
11138
|
+
"deepseek-reasoner": {
|
|
11139
|
+
input: 0.55,
|
|
11140
|
+
output: 2.19,
|
|
11141
|
+
cacheRead: 0.055,
|
|
11142
|
+
cacheWrite: 0.55
|
|
11143
|
+
},
|
|
11144
|
+
"deepseek-*": {
|
|
11145
|
+
input: 0.27,
|
|
11146
|
+
output: 1.1,
|
|
11147
|
+
cacheRead: 0.027,
|
|
11148
|
+
cacheWrite: 0.27
|
|
11149
|
+
}
|
|
11150
|
+
},
|
|
11151
|
+
qwen: {
|
|
11152
|
+
"qwen-plus": { input: 0.4, output: 1.2 },
|
|
11153
|
+
"qwen-turbo": { input: 0.05, output: 0.2 }
|
|
11154
|
+
},
|
|
11155
|
+
zhipu: { "glm-4-plus": { input: 0.7, output: 0.7 } },
|
|
11156
|
+
moonshot: { "moonshot-v1-8k": { input: 1.68, output: 1.68 } },
|
|
11157
|
+
xiaomi: {},
|
|
11158
|
+
custom: {},
|
|
11159
|
+
env: {}
|
|
11160
|
+
},
|
|
11161
|
+
fallback: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }
|
|
11162
|
+
};
|
|
11163
|
+
function zeroAgg() {
|
|
11164
|
+
return {
|
|
11165
|
+
calls: 0,
|
|
11166
|
+
input: 0,
|
|
11167
|
+
output: 0,
|
|
11168
|
+
cacheRead: 0,
|
|
11169
|
+
cacheWrite: 0,
|
|
11170
|
+
costUsd: 0,
|
|
11171
|
+
unpriced: 0
|
|
11172
|
+
};
|
|
11055
11173
|
}
|
|
11056
|
-
function
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
11174
|
+
function addAgg(into, tokens, costUsd) {
|
|
11175
|
+
into.calls += 1;
|
|
11176
|
+
into.input += tokens.input;
|
|
11177
|
+
into.output += tokens.output;
|
|
11178
|
+
into.cacheRead += tokens.cacheRead;
|
|
11179
|
+
into.cacheWrite += tokens.cacheWrite;
|
|
11180
|
+
if (costUsd == null) into.unpriced += 1;
|
|
11181
|
+
else into.costUsd += costUsd;
|
|
11060
11182
|
}
|
|
11061
|
-
function
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
|
|
11068
|
-
|
|
11069
|
-
|
|
11070
|
-
|
|
11071
|
-
|
|
11072
|
-
|
|
11073
|
-
out.dataDir = val;
|
|
11074
|
-
i++;
|
|
11075
|
-
} else if (a === "--label") {
|
|
11076
|
-
out.label = val;
|
|
11077
|
-
i++;
|
|
11078
|
-
} else if (a === "--host") {
|
|
11079
|
-
out.host = val;
|
|
11080
|
-
i++;
|
|
11081
|
-
} else if (a === "--port") {
|
|
11082
|
-
out.port = Number(val);
|
|
11083
|
-
i++;
|
|
11084
|
-
} else if (a === "-h" || a === "--help") {
|
|
11085
|
-
out.help = true;
|
|
11086
|
-
}
|
|
11183
|
+
function utcDay(iso) {
|
|
11184
|
+
return iso.slice(0, 10);
|
|
11185
|
+
}
|
|
11186
|
+
function monthOf(iso) {
|
|
11187
|
+
return iso.slice(0, 7);
|
|
11188
|
+
}
|
|
11189
|
+
function retainedMonths(now = /* @__PURE__ */ new Date()) {
|
|
11190
|
+
const out = /* @__PURE__ */ new Set();
|
|
11191
|
+
const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
|
|
11192
|
+
for (let i = 0; i < LEDGER_RETENTION_MONTHS; i += 1) {
|
|
11193
|
+
out.add(d.toISOString().slice(0, 7));
|
|
11194
|
+
d.setUTCMonth(d.getUTCMonth() - 1);
|
|
11087
11195
|
}
|
|
11088
11196
|
return out;
|
|
11089
11197
|
}
|
|
11090
|
-
function
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
|
|
11094
|
-
|
|
11095
|
-
}
|
|
11096
|
-
return id;
|
|
11198
|
+
function atomicWrite(file, content) {
|
|
11199
|
+
fs19.mkdirSync(path21.dirname(file), { recursive: true });
|
|
11200
|
+
const tmp = `${file}.tmp`;
|
|
11201
|
+
fs19.writeFileSync(tmp, content, "utf-8");
|
|
11202
|
+
fs19.renameSync(tmp, file);
|
|
11097
11203
|
}
|
|
11098
|
-
|
|
11099
|
-
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
const res = await fetch(`http://${host}:${port}/api/v1/fleet/status`, {
|
|
11103
|
-
headers: { Authorization: `Bearer ${adminKey}` },
|
|
11104
|
-
signal: ctrl.signal
|
|
11105
|
-
});
|
|
11106
|
-
return res.ok;
|
|
11107
|
-
} catch {
|
|
11108
|
-
return false;
|
|
11109
|
-
} finally {
|
|
11110
|
-
clearTimeout(timer);
|
|
11204
|
+
var UsageLedger = class {
|
|
11205
|
+
constructor(root) {
|
|
11206
|
+
this.root = root;
|
|
11207
|
+
this.dir = path21.join(root, "usage");
|
|
11111
11208
|
}
|
|
11112
|
-
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
});
|
|
11122
|
-
const text = await res.text();
|
|
11123
|
-
let payload = null;
|
|
11124
|
-
try {
|
|
11125
|
-
payload = text ? JSON.parse(text) : null;
|
|
11126
|
-
} catch {
|
|
11209
|
+
root;
|
|
11210
|
+
dir;
|
|
11211
|
+
rollup;
|
|
11212
|
+
pricing;
|
|
11213
|
+
rollupDirty = false;
|
|
11214
|
+
rollupTimer = null;
|
|
11215
|
+
inited = false;
|
|
11216
|
+
get ledgerDir() {
|
|
11217
|
+
return this.dir;
|
|
11127
11218
|
}
|
|
11128
|
-
|
|
11129
|
-
|
|
11219
|
+
ledgerFile(month) {
|
|
11220
|
+
return path21.join(this.ledgerDir, `ledger-${month}.jsonl`);
|
|
11130
11221
|
}
|
|
11131
|
-
|
|
11132
|
-
|
|
11133
|
-
async function linkNode(opts) {
|
|
11134
|
-
const rawDataDir = opts.dataDir?.trim() || process.env.DATA_DIR?.trim() || void 0;
|
|
11135
|
-
const explicitDataDir = rawDataDir ? expandHome(rawDataDir) : void 0;
|
|
11136
|
-
const host = opts.host?.trim() || process.env.HOST?.trim() || DEFAULT_SERVE_HOST;
|
|
11137
|
-
const port = opts.port ?? Number(process.env.PORT ?? DEFAULT_SERVE_PORT);
|
|
11138
|
-
const running = discoverRunningServeInstances();
|
|
11139
|
-
const candidates = buildHotCandidates(explicitDataDir, running, { host, port });
|
|
11140
|
-
for (const inst of candidates) {
|
|
11141
|
-
const store2 = new Store(inst.dataDir);
|
|
11142
|
-
const adminKey = process.env.ADMIN_API_KEY ?? store2.loadAdminKey();
|
|
11143
|
-
if (!adminKey) continue;
|
|
11144
|
-
if (!await probeServer(inst.host, inst.port, adminKey)) continue;
|
|
11145
|
-
const status = await enrollViaServer(inst.host, inst.port, adminKey, opts);
|
|
11146
|
-
return { mode: "hot", ...status, dataDir: inst.dataDir };
|
|
11222
|
+
get rollupFile() {
|
|
11223
|
+
return path21.join(this.ledgerDir, "rollup.json");
|
|
11147
11224
|
}
|
|
11148
|
-
|
|
11149
|
-
|
|
11150
|
-
const nodeId = ensureNodeId(store);
|
|
11151
|
-
const cred = await hubEnrollByCode(opts.hubUrl, {
|
|
11152
|
-
code: opts.code,
|
|
11153
|
-
nodeId,
|
|
11154
|
-
label: opts.label
|
|
11155
|
-
});
|
|
11156
|
-
try {
|
|
11157
|
-
store.saveFleetCredential({
|
|
11158
|
-
...cred,
|
|
11159
|
-
label: opts.label ?? cred.label,
|
|
11160
|
-
enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11161
|
-
});
|
|
11162
|
-
} catch (e) {
|
|
11163
|
-
const err = e;
|
|
11164
|
-
if (err.code === "EACCES" || err.code === "EPERM") {
|
|
11165
|
-
throw new Error(
|
|
11166
|
-
`\u65E0\u6CD5\u5199\u5165\u6570\u636E\u76EE\u5F55 ${dataDir}\uFF08${err.code}: ${err.message}\uFF09
|
|
11167
|
-
\u8BE5\u76EE\u5F55\u5F53\u524D\u7528\u6237\u6CA1\u6709\u5199\u6743\u9650\u3002\u4E24\u79CD\u6539\u6CD5\uFF1A
|
|
11168
|
-
1) \u53BB\u6389 --data-dir\uFF0C\u8BA9 link \u81EA\u52A8\u53D1\u73B0\u672C\u673A\u8FD0\u884C\u7684\u8282\u70B9\uFF08\u63A8\u8350\uFF09\uFF1B
|
|
11169
|
-
2) \u7528\u5F53\u524D\u7528\u6237\u53EF\u5199\u7684\u76EE\u5F55\uFF0C\u672C\u5E73\u53F0\u5B89\u88C5\u811A\u672C\u9ED8\u8BA4\uFF1A${installDataDirHint()}
|
|
11170
|
-
\uFF08\u63A5\u5165\u7801\u4E00\u6B21\u6027\uFF0C\u9700\u8981\u91CD\u65B0\u751F\u6210\uFF09`
|
|
11171
|
-
);
|
|
11172
|
-
}
|
|
11173
|
-
throw e;
|
|
11225
|
+
get pricingFile() {
|
|
11226
|
+
return path21.join(this.ledgerDir, "pricing.json");
|
|
11174
11227
|
}
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
dataDir,
|
|
11184
|
-
explicitDataDir: Boolean(explicitDataDir),
|
|
11185
|
-
runningServiceDirs: otherRunningDirs
|
|
11186
|
-
};
|
|
11187
|
-
}
|
|
11188
|
-
function printLinkHelp() {
|
|
11189
|
-
cliLog("\u7528\u6CD5: zqagent link --hub <url> --code <\u6CE8\u518C\u7801> [--label \u540D\u79F0] [--data-dir \u76EE\u5F55]");
|
|
11190
|
-
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");
|
|
11191
|
-
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");
|
|
11192
|
-
cliLog(" \u5426\u5219\u5199\u5165 <\u6570\u636E\u76EE\u5F55>/fleet.json\uFF0C\u4E0B\u6B21\u542F\u52A8\u81EA\u52A8\u63A5\u5165\u3002");
|
|
11193
|
-
}
|
|
11194
|
-
async function runLinkCommand(argv) {
|
|
11195
|
-
const args = parseLinkArgs(argv);
|
|
11196
|
-
if (args.help) {
|
|
11197
|
-
printLinkHelp();
|
|
11198
|
-
return true;
|
|
11199
|
-
}
|
|
11200
|
-
const hubUrl = (args.hubUrl ?? process.env.HUB_URL ?? "").trim().replace(/\/$/, "");
|
|
11201
|
-
const code = (args.code ?? "").trim();
|
|
11202
|
-
if (!hubUrl || !code) {
|
|
11203
|
-
cliErr("\u7F3A\u5C11 --hub \u6216 --code\u3002");
|
|
11204
|
-
printLinkHelp();
|
|
11205
|
-
return false;
|
|
11228
|
+
// ===================== 初始化 =====================
|
|
11229
|
+
init(now = /* @__PURE__ */ new Date()) {
|
|
11230
|
+
if (this.inited) return;
|
|
11231
|
+
fs19.mkdirSync(this.ledgerDir, { recursive: true });
|
|
11232
|
+
this.pricing = this.loadPricing();
|
|
11233
|
+
this.rollup = this.loadRollup(now);
|
|
11234
|
+
this.pruneLedgers(now);
|
|
11235
|
+
this.inited = true;
|
|
11206
11236
|
}
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11219
|
-
|
|
11220
|
-
|
|
11221
|
-
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
|
|
11225
|
-
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
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");
|
|
11233
|
-
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");
|
|
11234
|
-
cliLog(` zqagent link --hub <Hub\u5730\u5740> --code <\u65B0\u63A5\u5165\u7801> --data-dir "${r.runningServiceDirs[0]}"`);
|
|
11235
|
-
} else if (!r.explicitDataDir) {
|
|
11236
|
-
cliLog("");
|
|
11237
|
-
cliLog("\u26A0\uFE0F \u672A\u6307\u5B9A --data-dir\uFF0C\u51ED\u636E\u5199\u5165\u4E86\u5F53\u524D\u76EE\u5F55\u4E0B\u7684 .zqagent_data\u3002");
|
|
11238
|
-
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");
|
|
11239
|
-
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");
|
|
11240
|
-
cliLog(" zqagent link --hub <Hub\u5730\u5740> --code <\u65B0\u63A5\u5165\u7801> --data-dir <\u670D\u52A1\u6570\u636E\u76EE\u5F55>");
|
|
11241
|
-
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`);
|
|
11237
|
+
loadPricing() {
|
|
11238
|
+
try {
|
|
11239
|
+
const raw = fs19.readFileSync(this.pricingFile, "utf-8");
|
|
11240
|
+
const parsed = JSON.parse(raw);
|
|
11241
|
+
const vendors = {};
|
|
11242
|
+
for (const v of /* @__PURE__ */ new Set([
|
|
11243
|
+
...Object.keys(DEFAULT_PRICING.vendors),
|
|
11244
|
+
...Object.keys(parsed.vendors ?? {})
|
|
11245
|
+
])) {
|
|
11246
|
+
vendors[v] = {
|
|
11247
|
+
...DEFAULT_PRICING.vendors[v] ?? {},
|
|
11248
|
+
...(parsed.vendors ?? {})[v] ?? {}
|
|
11249
|
+
};
|
|
11250
|
+
}
|
|
11251
|
+
return {
|
|
11252
|
+
schema: USAGE_SCHEMA,
|
|
11253
|
+
base: "USD",
|
|
11254
|
+
rate: { ...DEFAULT_PRICING.rate, ...parsed.rate ?? {} },
|
|
11255
|
+
vendors,
|
|
11256
|
+
fallback: { ...DEFAULT_PRICING.fallback, ...parsed.fallback ?? {} }
|
|
11257
|
+
};
|
|
11258
|
+
} catch {
|
|
11259
|
+
try {
|
|
11260
|
+
atomicWrite(this.pricingFile, JSON.stringify(DEFAULT_PRICING, null, 2));
|
|
11261
|
+
} catch {
|
|
11242
11262
|
}
|
|
11263
|
+
return JSON.parse(JSON.stringify(DEFAULT_PRICING));
|
|
11243
11264
|
}
|
|
11244
|
-
return true;
|
|
11245
|
-
} catch (e) {
|
|
11246
|
-
cliErr(`\u63A5\u5165\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
|
|
11247
|
-
return false;
|
|
11248
11265
|
}
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
|
|
11254
|
-
|
|
11255
|
-
|
|
11256
|
-
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
}
|
|
11271
|
-
|
|
11272
|
-
if (!file) return [];
|
|
11273
|
-
try {
|
|
11274
|
-
if (!import_node_fs.default.existsSync(file)) return [];
|
|
11275
|
-
const raw = JSON.parse(import_node_fs.default.readFileSync(file, "utf8"));
|
|
11276
|
-
const list = Array.isArray(raw) ? raw : raw && typeof raw === "object" && Array.isArray(raw.servers) ? raw.servers : [];
|
|
11277
|
-
return list.filter(isValidMcpConfig);
|
|
11278
|
-
} catch (err) {
|
|
11279
|
-
console.error(`[mcp] \u8BFB\u53D6\u914D\u7F6E\u5931\u8D25 ${file}: ${err.message}`);
|
|
11280
|
-
return [];
|
|
11266
|
+
loadRollup(now) {
|
|
11267
|
+
try {
|
|
11268
|
+
const raw = fs19.readFileSync(this.rollupFile, "utf-8");
|
|
11269
|
+
const parsed = JSON.parse(raw);
|
|
11270
|
+
return {
|
|
11271
|
+
schema: USAGE_SCHEMA,
|
|
11272
|
+
since: parsed.since ?? now.toISOString(),
|
|
11273
|
+
legacy: parsed.legacy,
|
|
11274
|
+
total: { ...zeroAgg(), ...parsed.total },
|
|
11275
|
+
byDay: parsed.byDay ?? {},
|
|
11276
|
+
byModel: parsed.byModel ?? {},
|
|
11277
|
+
byProject: parsed.byProject ?? {}
|
|
11278
|
+
};
|
|
11279
|
+
} catch {
|
|
11280
|
+
return {
|
|
11281
|
+
schema: USAGE_SCHEMA,
|
|
11282
|
+
since: now.toISOString(),
|
|
11283
|
+
total: zeroAgg(),
|
|
11284
|
+
byDay: {},
|
|
11285
|
+
byModel: {},
|
|
11286
|
+
byProject: {}
|
|
11287
|
+
};
|
|
11288
|
+
}
|
|
11281
11289
|
}
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
|
|
11288
|
-
}
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11292
|
-
|
|
11293
|
-
|
|
11290
|
+
/** 删除超出保留期的账本文件,并裁剪 byDay */
|
|
11291
|
+
pruneLedgers(now) {
|
|
11292
|
+
const keep = retainedMonths(now);
|
|
11293
|
+
let changed = false;
|
|
11294
|
+
try {
|
|
11295
|
+
for (const f of fs19.readdirSync(this.ledgerDir)) {
|
|
11296
|
+
const m = /^ledger-(\d{4}-\d{2})\.jsonl$/.exec(f);
|
|
11297
|
+
if (m && !keep.has(m[1])) {
|
|
11298
|
+
fs19.unlinkSync(path21.join(this.ledgerDir, f));
|
|
11299
|
+
}
|
|
11300
|
+
}
|
|
11301
|
+
} catch {
|
|
11302
|
+
}
|
|
11303
|
+
for (const day of Object.keys(this.rollup.byDay)) {
|
|
11304
|
+
if (!keep.has(day.slice(0, 7))) {
|
|
11305
|
+
delete this.rollup.byDay[day];
|
|
11306
|
+
changed = true;
|
|
11307
|
+
}
|
|
11308
|
+
}
|
|
11309
|
+
if (changed) this.saveRollupNow();
|
|
11294
11310
|
}
|
|
11295
|
-
|
|
11296
|
-
|
|
11297
|
-
return
|
|
11298
|
-
return [];
|
|
11299
|
-
}
|
|
11300
|
-
|
|
11301
|
-
// src/server/nodeLlm.ts
|
|
11302
|
-
init_cjs_shims();
|
|
11303
|
-
var GLOBAL_PROVIDER_ID = "__env__";
|
|
11304
|
-
function envProvider() {
|
|
11305
|
-
const apiKey = process.env.OPENAI_API_KEY;
|
|
11306
|
-
if (!apiKey) return null;
|
|
11307
|
-
return {
|
|
11308
|
-
id: GLOBAL_PROVIDER_ID,
|
|
11309
|
-
name: process.env.OPENAI_MODEL || process.env.MODEL || "\u5168\u5C40 LLM",
|
|
11310
|
-
type: "env",
|
|
11311
|
-
baseURL: process.env.OPENAI_BASE_URL ?? "",
|
|
11312
|
-
model: process.env.OPENAI_MODEL || process.env.MODEL || "",
|
|
11313
|
-
apiKey
|
|
11314
|
-
};
|
|
11315
|
-
}
|
|
11316
|
-
function normReasoningEffort(v) {
|
|
11317
|
-
return v === "low" || v === "medium" || v === "high" ? v : null;
|
|
11318
|
-
}
|
|
11319
|
-
function normalizeModelList(v) {
|
|
11320
|
-
if (!Array.isArray(v)) return void 0;
|
|
11321
|
-
const out = [];
|
|
11322
|
-
const seen = /* @__PURE__ */ new Set();
|
|
11323
|
-
for (const x of v) {
|
|
11324
|
-
const s = String(x ?? "").trim();
|
|
11325
|
-
if (!s || seen.has(s)) continue;
|
|
11326
|
-
seen.add(s);
|
|
11327
|
-
out.push(s);
|
|
11328
|
-
if (out.length >= 500) break;
|
|
11311
|
+
// ===================== 价格 =====================
|
|
11312
|
+
getPricing() {
|
|
11313
|
+
return this.pricing;
|
|
11329
11314
|
}
|
|
11330
|
-
|
|
11331
|
-
|
|
11332
|
-
|
|
11333
|
-
|
|
11334
|
-
|
|
11335
|
-
|
|
11336
|
-
{
|
|
11337
|
-
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
11341
|
-
|
|
11342
|
-
|
|
11343
|
-
|
|
11315
|
+
/** 更新价格/汇率(整表覆盖式合并) */
|
|
11316
|
+
updatePricing(patch) {
|
|
11317
|
+
this.pricing = {
|
|
11318
|
+
schema: USAGE_SCHEMA,
|
|
11319
|
+
base: "USD",
|
|
11320
|
+
rate: { ...this.pricing.rate, ...patch.rate ?? {} },
|
|
11321
|
+
vendors: { ...this.pricing.vendors, ...patch.vendors ?? {} },
|
|
11322
|
+
fallback: { ...this.pricing.fallback, ...patch.fallback ?? {} }
|
|
11323
|
+
};
|
|
11324
|
+
atomicWrite(this.pricingFile, JSON.stringify(this.pricing, null, 2));
|
|
11325
|
+
return this.pricing;
|
|
11326
|
+
}
|
|
11327
|
+
priceFor(vendor, model) {
|
|
11328
|
+
const table = this.pricing.vendors[vendor];
|
|
11329
|
+
if (table) {
|
|
11330
|
+
if (table[model]) return table[model];
|
|
11331
|
+
for (const key of Object.keys(table)) {
|
|
11332
|
+
if (key.endsWith("*") && model.startsWith(key.slice(0, -1)))
|
|
11333
|
+
return table[key];
|
|
11344
11334
|
}
|
|
11345
|
-
] : [],
|
|
11346
|
-
...cfg.providers.map((p) => ({
|
|
11347
|
-
id: p.id,
|
|
11348
|
-
name: p.name,
|
|
11349
|
-
type: p.type ?? "",
|
|
11350
|
-
baseURL: p.baseURL,
|
|
11351
|
-
model: p.model,
|
|
11352
|
-
hasApiKey: Boolean(p.apiKey),
|
|
11353
|
-
models: p.models ?? [],
|
|
11354
|
-
nonChat: p.nonChat ?? [],
|
|
11355
|
-
modelMeta: p.modelMeta ?? [],
|
|
11356
|
-
reasoningEffort: p.reasoningEffort ?? null,
|
|
11357
|
-
global: false
|
|
11358
|
-
}))
|
|
11359
|
-
];
|
|
11360
|
-
return {
|
|
11361
|
-
defaultProviderId: cfg.defaultProviderId ?? null,
|
|
11362
|
-
providers,
|
|
11363
|
-
/** 未显式设置默认时,是否由环境变量全局配置兜底 */
|
|
11364
|
-
globalIsDefault: !cfg.defaultProviderId && Boolean(g)
|
|
11365
|
-
};
|
|
11366
|
-
}
|
|
11367
|
-
function applyNodeLlmPatch(cfg, raw) {
|
|
11368
|
-
const next = { providers: cfg.providers, defaultProviderId: cfg.defaultProviderId };
|
|
11369
|
-
if (Array.isArray(raw?.providers)) {
|
|
11370
|
-
const old = new Map(cfg.providers.map((p) => [p.id, p]));
|
|
11371
|
-
next.providers = raw.providers.filter((x) => Boolean(x) && typeof x === "object").filter((x) => x.global !== true && String(x.id ?? "") !== GLOBAL_PROVIDER_ID).map((x) => {
|
|
11372
|
-
const id = String(x.id ?? "").trim();
|
|
11373
|
-
if (!id) throw new ApiError(400, "bad_request", "\u4F9B\u5E94\u5546 id \u4E0D\u80FD\u4E3A\u7A7A");
|
|
11374
|
-
const prev = old.get(id);
|
|
11375
|
-
const apiKey = String(x.apiKey ?? "").trim();
|
|
11376
|
-
const models = normalizeModelList(x.models) ?? prev?.models;
|
|
11377
|
-
const nonChat = normalizeModelList(x.nonChat) ?? prev?.nonChat;
|
|
11378
|
-
const modelMeta = normalizeModelMeta(x.modelMeta) ?? prev?.modelMeta;
|
|
11379
|
-
return {
|
|
11380
|
-
id,
|
|
11381
|
-
name: String(x.name ?? prev?.name ?? id).trim(),
|
|
11382
|
-
type: x.type == null ? prev?.type : String(x.type),
|
|
11383
|
-
baseURL: String(x.baseURL ?? prev?.baseURL ?? "").trim(),
|
|
11384
|
-
model: String(x.model ?? prev?.model ?? "").trim(),
|
|
11385
|
-
apiKey: apiKey || prev?.apiKey,
|
|
11386
|
-
reasoningEffort: x.reasoningEffort === void 0 ? prev?.reasoningEffort ?? null : normReasoningEffort(x.reasoningEffort),
|
|
11387
|
-
...models ? { models } : {},
|
|
11388
|
-
...nonChat ? { nonChat } : {},
|
|
11389
|
-
...modelMeta ? { modelMeta } : {}
|
|
11390
|
-
};
|
|
11391
|
-
});
|
|
11392
|
-
}
|
|
11393
|
-
if (typeof raw?.defaultProviderId === "string") {
|
|
11394
|
-
const id = raw.defaultProviderId.trim();
|
|
11395
|
-
next.defaultProviderId = id || void 0;
|
|
11396
|
-
} else if (raw?.defaultProviderId === null) {
|
|
11397
|
-
next.defaultProviderId = void 0;
|
|
11398
|
-
}
|
|
11399
|
-
return next;
|
|
11400
|
-
}
|
|
11401
|
-
function findNodeProvider(store, id) {
|
|
11402
|
-
if (!id) return null;
|
|
11403
|
-
if (id === GLOBAL_PROVIDER_ID) return envProvider();
|
|
11404
|
-
return store.loadNodeLlm().providers.find((p) => p.id === id) ?? null;
|
|
11405
|
-
}
|
|
11406
|
-
function nodeDefaultProvider(store) {
|
|
11407
|
-
const cfg = store.loadNodeLlm();
|
|
11408
|
-
if (cfg.providers.length === 0) return null;
|
|
11409
|
-
return cfg.providers.find((p) => p.id === cfg.defaultProviderId) ?? cfg.providers[0] ?? null;
|
|
11410
|
-
}
|
|
11411
|
-
function resolveSessionProvider(store, tenant, providerId) {
|
|
11412
|
-
const own = tenant.provider ?? {};
|
|
11413
|
-
if (providerId) {
|
|
11414
|
-
const picked = findNodeProvider(store, providerId);
|
|
11415
|
-
if (picked) {
|
|
11416
|
-
return {
|
|
11417
|
-
apiKey: picked.apiKey || own.apiKey,
|
|
11418
|
-
baseURL: picked.baseURL || own.baseURL,
|
|
11419
|
-
model: picked.model,
|
|
11420
|
-
providerId,
|
|
11421
|
-
reasoningEffort: picked.reasoningEffort ?? null,
|
|
11422
|
-
...picked.modelMeta ? { modelMeta: picked.modelMeta } : {}
|
|
11423
|
-
};
|
|
11424
11335
|
}
|
|
11425
|
-
|
|
11426
|
-
|
|
11427
|
-
|
|
11428
|
-
|
|
11429
|
-
|
|
11430
|
-
|
|
11431
|
-
|
|
11432
|
-
model: def.model || tenant.model,
|
|
11433
|
-
reasoningEffort: def.reasoningEffort ?? null,
|
|
11434
|
-
...def.modelMeta ? { modelMeta: def.modelMeta } : {}
|
|
11435
|
-
};
|
|
11436
|
-
}
|
|
11437
|
-
return { ...own, model: tenant.model };
|
|
11438
|
-
}
|
|
11439
|
-
|
|
11440
|
-
// src/server/usage.ts
|
|
11441
|
-
init_cjs_shims();
|
|
11442
|
-
var fs20 = __toESM(require("fs"), 1);
|
|
11443
|
-
var path23 = __toESM(require("path"), 1);
|
|
11444
|
-
var LEDGER_RETENTION_MONTHS = 12;
|
|
11445
|
-
var USAGE_SCHEMA = 1;
|
|
11446
|
-
var DEFAULT_PRICING = {
|
|
11447
|
-
schema: USAGE_SCHEMA,
|
|
11448
|
-
base: "USD",
|
|
11449
|
-
rate: { CNY: 7.2 },
|
|
11450
|
-
vendors: {
|
|
11451
|
-
openai: {
|
|
11452
|
-
"gpt-4o": { input: 2.5, output: 10, cacheRead: 1.25 },
|
|
11453
|
-
"gpt-4o-mini": { input: 0.15, output: 0.6, cacheRead: 0.075 },
|
|
11454
|
-
"gpt-4.1": { input: 2, output: 8, cacheRead: 0.5 }
|
|
11455
|
-
},
|
|
11456
|
-
deepseek: {
|
|
11457
|
-
"deepseek-flash": {
|
|
11458
|
-
input: 0.27,
|
|
11459
|
-
output: 1.1,
|
|
11460
|
-
cacheRead: 0.027,
|
|
11461
|
-
cacheWrite: 0.27
|
|
11462
|
-
},
|
|
11463
|
-
"deepseek-reasoner": {
|
|
11464
|
-
input: 0.55,
|
|
11465
|
-
output: 2.19,
|
|
11466
|
-
cacheRead: 0.055,
|
|
11467
|
-
cacheWrite: 0.55
|
|
11468
|
-
},
|
|
11469
|
-
"deepseek-*": {
|
|
11470
|
-
input: 0.27,
|
|
11471
|
-
output: 1.1,
|
|
11472
|
-
cacheRead: 0.027,
|
|
11473
|
-
cacheWrite: 0.27
|
|
11336
|
+
for (const v of Object.values(this.pricing.vendors)) {
|
|
11337
|
+
if (v[model]) return v[model];
|
|
11338
|
+
}
|
|
11339
|
+
for (const v of Object.values(this.pricing.vendors)) {
|
|
11340
|
+
for (const key of Object.keys(v)) {
|
|
11341
|
+
if (key.endsWith("*") && model.startsWith(key.slice(0, -1)))
|
|
11342
|
+
return v[key];
|
|
11474
11343
|
}
|
|
11475
|
-
}
|
|
11476
|
-
|
|
11477
|
-
"qwen-plus": { input: 0.4, output: 1.2 },
|
|
11478
|
-
"qwen-turbo": { input: 0.05, output: 0.2 }
|
|
11479
|
-
},
|
|
11480
|
-
zhipu: { "glm-4-plus": { input: 0.7, output: 0.7 } },
|
|
11481
|
-
moonshot: { "moonshot-v1-8k": { input: 1.68, output: 1.68 } },
|
|
11482
|
-
xiaomi: {},
|
|
11483
|
-
custom: {},
|
|
11484
|
-
env: {}
|
|
11485
|
-
},
|
|
11486
|
-
fallback: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }
|
|
11487
|
-
};
|
|
11488
|
-
function zeroAgg() {
|
|
11489
|
-
return {
|
|
11490
|
-
calls: 0,
|
|
11491
|
-
input: 0,
|
|
11492
|
-
output: 0,
|
|
11493
|
-
cacheRead: 0,
|
|
11494
|
-
cacheWrite: 0,
|
|
11495
|
-
costUsd: 0,
|
|
11496
|
-
unpriced: 0
|
|
11497
|
-
};
|
|
11498
|
-
}
|
|
11499
|
-
function addAgg(into, tokens, costUsd) {
|
|
11500
|
-
into.calls += 1;
|
|
11501
|
-
into.input += tokens.input;
|
|
11502
|
-
into.output += tokens.output;
|
|
11503
|
-
into.cacheRead += tokens.cacheRead;
|
|
11504
|
-
into.cacheWrite += tokens.cacheWrite;
|
|
11505
|
-
if (costUsd == null) into.unpriced += 1;
|
|
11506
|
-
else into.costUsd += costUsd;
|
|
11507
|
-
}
|
|
11508
|
-
function utcDay(iso) {
|
|
11509
|
-
return iso.slice(0, 10);
|
|
11510
|
-
}
|
|
11511
|
-
function monthOf(iso) {
|
|
11512
|
-
return iso.slice(0, 7);
|
|
11513
|
-
}
|
|
11514
|
-
function retainedMonths(now = /* @__PURE__ */ new Date()) {
|
|
11515
|
-
const out = /* @__PURE__ */ new Set();
|
|
11516
|
-
const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
|
|
11517
|
-
for (let i = 0; i < LEDGER_RETENTION_MONTHS; i += 1) {
|
|
11518
|
-
out.add(d.toISOString().slice(0, 7));
|
|
11519
|
-
d.setUTCMonth(d.getUTCMonth() - 1);
|
|
11344
|
+
}
|
|
11345
|
+
return null;
|
|
11520
11346
|
}
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
11530
|
-
constructor(root) {
|
|
11531
|
-
this.root = root;
|
|
11532
|
-
this.dir = path23.join(root, "usage");
|
|
11347
|
+
/** 成本(USD):input 已含 cacheRead,故按非缓存部分计价 */
|
|
11348
|
+
costOf(vendor, model, t) {
|
|
11349
|
+
const p = this.priceFor(vendor, model);
|
|
11350
|
+
if (!p) return null;
|
|
11351
|
+
const cached3 = Math.min(t.cacheRead, t.input);
|
|
11352
|
+
const fresh = Math.max(0, t.input - cached3);
|
|
11353
|
+
const M = 1e6;
|
|
11354
|
+
const cost = (fresh * p.input + cached3 * (p.cacheRead ?? p.input) + t.output * p.output + t.cacheWrite * (p.cacheWrite ?? 0)) / M;
|
|
11355
|
+
return Number.isFinite(cost) ? cost : null;
|
|
11533
11356
|
}
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
11538
|
-
rollupDirty = false;
|
|
11539
|
-
rollupTimer = null;
|
|
11540
|
-
inited = false;
|
|
11541
|
-
get ledgerDir() {
|
|
11542
|
-
return this.dir;
|
|
11357
|
+
convert(usd, currency) {
|
|
11358
|
+
if (!currency || currency === "USD") return usd;
|
|
11359
|
+
const r = this.pricing.rate[currency];
|
|
11360
|
+
return typeof r === "number" && r > 0 ? usd * r : usd;
|
|
11543
11361
|
}
|
|
11544
|
-
|
|
11545
|
-
|
|
11362
|
+
// ===================== 记账 =====================
|
|
11363
|
+
/** 追加一条用量(串行 + appendFileSync;同步返回,便于在事件回调里调用) */
|
|
11364
|
+
record(input) {
|
|
11365
|
+
this.ensureInit();
|
|
11366
|
+
const costUsd = this.costOf(input.vendor, input.model, input);
|
|
11367
|
+
const rec = {
|
|
11368
|
+
...input,
|
|
11369
|
+
id: input.id ?? `${input.sessionId}:${input.ts}:${Math.random().toString(36).slice(2, 8)}`,
|
|
11370
|
+
costUsd,
|
|
11371
|
+
priced: costUsd != null
|
|
11372
|
+
};
|
|
11373
|
+
const line = JSON.stringify(rec) + "\n";
|
|
11374
|
+
try {
|
|
11375
|
+
fs19.appendFileSync(this.ledgerFile(monthOf(rec.ts)), line);
|
|
11376
|
+
} catch (e) {
|
|
11377
|
+
console.error(`[usage] \u5199\u8D26\u672C\u5931\u8D25: ${String(e)}`);
|
|
11378
|
+
}
|
|
11379
|
+
addAgg(this.rollup.total, rec, costUsd);
|
|
11380
|
+
const day = this.rollup.byDay[utcDay(rec.ts)] ?? (this.rollup.byDay[utcDay(rec.ts)] = zeroAgg());
|
|
11381
|
+
addAgg(day, rec, costUsd);
|
|
11382
|
+
const mk = `${rec.vendor}/${rec.model}`;
|
|
11383
|
+
const bm = this.rollup.byModel[mk] ?? (this.rollup.byModel[mk] = zeroAgg());
|
|
11384
|
+
addAgg(bm, rec, costUsd);
|
|
11385
|
+
const bp = this.rollup.byProject[rec.projectId] ?? (this.rollup.byProject[rec.projectId] = zeroAgg());
|
|
11386
|
+
addAgg(bp, rec, costUsd);
|
|
11387
|
+
this.scheduleRollupSave();
|
|
11388
|
+
return rec;
|
|
11546
11389
|
}
|
|
11547
|
-
|
|
11548
|
-
|
|
11390
|
+
/** 写入历史基线(仅一次;迁移自既有消息 usage) */
|
|
11391
|
+
seedLegacy(agg, throughTs) {
|
|
11392
|
+
this.ensureInit();
|
|
11393
|
+
if (this.rollup.legacy) return;
|
|
11394
|
+
this.rollup.legacy = { ...agg, throughTs };
|
|
11395
|
+
if (throughTs < this.rollup.since) this.rollup.since = throughTs;
|
|
11396
|
+
this.rollup.total.calls += agg.calls;
|
|
11397
|
+
this.rollup.total.input += agg.input;
|
|
11398
|
+
this.rollup.total.output += agg.output;
|
|
11399
|
+
this.rollup.total.cacheRead += agg.cacheRead;
|
|
11400
|
+
this.rollup.total.cacheWrite += agg.cacheWrite;
|
|
11401
|
+
this.rollup.total.costUsd += agg.costUsd;
|
|
11402
|
+
this.rollup.total.unpriced += agg.unpriced;
|
|
11403
|
+
this.saveRollupNow();
|
|
11549
11404
|
}
|
|
11550
|
-
|
|
11551
|
-
|
|
11405
|
+
ensureInit() {
|
|
11406
|
+
if (!this.inited) this.init();
|
|
11552
11407
|
}
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
if (this.
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
this.
|
|
11408
|
+
scheduleRollupSave() {
|
|
11409
|
+
this.rollupDirty = true;
|
|
11410
|
+
if (this.rollupTimer) return;
|
|
11411
|
+
this.rollupTimer = setTimeout(() => {
|
|
11412
|
+
this.rollupTimer = null;
|
|
11413
|
+
if (this.rollupDirty) this.saveRollupNow();
|
|
11414
|
+
}, 1500);
|
|
11415
|
+
this.rollupTimer.unref?.();
|
|
11561
11416
|
}
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
const raw = fs20.readFileSync(this.pricingFile, "utf-8");
|
|
11565
|
-
const parsed = JSON.parse(raw);
|
|
11566
|
-
const vendors = {};
|
|
11567
|
-
for (const v of /* @__PURE__ */ new Set([
|
|
11568
|
-
...Object.keys(DEFAULT_PRICING.vendors),
|
|
11569
|
-
...Object.keys(parsed.vendors ?? {})
|
|
11570
|
-
])) {
|
|
11571
|
-
vendors[v] = {
|
|
11572
|
-
...DEFAULT_PRICING.vendors[v] ?? {},
|
|
11573
|
-
...(parsed.vendors ?? {})[v] ?? {}
|
|
11574
|
-
};
|
|
11575
|
-
}
|
|
11576
|
-
return {
|
|
11577
|
-
schema: USAGE_SCHEMA,
|
|
11578
|
-
base: "USD",
|
|
11579
|
-
rate: { ...DEFAULT_PRICING.rate, ...parsed.rate ?? {} },
|
|
11580
|
-
vendors,
|
|
11581
|
-
fallback: { ...DEFAULT_PRICING.fallback, ...parsed.fallback ?? {} }
|
|
11582
|
-
};
|
|
11583
|
-
} catch {
|
|
11584
|
-
try {
|
|
11585
|
-
atomicWrite(this.pricingFile, JSON.stringify(DEFAULT_PRICING, null, 2));
|
|
11586
|
-
} catch {
|
|
11587
|
-
}
|
|
11588
|
-
return JSON.parse(JSON.stringify(DEFAULT_PRICING));
|
|
11589
|
-
}
|
|
11590
|
-
}
|
|
11591
|
-
loadRollup(now) {
|
|
11592
|
-
try {
|
|
11593
|
-
const raw = fs20.readFileSync(this.rollupFile, "utf-8");
|
|
11594
|
-
const parsed = JSON.parse(raw);
|
|
11595
|
-
return {
|
|
11596
|
-
schema: USAGE_SCHEMA,
|
|
11597
|
-
since: parsed.since ?? now.toISOString(),
|
|
11598
|
-
legacy: parsed.legacy,
|
|
11599
|
-
total: { ...zeroAgg(), ...parsed.total },
|
|
11600
|
-
byDay: parsed.byDay ?? {},
|
|
11601
|
-
byModel: parsed.byModel ?? {},
|
|
11602
|
-
byProject: parsed.byProject ?? {}
|
|
11603
|
-
};
|
|
11604
|
-
} catch {
|
|
11605
|
-
return {
|
|
11606
|
-
schema: USAGE_SCHEMA,
|
|
11607
|
-
since: now.toISOString(),
|
|
11608
|
-
total: zeroAgg(),
|
|
11609
|
-
byDay: {},
|
|
11610
|
-
byModel: {},
|
|
11611
|
-
byProject: {}
|
|
11612
|
-
};
|
|
11613
|
-
}
|
|
11614
|
-
}
|
|
11615
|
-
/** 删除超出保留期的账本文件,并裁剪 byDay */
|
|
11616
|
-
pruneLedgers(now) {
|
|
11617
|
-
const keep = retainedMonths(now);
|
|
11618
|
-
let changed = false;
|
|
11619
|
-
try {
|
|
11620
|
-
for (const f of fs20.readdirSync(this.ledgerDir)) {
|
|
11621
|
-
const m = /^ledger-(\d{4}-\d{2})\.jsonl$/.exec(f);
|
|
11622
|
-
if (m && !keep.has(m[1])) {
|
|
11623
|
-
fs20.unlinkSync(path23.join(this.ledgerDir, f));
|
|
11624
|
-
}
|
|
11625
|
-
}
|
|
11626
|
-
} catch {
|
|
11627
|
-
}
|
|
11628
|
-
for (const day of Object.keys(this.rollup.byDay)) {
|
|
11629
|
-
if (!keep.has(day.slice(0, 7))) {
|
|
11630
|
-
delete this.rollup.byDay[day];
|
|
11631
|
-
changed = true;
|
|
11632
|
-
}
|
|
11633
|
-
}
|
|
11634
|
-
if (changed) this.saveRollupNow();
|
|
11635
|
-
}
|
|
11636
|
-
// ===================== 价格 =====================
|
|
11637
|
-
getPricing() {
|
|
11638
|
-
return this.pricing;
|
|
11639
|
-
}
|
|
11640
|
-
/** 更新价格/汇率(整表覆盖式合并) */
|
|
11641
|
-
updatePricing(patch) {
|
|
11642
|
-
this.pricing = {
|
|
11643
|
-
schema: USAGE_SCHEMA,
|
|
11644
|
-
base: "USD",
|
|
11645
|
-
rate: { ...this.pricing.rate, ...patch.rate ?? {} },
|
|
11646
|
-
vendors: { ...this.pricing.vendors, ...patch.vendors ?? {} },
|
|
11647
|
-
fallback: { ...this.pricing.fallback, ...patch.fallback ?? {} }
|
|
11648
|
-
};
|
|
11649
|
-
atomicWrite(this.pricingFile, JSON.stringify(this.pricing, null, 2));
|
|
11650
|
-
return this.pricing;
|
|
11651
|
-
}
|
|
11652
|
-
priceFor(vendor, model) {
|
|
11653
|
-
const table = this.pricing.vendors[vendor];
|
|
11654
|
-
if (table) {
|
|
11655
|
-
if (table[model]) return table[model];
|
|
11656
|
-
for (const key of Object.keys(table)) {
|
|
11657
|
-
if (key.endsWith("*") && model.startsWith(key.slice(0, -1)))
|
|
11658
|
-
return table[key];
|
|
11659
|
-
}
|
|
11660
|
-
}
|
|
11661
|
-
for (const v of Object.values(this.pricing.vendors)) {
|
|
11662
|
-
if (v[model]) return v[model];
|
|
11663
|
-
}
|
|
11664
|
-
for (const v of Object.values(this.pricing.vendors)) {
|
|
11665
|
-
for (const key of Object.keys(v)) {
|
|
11666
|
-
if (key.endsWith("*") && model.startsWith(key.slice(0, -1)))
|
|
11667
|
-
return v[key];
|
|
11668
|
-
}
|
|
11669
|
-
}
|
|
11670
|
-
return null;
|
|
11671
|
-
}
|
|
11672
|
-
/** 成本(USD):input 已含 cacheRead,故按非缓存部分计价 */
|
|
11673
|
-
costOf(vendor, model, t) {
|
|
11674
|
-
const p = this.priceFor(vendor, model);
|
|
11675
|
-
if (!p) return null;
|
|
11676
|
-
const cached3 = Math.min(t.cacheRead, t.input);
|
|
11677
|
-
const fresh = Math.max(0, t.input - cached3);
|
|
11678
|
-
const M = 1e6;
|
|
11679
|
-
const cost = (fresh * p.input + cached3 * (p.cacheRead ?? p.input) + t.output * p.output + t.cacheWrite * (p.cacheWrite ?? 0)) / M;
|
|
11680
|
-
return Number.isFinite(cost) ? cost : null;
|
|
11681
|
-
}
|
|
11682
|
-
convert(usd, currency) {
|
|
11683
|
-
if (!currency || currency === "USD") return usd;
|
|
11684
|
-
const r = this.pricing.rate[currency];
|
|
11685
|
-
return typeof r === "number" && r > 0 ? usd * r : usd;
|
|
11686
|
-
}
|
|
11687
|
-
// ===================== 记账 =====================
|
|
11688
|
-
/** 追加一条用量(串行 + appendFileSync;同步返回,便于在事件回调里调用) */
|
|
11689
|
-
record(input) {
|
|
11690
|
-
this.ensureInit();
|
|
11691
|
-
const costUsd = this.costOf(input.vendor, input.model, input);
|
|
11692
|
-
const rec = {
|
|
11693
|
-
...input,
|
|
11694
|
-
id: input.id ?? `${input.sessionId}:${input.ts}:${Math.random().toString(36).slice(2, 8)}`,
|
|
11695
|
-
costUsd,
|
|
11696
|
-
priced: costUsd != null
|
|
11697
|
-
};
|
|
11698
|
-
const line = JSON.stringify(rec) + "\n";
|
|
11699
|
-
try {
|
|
11700
|
-
fs20.appendFileSync(this.ledgerFile(monthOf(rec.ts)), line);
|
|
11701
|
-
} catch (e) {
|
|
11702
|
-
console.error(`[usage] \u5199\u8D26\u672C\u5931\u8D25: ${String(e)}`);
|
|
11703
|
-
}
|
|
11704
|
-
addAgg(this.rollup.total, rec, costUsd);
|
|
11705
|
-
const day = this.rollup.byDay[utcDay(rec.ts)] ?? (this.rollup.byDay[utcDay(rec.ts)] = zeroAgg());
|
|
11706
|
-
addAgg(day, rec, costUsd);
|
|
11707
|
-
const mk = `${rec.vendor}/${rec.model}`;
|
|
11708
|
-
const bm = this.rollup.byModel[mk] ?? (this.rollup.byModel[mk] = zeroAgg());
|
|
11709
|
-
addAgg(bm, rec, costUsd);
|
|
11710
|
-
const bp = this.rollup.byProject[rec.projectId] ?? (this.rollup.byProject[rec.projectId] = zeroAgg());
|
|
11711
|
-
addAgg(bp, rec, costUsd);
|
|
11712
|
-
this.scheduleRollupSave();
|
|
11713
|
-
return rec;
|
|
11714
|
-
}
|
|
11715
|
-
/** 写入历史基线(仅一次;迁移自既有消息 usage) */
|
|
11716
|
-
seedLegacy(agg, throughTs) {
|
|
11717
|
-
this.ensureInit();
|
|
11718
|
-
if (this.rollup.legacy) return;
|
|
11719
|
-
this.rollup.legacy = { ...agg, throughTs };
|
|
11720
|
-
if (throughTs < this.rollup.since) this.rollup.since = throughTs;
|
|
11721
|
-
this.rollup.total.calls += agg.calls;
|
|
11722
|
-
this.rollup.total.input += agg.input;
|
|
11723
|
-
this.rollup.total.output += agg.output;
|
|
11724
|
-
this.rollup.total.cacheRead += agg.cacheRead;
|
|
11725
|
-
this.rollup.total.cacheWrite += agg.cacheWrite;
|
|
11726
|
-
this.rollup.total.costUsd += agg.costUsd;
|
|
11727
|
-
this.rollup.total.unpriced += agg.unpriced;
|
|
11728
|
-
this.saveRollupNow();
|
|
11729
|
-
}
|
|
11730
|
-
ensureInit() {
|
|
11731
|
-
if (!this.inited) this.init();
|
|
11732
|
-
}
|
|
11733
|
-
scheduleRollupSave() {
|
|
11734
|
-
this.rollupDirty = true;
|
|
11735
|
-
if (this.rollupTimer) return;
|
|
11736
|
-
this.rollupTimer = setTimeout(() => {
|
|
11737
|
-
this.rollupTimer = null;
|
|
11738
|
-
if (this.rollupDirty) this.saveRollupNow();
|
|
11739
|
-
}, 1500);
|
|
11740
|
-
this.rollupTimer.unref?.();
|
|
11741
|
-
}
|
|
11742
|
-
saveRollupNow() {
|
|
11743
|
-
this.rollupDirty = false;
|
|
11417
|
+
saveRollupNow() {
|
|
11418
|
+
this.rollupDirty = false;
|
|
11744
11419
|
try {
|
|
11745
11420
|
atomicWrite(this.rollupFile, JSON.stringify(this.rollup, null, 2));
|
|
11746
11421
|
} catch (e) {
|
|
@@ -11869,10 +11544,10 @@ var UsageLedger = class {
|
|
|
11869
11544
|
const rows = [];
|
|
11870
11545
|
for (const month of months) {
|
|
11871
11546
|
const file = this.ledgerFile(month);
|
|
11872
|
-
if (!
|
|
11547
|
+
if (!fs19.existsSync(file)) continue;
|
|
11873
11548
|
let content = "";
|
|
11874
11549
|
try {
|
|
11875
|
-
content =
|
|
11550
|
+
content = fs19.readFileSync(file, "utf-8");
|
|
11876
11551
|
} catch {
|
|
11877
11552
|
continue;
|
|
11878
11553
|
}
|
|
@@ -11981,10 +11656,10 @@ var UsageLedger = class {
|
|
|
11981
11656
|
const seen = /* @__PURE__ */ new Set();
|
|
11982
11657
|
for (const month of this.monthsInRange("", "")) {
|
|
11983
11658
|
const file = this.ledgerFile(month);
|
|
11984
|
-
if (!
|
|
11659
|
+
if (!fs19.existsSync(file)) continue;
|
|
11985
11660
|
let content = "";
|
|
11986
11661
|
try {
|
|
11987
|
-
content =
|
|
11662
|
+
content = fs19.readFileSync(file, "utf-8");
|
|
11988
11663
|
} catch {
|
|
11989
11664
|
continue;
|
|
11990
11665
|
}
|
|
@@ -13295,7 +12970,7 @@ data: ${JSON.stringify(entry.data)}
|
|
|
13295
12970
|
softThresholdPct: parseRatio(process.env.COMPACTION_SOFT_THRESHOLD_PCT),
|
|
13296
12971
|
capTokens: parseOptionalPositiveNumber(process.env.COMPACTION_CAP_TOKENS) ?? null,
|
|
13297
12972
|
// 超预算工具结果按租户/工作区隔离落盘(多租户共用一个状态目录会混内容)
|
|
13298
|
-
toolResultDir:
|
|
12973
|
+
toolResultDir: path22.join(workspace, ".agent", "tool-results")
|
|
13299
12974
|
});
|
|
13300
12975
|
engine.setApprover(this._makeApprover(rt));
|
|
13301
12976
|
const mcpConfigs = loadServerMcpConfigs(tenant);
|
|
@@ -13469,132 +13144,912 @@ var ApiError = class extends Error {
|
|
|
13469
13144
|
this.status = status;
|
|
13470
13145
|
this.code = code;
|
|
13471
13146
|
}
|
|
13472
|
-
status;
|
|
13473
|
-
code;
|
|
13474
|
-
};
|
|
13475
|
-
|
|
13476
|
-
// src/server/
|
|
13477
|
-
|
|
13478
|
-
|
|
13479
|
-
|
|
13147
|
+
status;
|
|
13148
|
+
code;
|
|
13149
|
+
};
|
|
13150
|
+
|
|
13151
|
+
// src/server/projects.ts
|
|
13152
|
+
var DEFAULT_MODEL = () => process.env.OPENAI_MODEL || process.env.MODEL || "gpt-4o";
|
|
13153
|
+
function toProjectSummary(store, tenant) {
|
|
13154
|
+
return {
|
|
13155
|
+
id: tenant.id,
|
|
13156
|
+
name: tenant.name ?? tenant.id,
|
|
13157
|
+
model: tenant.model,
|
|
13158
|
+
baseURL: tenant.provider?.baseURL ?? "",
|
|
13159
|
+
hasApiKey: Boolean(tenant.provider?.apiKey),
|
|
13160
|
+
workspaceRoot: tenant.workspaceRoot ?? null,
|
|
13161
|
+
sessionCount: store.listSessions(tenant.id).length
|
|
13162
|
+
};
|
|
13163
|
+
}
|
|
13164
|
+
function providerViews(tenant) {
|
|
13165
|
+
return {
|
|
13166
|
+
activeProviderId: tenant.activeProviderId ?? null,
|
|
13167
|
+
providers: (tenant.llmProviders ?? []).map((p) => ({
|
|
13168
|
+
id: p.id,
|
|
13169
|
+
name: p.name,
|
|
13170
|
+
type: p.type ?? "",
|
|
13171
|
+
baseURL: p.baseURL,
|
|
13172
|
+
model: p.model,
|
|
13173
|
+
models: p.models ?? [],
|
|
13174
|
+
modelMeta: p.modelMeta ?? [],
|
|
13175
|
+
hasApiKey: Boolean(p.apiKey)
|
|
13176
|
+
}))
|
|
13177
|
+
};
|
|
13178
|
+
}
|
|
13179
|
+
function applyProvidersPatch(tenant, raw) {
|
|
13180
|
+
if (Array.isArray(raw.providers)) {
|
|
13181
|
+
const existing = new Map((tenant.llmProviders ?? []).map((p) => [p.id, p]));
|
|
13182
|
+
const next = [];
|
|
13183
|
+
for (const item of raw.providers) {
|
|
13184
|
+
if (!item || typeof item !== "object") continue;
|
|
13185
|
+
const o = item;
|
|
13186
|
+
const id = String(o.id ?? "").trim() || newId();
|
|
13187
|
+
const prev = existing.get(id);
|
|
13188
|
+
const apiKey = typeof o.apiKey === "string" && o.apiKey.trim() ? o.apiKey.trim() : prev?.apiKey;
|
|
13189
|
+
const models = normalizeModelList(o.models) ?? prev?.models;
|
|
13190
|
+
const modelMeta = normalizeModelMeta(o.modelMeta) ?? prev?.modelMeta;
|
|
13191
|
+
next.push({
|
|
13192
|
+
id,
|
|
13193
|
+
name: String(o.name ?? "").trim() || id,
|
|
13194
|
+
type: typeof o.type === "string" ? o.type : prev?.type,
|
|
13195
|
+
baseURL: String(o.baseURL ?? "").trim(),
|
|
13196
|
+
model: String(o.model ?? "").trim(),
|
|
13197
|
+
...apiKey ? { apiKey } : {},
|
|
13198
|
+
...models ? { models } : {},
|
|
13199
|
+
...modelMeta ? { modelMeta } : {}
|
|
13200
|
+
});
|
|
13201
|
+
}
|
|
13202
|
+
tenant.llmProviders = next;
|
|
13203
|
+
}
|
|
13204
|
+
if (typeof raw.activeProviderId === "string") {
|
|
13205
|
+
const activeId = raw.activeProviderId.trim();
|
|
13206
|
+
tenant.activeProviderId = activeId || void 0;
|
|
13207
|
+
const entry = (tenant.llmProviders ?? []).find((p) => p.id === activeId);
|
|
13208
|
+
if (entry) {
|
|
13209
|
+
tenant.provider = tenant.provider ?? {};
|
|
13210
|
+
tenant.provider.baseURL = entry.baseURL || void 0;
|
|
13211
|
+
if (entry.apiKey) tenant.provider.apiKey = entry.apiKey;
|
|
13212
|
+
if (entry.model) tenant.model = entry.model;
|
|
13213
|
+
}
|
|
13214
|
+
}
|
|
13215
|
+
}
|
|
13216
|
+
function allProjectSummaries(store) {
|
|
13217
|
+
return store.listTenants().map((id) => store.loadTenant(id)).filter((t) => t !== null).map((t) => toProjectSummary(store, t));
|
|
13218
|
+
}
|
|
13219
|
+
function lastUserMessage(rec) {
|
|
13220
|
+
const sent = (rec.lastInput ?? "").trim();
|
|
13221
|
+
if (sent) {
|
|
13222
|
+
return sent.length > LAST_USER_MESSAGE_MAX ? `${sent.slice(0, LAST_USER_MESSAGE_MAX)}\u2026` : sent;
|
|
13223
|
+
}
|
|
13224
|
+
const msgs = rec.messages;
|
|
13225
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
13226
|
+
const m = msgs[i];
|
|
13227
|
+
if (!m || m.role !== "user" || typeof m.content !== "string") continue;
|
|
13228
|
+
const text = m.content.trim();
|
|
13229
|
+
if (!text) continue;
|
|
13230
|
+
return text.length > LAST_USER_MESSAGE_MAX ? `${text.slice(0, LAST_USER_MESSAGE_MAX)}\u2026` : text;
|
|
13231
|
+
}
|
|
13232
|
+
return null;
|
|
13233
|
+
}
|
|
13234
|
+
function lastCompletedAt(rec) {
|
|
13235
|
+
if (rec.lastCompletedAt) return rec.lastCompletedAt;
|
|
13236
|
+
if (rec.status !== "completed") return null;
|
|
13237
|
+
const msgs = rec.messages;
|
|
13238
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
13239
|
+
const m = msgs[i];
|
|
13240
|
+
if (!m || m.role !== "assistant") continue;
|
|
13241
|
+
if (typeof m.ts === "number" && Number.isFinite(m.ts)) {
|
|
13242
|
+
return new Date(m.ts).toISOString();
|
|
13243
|
+
}
|
|
13244
|
+
return null;
|
|
13245
|
+
}
|
|
13246
|
+
return null;
|
|
13247
|
+
}
|
|
13248
|
+
function allSessionStates(store, manager) {
|
|
13249
|
+
const out = [];
|
|
13250
|
+
for (const id of store.listTenants()) {
|
|
13251
|
+
const t = store.loadTenant(id);
|
|
13252
|
+
if (!t) continue;
|
|
13253
|
+
try {
|
|
13254
|
+
for (const s of manager.listSessions(t.id)) {
|
|
13255
|
+
out.push({
|
|
13256
|
+
projectId: t.id,
|
|
13257
|
+
projectName: t.name ?? t.id,
|
|
13258
|
+
sessionId: s.sessionId,
|
|
13259
|
+
name: s.name ?? null,
|
|
13260
|
+
status: s.status,
|
|
13261
|
+
lastUserMessage: lastUserMessage(s),
|
|
13262
|
+
lastCompletedAt: lastCompletedAt(s)
|
|
13263
|
+
});
|
|
13264
|
+
}
|
|
13265
|
+
} catch {
|
|
13266
|
+
}
|
|
13267
|
+
}
|
|
13268
|
+
return out;
|
|
13269
|
+
}
|
|
13270
|
+
function ensureNodeId(store) {
|
|
13271
|
+
let id = store.loadNodeId();
|
|
13272
|
+
if (!id) {
|
|
13273
|
+
id = newId();
|
|
13274
|
+
store.saveNodeId(id);
|
|
13275
|
+
}
|
|
13276
|
+
return id;
|
|
13277
|
+
}
|
|
13278
|
+
function createProject(store, input) {
|
|
13279
|
+
const raw = input ?? {};
|
|
13280
|
+
const id = String(raw.id ?? "").trim() || newId();
|
|
13281
|
+
if (store.loadTenant(id)) {
|
|
13282
|
+
throw new ApiError(409, "project_exists", `\u9879\u76EE ${id} \u5DF2\u5B58\u5728`);
|
|
13283
|
+
}
|
|
13284
|
+
const workspaceRoot = typeof raw.workspaceRoot === "string" && raw.workspaceRoot.trim() ? path23.resolve(raw.workspaceRoot.trim()) : void 0;
|
|
13285
|
+
const explicitName = typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : "";
|
|
13286
|
+
const defaultName = workspaceRoot ? path23.basename(workspaceRoot) : id;
|
|
13287
|
+
const tenant = {
|
|
13288
|
+
id,
|
|
13289
|
+
name: explicitName || defaultName,
|
|
13290
|
+
apiKey: generateApiKey(),
|
|
13291
|
+
model: typeof raw.model === "string" && raw.model.trim() ? raw.model.trim() : DEFAULT_MODEL(),
|
|
13292
|
+
provider: {
|
|
13293
|
+
apiKey: typeof raw.providerApiKey === "string" && raw.providerApiKey.trim() ? raw.providerApiKey.trim() : void 0,
|
|
13294
|
+
baseURL: typeof raw.baseURL === "string" && raw.baseURL.trim() ? raw.baseURL.trim() : void 0
|
|
13295
|
+
},
|
|
13296
|
+
workspaceRoot,
|
|
13297
|
+
allowedCommands: Array.isArray(raw.allowedCommands) ? raw.allowedCommands.map((c) => String(c)) : []
|
|
13298
|
+
};
|
|
13299
|
+
const def = nodeDefaultProvider(store);
|
|
13300
|
+
if (def) {
|
|
13301
|
+
if (!tenant.provider?.apiKey && def.apiKey) tenant.provider = { ...tenant.provider, apiKey: def.apiKey };
|
|
13302
|
+
if (!tenant.provider?.baseURL && def.baseURL) tenant.provider = { ...tenant.provider, baseURL: def.baseURL };
|
|
13303
|
+
if (!(typeof raw.model === "string" && raw.model.trim()) && def.model) tenant.model = def.model;
|
|
13304
|
+
const nodeCfg = store.loadNodeLlm();
|
|
13305
|
+
tenant.llmProviders = nodeCfg.providers.map((p) => ({ ...p }));
|
|
13306
|
+
tenant.activeProviderId = nodeCfg.defaultProviderId ?? nodeCfg.providers[0]?.id;
|
|
13307
|
+
}
|
|
13308
|
+
store.saveTenant(tenant);
|
|
13309
|
+
return tenant;
|
|
13310
|
+
}
|
|
13311
|
+
function buildNodeInfo(store, opts) {
|
|
13312
|
+
return {
|
|
13313
|
+
nodeId: opts.nodeId ?? ensureNodeId(store),
|
|
13314
|
+
platform: process.platform,
|
|
13315
|
+
mode: process.env.NODE_MODE ?? "standalone",
|
|
13316
|
+
version: "0.2.12",
|
|
13317
|
+
admin: opts.admin,
|
|
13318
|
+
projects: opts.projects
|
|
13319
|
+
};
|
|
13320
|
+
}
|
|
13321
|
+
|
|
13322
|
+
// src/server/fleet-config.ts
|
|
13323
|
+
init_cjs_shims();
|
|
13324
|
+
function fleetConfigFromEnv(store) {
|
|
13325
|
+
const fleetToken = process.env.FLEET_TOKEN;
|
|
13326
|
+
const fleetSecret = process.env.FLEET_SECRET;
|
|
13327
|
+
if (!fleetToken || !fleetSecret) return null;
|
|
13328
|
+
return {
|
|
13329
|
+
hubUrl: process.env.HUB_URL,
|
|
13330
|
+
fleetToken,
|
|
13331
|
+
fleetSecret,
|
|
13332
|
+
nodeId: ensureNodeId(store),
|
|
13333
|
+
gatewayUrl: process.env.FLEET_GATEWAY_URL
|
|
13334
|
+
};
|
|
13335
|
+
}
|
|
13336
|
+
function resolveFleetConfig(store) {
|
|
13337
|
+
const saved = store.loadFleetCredential();
|
|
13338
|
+
if (saved?.fleetToken && saved.fleetSecret) {
|
|
13339
|
+
return { ...saved, nodeId: saved.nodeId || ensureNodeId(store) };
|
|
13340
|
+
}
|
|
13341
|
+
return fleetConfigFromEnv(store);
|
|
13342
|
+
}
|
|
13343
|
+
|
|
13344
|
+
// src/cli/account-enroll.ts
|
|
13345
|
+
var SKIP_ANSWERS = /* @__PURE__ */ new Set(["-", "skip", "none", "no"]);
|
|
13346
|
+
function resolveDefaultHub(hubUrl, env3 = process.env) {
|
|
13347
|
+
return (hubUrl ?? env3.HUB_URL ?? DEFAULT_HUB_URL).trim().replace(/\/$/, "");
|
|
13348
|
+
}
|
|
13349
|
+
function parseHubAnswer(answer, fallback) {
|
|
13350
|
+
const a = answer.trim();
|
|
13351
|
+
if (SKIP_ANSWERS.has(a.toLowerCase())) return null;
|
|
13352
|
+
return (a || fallback).replace(/\/$/, "");
|
|
13353
|
+
}
|
|
13354
|
+
async function promptHubUrl(rl2, hubUrl) {
|
|
13355
|
+
const fallback = resolveDefaultHub(hubUrl);
|
|
13356
|
+
const answer = await rl2.question(`Hub \u5730\u5740 [${fallback}]\uFF1A`);
|
|
13357
|
+
return parseHubAnswer(answer, fallback);
|
|
13358
|
+
}
|
|
13359
|
+
async function promptAccountLogin(rl2, hubUrl) {
|
|
13360
|
+
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");
|
|
13361
|
+
const mode = (await rl2.question("\u8BF7\u9009\u62E9 [1]\uFF1A")).trim() || "1";
|
|
13362
|
+
const input = {};
|
|
13363
|
+
if (mode === "1") {
|
|
13364
|
+
input.email = (await rl2.question("\u90AE\u7BB1\uFF1A")).trim();
|
|
13365
|
+
input.password = await askHidden(rl2, "\u5BC6\u7801\uFF1A");
|
|
13366
|
+
if (!input.email || !input.password) {
|
|
13367
|
+
cliErr("\u90AE\u7BB1\u4E0E\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
13368
|
+
return null;
|
|
13369
|
+
}
|
|
13370
|
+
} else if (mode === "2") {
|
|
13371
|
+
input.phone = (await rl2.question("\u624B\u673A\u53F7\uFF1A")).trim();
|
|
13372
|
+
input.password = await askHidden(rl2, "\u5BC6\u7801\uFF1A");
|
|
13373
|
+
if (!input.phone || !input.password) {
|
|
13374
|
+
cliErr("\u624B\u673A\u53F7\u4E0E\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
13375
|
+
return null;
|
|
13376
|
+
}
|
|
13377
|
+
} else if (mode === "3") {
|
|
13378
|
+
input.phone = (await rl2.question("\u624B\u673A\u53F7\uFF1A")).trim();
|
|
13379
|
+
if (!input.phone) {
|
|
13380
|
+
cliErr("\u624B\u673A\u53F7\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
13381
|
+
return null;
|
|
13382
|
+
}
|
|
13383
|
+
try {
|
|
13384
|
+
const sent = await hubSendSms(resolveDefaultHub(hubUrl), {
|
|
13385
|
+
phone: input.phone,
|
|
13386
|
+
purpose: "login"
|
|
13387
|
+
});
|
|
13388
|
+
if (sent.debugCode) cliLog(`\uFF08\u8C03\u8BD5\u6A21\u5F0F\u9A8C\u8BC1\u7801\uFF1A${sent.debugCode}\uFF09`);
|
|
13389
|
+
else cliLog("\u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001\uFF0C5 \u5206\u949F\u5185\u6709\u6548\u3002");
|
|
13390
|
+
} catch (e) {
|
|
13391
|
+
cliErr(`\u77ED\u4FE1\u9A8C\u8BC1\u7801\u53D1\u9001\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
13392
|
+
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");
|
|
13393
|
+
cliLog(" zqagent link --hub <Hub\u5730\u5740> --code <\u63A5\u5165\u7801>");
|
|
13394
|
+
return null;
|
|
13395
|
+
}
|
|
13396
|
+
input.code = (await rl2.question("\u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF1A")).trim();
|
|
13397
|
+
if (!input.code) {
|
|
13398
|
+
cliErr("\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
13399
|
+
return null;
|
|
13400
|
+
}
|
|
13401
|
+
} else {
|
|
13402
|
+
cliErr("\u672A\u77E5\u7684\u767B\u5F55\u65B9\u5F0F\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
13403
|
+
return null;
|
|
13404
|
+
}
|
|
13405
|
+
return input;
|
|
13406
|
+
}
|
|
13407
|
+
async function promptLinkAccount(rl2, hubUrl, opts = {}) {
|
|
13408
|
+
const fallback = resolveDefaultHub(hubUrl);
|
|
13409
|
+
let resolved = fallback;
|
|
13410
|
+
if (opts.askHub !== false) {
|
|
13411
|
+
const answer = await promptHubUrl(rl2, fallback);
|
|
13412
|
+
if (!answer) {
|
|
13413
|
+
cliLog("\u5DF2\u8DF3\u8FC7\u63A5\u5165\uFF1A\u8282\u70B9\u4FDD\u6301\u7EAF\u672C\u5730\u8FD0\u884C\u3002");
|
|
13414
|
+
return null;
|
|
13415
|
+
}
|
|
13416
|
+
resolved = answer;
|
|
13417
|
+
}
|
|
13418
|
+
const auth = await promptAccountLogin(rl2, resolved);
|
|
13419
|
+
if (!auth) return null;
|
|
13420
|
+
return { hubUrl: resolved, auth };
|
|
13421
|
+
}
|
|
13422
|
+
async function promptPassword(rl2, prompt = "\u5BC6\u7801\uFF1A") {
|
|
13423
|
+
return askHidden(rl2, prompt);
|
|
13424
|
+
}
|
|
13425
|
+
function resolveDataDir(dataDir) {
|
|
13426
|
+
return path24.resolve(dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
|
|
13427
|
+
}
|
|
13428
|
+
async function maybeAccountEnroll(opts = {}) {
|
|
13429
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return;
|
|
13430
|
+
let store;
|
|
13431
|
+
try {
|
|
13432
|
+
store = new Store(resolveDataDir(opts.dataDir));
|
|
13433
|
+
if (resolveFleetConfig(store)) return;
|
|
13434
|
+
} catch (e) {
|
|
13435
|
+
cliErr(`\u63A5\u5165\u68C0\u67E5\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
13436
|
+
return;
|
|
13437
|
+
}
|
|
13438
|
+
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
13439
|
+
try {
|
|
13440
|
+
await runWizard(rl2, store, opts);
|
|
13441
|
+
} catch (e) {
|
|
13442
|
+
cliErr(`\u63A5\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
13443
|
+
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>");
|
|
13444
|
+
} finally {
|
|
13445
|
+
rl2.close();
|
|
13446
|
+
}
|
|
13447
|
+
}
|
|
13448
|
+
async function runWizard(rl2, store, opts) {
|
|
13449
|
+
cliLog("");
|
|
13450
|
+
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");
|
|
13451
|
+
const prompted = await promptLinkAccount(rl2, opts.hubUrl);
|
|
13452
|
+
if (!prompted) return;
|
|
13453
|
+
const nodeId = ensureNodeId(store);
|
|
13454
|
+
const cred = await hubEnrollByAccount(prompted.hubUrl, {
|
|
13455
|
+
...prompted.auth,
|
|
13456
|
+
nodeId,
|
|
13457
|
+
label: opts.label
|
|
13458
|
+
});
|
|
13459
|
+
store.saveFleetCredential({
|
|
13460
|
+
...cred,
|
|
13461
|
+
label: opts.label ?? cred.label,
|
|
13462
|
+
enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13463
|
+
});
|
|
13464
|
+
cliLog(`\u2705 \u5DF2\u63A5\u5165 Hub\uFF1A\u8282\u70B9 ${cred.nodeId}\uFF08\u7F51\u5173 ${cred.gatewayUrl ?? "\u672A\u4E0B\u53D1"}\uFF09`);
|
|
13465
|
+
cliLog(" \u51ED\u636E\u5DF2\u4FDD\u5B58\u5230 fleet.json\uFF0C\u672C\u6B21\u542F\u52A8\u5373\u8FDE\u63A5 Hub\u3002");
|
|
13466
|
+
}
|
|
13467
|
+
async function askHidden(rl2, prompt) {
|
|
13468
|
+
if (!process.stdin.isTTY) return (await rl2.question(prompt)).trim();
|
|
13469
|
+
return new Promise((resolve24) => {
|
|
13470
|
+
const saved = process.stdin.listeners("data");
|
|
13471
|
+
process.stdin.removeAllListeners("data");
|
|
13472
|
+
cliWrite(prompt);
|
|
13473
|
+
rl2.pause();
|
|
13474
|
+
process.stdin.setRawMode(true);
|
|
13475
|
+
process.stdin.resume();
|
|
13476
|
+
let buf = "";
|
|
13477
|
+
const cleanup = () => {
|
|
13478
|
+
process.stdin.removeListener("data", onData);
|
|
13479
|
+
for (const listener of saved) {
|
|
13480
|
+
process.stdin.on("data", listener);
|
|
13481
|
+
}
|
|
13482
|
+
process.stdin.setRawMode(true);
|
|
13483
|
+
rl2.resume();
|
|
13484
|
+
};
|
|
13485
|
+
const onData = (chunk) => {
|
|
13486
|
+
const s = chunk.toString().replace(/\x1b\[[0-9;?]*[A-Za-z~]/g, "").replace(/\x1bO[A-Za-z]/g, "");
|
|
13487
|
+
for (const ch of s) {
|
|
13488
|
+
if (ch === "\r" || ch === "\n") {
|
|
13489
|
+
cleanup();
|
|
13490
|
+
cliWrite("\n");
|
|
13491
|
+
resolve24(buf);
|
|
13492
|
+
return;
|
|
13493
|
+
}
|
|
13494
|
+
if (ch === "") {
|
|
13495
|
+
cleanup();
|
|
13496
|
+
cliWrite("\n");
|
|
13497
|
+
resolve24("");
|
|
13498
|
+
return;
|
|
13499
|
+
}
|
|
13500
|
+
if (ch === "\x7F" || ch === "\b") {
|
|
13501
|
+
if (buf.length > 0) {
|
|
13502
|
+
buf = buf.slice(0, -1);
|
|
13503
|
+
cliWrite("\b \b");
|
|
13504
|
+
}
|
|
13505
|
+
} else if (ch >= " ") {
|
|
13506
|
+
buf += ch;
|
|
13507
|
+
cliWrite("*");
|
|
13508
|
+
}
|
|
13509
|
+
}
|
|
13510
|
+
};
|
|
13511
|
+
process.stdin.on("data", onData);
|
|
13512
|
+
});
|
|
13513
|
+
}
|
|
13514
|
+
|
|
13515
|
+
// src/cli/serve-instances.ts
|
|
13516
|
+
init_cjs_shims();
|
|
13517
|
+
var import_node_child_process5 = require("child_process");
|
|
13518
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
13519
|
+
var os5 = __toESM(require("os"), 1);
|
|
13520
|
+
var path26 = __toESM(require("path"), 1);
|
|
13521
|
+
|
|
13522
|
+
// src/update/platform.ts
|
|
13523
|
+
init_cjs_shims();
|
|
13524
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
13525
|
+
var os4 = __toESM(require("os"), 1);
|
|
13526
|
+
var path25 = __toESM(require("path"), 1);
|
|
13527
|
+
var import_node_child_process4 = require("child_process");
|
|
13528
|
+
var import_node_module3 = require("module");
|
|
13529
|
+
function currentVersion() {
|
|
13530
|
+
const injected = "0.2.12"?.trim();
|
|
13531
|
+
if (injected) return injected;
|
|
13532
|
+
try {
|
|
13533
|
+
const req2 = (0, import_node_module3.createRequire)(importMetaUrl);
|
|
13534
|
+
const pkg = req2("../../package.json");
|
|
13535
|
+
if (pkg?.version) return pkg.version;
|
|
13536
|
+
} catch {
|
|
13537
|
+
}
|
|
13538
|
+
return "dev";
|
|
13539
|
+
}
|
|
13540
|
+
function isSeaRuntime() {
|
|
13541
|
+
if (process.env.ZQAGENT_SEA === "1") return true;
|
|
13542
|
+
const base = path25.basename(process.execPath).toLowerCase().replace(/\.exe$/, "");
|
|
13543
|
+
return base !== "node" && base !== "nodejs";
|
|
13544
|
+
}
|
|
13545
|
+
var DEFAULT_SERVICE_NAME = "zqagent";
|
|
13546
|
+
var DEFAULT_SERVICE_LABEL = "com.zqagent.node";
|
|
13547
|
+
function serviceManagerFromCgroup(cgroup, serviceName = DEFAULT_SERVICE_NAME) {
|
|
13548
|
+
const unitName = `${serviceName}.service`;
|
|
13549
|
+
for (const line of cgroup.split("\n")) {
|
|
13550
|
+
const idx = line.lastIndexOf(":");
|
|
13551
|
+
if (idx < 0) continue;
|
|
13552
|
+
const unitPath = line.slice(idx + 1).trim();
|
|
13553
|
+
if (unitPath.split("/").includes(unitName)) return "systemd";
|
|
13554
|
+
}
|
|
13555
|
+
return null;
|
|
13556
|
+
}
|
|
13557
|
+
function launchdDomain() {
|
|
13558
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
13559
|
+
return uid === 0 ? "system" : `gui/${uid}`;
|
|
13560
|
+
}
|
|
13561
|
+
function launchdLabel() {
|
|
13562
|
+
return process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL;
|
|
13563
|
+
}
|
|
13564
|
+
function launchdPlistPath() {
|
|
13565
|
+
const label = launchdLabel();
|
|
13566
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
13567
|
+
if (uid === 0) return `/Library/LaunchDaemons/${label}.plist`;
|
|
13568
|
+
return path25.join(os4.homedir(), "Library", "LaunchAgents", `${label}.plist`);
|
|
13569
|
+
}
|
|
13570
|
+
function serviceManagerFromLaunchctl(output, pid, execPath, sea = true) {
|
|
13571
|
+
const pidMatch = /^\s*pid = (\d+)\s*$/m.exec(output);
|
|
13572
|
+
if (pidMatch && Number(pidMatch[1]) === pid) return "launchd";
|
|
13573
|
+
const program = /^\s*program = (.+?)\s*$/m.exec(output);
|
|
13574
|
+
if (program) {
|
|
13575
|
+
const shown = program[1].replace(/^"|"$/g, "");
|
|
13576
|
+
if (path25.resolve(shown) === path25.resolve(execPath)) return "launchd";
|
|
13577
|
+
}
|
|
13578
|
+
if (!sea && /^\s*state = /m.test(output)) return "launchd";
|
|
13579
|
+
return null;
|
|
13580
|
+
}
|
|
13581
|
+
function parseLaunchdEnvironment(xml) {
|
|
13582
|
+
const out = {};
|
|
13583
|
+
const marker = xml.indexOf("<key>EnvironmentVariables</key>");
|
|
13584
|
+
if (marker < 0) return out;
|
|
13585
|
+
const open = xml.indexOf("<dict>", marker);
|
|
13586
|
+
if (open < 0) return out;
|
|
13587
|
+
const close = xml.indexOf("</dict>", open);
|
|
13588
|
+
if (close < 0) return out;
|
|
13589
|
+
const body = xml.slice(open + "<dict>".length, close);
|
|
13590
|
+
for (const m of body.matchAll(/<key>([^<]+)<\/key>\s*<string>([^<]*)<\/string>/g)) {
|
|
13591
|
+
out[m[1]] = m[2];
|
|
13592
|
+
}
|
|
13593
|
+
return out;
|
|
13594
|
+
}
|
|
13595
|
+
function detectServiceManager() {
|
|
13596
|
+
if (process.platform === "darwin") return detectLaunchd();
|
|
13597
|
+
if (process.platform !== "linux") return null;
|
|
13598
|
+
const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
|
|
13599
|
+
try {
|
|
13600
|
+
return serviceManagerFromCgroup(
|
|
13601
|
+
fs20.readFileSync("/proc/self/cgroup", "utf8"),
|
|
13602
|
+
serviceName
|
|
13603
|
+
);
|
|
13604
|
+
} catch {
|
|
13605
|
+
return null;
|
|
13606
|
+
}
|
|
13607
|
+
}
|
|
13608
|
+
function detectLaunchd() {
|
|
13609
|
+
try {
|
|
13610
|
+
const res = (0, import_node_child_process4.spawnSync)(
|
|
13611
|
+
"launchctl",
|
|
13612
|
+
["print", `${launchdDomain()}/${launchdLabel()}`],
|
|
13613
|
+
{ encoding: "utf8", timeout: 3e3 }
|
|
13614
|
+
);
|
|
13615
|
+
if (res.status !== 0 || !res.stdout) return null;
|
|
13616
|
+
return serviceManagerFromLaunchctl(
|
|
13617
|
+
res.stdout,
|
|
13618
|
+
process.pid,
|
|
13619
|
+
process.execPath,
|
|
13620
|
+
isSeaRuntime()
|
|
13621
|
+
);
|
|
13622
|
+
} catch {
|
|
13623
|
+
return null;
|
|
13624
|
+
}
|
|
13625
|
+
}
|
|
13626
|
+
function serviceManager() {
|
|
13627
|
+
const v = process.env.ZQAGENT_SERVICE_MANAGER?.trim().toLowerCase();
|
|
13628
|
+
if (v === "systemd" || v === "launchd") return v;
|
|
13629
|
+
return detectServiceManager();
|
|
13630
|
+
}
|
|
13631
|
+
function parseServiceEnvironment(raw) {
|
|
13632
|
+
const out = {};
|
|
13633
|
+
for (const token of raw.trim().split(/\s+/)) {
|
|
13634
|
+
const idx = token.indexOf("=");
|
|
13635
|
+
if (idx > 0) out[token.slice(0, idx)] = token.slice(idx + 1);
|
|
13636
|
+
}
|
|
13637
|
+
return out;
|
|
13638
|
+
}
|
|
13639
|
+
var cachedServiceEnv = null;
|
|
13640
|
+
function readServiceEnvironment() {
|
|
13641
|
+
const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
|
|
13642
|
+
try {
|
|
13643
|
+
const res = (0, import_node_child_process4.spawnSync)(
|
|
13644
|
+
"systemctl",
|
|
13645
|
+
["show", serviceName, "--property=Environment", "--value", "--no-pager"],
|
|
13646
|
+
{ encoding: "utf8", timeout: 3e3 }
|
|
13647
|
+
);
|
|
13648
|
+
if (res.status !== 0 || !res.stdout) return {};
|
|
13649
|
+
return parseServiceEnvironment(res.stdout);
|
|
13650
|
+
} catch {
|
|
13651
|
+
return {};
|
|
13652
|
+
}
|
|
13653
|
+
}
|
|
13654
|
+
function serviceEnvValue(key) {
|
|
13655
|
+
if (process.platform === "darwin") {
|
|
13656
|
+
if (serviceManager() !== "launchd") return void 0;
|
|
13657
|
+
cachedLaunchdEnv ??= readLaunchdEnvironment();
|
|
13658
|
+
return cachedLaunchdEnv[key];
|
|
13659
|
+
}
|
|
13660
|
+
if (process.platform !== "linux") return void 0;
|
|
13661
|
+
if (serviceManager() !== "systemd") return void 0;
|
|
13662
|
+
cachedServiceEnv ??= readServiceEnvironment();
|
|
13663
|
+
return cachedServiceEnv[key];
|
|
13664
|
+
}
|
|
13665
|
+
var cachedLaunchdEnv = null;
|
|
13666
|
+
function readLaunchdEnvironment() {
|
|
13667
|
+
try {
|
|
13668
|
+
return parseLaunchdEnvironment(fs20.readFileSync(launchdPlistPath(), "utf8"));
|
|
13669
|
+
} catch {
|
|
13670
|
+
return {};
|
|
13671
|
+
}
|
|
13672
|
+
}
|
|
13673
|
+
function selfUpdateCapability(hasPublicKey) {
|
|
13674
|
+
if (!isSeaRuntime()) {
|
|
13675
|
+
return {
|
|
13676
|
+
ok: false,
|
|
13677
|
+
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"
|
|
13678
|
+
};
|
|
13679
|
+
}
|
|
13680
|
+
if (!serviceManager()) {
|
|
13681
|
+
return {
|
|
13682
|
+
ok: false,
|
|
13683
|
+
reason: "\u672A\u88AB systemd/launchd \u6258\u7BA1\uFF1A\u8BF7\u7528 deploy/service/install.sh \u5B89\u88C5\uFF0C\u6216\u624B\u52A8\u5347\u7EA7"
|
|
13684
|
+
};
|
|
13685
|
+
}
|
|
13686
|
+
if (!hasPublicKey) {
|
|
13687
|
+
return { ok: false, reason: "\u672A\u914D\u7F6E ZQAGENT_UPDATE_PUBKEY\uFF0C\u65E0\u6CD5\u9A8C\u7B7E\uFF0C\u5DF2\u7981\u7528\u81EA\u52A8\u66F4\u65B0" };
|
|
13688
|
+
}
|
|
13689
|
+
return { ok: true };
|
|
13690
|
+
}
|
|
13480
13691
|
|
|
13481
|
-
// src/
|
|
13482
|
-
|
|
13483
|
-
var
|
|
13484
|
-
var
|
|
13485
|
-
|
|
13486
|
-
|
|
13487
|
-
|
|
13488
|
-
|
|
13489
|
-
|
|
13490
|
-
|
|
13491
|
-
|
|
13492
|
-
|
|
13493
|
-
|
|
13692
|
+
// src/cli/serve-instances.ts
|
|
13693
|
+
var DEFAULT_SERVE_HOST = "127.0.0.1";
|
|
13694
|
+
var DEFAULT_SERVE_PORT = 8787;
|
|
13695
|
+
var DEFAULT_SERVICE_NAME2 = "zqagent";
|
|
13696
|
+
var DEFAULT_SERVICE_LABEL2 = "com.zqagent.node";
|
|
13697
|
+
function serveSubcommandIndex(argv) {
|
|
13698
|
+
for (let i = 1; i < argv.length; i++) {
|
|
13699
|
+
if (argv[i].startsWith("-")) continue;
|
|
13700
|
+
return argv[i] === "serve" ? i : -1;
|
|
13701
|
+
}
|
|
13702
|
+
return -1;
|
|
13703
|
+
}
|
|
13704
|
+
function parseServeArgs(argv) {
|
|
13705
|
+
const at = serveSubcommandIndex(argv);
|
|
13706
|
+
if (at < 0) return null;
|
|
13707
|
+
let dataDir = null;
|
|
13708
|
+
let host = DEFAULT_SERVE_HOST;
|
|
13709
|
+
let port = DEFAULT_SERVE_PORT;
|
|
13710
|
+
for (let i = at + 1; i < argv.length; i++) {
|
|
13711
|
+
const arg = argv[i];
|
|
13712
|
+
if (arg === "--data-dir" && argv[i + 1]) {
|
|
13713
|
+
dataDir = argv[++i];
|
|
13714
|
+
} else if (arg.startsWith("--data-dir=")) {
|
|
13715
|
+
dataDir = arg.slice("--data-dir=".length);
|
|
13716
|
+
} else if (arg === "--host" && argv[i + 1]) {
|
|
13717
|
+
host = argv[++i];
|
|
13718
|
+
} else if (arg.startsWith("--host=")) {
|
|
13719
|
+
host = arg.slice("--host=".length);
|
|
13720
|
+
} else if (arg === "--port" && argv[i + 1]) {
|
|
13721
|
+
port = Number(argv[++i]);
|
|
13722
|
+
} else if (arg.startsWith("--port=")) {
|
|
13723
|
+
port = Number(arg.slice("--port=".length));
|
|
13724
|
+
}
|
|
13725
|
+
}
|
|
13726
|
+
if (!Number.isFinite(port) || port <= 0) port = DEFAULT_SERVE_PORT;
|
|
13727
|
+
if (host === "0.0.0.0" || host === "::" || host === "") host = DEFAULT_SERVE_HOST;
|
|
13728
|
+
return { dataDir, host, port };
|
|
13729
|
+
}
|
|
13730
|
+
function buildHotCandidates(explicitDataDir, discovered, fallback) {
|
|
13731
|
+
const out = [];
|
|
13732
|
+
const push = (inst) => {
|
|
13733
|
+
if (!out.some((o) => o.dataDir === inst.dataDir)) out.push(inst);
|
|
13494
13734
|
};
|
|
13735
|
+
if (explicitDataDir) push({ dataDir: path26.resolve(explicitDataDir), ...fallback });
|
|
13736
|
+
for (const inst of discovered) if (inst.managed) push(inst);
|
|
13737
|
+
for (const inst of discovered) if (!inst.managed) push(inst);
|
|
13738
|
+
if (!explicitDataDir) push({ dataDir: path26.resolve(DEFAULT_DATA_DIR), ...fallback });
|
|
13739
|
+
return out;
|
|
13495
13740
|
}
|
|
13496
|
-
function
|
|
13741
|
+
function isWindowsAbsolute(p) {
|
|
13742
|
+
return /^[A-Za-z]:[\\/]/.test(p) || /^\\\\/.test(p);
|
|
13743
|
+
}
|
|
13744
|
+
function isAbsolutePath(p) {
|
|
13745
|
+
return path26.isAbsolute(p) || isWindowsAbsolute(p);
|
|
13746
|
+
}
|
|
13747
|
+
function normalizePath(p) {
|
|
13748
|
+
return isWindowsAbsolute(p) ? path26.win32.normalize(p) : path26.normalize(p);
|
|
13749
|
+
}
|
|
13750
|
+
function parseServeCommandLine(line) {
|
|
13751
|
+
if (!/(?:^|\s)["']?serve["']?(?=\s|$)/.test(line)) return null;
|
|
13752
|
+
const m = /--data-dir(?:=|\s+)(?:"([^"]+)"|'([^']+)'|(.+?))(?=\s+--\w|\s*$)/.exec(line);
|
|
13753
|
+
const rawDataDir = (m?.[1] ?? m?.[2] ?? m?.[3] ?? "").trim();
|
|
13754
|
+
if (!rawDataDir || !isAbsolutePath(rawDataDir)) return null;
|
|
13755
|
+
const host = /--host(?:=|\s+)(?:"([^"]+)"|'([^']+)'|(\S+))/.exec(line);
|
|
13756
|
+
const rawHost = (host?.[1] ?? host?.[2] ?? host?.[3] ?? DEFAULT_SERVE_HOST).trim();
|
|
13757
|
+
const portMatch = /--port(?:=|\s+)(\d+)/.exec(line);
|
|
13758
|
+
const port = Number(portMatch?.[1] ?? DEFAULT_SERVE_PORT);
|
|
13497
13759
|
return {
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
name: p.name,
|
|
13502
|
-
type: p.type ?? "",
|
|
13503
|
-
baseURL: p.baseURL,
|
|
13504
|
-
model: p.model,
|
|
13505
|
-
models: p.models ?? [],
|
|
13506
|
-
modelMeta: p.modelMeta ?? [],
|
|
13507
|
-
hasApiKey: Boolean(p.apiKey)
|
|
13508
|
-
}))
|
|
13760
|
+
dataDir: normalizePath(rawDataDir),
|
|
13761
|
+
host: rawHost === "0.0.0.0" || rawHost === "::" || rawHost === "" ? DEFAULT_SERVE_HOST : rawHost,
|
|
13762
|
+
port: Number.isFinite(port) && port > 0 ? port : DEFAULT_SERVE_PORT
|
|
13509
13763
|
};
|
|
13510
13764
|
}
|
|
13511
|
-
function
|
|
13512
|
-
|
|
13513
|
-
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
|
|
13525
|
-
name: String(o.name ?? "").trim() || id,
|
|
13526
|
-
type: typeof o.type === "string" ? o.type : prev?.type,
|
|
13527
|
-
baseURL: String(o.baseURL ?? "").trim(),
|
|
13528
|
-
model: String(o.model ?? "").trim(),
|
|
13529
|
-
...apiKey ? { apiKey } : {},
|
|
13530
|
-
...models ? { models } : {},
|
|
13531
|
-
...modelMeta ? { modelMeta } : {}
|
|
13532
|
-
});
|
|
13765
|
+
function processCwd(pid) {
|
|
13766
|
+
try {
|
|
13767
|
+
return fs21.readlinkSync(`/proc/${pid}/cwd`);
|
|
13768
|
+
} catch {
|
|
13769
|
+
return null;
|
|
13770
|
+
}
|
|
13771
|
+
}
|
|
13772
|
+
function processEnv(pid) {
|
|
13773
|
+
const out = {};
|
|
13774
|
+
try {
|
|
13775
|
+
const raw = fs21.readFileSync(`/proc/${pid}/environ`, "utf-8");
|
|
13776
|
+
for (const entry of raw.split("\0")) {
|
|
13777
|
+
const eq = entry.indexOf("=");
|
|
13778
|
+
if (eq > 0) out[entry.slice(0, eq)] = entry.slice(eq + 1);
|
|
13533
13779
|
}
|
|
13534
|
-
|
|
13780
|
+
} catch {
|
|
13535
13781
|
}
|
|
13536
|
-
|
|
13537
|
-
|
|
13538
|
-
|
|
13539
|
-
|
|
13540
|
-
|
|
13541
|
-
|
|
13542
|
-
|
|
13543
|
-
|
|
13544
|
-
|
|
13782
|
+
return out;
|
|
13783
|
+
}
|
|
13784
|
+
function resolveDataDir2(rawDataDir, cwd, env3) {
|
|
13785
|
+
const pick = rawDataDir ?? env3.DATA_DIR ?? null;
|
|
13786
|
+
if (pick) return path26.isAbsolute(pick) ? path26.normalize(pick) : cwd ? path26.resolve(cwd, pick) : null;
|
|
13787
|
+
return cwd ? path26.resolve(cwd, DEFAULT_DATA_DIR) : null;
|
|
13788
|
+
}
|
|
13789
|
+
function isManagedBySystemd(pid, env3) {
|
|
13790
|
+
if (env3.ZQAGENT_SERVICE_MANAGER?.trim()) return true;
|
|
13791
|
+
try {
|
|
13792
|
+
const cgroup = fs21.readFileSync(`/proc/${pid}/cgroup`, "utf-8");
|
|
13793
|
+
const serviceName = env3.ZQAGENT_SERVICE_NAME?.trim() || "zqagent";
|
|
13794
|
+
return serviceManagerFromCgroup(cgroup, serviceName) !== null;
|
|
13795
|
+
} catch {
|
|
13796
|
+
return false;
|
|
13797
|
+
}
|
|
13798
|
+
}
|
|
13799
|
+
function discoverFromProc() {
|
|
13800
|
+
const out = [];
|
|
13801
|
+
let pids;
|
|
13802
|
+
try {
|
|
13803
|
+
pids = fs21.readdirSync("/proc");
|
|
13804
|
+
} catch {
|
|
13805
|
+
return out;
|
|
13806
|
+
}
|
|
13807
|
+
for (const name of pids) {
|
|
13808
|
+
if (!/^\d+$/.test(name)) continue;
|
|
13809
|
+
const pid = Number(name);
|
|
13810
|
+
if (pid === process.pid) continue;
|
|
13811
|
+
let argv;
|
|
13812
|
+
let env3;
|
|
13813
|
+
try {
|
|
13814
|
+
argv = fs21.readFileSync(`/proc/${pid}/cmdline`, "utf-8").split("\0").filter(Boolean);
|
|
13815
|
+
env3 = processEnv(pid);
|
|
13816
|
+
} catch {
|
|
13817
|
+
continue;
|
|
13545
13818
|
}
|
|
13819
|
+
const parsed = parseServeArgs(argv);
|
|
13820
|
+
if (!parsed) continue;
|
|
13821
|
+
const dataDir = resolveDataDir2(parsed.dataDir, processCwd(pid), env3);
|
|
13822
|
+
if (!dataDir) continue;
|
|
13823
|
+
out.push({
|
|
13824
|
+
dataDir,
|
|
13825
|
+
host: parsed.host,
|
|
13826
|
+
port: parsed.port,
|
|
13827
|
+
managed: isManagedBySystemd(pid, env3)
|
|
13828
|
+
});
|
|
13546
13829
|
}
|
|
13830
|
+
return out;
|
|
13547
13831
|
}
|
|
13548
|
-
function
|
|
13549
|
-
|
|
13832
|
+
function discoverFromPs() {
|
|
13833
|
+
const out = [];
|
|
13834
|
+
const res = (0, import_node_child_process5.spawnSync)("ps", ["-axo", "command="], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
|
|
13835
|
+
if (res.status !== 0 || !res.stdout) return out;
|
|
13836
|
+
for (const line of res.stdout.split("\n")) {
|
|
13837
|
+
const inst = parseServeCommandLine(line);
|
|
13838
|
+
if (inst) out.push(inst);
|
|
13839
|
+
}
|
|
13840
|
+
return out;
|
|
13550
13841
|
}
|
|
13551
|
-
function
|
|
13552
|
-
const
|
|
13553
|
-
|
|
13554
|
-
|
|
13842
|
+
function discoverFromWindows() {
|
|
13843
|
+
const out = [];
|
|
13844
|
+
const script = `[Console]::OutputEncoding=[Text.Encoding]::UTF8; Get-CimInstance Win32_Process -Filter "Name='zqagent.exe' OR Name='node.exe'" | ForEach-Object { $_.CommandLine }`;
|
|
13845
|
+
const res = (0, import_node_child_process5.spawnSync)(
|
|
13846
|
+
"powershell.exe",
|
|
13847
|
+
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
13848
|
+
{ encoding: "utf-8", timeout: 15e3, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
|
|
13849
|
+
);
|
|
13850
|
+
if (res.status !== 0 || !res.stdout) return out;
|
|
13851
|
+
for (const line of res.stdout.replace(/^\uFEFF/, "").split(/\r?\n/)) {
|
|
13852
|
+
const inst = parseServeCommandLine(line);
|
|
13853
|
+
if (inst) out.push(inst);
|
|
13555
13854
|
}
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
|
|
13560
|
-
|
|
13561
|
-
|
|
13562
|
-
|
|
13855
|
+
return out;
|
|
13856
|
+
}
|
|
13857
|
+
function decodeXmlEntities(s) {
|
|
13858
|
+
return s.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&");
|
|
13859
|
+
}
|
|
13860
|
+
function parseLaunchdProgramArguments(xml) {
|
|
13861
|
+
const marker = xml.indexOf("<key>ProgramArguments</key>");
|
|
13862
|
+
if (marker < 0) return [];
|
|
13863
|
+
const open = xml.indexOf("<array>", marker);
|
|
13864
|
+
if (open < 0) return [];
|
|
13865
|
+
const close = xml.indexOf("</array>", open);
|
|
13866
|
+
if (close < 0) return [];
|
|
13867
|
+
return [...xml.slice(open + "<array>".length, close).matchAll(/<string>([^<]*)<\/string>/g)].map(
|
|
13868
|
+
(m) => decodeXmlEntities(m[1])
|
|
13869
|
+
);
|
|
13870
|
+
}
|
|
13871
|
+
function launchdServiceInstances() {
|
|
13872
|
+
if (process.platform !== "darwin") return [];
|
|
13873
|
+
const label = process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL2;
|
|
13874
|
+
const plists = [
|
|
13875
|
+
`/Library/LaunchDaemons/${label}.plist`,
|
|
13876
|
+
path26.join(os5.homedir(), "Library", "LaunchAgents", `${label}.plist`)
|
|
13877
|
+
];
|
|
13878
|
+
const out = [];
|
|
13879
|
+
for (const plist of plists) {
|
|
13880
|
+
let xml;
|
|
13881
|
+
try {
|
|
13882
|
+
xml = fs21.readFileSync(plist, "utf-8");
|
|
13883
|
+
} catch {
|
|
13884
|
+
continue;
|
|
13885
|
+
}
|
|
13886
|
+
const parsed = parseServeArgs(parseLaunchdProgramArguments(xml));
|
|
13887
|
+
if (!parsed?.dataDir || !isAbsolutePath(parsed.dataDir)) continue;
|
|
13888
|
+
out.push({
|
|
13889
|
+
dataDir: normalizePath(parsed.dataDir),
|
|
13890
|
+
host: parsed.host,
|
|
13891
|
+
port: parsed.port,
|
|
13892
|
+
managed: true
|
|
13893
|
+
});
|
|
13563
13894
|
}
|
|
13564
|
-
return
|
|
13895
|
+
return out;
|
|
13565
13896
|
}
|
|
13566
|
-
function
|
|
13567
|
-
|
|
13568
|
-
|
|
13569
|
-
|
|
13570
|
-
for (
|
|
13571
|
-
const
|
|
13572
|
-
if (
|
|
13573
|
-
|
|
13574
|
-
|
|
13897
|
+
function parseSystemdUnit(text) {
|
|
13898
|
+
let dataDir = null;
|
|
13899
|
+
let host = DEFAULT_SERVE_HOST;
|
|
13900
|
+
let port = DEFAULT_SERVE_PORT;
|
|
13901
|
+
for (const line of text.split("\n")) {
|
|
13902
|
+
const trimmed = line.trim();
|
|
13903
|
+
if (trimmed.startsWith("WorkingDirectory=")) {
|
|
13904
|
+
const v = trimmed.slice("WorkingDirectory=".length).trim();
|
|
13905
|
+
if (v && isAbsolutePath(v)) dataDir = v;
|
|
13906
|
+
} else if (trimmed.startsWith("ExecStart=")) {
|
|
13907
|
+
const tokens = trimmed.slice("ExecStart=".length).trim().split(/\s+/).map((t) => t.replace(/^["']|["']$/g, ""));
|
|
13908
|
+
const parsed = parseServeArgs(tokens);
|
|
13909
|
+
if (!parsed) continue;
|
|
13910
|
+
if (parsed.dataDir && isAbsolutePath(parsed.dataDir)) dataDir = parsed.dataDir;
|
|
13911
|
+
host = parsed.host;
|
|
13912
|
+
port = parsed.port;
|
|
13913
|
+
}
|
|
13914
|
+
}
|
|
13915
|
+
if (!dataDir) return null;
|
|
13916
|
+
return { dataDir: normalizePath(dataDir), host, port, managed: true };
|
|
13917
|
+
}
|
|
13918
|
+
function systemdServiceInstances() {
|
|
13919
|
+
if (process.platform !== "linux") return [];
|
|
13920
|
+
const unit = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME2;
|
|
13921
|
+
const configHome = process.env.XDG_CONFIG_HOME?.trim() || path26.join(os5.homedir(), ".config");
|
|
13922
|
+
const units = [
|
|
13923
|
+
`/etc/systemd/system/${unit}.service`,
|
|
13924
|
+
path26.join(configHome, "systemd", "user", `${unit}.service`)
|
|
13925
|
+
];
|
|
13926
|
+
const out = [];
|
|
13927
|
+
for (const file of units) {
|
|
13928
|
+
let text;
|
|
13929
|
+
try {
|
|
13930
|
+
text = fs21.readFileSync(file, "utf-8");
|
|
13931
|
+
} catch {
|
|
13932
|
+
continue;
|
|
13575
13933
|
}
|
|
13576
|
-
|
|
13934
|
+
const inst = parseSystemdUnit(text);
|
|
13935
|
+
if (inst) out.push(inst);
|
|
13936
|
+
}
|
|
13937
|
+
return out;
|
|
13938
|
+
}
|
|
13939
|
+
function windowsServiceInstances() {
|
|
13940
|
+
if (process.platform !== "win32") return [];
|
|
13941
|
+
const appdata = process.env.APPDATA?.trim();
|
|
13942
|
+
if (!appdata) return [];
|
|
13943
|
+
const base = path26.join(appdata, "zqagent");
|
|
13944
|
+
try {
|
|
13945
|
+
const raw = fs21.readFileSync(path26.join(base, "runtime", "service.json"), "utf-8");
|
|
13946
|
+
const v = JSON.parse(raw);
|
|
13947
|
+
const dataDir = v.dataDir && isAbsolutePath(v.dataDir) ? v.dataDir : base;
|
|
13948
|
+
const port = Number(v.port);
|
|
13949
|
+
return [
|
|
13950
|
+
{
|
|
13951
|
+
dataDir: normalizePath(dataDir),
|
|
13952
|
+
host: DEFAULT_SERVE_HOST,
|
|
13953
|
+
port: Number.isFinite(port) && port > 0 ? port : DEFAULT_SERVE_PORT,
|
|
13954
|
+
managed: true
|
|
13955
|
+
}
|
|
13956
|
+
];
|
|
13957
|
+
} catch {
|
|
13958
|
+
return [];
|
|
13959
|
+
}
|
|
13960
|
+
}
|
|
13961
|
+
function mergeServeInstances(discovered, managed) {
|
|
13962
|
+
const out = [];
|
|
13963
|
+
const push = (inst) => {
|
|
13964
|
+
if (!out.some((o) => o.dataDir === inst.dataDir)) out.push(inst);
|
|
13965
|
+
};
|
|
13966
|
+
for (const inst of discovered) {
|
|
13967
|
+
const hit = managed.find((m) => m.dataDir === inst.dataDir);
|
|
13968
|
+
push(hit ? { ...inst, managed: true } : inst);
|
|
13577
13969
|
}
|
|
13578
|
-
|
|
13970
|
+
for (const inst of managed) push(inst);
|
|
13971
|
+
return out;
|
|
13579
13972
|
}
|
|
13580
|
-
function
|
|
13581
|
-
const
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
|
|
13587
|
-
|
|
13588
|
-
|
|
13589
|
-
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
|
|
13593
|
-
|
|
13594
|
-
|
|
13595
|
-
|
|
13596
|
-
|
|
13597
|
-
|
|
13973
|
+
function discoverRunningServeInstances() {
|
|
13974
|
+
const found = process.platform === "linux" ? discoverFromProc() : process.platform === "win32" ? discoverFromWindows() : discoverFromPs();
|
|
13975
|
+
const declared = process.platform === "linux" ? systemdServiceInstances() : process.platform === "win32" ? windowsServiceInstances() : launchdServiceInstances();
|
|
13976
|
+
return mergeServeInstances(found, declared);
|
|
13977
|
+
}
|
|
13978
|
+
|
|
13979
|
+
// src/cli/link.ts
|
|
13980
|
+
function expandHome(p) {
|
|
13981
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
13982
|
+
if (!home) return p;
|
|
13983
|
+
if (p === "~") return home;
|
|
13984
|
+
if (p.startsWith("~/") || p.startsWith("~\\")) return path27.join(home, p.slice(2));
|
|
13985
|
+
return p;
|
|
13986
|
+
}
|
|
13987
|
+
function installDataDirHint() {
|
|
13988
|
+
if (process.platform === "darwin") return "$HOME/Library/Application Support/zqagent";
|
|
13989
|
+
if (process.platform === "win32") return "%APPDATA%\\zqagent";
|
|
13990
|
+
return "/var/lib/zqagent\uFF08\u9700 root\uFF1B\u666E\u901A\u7528\u6237\u7528 ~/.zqagent_data\uFF09";
|
|
13991
|
+
}
|
|
13992
|
+
function buildAccountAuth(flags, env3 = process.env) {
|
|
13993
|
+
const username = (flags.username ?? env3.ZQAGENT_HUB_USERNAME ?? "").trim();
|
|
13994
|
+
let email = (flags.email ?? "").trim();
|
|
13995
|
+
let phone = (flags.phone ?? "").trim();
|
|
13996
|
+
if (username && !email && !phone) {
|
|
13997
|
+
if (username.includes("@")) email = username;
|
|
13998
|
+
else phone = username;
|
|
13999
|
+
}
|
|
14000
|
+
if (!email && !phone) return null;
|
|
14001
|
+
const password = flags.password ?? env3.ZQAGENT_HUB_PASSWORD ?? "";
|
|
14002
|
+
const smsCode = (flags.smsCode ?? env3.ZQAGENT_HUB_SMS_CODE ?? "").trim();
|
|
14003
|
+
return {
|
|
14004
|
+
email: email ? email.toLowerCase() : void 0,
|
|
14005
|
+
phone: phone || void 0,
|
|
14006
|
+
password: password || void 0,
|
|
14007
|
+
smsCode: smsCode || void 0
|
|
14008
|
+
};
|
|
14009
|
+
}
|
|
14010
|
+
function isCompleteAccount(account) {
|
|
14011
|
+
return Boolean(account && (account.password || account.smsCode));
|
|
14012
|
+
}
|
|
14013
|
+
function parseLinkArgs(argv) {
|
|
14014
|
+
const out = {};
|
|
14015
|
+
for (let i = 0; i < argv.length; i++) {
|
|
14016
|
+
const a = argv[i];
|
|
14017
|
+
const val = argv[i + 1];
|
|
14018
|
+
if (a === "--hub") {
|
|
14019
|
+
out.hubUrl = val;
|
|
14020
|
+
i++;
|
|
14021
|
+
} else if (a === "--code") {
|
|
14022
|
+
out.code = val;
|
|
14023
|
+
i++;
|
|
14024
|
+
} else if (a === "--username" || a === "--user") {
|
|
14025
|
+
out.username = val;
|
|
14026
|
+
i++;
|
|
14027
|
+
} else if (a === "--email") {
|
|
14028
|
+
out.email = val;
|
|
14029
|
+
i++;
|
|
14030
|
+
} else if (a === "--phone") {
|
|
14031
|
+
out.phone = val;
|
|
14032
|
+
i++;
|
|
14033
|
+
} else if (a === "--password") {
|
|
14034
|
+
out.password = val;
|
|
14035
|
+
i++;
|
|
14036
|
+
} else if (a === "--sms-code") {
|
|
14037
|
+
out.smsCode = val;
|
|
14038
|
+
i++;
|
|
14039
|
+
} else if (a === "--data-dir") {
|
|
14040
|
+
out.dataDir = val;
|
|
14041
|
+
i++;
|
|
14042
|
+
} else if (a === "--label") {
|
|
14043
|
+
out.label = val;
|
|
14044
|
+
i++;
|
|
14045
|
+
} else if (a === "--host") {
|
|
14046
|
+
out.host = val;
|
|
14047
|
+
i++;
|
|
14048
|
+
} else if (a === "--port") {
|
|
14049
|
+
out.port = Number(val);
|
|
14050
|
+
i++;
|
|
14051
|
+
} else if (a === "-h" || a === "--help") {
|
|
14052
|
+
out.help = true;
|
|
13598
14053
|
}
|
|
13599
14054
|
}
|
|
13600
14055
|
return out;
|
|
@@ -13607,50 +14062,285 @@ function ensureNodeId2(store) {
|
|
|
13607
14062
|
}
|
|
13608
14063
|
return id;
|
|
13609
14064
|
}
|
|
13610
|
-
function
|
|
13611
|
-
const
|
|
13612
|
-
const
|
|
13613
|
-
|
|
13614
|
-
|
|
14065
|
+
async function probeServer(host, port, adminKey) {
|
|
14066
|
+
const ctrl = new AbortController();
|
|
14067
|
+
const timer = setTimeout(() => ctrl.abort(), 1500);
|
|
14068
|
+
try {
|
|
14069
|
+
const res = await fetch(`http://${host}:${port}/api/v1/fleet/status`, {
|
|
14070
|
+
headers: { Authorization: `Bearer ${adminKey}` },
|
|
14071
|
+
signal: ctrl.signal
|
|
14072
|
+
});
|
|
14073
|
+
return res.ok;
|
|
14074
|
+
} catch {
|
|
14075
|
+
return false;
|
|
14076
|
+
} finally {
|
|
14077
|
+
clearTimeout(timer);
|
|
13615
14078
|
}
|
|
13616
|
-
|
|
13617
|
-
|
|
13618
|
-
const
|
|
13619
|
-
|
|
13620
|
-
|
|
13621
|
-
|
|
13622
|
-
|
|
13623
|
-
model: typeof raw.model === "string" && raw.model.trim() ? raw.model.trim() : DEFAULT_MODEL(),
|
|
13624
|
-
provider: {
|
|
13625
|
-
apiKey: typeof raw.providerApiKey === "string" && raw.providerApiKey.trim() ? raw.providerApiKey.trim() : void 0,
|
|
13626
|
-
baseURL: typeof raw.baseURL === "string" && raw.baseURL.trim() ? raw.baseURL.trim() : void 0
|
|
14079
|
+
}
|
|
14080
|
+
async function enrollViaServer(host, port, adminKey, opts) {
|
|
14081
|
+
const res = await fetch(`http://${host}:${port}/api/v1/fleet/enroll`, {
|
|
14082
|
+
method: "POST",
|
|
14083
|
+
headers: {
|
|
14084
|
+
"Content-Type": "application/json",
|
|
14085
|
+
Authorization: `Bearer ${adminKey}`
|
|
13627
14086
|
},
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
|
|
13631
|
-
|
|
13632
|
-
|
|
13633
|
-
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
14087
|
+
body: JSON.stringify({
|
|
14088
|
+
hubUrl: opts.hubUrl,
|
|
14089
|
+
code: opts.code,
|
|
14090
|
+
email: opts.account?.email,
|
|
14091
|
+
phone: opts.account?.phone,
|
|
14092
|
+
password: opts.account?.password,
|
|
14093
|
+
smsCode: opts.account?.smsCode,
|
|
14094
|
+
label: opts.label
|
|
14095
|
+
})
|
|
14096
|
+
});
|
|
14097
|
+
const text = await res.text();
|
|
14098
|
+
let payload = null;
|
|
14099
|
+
try {
|
|
14100
|
+
payload = text ? JSON.parse(text) : null;
|
|
14101
|
+
} catch {
|
|
13639
14102
|
}
|
|
13640
|
-
|
|
13641
|
-
|
|
14103
|
+
if (!res.ok) {
|
|
14104
|
+
throw new Error(payload?.error?.message ?? `HTTP ${res.status}`);
|
|
14105
|
+
}
|
|
14106
|
+
return payload?.data;
|
|
13642
14107
|
}
|
|
13643
|
-
function
|
|
14108
|
+
function hotWarnings(inst, running) {
|
|
14109
|
+
const warnings = [];
|
|
14110
|
+
const managed = running.filter((r) => r.managed && r.dataDir !== inst.dataDir);
|
|
14111
|
+
if (!inst.managed && managed.length > 0) {
|
|
14112
|
+
warnings.push(
|
|
14113
|
+
`\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`
|
|
14114
|
+
);
|
|
14115
|
+
warnings.push(
|
|
14116
|
+
"\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"
|
|
14117
|
+
);
|
|
14118
|
+
}
|
|
14119
|
+
const others = [...new Set(running.map((r) => r.dataDir).filter((d) => d !== inst.dataDir))];
|
|
14120
|
+
if (others.length > 0) {
|
|
14121
|
+
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`);
|
|
14122
|
+
}
|
|
14123
|
+
return warnings;
|
|
14124
|
+
}
|
|
14125
|
+
async function linkNode(opts) {
|
|
14126
|
+
if (!opts.code && !isCompleteAccount(opts.account ?? null)) {
|
|
14127
|
+
throw new Error("\u7F3A\u5C11\u63A5\u5165\u7801\uFF0C\u6216 Hub \u8D26\u53F7\u5BC6\u7801/\u77ED\u4FE1\u9A8C\u8BC1\u7801");
|
|
14128
|
+
}
|
|
14129
|
+
const hubUrl = opts.hubUrl.trim().replace(/\/$/, "");
|
|
14130
|
+
if (!hubUrl) throw new Error("\u7F3A\u5C11 Hub \u5730\u5740");
|
|
14131
|
+
const rawDataDir = opts.dataDir?.trim() || process.env.DATA_DIR?.trim() || void 0;
|
|
14132
|
+
const explicitDataDir = rawDataDir ? expandHome(rawDataDir) : void 0;
|
|
14133
|
+
const host = opts.host?.trim() || process.env.HOST?.trim() || DEFAULT_SERVE_HOST;
|
|
14134
|
+
const port = opts.port ?? Number(process.env.PORT ?? DEFAULT_SERVE_PORT);
|
|
14135
|
+
const running = discoverRunningServeInstances();
|
|
14136
|
+
const candidates = buildHotCandidates(explicitDataDir, running, { host, port });
|
|
14137
|
+
for (const inst of candidates) {
|
|
14138
|
+
const store2 = new Store(inst.dataDir);
|
|
14139
|
+
const adminKey = process.env.ADMIN_API_KEY ?? store2.loadAdminKey();
|
|
14140
|
+
if (!adminKey) continue;
|
|
14141
|
+
if (!await probeServer(inst.host, inst.port, adminKey)) continue;
|
|
14142
|
+
const status = await enrollViaServer(inst.host, inst.port, adminKey, { ...opts, hubUrl });
|
|
14143
|
+
return {
|
|
14144
|
+
mode: "hot",
|
|
14145
|
+
...status,
|
|
14146
|
+
dataDir: inst.dataDir,
|
|
14147
|
+
managed: inst.managed,
|
|
14148
|
+
warnings: hotWarnings(inst, running)
|
|
14149
|
+
};
|
|
14150
|
+
}
|
|
14151
|
+
const managedDir = running.find((r) => r.managed)?.dataDir;
|
|
14152
|
+
const dataDir = path27.resolve(explicitDataDir ?? managedDir ?? DEFAULT_DATA_DIR);
|
|
14153
|
+
const targetedService = !explicitDataDir && Boolean(managedDir) && dataDir === managedDir;
|
|
14154
|
+
const store = new Store(dataDir);
|
|
14155
|
+
const nodeId = ensureNodeId2(store);
|
|
14156
|
+
const account = opts.account;
|
|
14157
|
+
const cred = account && isCompleteAccount(account) ? await hubEnrollByAccount(hubUrl, {
|
|
14158
|
+
email: account.email,
|
|
14159
|
+
phone: account.phone,
|
|
14160
|
+
password: account.password,
|
|
14161
|
+
code: account.smsCode,
|
|
14162
|
+
nodeId,
|
|
14163
|
+
label: opts.label
|
|
14164
|
+
}) : await hubEnrollByCode(hubUrl, {
|
|
14165
|
+
code: opts.code,
|
|
14166
|
+
nodeId,
|
|
14167
|
+
label: opts.label
|
|
14168
|
+
});
|
|
14169
|
+
try {
|
|
14170
|
+
store.saveFleetCredential({
|
|
14171
|
+
...cred,
|
|
14172
|
+
label: opts.label ?? cred.label,
|
|
14173
|
+
enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14174
|
+
});
|
|
14175
|
+
} catch (e) {
|
|
14176
|
+
const err = e;
|
|
14177
|
+
if (err.code === "EACCES" || err.code === "EPERM") {
|
|
14178
|
+
throw new Error(
|
|
14179
|
+
`\u65E0\u6CD5\u5199\u5165\u6570\u636E\u76EE\u5F55 ${dataDir}\uFF08${err.code}: ${err.message}\uFF09
|
|
14180
|
+
\u8BE5\u76EE\u5F55\u5F53\u524D\u7528\u6237\u6CA1\u6709\u5199\u6743\u9650\u3002\u4E24\u79CD\u6539\u6CD5\uFF1A
|
|
14181
|
+
1) \u53BB\u6389 --data-dir\uFF0C\u8BA9 link \u81EA\u52A8\u53D1\u73B0\u672C\u673A\u8FD0\u884C\u7684\u8282\u70B9\uFF08\u63A8\u8350\uFF09\uFF1B
|
|
14182
|
+
2) \u7528\u5F53\u524D\u7528\u6237\u53EF\u5199\u7684\u76EE\u5F55\uFF0C\u672C\u5E73\u53F0\u5B89\u88C5\u811A\u672C\u9ED8\u8BA4\uFF1A${installDataDirHint()}
|
|
14183
|
+
\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`
|
|
14184
|
+
);
|
|
14185
|
+
}
|
|
14186
|
+
throw e;
|
|
14187
|
+
}
|
|
14188
|
+
const otherRunningDirs = [
|
|
14189
|
+
...new Set(running.map((r) => r.dataDir).filter((d) => d !== dataDir))
|
|
14190
|
+
];
|
|
13644
14191
|
return {
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
14192
|
+
mode: "saved",
|
|
14193
|
+
nodeId,
|
|
14194
|
+
gatewayUrl: cred.gatewayUrl,
|
|
14195
|
+
label: opts.label,
|
|
14196
|
+
dataDir,
|
|
14197
|
+
explicitDataDir: Boolean(explicitDataDir),
|
|
14198
|
+
runningServiceDirs: otherRunningDirs,
|
|
14199
|
+
targetedService
|
|
14200
|
+
};
|
|
14201
|
+
}
|
|
14202
|
+
function printLinkHelp() {
|
|
14203
|
+
cliLog("\u7528\u6CD5: zqagent link [--hub <url>] [--username <\u90AE\u7BB1/\u624B\u673A\u53F7> --password <\u5BC6\u7801>] [--label \u540D\u79F0]");
|
|
14204
|
+
cliLog(" zqagent link [--hub <url>] --code <\u4E00\u6B21\u6027\u63A5\u5165\u7801> [--label \u540D\u79F0]");
|
|
14205
|
+
cliLog(" \u65B9\u5F0F\u4E00\uFF08\u63A8\u8350\uFF09\uFF1A\u7528 Hub \u5DF2\u6CE8\u518C\u7684\u8D26\u53F7\u76F4\u63A5\u63A5\u5165\uFF1A");
|
|
14206
|
+
cliLog(" zqagent link --hub https://hub.cd-zq.com --username you@example.com --password '<\u5BC6\u7801>'");
|
|
14207
|
+
cliLog(" zqagent link --hub https://hub.cd-zq.com --username 13800000000 --password '<\u5BC6\u7801>'");
|
|
14208
|
+
cliLog(" zqagent link --hub https://hub.cd-zq.com --username 13800000000 --sms-code <\u9A8C\u8BC1\u7801>");
|
|
14209
|
+
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");
|
|
14210
|
+
cliLog(" zqagent link --hub https://hub.cd-zq.com --code <\u63A5\u5165\u7801>");
|
|
14211
|
+
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");
|
|
14212
|
+
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");
|
|
14213
|
+
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");
|
|
14214
|
+
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");
|
|
14215
|
+
}
|
|
14216
|
+
async function runLinkCommand(argv, ctx = {}) {
|
|
14217
|
+
const args = parseLinkArgs(argv);
|
|
14218
|
+
if (args.help) {
|
|
14219
|
+
printLinkHelp();
|
|
14220
|
+
return true;
|
|
14221
|
+
}
|
|
14222
|
+
const explicitHub = Boolean((args.hubUrl ?? process.env.HUB_URL ?? "").trim());
|
|
14223
|
+
let hubUrl = (args.hubUrl ?? process.env.HUB_URL ?? DEFAULT_HUB_URL).trim().replace(/\/$/, "");
|
|
14224
|
+
const code = (args.code ?? "").trim();
|
|
14225
|
+
let account = buildAccountAuth(args);
|
|
14226
|
+
const interactive = ctx.interactive ?? (process.stdin.isTTY && process.stdout.isTTY);
|
|
14227
|
+
if (code && account) {
|
|
14228
|
+
cliErr("--code \u4E0E Hub \u8D26\u53F7\uFF08--username/--email/--phone/--password\uFF09\u53EA\u80FD\u4E8C\u9009\u4E00\u3002");
|
|
14229
|
+
return false;
|
|
14230
|
+
}
|
|
14231
|
+
if (!account && (args.password || args.smsCode)) {
|
|
14232
|
+
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");
|
|
14233
|
+
return false;
|
|
14234
|
+
}
|
|
14235
|
+
const asPrompter = (rl2) => ({
|
|
14236
|
+
question: (q) => new Promise((resolve24) => rl2.question(q, resolve24)),
|
|
14237
|
+
pause: () => rl2.pause(),
|
|
14238
|
+
resume: () => rl2.resume()
|
|
14239
|
+
});
|
|
14240
|
+
let ownedRl = null;
|
|
14241
|
+
const getRl = () => {
|
|
14242
|
+
if (ctx.rl) return asPrompter(ctx.rl);
|
|
14243
|
+
if (!interactive) return null;
|
|
14244
|
+
ownedRl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
14245
|
+
return asPrompter(ownedRl);
|
|
13651
14246
|
};
|
|
14247
|
+
const closeOwnedRl = () => {
|
|
14248
|
+
if (ownedRl) ownedRl.close();
|
|
14249
|
+
};
|
|
14250
|
+
try {
|
|
14251
|
+
if (!code && !isCompleteAccount(account)) {
|
|
14252
|
+
const rl2 = getRl();
|
|
14253
|
+
if (!rl2) {
|
|
14254
|
+
cliErr("\u7F3A\u5C11\u63A5\u5165\u51ED\u636E\uFF1A\u8BF7\u7528 --username/--password\uFF0C\u6216 --code <\u63A5\u5165\u7801>\u3002");
|
|
14255
|
+
printLinkHelp();
|
|
14256
|
+
return false;
|
|
14257
|
+
}
|
|
14258
|
+
if (account) {
|
|
14259
|
+
const password = await promptPassword(rl2);
|
|
14260
|
+
if (!password) {
|
|
14261
|
+
cliErr("\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u53D6\u6D88\u63A5\u5165\u3002");
|
|
14262
|
+
return false;
|
|
14263
|
+
}
|
|
14264
|
+
account = { ...account, password };
|
|
14265
|
+
} else {
|
|
14266
|
+
const prompted = await promptLinkAccount(rl2, hubUrl, { askHub: !explicitHub });
|
|
14267
|
+
if (!prompted) return true;
|
|
14268
|
+
hubUrl = prompted.hubUrl;
|
|
14269
|
+
account = {
|
|
14270
|
+
email: prompted.auth.email,
|
|
14271
|
+
phone: prompted.auth.phone,
|
|
14272
|
+
password: prompted.auth.password,
|
|
14273
|
+
smsCode: prompted.auth.code
|
|
14274
|
+
};
|
|
14275
|
+
}
|
|
14276
|
+
}
|
|
14277
|
+
const r = await linkNode({
|
|
14278
|
+
hubUrl,
|
|
14279
|
+
code: code || void 0,
|
|
14280
|
+
account: account ?? void 0,
|
|
14281
|
+
dataDir: args.dataDir,
|
|
14282
|
+
label: args.label,
|
|
14283
|
+
host: args.host,
|
|
14284
|
+
port: args.port
|
|
14285
|
+
});
|
|
14286
|
+
if (r.mode === "hot") {
|
|
14287
|
+
cliLog("\u2705 \u5DF2\u63A5\u5165 Hub\uFF08\u70ED\u63A5\u5165\uFF0C\u514D\u91CD\u542F\uFF09");
|
|
14288
|
+
cliLog(` \u8282\u70B9: ${r.nodeId}${r.label ? ` (${r.label})` : ""}`);
|
|
14289
|
+
cliLog(` \u7F51\u5173: ${r.gatewayUrl ?? "\uFF08\u672A\u4E0B\u53D1\uFF09"} \u5728\u7EBF: ${r.online ? "\u662F" : "\u8FDE\u63A5\u4E2D\u2026"}`);
|
|
14290
|
+
cliLog(` \u6570\u636E\u76EE\u5F55: ${r.dataDir}${r.managed ? "\uFF08\u6258\u7BA1\u670D\u52A1\uFF0C\u5F00\u673A\u81EA\u542F\uFF09" : ""}`);
|
|
14291
|
+
if (r.warnings.length > 0) {
|
|
14292
|
+
cliLog("");
|
|
14293
|
+
for (const w of r.warnings) cliLog(`\u26A0\uFE0F ${w}`);
|
|
14294
|
+
}
|
|
14295
|
+
} else {
|
|
14296
|
+
cliLog("\u2705 \u63A5\u5165\u51ED\u636E\u5DF2\u4FDD\u5B58\uFF08\u672C\u673A\u6682\u65E0\u8FD0\u884C\u4E2D\u7684 server\uFF09");
|
|
14297
|
+
cliLog(` \u8282\u70B9: ${r.nodeId}`);
|
|
14298
|
+
cliLog(` \u7F51\u5173: ${r.gatewayUrl ?? "\uFF08\u672A\u4E0B\u53D1\uFF09"}`);
|
|
14299
|
+
cliLog(` \u6570\u636E\u76EE\u5F55: ${r.dataDir}`);
|
|
14300
|
+
cliLog(" \u4E0B\u6B21\u542F\u52A8 server \u5373\u81EA\u52A8\u63A5\u5165\uFF1B\u6216\u8FD0\u884C zqagent serve \u5E38\u9A7B\u4E3A\u8282\u70B9\u3002");
|
|
14301
|
+
if (r.targetedService) {
|
|
14302
|
+
cliLog("");
|
|
14303
|
+
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");
|
|
14304
|
+
cliLog(" \u7ACB\u5373\u751F\u6548\uFF1A\u91CD\u542F\u8BE5\u670D\u52A1\uFF08Linux: systemctl restart zqagent\uFF1B");
|
|
14305
|
+
cliLog(" macOS: launchctl kickstart -k gui/$(id -u)/com.zqagent.node\uFF09\u3002");
|
|
14306
|
+
} else if (r.runningServiceDirs.length > 0) {
|
|
14307
|
+
cliLog("");
|
|
14308
|
+
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");
|
|
14309
|
+
cliLog(` \u672C\u6B21\u5199\u5165: ${r.dataDir}`);
|
|
14310
|
+
for (const d of r.runningServiceDirs) cliLog(` \u670D\u52A1\u4F7F\u7528: ${d}`);
|
|
14311
|
+
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");
|
|
14312
|
+
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");
|
|
14313
|
+
cliLog(` zqagent link --hub <Hub\u5730\u5740> --username <\u90AE\u7BB1/\u624B\u673A\u53F7> --password '<\u5BC6\u7801>' --data-dir "${r.runningServiceDirs[0]}"`);
|
|
14314
|
+
} else if (!r.explicitDataDir) {
|
|
14315
|
+
cliLog("");
|
|
14316
|
+
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");
|
|
14317
|
+
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");
|
|
14318
|
+
cliLog(" curl -fsSL https://agent.cd-zq.com/install.sh | sh");
|
|
14319
|
+
cliLog(` \uFF08\u670D\u52A1\u9ED8\u8BA4\u6570\u636E\u76EE\u5F55\uFF1A${installDataDirHint()}\uFF09`);
|
|
14320
|
+
}
|
|
14321
|
+
}
|
|
14322
|
+
return true;
|
|
14323
|
+
} catch (e) {
|
|
14324
|
+
cliErr(`\u63A5\u5165\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
|
|
14325
|
+
return false;
|
|
14326
|
+
} finally {
|
|
14327
|
+
closeOwnedRl();
|
|
14328
|
+
}
|
|
13652
14329
|
}
|
|
13653
14330
|
|
|
14331
|
+
// src/cli/serve.ts
|
|
14332
|
+
init_cjs_shims();
|
|
14333
|
+
|
|
14334
|
+
// src/server/runtime.ts
|
|
14335
|
+
init_cjs_shims();
|
|
14336
|
+
var fs31 = __toESM(require("fs"), 1);
|
|
14337
|
+
var path38 = __toESM(require("path"), 1);
|
|
14338
|
+
|
|
14339
|
+
// src/server/routes.ts
|
|
14340
|
+
init_cjs_shims();
|
|
14341
|
+
var import_http = require("http");
|
|
14342
|
+
var path31 = __toESM(require("path"), 1);
|
|
14343
|
+
|
|
13654
14344
|
// src/server/auth.ts
|
|
13655
14345
|
init_cjs_shims();
|
|
13656
14346
|
var crypto4 = __toESM(require("crypto"), 1);
|
|
@@ -13824,34 +14514,34 @@ async function handleHubProxy(req2, res) {
|
|
|
13824
14514
|
|
|
13825
14515
|
// src/server/fsBrowser.ts
|
|
13826
14516
|
init_cjs_shims();
|
|
13827
|
-
var
|
|
13828
|
-
var
|
|
13829
|
-
var
|
|
14517
|
+
var fs22 = __toESM(require("fs"), 1);
|
|
14518
|
+
var os6 = __toESM(require("os"), 1);
|
|
14519
|
+
var path28 = __toESM(require("path"), 1);
|
|
13830
14520
|
var MAX_ENTRIES = 2e3;
|
|
13831
14521
|
var DEFAULT_SEARCH_LIMIT = 200;
|
|
13832
14522
|
var MAX_SEARCH_LIMIT = 1e3;
|
|
13833
14523
|
function listDirs(input) {
|
|
13834
|
-
const base = (input ?? "").trim() ||
|
|
13835
|
-
const target =
|
|
14524
|
+
const base = (input ?? "").trim() || os6.homedir();
|
|
14525
|
+
const target = path28.resolve(base);
|
|
13836
14526
|
let st;
|
|
13837
14527
|
try {
|
|
13838
|
-
st =
|
|
14528
|
+
st = fs22.statSync(target);
|
|
13839
14529
|
} catch {
|
|
13840
14530
|
throw new Error(`\u8DEF\u5F84\u4E0D\u5B58\u5728: ${target}`);
|
|
13841
14531
|
}
|
|
13842
14532
|
if (!st.isDirectory()) throw new Error(`\u4E0D\u662F\u76EE\u5F55: ${target}`);
|
|
13843
14533
|
let dirents;
|
|
13844
14534
|
try {
|
|
13845
|
-
dirents =
|
|
14535
|
+
dirents = fs22.readdirSync(target, { withFileTypes: true });
|
|
13846
14536
|
} catch {
|
|
13847
14537
|
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09: ${target}`);
|
|
13848
14538
|
}
|
|
13849
14539
|
const entries = dirents.map((d) => {
|
|
13850
|
-
const full =
|
|
14540
|
+
const full = path28.join(target, d.name);
|
|
13851
14541
|
let isDir = d.isDirectory();
|
|
13852
14542
|
if (d.isSymbolicLink()) {
|
|
13853
14543
|
try {
|
|
13854
|
-
isDir =
|
|
14544
|
+
isDir = fs22.statSync(full).isDirectory();
|
|
13855
14545
|
} catch {
|
|
13856
14546
|
}
|
|
13857
14547
|
}
|
|
@@ -13860,7 +14550,7 @@ function listDirs(input) {
|
|
|
13860
14550
|
entries.sort(
|
|
13861
14551
|
(a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
|
|
13862
14552
|
);
|
|
13863
|
-
const parentDir =
|
|
14553
|
+
const parentDir = path28.dirname(target);
|
|
13864
14554
|
return {
|
|
13865
14555
|
path: target,
|
|
13866
14556
|
parent: parentDir !== target ? parentDir : null,
|
|
@@ -13891,7 +14581,7 @@ var NAME_CACHE_MAX_DIRS = 4;
|
|
|
13891
14581
|
var NAME_CACHE_MAX_ENTRIES = 5e4;
|
|
13892
14582
|
var nameCache = /* @__PURE__ */ new Map();
|
|
13893
14583
|
function invalidateDirNames(target) {
|
|
13894
|
-
nameCache.delete(
|
|
14584
|
+
nameCache.delete(path28.resolve(target));
|
|
13895
14585
|
}
|
|
13896
14586
|
async function loadDirNames(target) {
|
|
13897
14587
|
const now = Date.now();
|
|
@@ -13903,7 +14593,7 @@ async function loadDirNames(target) {
|
|
|
13903
14593
|
}
|
|
13904
14594
|
let dirents;
|
|
13905
14595
|
try {
|
|
13906
|
-
dirents = await
|
|
14596
|
+
dirents = await fs22.promises.readdir(target, { withFileTypes: true });
|
|
13907
14597
|
} catch {
|
|
13908
14598
|
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09: ${target}`);
|
|
13909
14599
|
}
|
|
@@ -13926,22 +14616,22 @@ async function loadDirNames(target) {
|
|
|
13926
14616
|
return entries;
|
|
13927
14617
|
}
|
|
13928
14618
|
async function toDirEntry(dir, e) {
|
|
13929
|
-
const full =
|
|
14619
|
+
const full = path28.join(dir, e.name);
|
|
13930
14620
|
let isDir = e.isDir;
|
|
13931
14621
|
if (e.isLink) {
|
|
13932
14622
|
try {
|
|
13933
|
-
isDir = (await
|
|
14623
|
+
isDir = (await fs22.promises.stat(full)).isDirectory();
|
|
13934
14624
|
} catch {
|
|
13935
14625
|
}
|
|
13936
14626
|
}
|
|
13937
14627
|
return { name: e.name, path: full, type: isDir ? "dir" : "file" };
|
|
13938
14628
|
}
|
|
13939
14629
|
async function searchDirs(input, query, limit) {
|
|
13940
|
-
const base = (input ?? "").trim() ||
|
|
13941
|
-
const target =
|
|
14630
|
+
const base = (input ?? "").trim() || os6.homedir();
|
|
14631
|
+
const target = path28.resolve(base);
|
|
13942
14632
|
let st;
|
|
13943
14633
|
try {
|
|
13944
|
-
st = await
|
|
14634
|
+
st = await fs22.promises.stat(target);
|
|
13945
14635
|
} catch {
|
|
13946
14636
|
throw new Error(`\u8DEF\u5F84\u4E0D\u5B58\u5728: ${target}`);
|
|
13947
14637
|
}
|
|
@@ -13971,7 +14661,7 @@ async function searchDirs(input, query, limit) {
|
|
|
13971
14661
|
);
|
|
13972
14662
|
const hit = scored.slice(0, max);
|
|
13973
14663
|
const entries = await Promise.all(hit.map(({ entry }) => toDirEntry(target, entry)));
|
|
13974
|
-
const parentDir =
|
|
14664
|
+
const parentDir = path28.dirname(target);
|
|
13975
14665
|
return {
|
|
13976
14666
|
path: target,
|
|
13977
14667
|
parent: parentDir !== target ? parentDir : null,
|
|
@@ -13982,52 +14672,52 @@ async function searchDirs(input, query, limit) {
|
|
|
13982
14672
|
};
|
|
13983
14673
|
}
|
|
13984
14674
|
function makeDirIn(parentInput, name) {
|
|
13985
|
-
const parent =
|
|
14675
|
+
const parent = path28.resolve((parentInput ?? "").trim() || os6.homedir());
|
|
13986
14676
|
const clean = (name ?? "").trim();
|
|
13987
14677
|
if (!clean) throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u4E3A\u7A7A");
|
|
13988
14678
|
if (clean === "." || clean === "..") throw new Error("\u76EE\u5F55\u540D\u975E\u6CD5");
|
|
13989
|
-
const target =
|
|
13990
|
-
const rel =
|
|
13991
|
-
if (!rel || rel.startsWith("..") ||
|
|
14679
|
+
const target = path28.resolve(parent, clean);
|
|
14680
|
+
const rel = path28.relative(parent, target);
|
|
14681
|
+
if (!rel || rel.startsWith("..") || path28.isAbsolute(rel)) {
|
|
13992
14682
|
throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u8D8A\u51FA\u5F53\u524D\u76EE\u5F55");
|
|
13993
14683
|
}
|
|
13994
14684
|
let st = null;
|
|
13995
14685
|
try {
|
|
13996
|
-
st =
|
|
14686
|
+
st = fs22.statSync(target);
|
|
13997
14687
|
} catch {
|
|
13998
14688
|
st = null;
|
|
13999
14689
|
}
|
|
14000
14690
|
if (st && !st.isDirectory()) throw new Error(`\u5DF2\u5B58\u5728\u540C\u540D\u6587\u4EF6: ${target}`);
|
|
14001
14691
|
try {
|
|
14002
|
-
|
|
14692
|
+
fs22.mkdirSync(target, { recursive: true });
|
|
14003
14693
|
} catch (e) {
|
|
14004
14694
|
throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
|
|
14005
14695
|
}
|
|
14006
14696
|
invalidateDirNames(parent);
|
|
14007
|
-
return { name:
|
|
14697
|
+
return { name: path28.basename(target), path: target, type: "dir" };
|
|
14008
14698
|
}
|
|
14009
14699
|
|
|
14010
14700
|
// src/server/projectFiles.ts
|
|
14011
14701
|
init_cjs_shims();
|
|
14012
|
-
var
|
|
14013
|
-
var
|
|
14702
|
+
var fs23 = __toESM(require("fs"), 1);
|
|
14703
|
+
var path29 = __toESM(require("path"), 1);
|
|
14014
14704
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
14015
14705
|
var MAX_DOWNLOAD_BYTES = 16 * 1024 * 1024;
|
|
14016
14706
|
var MAX_ENTRIES2 = 2e3;
|
|
14017
14707
|
function toPosix(p) {
|
|
14018
|
-
return p.split(
|
|
14708
|
+
return p.split(path29.sep).join("/");
|
|
14019
14709
|
}
|
|
14020
14710
|
function projectRoot(workspaceRoot) {
|
|
14021
14711
|
const r = (workspaceRoot ?? "").trim();
|
|
14022
14712
|
if (!r) {
|
|
14023
14713
|
throw new Error("\u9879\u76EE\u672A\u8BBE\u7F6E\u5DE5\u4F5C\u533A\u76EE\u5F55\uFF08workspaceRoot\uFF09\uFF0C\u65E0\u6CD5\u6D4F\u89C8\u6587\u4EF6");
|
|
14024
14714
|
}
|
|
14025
|
-
const abs =
|
|
14026
|
-
if (!
|
|
14715
|
+
const abs = path29.resolve(r);
|
|
14716
|
+
if (!fs23.existsSync(abs)) {
|
|
14027
14717
|
throw new Error(`\u5DE5\u4F5C\u533A\u76EE\u5F55\u4E0D\u5B58\u5728: ${abs}`);
|
|
14028
14718
|
}
|
|
14029
14719
|
try {
|
|
14030
|
-
return
|
|
14720
|
+
return fs23.realpathSync(abs);
|
|
14031
14721
|
} catch {
|
|
14032
14722
|
return abs;
|
|
14033
14723
|
}
|
|
@@ -14045,37 +14735,37 @@ function listProjectFiles(workspaceRoot, relPath) {
|
|
|
14045
14735
|
const dir = resolveWithin(base, relPath ?? "");
|
|
14046
14736
|
let st;
|
|
14047
14737
|
try {
|
|
14048
|
-
st =
|
|
14738
|
+
st = fs23.statSync(dir);
|
|
14049
14739
|
} catch {
|
|
14050
|
-
throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(
|
|
14740
|
+
throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(path29.relative(base, dir)) || "/"}`);
|
|
14051
14741
|
}
|
|
14052
14742
|
if (!st.isDirectory()) throw new Error("\u76EE\u6807\u4E0D\u662F\u76EE\u5F55");
|
|
14053
14743
|
let dirents;
|
|
14054
14744
|
try {
|
|
14055
|
-
dirents =
|
|
14745
|
+
dirents = fs23.readdirSync(dir, { withFileTypes: true });
|
|
14056
14746
|
} catch {
|
|
14057
14747
|
throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09");
|
|
14058
14748
|
}
|
|
14059
14749
|
const entries = dirents.map((d) => {
|
|
14060
|
-
const full =
|
|
14750
|
+
const full = path29.join(dir, d.name);
|
|
14061
14751
|
let isDir = d.isDirectory();
|
|
14062
14752
|
if (d.isSymbolicLink()) {
|
|
14063
14753
|
try {
|
|
14064
|
-
isDir =
|
|
14754
|
+
isDir = fs23.statSync(full).isDirectory();
|
|
14065
14755
|
} catch {
|
|
14066
14756
|
}
|
|
14067
14757
|
}
|
|
14068
14758
|
let size = 0;
|
|
14069
14759
|
let mtime = "";
|
|
14070
14760
|
try {
|
|
14071
|
-
const s =
|
|
14761
|
+
const s = fs23.statSync(full);
|
|
14072
14762
|
size = s.size;
|
|
14073
14763
|
mtime = s.mtime.toISOString();
|
|
14074
14764
|
} catch {
|
|
14075
14765
|
}
|
|
14076
14766
|
return {
|
|
14077
14767
|
name: d.name,
|
|
14078
|
-
path: toPosix(
|
|
14768
|
+
path: toPosix(path29.relative(base, full)),
|
|
14079
14769
|
type: isDir ? "dir" : "file",
|
|
14080
14770
|
size,
|
|
14081
14771
|
mtime
|
|
@@ -14084,12 +14774,12 @@ function listProjectFiles(workspaceRoot, relPath) {
|
|
|
14084
14774
|
entries.sort(
|
|
14085
14775
|
(a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
|
|
14086
14776
|
);
|
|
14087
|
-
const relDir = toPosix(
|
|
14088
|
-
const parentAbs =
|
|
14777
|
+
const relDir = toPosix(path29.relative(base, dir));
|
|
14778
|
+
const parentAbs = path29.dirname(dir);
|
|
14089
14779
|
return {
|
|
14090
14780
|
root: base,
|
|
14091
14781
|
path: relDir,
|
|
14092
|
-
parent: isWithinRoot(base, parentAbs) ? toPosix(
|
|
14782
|
+
parent: isWithinRoot(base, parentAbs) ? toPosix(path29.relative(base, parentAbs)) : null,
|
|
14093
14783
|
entries: entries.slice(0, MAX_ENTRIES2)
|
|
14094
14784
|
};
|
|
14095
14785
|
}
|
|
@@ -14098,17 +14788,17 @@ function readProjectFile(workspaceRoot, relPath) {
|
|
|
14098
14788
|
const file = resolveWithin(base, relPath ?? "");
|
|
14099
14789
|
let st;
|
|
14100
14790
|
try {
|
|
14101
|
-
st =
|
|
14791
|
+
st = fs23.statSync(file);
|
|
14102
14792
|
} catch {
|
|
14103
14793
|
throw new Error("\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
14104
14794
|
}
|
|
14105
14795
|
if (!st.isFile()) throw new Error("\u76EE\u6807\u4E0D\u662F\u6587\u4EF6");
|
|
14106
|
-
const buf =
|
|
14796
|
+
const buf = fs23.readFileSync(file);
|
|
14107
14797
|
const binary = isBinary(buf);
|
|
14108
14798
|
const truncated = buf.length > MAX_FILE_BYTES;
|
|
14109
14799
|
const slice = truncated ? buf.subarray(0, MAX_FILE_BYTES) : buf;
|
|
14110
14800
|
return {
|
|
14111
|
-
path: toPosix(
|
|
14801
|
+
path: toPosix(path29.relative(base, file)),
|
|
14112
14802
|
size: st.size,
|
|
14113
14803
|
binary,
|
|
14114
14804
|
truncated,
|
|
@@ -14120,7 +14810,7 @@ function downloadProjectFile(workspaceRoot, relPath) {
|
|
|
14120
14810
|
const file = resolveWithin(base, relPath ?? "");
|
|
14121
14811
|
let st;
|
|
14122
14812
|
try {
|
|
14123
|
-
st =
|
|
14813
|
+
st = fs23.statSync(file);
|
|
14124
14814
|
} catch {
|
|
14125
14815
|
throw new Error("\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
14126
14816
|
}
|
|
@@ -14128,10 +14818,10 @@ function downloadProjectFile(workspaceRoot, relPath) {
|
|
|
14128
14818
|
if (st.size > MAX_DOWNLOAD_BYTES) {
|
|
14129
14819
|
throw new Error(`\u6587\u4EF6\u8D85\u8FC7\u4E0B\u8F7D\u4E0A\u9650\uFF08${MAX_DOWNLOAD_BYTES / (1024 * 1024)}MB\uFF09`);
|
|
14130
14820
|
}
|
|
14131
|
-
const buf =
|
|
14821
|
+
const buf = fs23.readFileSync(file);
|
|
14132
14822
|
return {
|
|
14133
|
-
path: toPosix(
|
|
14134
|
-
name:
|
|
14823
|
+
path: toPosix(path29.relative(base, file)),
|
|
14824
|
+
name: path29.basename(file),
|
|
14135
14825
|
size: buf.length,
|
|
14136
14826
|
base64: buf.toString("base64")
|
|
14137
14827
|
};
|
|
@@ -14153,12 +14843,12 @@ function writeProjectFile(workspaceRoot, relPath, content) {
|
|
|
14153
14843
|
throw new Error("\u5185\u5BB9\u8D85\u8FC7 2MB \u4E0A\u9650\uFF0C\u65E0\u6CD5\u4FDD\u5B58");
|
|
14154
14844
|
}
|
|
14155
14845
|
try {
|
|
14156
|
-
|
|
14157
|
-
|
|
14846
|
+
fs23.mkdirSync(path29.dirname(file), { recursive: true });
|
|
14847
|
+
fs23.writeFileSync(file, buf);
|
|
14158
14848
|
} catch (e) {
|
|
14159
14849
|
throw new Error(`\u5199\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
14160
14850
|
}
|
|
14161
|
-
return { path: toPosix(
|
|
14851
|
+
return { path: toPosix(path29.relative(base, file)), size: buf.length };
|
|
14162
14852
|
}
|
|
14163
14853
|
function createProjectDir(workspaceRoot, relPath) {
|
|
14164
14854
|
const base = projectRoot(workspaceRoot);
|
|
@@ -14166,26 +14856,26 @@ function createProjectDir(workspaceRoot, relPath) {
|
|
|
14166
14856
|
if (!rel) throw new Error("\u76EE\u5F55\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
|
|
14167
14857
|
const dir = resolveWithin(base, rel);
|
|
14168
14858
|
try {
|
|
14169
|
-
|
|
14859
|
+
fs23.mkdirSync(dir, { recursive: true });
|
|
14170
14860
|
} catch (e) {
|
|
14171
14861
|
throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
14172
14862
|
}
|
|
14173
|
-
return { path: toPosix(
|
|
14863
|
+
return { path: toPosix(path29.relative(base, dir)) };
|
|
14174
14864
|
}
|
|
14175
14865
|
function createProjectFile(workspaceRoot, relPath, content = "") {
|
|
14176
14866
|
const base = projectRoot(workspaceRoot);
|
|
14177
14867
|
const rel = (relPath ?? "").trim();
|
|
14178
14868
|
if (!rel) throw new Error("\u6587\u4EF6\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
|
|
14179
14869
|
const file = resolveWithin(base, rel);
|
|
14180
|
-
if (
|
|
14870
|
+
if (fs23.existsSync(file)) throw new Error("\u6587\u4EF6\u5DF2\u5B58\u5728");
|
|
14181
14871
|
const buf = Buffer.from(String(content ?? ""), "utf-8");
|
|
14182
14872
|
try {
|
|
14183
|
-
|
|
14184
|
-
|
|
14873
|
+
fs23.mkdirSync(path29.dirname(file), { recursive: true });
|
|
14874
|
+
fs23.writeFileSync(file, buf);
|
|
14185
14875
|
} catch (e) {
|
|
14186
14876
|
throw new Error(`\u521B\u5EFA\u6587\u4EF6\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
14187
14877
|
}
|
|
14188
|
-
return { path: toPosix(
|
|
14878
|
+
return { path: toPosix(path29.relative(base, file)), size: buf.length };
|
|
14189
14879
|
}
|
|
14190
14880
|
function searchProjectFiles(workspaceRoot, query) {
|
|
14191
14881
|
const base = projectRoot(workspaceRoot);
|
|
@@ -14208,7 +14898,7 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
14208
14898
|
if (out.length >= LIMIT) return;
|
|
14209
14899
|
let dirents;
|
|
14210
14900
|
try {
|
|
14211
|
-
dirents =
|
|
14901
|
+
dirents = fs23.readdirSync(dir, { withFileTypes: true });
|
|
14212
14902
|
} catch {
|
|
14213
14903
|
return;
|
|
14214
14904
|
}
|
|
@@ -14219,7 +14909,7 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
14219
14909
|
let isDir = d.isDirectory();
|
|
14220
14910
|
if (d.isSymbolicLink()) {
|
|
14221
14911
|
try {
|
|
14222
|
-
isDir =
|
|
14912
|
+
isDir = fs23.statSync(path29.join(dir, d.name)).isDirectory();
|
|
14223
14913
|
} catch {
|
|
14224
14914
|
isDir = false;
|
|
14225
14915
|
}
|
|
@@ -14227,7 +14917,7 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
14227
14917
|
if (d.name.toLowerCase().includes(q)) {
|
|
14228
14918
|
out.push({ path: rel, type: isDir ? "dir" : "file" });
|
|
14229
14919
|
}
|
|
14230
|
-
if (isDir) walk(
|
|
14920
|
+
if (isDir) walk(path29.join(dir, d.name), rel);
|
|
14231
14921
|
}
|
|
14232
14922
|
};
|
|
14233
14923
|
walk(base, "");
|
|
@@ -14236,8 +14926,8 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
14236
14926
|
|
|
14237
14927
|
// src/server/projectOps.ts
|
|
14238
14928
|
init_cjs_shims();
|
|
14239
|
-
var
|
|
14240
|
-
var
|
|
14929
|
+
var os7 = __toESM(require("os"), 1);
|
|
14930
|
+
var path30 = __toESM(require("path"), 1);
|
|
14241
14931
|
var MAX_STDOUT2 = 2e4;
|
|
14242
14932
|
var MAX_STDERR2 = 1e4;
|
|
14243
14933
|
var MAX_BUFFER3 = 1024 * 1024 * 5;
|
|
@@ -14251,7 +14941,7 @@ function resolveInvocation2(spec, prepared) {
|
|
|
14251
14941
|
}
|
|
14252
14942
|
function workRoot(workspaceRoot) {
|
|
14253
14943
|
const r = (workspaceRoot ?? "").trim();
|
|
14254
|
-
return r ?
|
|
14944
|
+
return r ? path30.resolve(r) : os7.homedir();
|
|
14255
14945
|
}
|
|
14256
14946
|
async function runProjectCommand(workspaceRoot, command, timeoutSeconds) {
|
|
14257
14947
|
const cmd = String(command ?? "");
|
|
@@ -14562,11 +15252,11 @@ function projectStats(manager, tenantId) {
|
|
|
14562
15252
|
|
|
14563
15253
|
// src/server/nodeHost.ts
|
|
14564
15254
|
init_cjs_shims();
|
|
14565
|
-
var
|
|
14566
|
-
var
|
|
15255
|
+
var fs24 = __toESM(require("fs"), 1);
|
|
15256
|
+
var os8 = __toESM(require("os"), 1);
|
|
14567
15257
|
function diskInfo(pathStr) {
|
|
14568
15258
|
try {
|
|
14569
|
-
const st =
|
|
15259
|
+
const st = fs24.statfsSync(pathStr);
|
|
14570
15260
|
return {
|
|
14571
15261
|
path: pathStr,
|
|
14572
15262
|
total: Number(st.blocks) * Number(st.bsize),
|
|
@@ -14578,7 +15268,7 @@ function diskInfo(pathStr) {
|
|
|
14578
15268
|
}
|
|
14579
15269
|
function networkInfo() {
|
|
14580
15270
|
const out = [];
|
|
14581
|
-
const ifaces =
|
|
15271
|
+
const ifaces = os8.networkInterfaces();
|
|
14582
15272
|
for (const [name, list] of Object.entries(ifaces)) {
|
|
14583
15273
|
for (const info of list ?? []) {
|
|
14584
15274
|
out.push({
|
|
@@ -14629,23 +15319,23 @@ function overview(store, manager) {
|
|
|
14629
15319
|
return { projects, sessions: { total, running, waiting, items }, usage: { tokensIn, tokensOut } };
|
|
14630
15320
|
}
|
|
14631
15321
|
function buildNodeHost(store, manager, diskPath) {
|
|
14632
|
-
const cpus2 =
|
|
15322
|
+
const cpus2 = os8.cpus();
|
|
14633
15323
|
const ov = overview(store, manager);
|
|
14634
15324
|
return {
|
|
14635
15325
|
nodeId: store.loadNodeId() ?? "",
|
|
14636
|
-
hostname:
|
|
15326
|
+
hostname: os8.hostname(),
|
|
14637
15327
|
platform: process.platform,
|
|
14638
15328
|
arch: process.arch,
|
|
14639
|
-
release:
|
|
14640
|
-
uptimeSec: Math.round(
|
|
14641
|
-
version: "0.2.
|
|
15329
|
+
release: os8.release(),
|
|
15330
|
+
uptimeSec: Math.round(os8.uptime()),
|
|
15331
|
+
version: "0.2.12",
|
|
14642
15332
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
14643
15333
|
cpu: {
|
|
14644
15334
|
count: cpus2.length,
|
|
14645
15335
|
model: cpus2[0]?.model ?? "",
|
|
14646
|
-
loadAvg:
|
|
15336
|
+
loadAvg: os8.loadavg().map((n) => Math.round(n * 100) / 100)
|
|
14647
15337
|
},
|
|
14648
|
-
memory: { total:
|
|
15338
|
+
memory: { total: os8.totalmem(), free: os8.freemem() },
|
|
14649
15339
|
network: networkInfo(),
|
|
14650
15340
|
disk: diskInfo(diskPath || process.cwd()),
|
|
14651
15341
|
...ov
|
|
@@ -15008,7 +15698,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
15008
15698
|
ok(res, opts.fleet.status());
|
|
15009
15699
|
}
|
|
15010
15700
|
},
|
|
15011
|
-
//
|
|
15701
|
+
// 运行时热接入:凭一次性注册码或 Hub 账号接入(落盘 fleet.json + 立即连接,免重启)
|
|
15012
15702
|
{
|
|
15013
15703
|
method: "POST",
|
|
15014
15704
|
pattern: ["fleet", "enroll"],
|
|
@@ -15020,15 +15710,42 @@ function createApp(store, manager, opts = {}) {
|
|
|
15020
15710
|
const raw = body ?? {};
|
|
15021
15711
|
const hubUrl = String(raw.hubUrl ?? "").trim().replace(/\/$/, "");
|
|
15022
15712
|
const code = String(raw.code ?? "").trim();
|
|
15023
|
-
|
|
15024
|
-
|
|
15713
|
+
const email = String(raw.email ?? "").trim();
|
|
15714
|
+
const phone = String(raw.phone ?? "").trim();
|
|
15715
|
+
const password = String(raw.password ?? "");
|
|
15716
|
+
const smsCode = String(raw.smsCode ?? "").trim();
|
|
15717
|
+
const hasAccount = Boolean(email || phone);
|
|
15718
|
+
if (!hubUrl) {
|
|
15719
|
+
throw new ApiError(400, "bad_request", "hubUrl \u5FC5\u586B");
|
|
15720
|
+
}
|
|
15721
|
+
if (code && hasAccount) {
|
|
15722
|
+
throw new ApiError(400, "bad_request", "code \u4E0E\u8D26\u53F7\u51ED\u636E\u53EA\u80FD\u4E8C\u9009\u4E00");
|
|
15723
|
+
}
|
|
15724
|
+
if (!code && !hasAccount) {
|
|
15725
|
+
throw new ApiError(400, "bad_request", "\u9700\u8981 code\uFF0C\u6216 email/phone + password/smsCode");
|
|
15726
|
+
}
|
|
15727
|
+
if (hasAccount && !password && !smsCode) {
|
|
15728
|
+
throw new ApiError(400, "bad_request", "\u8D26\u53F7\u63A5\u5165\u9700\u8981 password \u6216 smsCode");
|
|
15025
15729
|
}
|
|
15026
15730
|
const label = typeof raw.label === "string" ? raw.label.trim() : void 0;
|
|
15027
15731
|
try {
|
|
15028
|
-
ok(
|
|
15732
|
+
ok(
|
|
15733
|
+
res,
|
|
15734
|
+
await opts.fleet.enroll({
|
|
15735
|
+
hubUrl,
|
|
15736
|
+
code: code || void 0,
|
|
15737
|
+
account: hasAccount ? {
|
|
15738
|
+
email: email || void 0,
|
|
15739
|
+
phone: phone || void 0,
|
|
15740
|
+
password: password || void 0,
|
|
15741
|
+
smsCode: smsCode || void 0
|
|
15742
|
+
} : void 0,
|
|
15743
|
+
label
|
|
15744
|
+
})
|
|
15745
|
+
);
|
|
15029
15746
|
} catch (e) {
|
|
15030
15747
|
const code2 = e.code;
|
|
15031
|
-
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;
|
|
15748
|
+
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;
|
|
15032
15749
|
const msg = e instanceof Error ? e.message : String(e);
|
|
15033
15750
|
throw new ApiError(
|
|
15034
15751
|
status,
|
|
@@ -15213,7 +15930,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
15213
15930
|
applyProvidersPatch(tenant, raw);
|
|
15214
15931
|
if (typeof raw.workspaceRoot === "string") {
|
|
15215
15932
|
const ws = raw.workspaceRoot.trim();
|
|
15216
|
-
const next = ws ?
|
|
15933
|
+
const next = ws ? path31.resolve(ws) : void 0;
|
|
15217
15934
|
if (tenant.workspaceRoot) {
|
|
15218
15935
|
if (next !== tenant.workspaceRoot) {
|
|
15219
15936
|
throw new ApiError(
|
|
@@ -16200,7 +16917,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
16200
16917
|
json(res, 200, {
|
|
16201
16918
|
status: "ok",
|
|
16202
16919
|
// 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
|
|
16203
|
-
version: "0.2.
|
|
16920
|
+
version: "0.2.12",
|
|
16204
16921
|
features: { mcp: hasServerMcpConfig() }
|
|
16205
16922
|
});
|
|
16206
16923
|
return;
|
|
@@ -16295,7 +17012,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
16295
17012
|
|
|
16296
17013
|
// src/server/fleet/FleetNodeBridge.ts
|
|
16297
17014
|
init_cjs_shims();
|
|
16298
|
-
var
|
|
17015
|
+
var os9 = __toESM(require("os"), 1);
|
|
16299
17016
|
var import_node_perf_hooks = require("perf_hooks");
|
|
16300
17017
|
|
|
16301
17018
|
// src/server/fleet/FleetCommands.ts
|
|
@@ -17489,7 +18206,7 @@ function withTimeout(p, ms) {
|
|
|
17489
18206
|
}
|
|
17490
18207
|
function primaryIp() {
|
|
17491
18208
|
let v6;
|
|
17492
|
-
for (const infos of Object.values(
|
|
18209
|
+
for (const infos of Object.values(os9.networkInterfaces())) {
|
|
17493
18210
|
for (const info of infos ?? []) {
|
|
17494
18211
|
if (info.internal) continue;
|
|
17495
18212
|
if (info.family === "IPv4") return info.address;
|
|
@@ -17503,7 +18220,7 @@ function primaryIp() {
|
|
|
17503
18220
|
var FleetNodeBridge = class {
|
|
17504
18221
|
constructor(opts) {
|
|
17505
18222
|
this.opts = opts;
|
|
17506
|
-
this.nodeId = opts.nodeId ??
|
|
18223
|
+
this.nodeId = opts.nodeId ?? ensureNodeId(opts.deps.store);
|
|
17507
18224
|
}
|
|
17508
18225
|
opts;
|
|
17509
18226
|
/** 是否成功连接过(区分「一直连不上」与「连上后断线」) */
|
|
@@ -17838,7 +18555,7 @@ var FleetNodeBridge = class {
|
|
|
17838
18555
|
label: this.opts.deps.store.loadNodeLabel() ?? void 0,
|
|
17839
18556
|
platform: process.platform,
|
|
17840
18557
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
17841
|
-
version: "0.2.
|
|
18558
|
+
version: "0.2.12",
|
|
17842
18559
|
ip: primaryIp()
|
|
17843
18560
|
};
|
|
17844
18561
|
}
|
|
@@ -17893,7 +18610,7 @@ var FleetNodeBridge = class {
|
|
|
17893
18610
|
label: this.opts.deps.store.loadNodeLabel() ?? void 0,
|
|
17894
18611
|
platform: process.platform,
|
|
17895
18612
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
17896
|
-
version: "0.2.
|
|
18613
|
+
version: "0.2.12",
|
|
17897
18614
|
ip: primaryIp(),
|
|
17898
18615
|
projects,
|
|
17899
18616
|
totals,
|
|
@@ -18081,28 +18798,6 @@ var FleetNodeBridge = class {
|
|
|
18081
18798
|
}
|
|
18082
18799
|
};
|
|
18083
18800
|
|
|
18084
|
-
// src/server/fleet-config.ts
|
|
18085
|
-
init_cjs_shims();
|
|
18086
|
-
function fleetConfigFromEnv(store) {
|
|
18087
|
-
const fleetToken = process.env.FLEET_TOKEN;
|
|
18088
|
-
const fleetSecret = process.env.FLEET_SECRET;
|
|
18089
|
-
if (!fleetToken || !fleetSecret) return null;
|
|
18090
|
-
return {
|
|
18091
|
-
hubUrl: process.env.HUB_URL,
|
|
18092
|
-
fleetToken,
|
|
18093
|
-
fleetSecret,
|
|
18094
|
-
nodeId: ensureNodeId2(store),
|
|
18095
|
-
gatewayUrl: process.env.FLEET_GATEWAY_URL
|
|
18096
|
-
};
|
|
18097
|
-
}
|
|
18098
|
-
function resolveFleetConfig(store) {
|
|
18099
|
-
const saved = store.loadFleetCredential();
|
|
18100
|
-
if (saved?.fleetToken && saved.fleetSecret) {
|
|
18101
|
-
return { ...saved, nodeId: saved.nodeId || ensureNodeId2(store) };
|
|
18102
|
-
}
|
|
18103
|
-
return fleetConfigFromEnv(store);
|
|
18104
|
-
}
|
|
18105
|
-
|
|
18106
18801
|
// src/server/notify/index.ts
|
|
18107
18802
|
init_cjs_shims();
|
|
18108
18803
|
|
|
@@ -18662,8 +19357,8 @@ init_cjs_shims();
|
|
|
18662
19357
|
|
|
18663
19358
|
// src/server/qq/bindings.ts
|
|
18664
19359
|
init_cjs_shims();
|
|
18665
|
-
var
|
|
18666
|
-
var
|
|
19360
|
+
var fs25 = __toESM(require("fs"), 1);
|
|
19361
|
+
var path32 = __toESM(require("path"), 1);
|
|
18667
19362
|
function conversationKey(target) {
|
|
18668
19363
|
switch (target.kind) {
|
|
18669
19364
|
case "c2c":
|
|
@@ -18702,12 +19397,12 @@ var QqBindingsStore = class _QqBindingsStore {
|
|
|
18702
19397
|
cache = null;
|
|
18703
19398
|
/** 基于 DATA_DIR 构造 */
|
|
18704
19399
|
static in(dataDir) {
|
|
18705
|
-
return new _QqBindingsStore(
|
|
19400
|
+
return new _QqBindingsStore(path32.join(dataDir, "qq", "bindings.json"));
|
|
18706
19401
|
}
|
|
18707
19402
|
load() {
|
|
18708
19403
|
if (this.cache) return this.cache;
|
|
18709
19404
|
try {
|
|
18710
|
-
const raw = JSON.parse(
|
|
19405
|
+
const raw = JSON.parse(fs25.readFileSync(this.file, "utf-8"));
|
|
18711
19406
|
this.cache = {
|
|
18712
19407
|
conversations: raw.conversations ?? {}
|
|
18713
19408
|
};
|
|
@@ -18739,8 +19434,8 @@ var QqBindingsStore = class _QqBindingsStore {
|
|
|
18739
19434
|
return null;
|
|
18740
19435
|
}
|
|
18741
19436
|
persist() {
|
|
18742
|
-
|
|
18743
|
-
|
|
19437
|
+
fs25.mkdirSync(path32.dirname(this.file), { recursive: true });
|
|
19438
|
+
fs25.writeFileSync(this.file, JSON.stringify(this.cache, null, 2), "utf-8");
|
|
18744
19439
|
}
|
|
18745
19440
|
};
|
|
18746
19441
|
|
|
@@ -19152,8 +19847,8 @@ ${lines.join("\n")}`, msgId);
|
|
|
19152
19847
|
|
|
19153
19848
|
// src/server/qq/QqManager.ts
|
|
19154
19849
|
init_cjs_shims();
|
|
19155
|
-
var
|
|
19156
|
-
var
|
|
19850
|
+
var fs26 = __toESM(require("fs"), 1);
|
|
19851
|
+
var path33 = __toESM(require("path"), 1);
|
|
19157
19852
|
var QqManager = class {
|
|
19158
19853
|
constructor(opts) {
|
|
19159
19854
|
this.opts = opts;
|
|
@@ -19162,7 +19857,7 @@ var QqManager = class {
|
|
|
19162
19857
|
adapter = null;
|
|
19163
19858
|
config = null;
|
|
19164
19859
|
get configFile() {
|
|
19165
|
-
return
|
|
19860
|
+
return path33.join(this.opts.dataDir, "qq", "config.json");
|
|
19166
19861
|
}
|
|
19167
19862
|
/** 启动:读配置(env 优先,其次文件),有则建连接 */
|
|
19168
19863
|
start() {
|
|
@@ -19200,7 +19895,7 @@ var QqManager = class {
|
|
|
19200
19895
|
/** 清空配置:删除文件 + 断开 */
|
|
19201
19896
|
clearConfig() {
|
|
19202
19897
|
try {
|
|
19203
|
-
|
|
19898
|
+
fs26.rmSync(this.configFile, { force: true });
|
|
19204
19899
|
} catch {
|
|
19205
19900
|
}
|
|
19206
19901
|
this.stop();
|
|
@@ -19242,7 +19937,7 @@ var QqManager = class {
|
|
|
19242
19937
|
}
|
|
19243
19938
|
_readConfigFile() {
|
|
19244
19939
|
try {
|
|
19245
|
-
const raw = JSON.parse(
|
|
19940
|
+
const raw = JSON.parse(fs26.readFileSync(this.configFile, "utf-8"));
|
|
19246
19941
|
if (raw.appId && raw.appSecret) {
|
|
19247
19942
|
return {
|
|
19248
19943
|
appId: raw.appId,
|
|
@@ -19255,8 +19950,8 @@ var QqManager = class {
|
|
|
19255
19950
|
return null;
|
|
19256
19951
|
}
|
|
19257
19952
|
_persistConfig(cfg) {
|
|
19258
|
-
|
|
19259
|
-
|
|
19953
|
+
fs26.mkdirSync(path33.dirname(this.configFile), { recursive: true });
|
|
19954
|
+
fs26.writeFileSync(this.configFile, JSON.stringify(cfg, null, 2), "utf-8");
|
|
19260
19955
|
}
|
|
19261
19956
|
};
|
|
19262
19957
|
|
|
@@ -19305,16 +20000,16 @@ var PairingCodeStore = class {
|
|
|
19305
20000
|
// src/update/controller.ts
|
|
19306
20001
|
init_cjs_shims();
|
|
19307
20002
|
var fs30 = __toESM(require("fs"), 1);
|
|
19308
|
-
var
|
|
20003
|
+
var path37 = __toESM(require("path"), 1);
|
|
19309
20004
|
|
|
19310
20005
|
// src/update/downloader.ts
|
|
19311
20006
|
init_cjs_shims();
|
|
19312
20007
|
var import_node_crypto5 = require("crypto");
|
|
19313
|
-
var
|
|
20008
|
+
var fs27 = __toESM(require("fs"), 1);
|
|
19314
20009
|
var import_node_stream2 = require("stream");
|
|
19315
20010
|
var import_promises2 = require("stream/promises");
|
|
19316
|
-
var
|
|
19317
|
-
var
|
|
20011
|
+
var import_node_child_process6 = require("child_process");
|
|
20012
|
+
var path34 = __toESM(require("path"), 1);
|
|
19318
20013
|
|
|
19319
20014
|
// src/update/manifest.ts
|
|
19320
20015
|
init_cjs_shims();
|
|
@@ -19480,267 +20175,97 @@ async function fetchManifest(url, publicKey, opts = {}) {
|
|
|
19480
20175
|
}
|
|
19481
20176
|
let parsed;
|
|
19482
20177
|
try {
|
|
19483
|
-
parsed = JSON.parse(raw.toString("utf-8"));
|
|
19484
|
-
} catch (err) {
|
|
19485
|
-
return { error: `\u6E05\u5355\u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${err.message}` };
|
|
19486
|
-
}
|
|
19487
|
-
const { manifest, error: error2 } = parseManifest(parsed, opts);
|
|
19488
|
-
if (!manifest) return { error: error2 };
|
|
19489
|
-
return { manifest, raw };
|
|
19490
|
-
}
|
|
19491
|
-
async function downloadBinary(bin, destPath, log = () => {
|
|
19492
|
-
}) {
|
|
19493
|
-
const partPath = `${destPath}.part`;
|
|
19494
|
-
fs26.mkdirSync(path32.dirname(destPath), { recursive: true });
|
|
19495
|
-
fs26.rmSync(partPath, { force: true });
|
|
19496
|
-
let res;
|
|
19497
|
-
try {
|
|
19498
|
-
res = await fetch(bin.url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS2) });
|
|
19499
|
-
} catch (err) {
|
|
19500
|
-
return { error: `\u4E0B\u8F7D\u5931\u8D25\uFF1A${err.message}` };
|
|
19501
|
-
}
|
|
19502
|
-
if (!res.ok) return { error: `\u4E0B\u8F7D\u5931\u8D25 HTTP ${res.status}` };
|
|
19503
|
-
if (!res.body) return { error: "\u4E0B\u8F7D\u54CD\u5E94\u6CA1\u6709 body" };
|
|
19504
|
-
const expected = bin.size && bin.size > 0 ? bin.size : void 0;
|
|
19505
|
-
const limit = expected ? Math.max(expected * 2, 1024 * 1024) : MAX_BINARY_BYTES;
|
|
19506
|
-
const hash = (0, import_node_crypto5.createHash)("sha256");
|
|
19507
|
-
let bytes = 0;
|
|
19508
|
-
try {
|
|
19509
|
-
const source = import_node_stream2.Readable.fromWeb(res.body);
|
|
19510
|
-
await (0, import_promises2.pipeline)(
|
|
19511
|
-
source,
|
|
19512
|
-
async function* (chunks) {
|
|
19513
|
-
for await (const chunk of chunks) {
|
|
19514
|
-
bytes += chunk.length;
|
|
19515
|
-
if (bytes > limit) throw new Error(`\u4EA7\u7269\u8D85\u8FC7\u5927\u5C0F\u4E0A\u9650\uFF08>${limit} \u5B57\u8282\uFF09`);
|
|
19516
|
-
hash.update(chunk);
|
|
19517
|
-
yield chunk;
|
|
19518
|
-
}
|
|
19519
|
-
},
|
|
19520
|
-
fs26.createWriteStream(partPath, { mode: 493 })
|
|
19521
|
-
);
|
|
19522
|
-
} catch (err) {
|
|
19523
|
-
fs26.rmSync(partPath, { force: true });
|
|
19524
|
-
return { error: `\u4E0B\u8F7D\u4E2D\u65AD\uFF1A${err.message}` };
|
|
19525
|
-
}
|
|
19526
|
-
const actual = hash.digest("hex");
|
|
19527
|
-
if (actual !== bin.sha256) {
|
|
19528
|
-
fs26.rmSync(partPath, { force: true });
|
|
19529
|
-
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` };
|
|
19530
|
-
}
|
|
19531
|
-
if (expected && bytes !== expected) {
|
|
19532
|
-
fs26.rmSync(partPath, { force: true });
|
|
19533
|
-
return { error: `\u4EA7\u7269\u5927\u5C0F\u4E0D\u5339\u914D\uFF08\u671F\u671B ${expected}\uFF0C\u5B9E\u9645 ${bytes}\uFF09` };
|
|
19534
|
-
}
|
|
19535
|
-
fs26.rmSync(destPath, { force: true });
|
|
19536
|
-
fs26.renameSync(partPath, destPath);
|
|
19537
|
-
fs26.chmodSync(destPath, 493);
|
|
19538
|
-
log(`\u5DF2\u4E0B\u8F7D ${path32.basename(destPath)}\uFF08${Math.round(bytes / 1024 / 1024)}MB\uFF0C\u6821\u9A8C\u901A\u8FC7\uFF09`);
|
|
19539
|
-
return { bytes };
|
|
19540
|
-
}
|
|
19541
|
-
function selfCheck(binPath, expectedVersion) {
|
|
19542
|
-
try {
|
|
19543
|
-
const r = (0, import_node_child_process5.spawnSync)(binPath, ["--version"], {
|
|
19544
|
-
timeout: 2e4,
|
|
19545
|
-
encoding: "utf-8",
|
|
19546
|
-
env: { ...process.env, ZQAGENT_AUTO_UPDATE: "0" }
|
|
19547
|
-
});
|
|
19548
|
-
if (r.error) return { ok: false, error: `\u6267\u884C\u81EA\u68C0\u5931\u8D25\uFF1A${r.error.message}` };
|
|
19549
|
-
if (r.status !== 0) return { ok: false, error: `\u81EA\u68C0\u9000\u51FA\u7801 ${r.status}\uFF1A${(r.stderr || "").trim()}` };
|
|
19550
|
-
const out = `${r.stdout ?? ""}${r.stderr ?? ""}`;
|
|
19551
|
-
if (!out.includes(expectedVersion)) {
|
|
19552
|
-
return { ok: false, error: `\u81EA\u68C0\u7248\u672C\u4E0D\u7B26\uFF08\u671F\u671B ${expectedVersion}\uFF0C\u8F93\u51FA\uFF1A${out.trim().slice(0, 120)}\uFF09` };
|
|
19553
|
-
}
|
|
19554
|
-
return { ok: true };
|
|
19555
|
-
} catch (err) {
|
|
19556
|
-
return { ok: false, error: `\u81EA\u68C0\u5F02\u5E38\uFF1A${err.message}` };
|
|
19557
|
-
}
|
|
19558
|
-
}
|
|
19559
|
-
|
|
19560
|
-
// src/update/platform.ts
|
|
19561
|
-
init_cjs_shims();
|
|
19562
|
-
var fs27 = __toESM(require("fs"), 1);
|
|
19563
|
-
var os8 = __toESM(require("os"), 1);
|
|
19564
|
-
var path33 = __toESM(require("path"), 1);
|
|
19565
|
-
var import_node_child_process6 = require("child_process");
|
|
19566
|
-
var import_node_module3 = require("module");
|
|
19567
|
-
function currentVersion() {
|
|
19568
|
-
const injected = "0.2.10"?.trim();
|
|
19569
|
-
if (injected) return injected;
|
|
19570
|
-
try {
|
|
19571
|
-
const req2 = (0, import_node_module3.createRequire)(importMetaUrl);
|
|
19572
|
-
const pkg = req2("../../package.json");
|
|
19573
|
-
if (pkg?.version) return pkg.version;
|
|
19574
|
-
} catch {
|
|
19575
|
-
}
|
|
19576
|
-
return "dev";
|
|
19577
|
-
}
|
|
19578
|
-
function isSeaRuntime() {
|
|
19579
|
-
if (process.env.ZQAGENT_SEA === "1") return true;
|
|
19580
|
-
const base = path33.basename(process.execPath).toLowerCase().replace(/\.exe$/, "");
|
|
19581
|
-
return base !== "node" && base !== "nodejs";
|
|
19582
|
-
}
|
|
19583
|
-
var DEFAULT_SERVICE_NAME = "zqagent";
|
|
19584
|
-
var DEFAULT_SERVICE_LABEL = "com.zqagent.node";
|
|
19585
|
-
function serviceManagerFromCgroup(cgroup, serviceName = DEFAULT_SERVICE_NAME) {
|
|
19586
|
-
const unitName = `${serviceName}.service`;
|
|
19587
|
-
for (const line of cgroup.split("\n")) {
|
|
19588
|
-
const idx = line.lastIndexOf(":");
|
|
19589
|
-
if (idx < 0) continue;
|
|
19590
|
-
const unitPath = line.slice(idx + 1).trim();
|
|
19591
|
-
if (unitPath.split("/").includes(unitName)) return "systemd";
|
|
19592
|
-
}
|
|
19593
|
-
return null;
|
|
19594
|
-
}
|
|
19595
|
-
function launchdDomain() {
|
|
19596
|
-
const uid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
19597
|
-
return uid === 0 ? "system" : `gui/${uid}`;
|
|
19598
|
-
}
|
|
19599
|
-
function launchdLabel() {
|
|
19600
|
-
return process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL;
|
|
19601
|
-
}
|
|
19602
|
-
function launchdPlistPath() {
|
|
19603
|
-
const label = launchdLabel();
|
|
19604
|
-
const uid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
19605
|
-
if (uid === 0) return `/Library/LaunchDaemons/${label}.plist`;
|
|
19606
|
-
return path33.join(os8.homedir(), "Library", "LaunchAgents", `${label}.plist`);
|
|
19607
|
-
}
|
|
19608
|
-
function serviceManagerFromLaunchctl(output, pid, execPath, sea = true) {
|
|
19609
|
-
const pidMatch = /^\s*pid = (\d+)\s*$/m.exec(output);
|
|
19610
|
-
if (pidMatch && Number(pidMatch[1]) === pid) return "launchd";
|
|
19611
|
-
const program = /^\s*program = (.+?)\s*$/m.exec(output);
|
|
19612
|
-
if (program) {
|
|
19613
|
-
const shown = program[1].replace(/^"|"$/g, "");
|
|
19614
|
-
if (path33.resolve(shown) === path33.resolve(execPath)) return "launchd";
|
|
19615
|
-
}
|
|
19616
|
-
if (!sea && /^\s*state = /m.test(output)) return "launchd";
|
|
19617
|
-
return null;
|
|
19618
|
-
}
|
|
19619
|
-
function parseLaunchdEnvironment(xml) {
|
|
19620
|
-
const out = {};
|
|
19621
|
-
const marker = xml.indexOf("<key>EnvironmentVariables</key>");
|
|
19622
|
-
if (marker < 0) return out;
|
|
19623
|
-
const open = xml.indexOf("<dict>", marker);
|
|
19624
|
-
if (open < 0) return out;
|
|
19625
|
-
const close = xml.indexOf("</dict>", open);
|
|
19626
|
-
if (close < 0) return out;
|
|
19627
|
-
const body = xml.slice(open + "<dict>".length, close);
|
|
19628
|
-
for (const m of body.matchAll(/<key>([^<]+)<\/key>\s*<string>([^<]*)<\/string>/g)) {
|
|
19629
|
-
out[m[1]] = m[2];
|
|
19630
|
-
}
|
|
19631
|
-
return out;
|
|
19632
|
-
}
|
|
19633
|
-
function detectServiceManager() {
|
|
19634
|
-
if (process.platform === "darwin") return detectLaunchd();
|
|
19635
|
-
if (process.platform !== "linux") return null;
|
|
19636
|
-
const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
|
|
19637
|
-
try {
|
|
19638
|
-
return serviceManagerFromCgroup(
|
|
19639
|
-
fs27.readFileSync("/proc/self/cgroup", "utf8"),
|
|
19640
|
-
serviceName
|
|
19641
|
-
);
|
|
19642
|
-
} catch {
|
|
19643
|
-
return null;
|
|
19644
|
-
}
|
|
19645
|
-
}
|
|
19646
|
-
function detectLaunchd() {
|
|
19647
|
-
try {
|
|
19648
|
-
const res = (0, import_node_child_process6.spawnSync)(
|
|
19649
|
-
"launchctl",
|
|
19650
|
-
["print", `${launchdDomain()}/${launchdLabel()}`],
|
|
19651
|
-
{ encoding: "utf8", timeout: 3e3 }
|
|
19652
|
-
);
|
|
19653
|
-
if (res.status !== 0 || !res.stdout) return null;
|
|
19654
|
-
return serviceManagerFromLaunchctl(
|
|
19655
|
-
res.stdout,
|
|
19656
|
-
process.pid,
|
|
19657
|
-
process.execPath,
|
|
19658
|
-
isSeaRuntime()
|
|
19659
|
-
);
|
|
19660
|
-
} catch {
|
|
19661
|
-
return null;
|
|
19662
|
-
}
|
|
19663
|
-
}
|
|
19664
|
-
function serviceManager() {
|
|
19665
|
-
const v = process.env.ZQAGENT_SERVICE_MANAGER?.trim().toLowerCase();
|
|
19666
|
-
if (v === "systemd" || v === "launchd") return v;
|
|
19667
|
-
return detectServiceManager();
|
|
19668
|
-
}
|
|
19669
|
-
function parseServiceEnvironment(raw) {
|
|
19670
|
-
const out = {};
|
|
19671
|
-
for (const token of raw.trim().split(/\s+/)) {
|
|
19672
|
-
const idx = token.indexOf("=");
|
|
19673
|
-
if (idx > 0) out[token.slice(0, idx)] = token.slice(idx + 1);
|
|
19674
|
-
}
|
|
19675
|
-
return out;
|
|
19676
|
-
}
|
|
19677
|
-
var cachedServiceEnv = null;
|
|
19678
|
-
function readServiceEnvironment() {
|
|
19679
|
-
const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
|
|
19680
|
-
try {
|
|
19681
|
-
const res = (0, import_node_child_process6.spawnSync)(
|
|
19682
|
-
"systemctl",
|
|
19683
|
-
["show", serviceName, "--property=Environment", "--value", "--no-pager"],
|
|
19684
|
-
{ encoding: "utf8", timeout: 3e3 }
|
|
19685
|
-
);
|
|
19686
|
-
if (res.status !== 0 || !res.stdout) return {};
|
|
19687
|
-
return parseServiceEnvironment(res.stdout);
|
|
19688
|
-
} catch {
|
|
19689
|
-
return {};
|
|
20178
|
+
parsed = JSON.parse(raw.toString("utf-8"));
|
|
20179
|
+
} catch (err) {
|
|
20180
|
+
return { error: `\u6E05\u5355\u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${err.message}` };
|
|
19690
20181
|
}
|
|
20182
|
+
const { manifest, error: error2 } = parseManifest(parsed, opts);
|
|
20183
|
+
if (!manifest) return { error: error2 };
|
|
20184
|
+
return { manifest, raw };
|
|
19691
20185
|
}
|
|
19692
|
-
function
|
|
19693
|
-
|
|
19694
|
-
|
|
19695
|
-
|
|
19696
|
-
|
|
20186
|
+
async function downloadBinary(bin, destPath, log = () => {
|
|
20187
|
+
}) {
|
|
20188
|
+
const partPath = `${destPath}.part`;
|
|
20189
|
+
fs27.mkdirSync(path34.dirname(destPath), { recursive: true });
|
|
20190
|
+
fs27.rmSync(partPath, { force: true });
|
|
20191
|
+
let res;
|
|
20192
|
+
try {
|
|
20193
|
+
res = await fetch(bin.url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS2) });
|
|
20194
|
+
} catch (err) {
|
|
20195
|
+
return { error: `\u4E0B\u8F7D\u5931\u8D25\uFF1A${err.message}` };
|
|
19697
20196
|
}
|
|
19698
|
-
if (
|
|
19699
|
-
if (
|
|
19700
|
-
|
|
19701
|
-
|
|
19702
|
-
|
|
19703
|
-
|
|
19704
|
-
function readLaunchdEnvironment() {
|
|
20197
|
+
if (!res.ok) return { error: `\u4E0B\u8F7D\u5931\u8D25 HTTP ${res.status}` };
|
|
20198
|
+
if (!res.body) return { error: "\u4E0B\u8F7D\u54CD\u5E94\u6CA1\u6709 body" };
|
|
20199
|
+
const expected = bin.size && bin.size > 0 ? bin.size : void 0;
|
|
20200
|
+
const limit = expected ? Math.max(expected * 2, 1024 * 1024) : MAX_BINARY_BYTES;
|
|
20201
|
+
const hash = (0, import_node_crypto5.createHash)("sha256");
|
|
20202
|
+
let bytes = 0;
|
|
19705
20203
|
try {
|
|
19706
|
-
|
|
19707
|
-
|
|
19708
|
-
|
|
20204
|
+
const source = import_node_stream2.Readable.fromWeb(res.body);
|
|
20205
|
+
await (0, import_promises2.pipeline)(
|
|
20206
|
+
source,
|
|
20207
|
+
async function* (chunks) {
|
|
20208
|
+
for await (const chunk of chunks) {
|
|
20209
|
+
bytes += chunk.length;
|
|
20210
|
+
if (bytes > limit) throw new Error(`\u4EA7\u7269\u8D85\u8FC7\u5927\u5C0F\u4E0A\u9650\uFF08>${limit} \u5B57\u8282\uFF09`);
|
|
20211
|
+
hash.update(chunk);
|
|
20212
|
+
yield chunk;
|
|
20213
|
+
}
|
|
20214
|
+
},
|
|
20215
|
+
fs27.createWriteStream(partPath, { mode: 493 })
|
|
20216
|
+
);
|
|
20217
|
+
} catch (err) {
|
|
20218
|
+
fs27.rmSync(partPath, { force: true });
|
|
20219
|
+
return { error: `\u4E0B\u8F7D\u4E2D\u65AD\uFF1A${err.message}` };
|
|
19709
20220
|
}
|
|
19710
|
-
|
|
19711
|
-
|
|
19712
|
-
|
|
19713
|
-
return {
|
|
19714
|
-
ok: false,
|
|
19715
|
-
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"
|
|
19716
|
-
};
|
|
20221
|
+
const actual = hash.digest("hex");
|
|
20222
|
+
if (actual !== bin.sha256) {
|
|
20223
|
+
fs27.rmSync(partPath, { force: true });
|
|
20224
|
+
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` };
|
|
19717
20225
|
}
|
|
19718
|
-
if (
|
|
19719
|
-
|
|
19720
|
-
|
|
19721
|
-
reason: "\u672A\u88AB systemd/launchd \u6258\u7BA1\uFF1A\u8BF7\u7528 deploy/service/install.sh \u5B89\u88C5\uFF0C\u6216\u624B\u52A8\u5347\u7EA7"
|
|
19722
|
-
};
|
|
20226
|
+
if (expected && bytes !== expected) {
|
|
20227
|
+
fs27.rmSync(partPath, { force: true });
|
|
20228
|
+
return { error: `\u4EA7\u7269\u5927\u5C0F\u4E0D\u5339\u914D\uFF08\u671F\u671B ${expected}\uFF0C\u5B9E\u9645 ${bytes}\uFF09` };
|
|
19723
20229
|
}
|
|
19724
|
-
|
|
19725
|
-
|
|
20230
|
+
fs27.rmSync(destPath, { force: true });
|
|
20231
|
+
fs27.renameSync(partPath, destPath);
|
|
20232
|
+
fs27.chmodSync(destPath, 493);
|
|
20233
|
+
log(`\u5DF2\u4E0B\u8F7D ${path34.basename(destPath)}\uFF08${Math.round(bytes / 1024 / 1024)}MB\uFF0C\u6821\u9A8C\u901A\u8FC7\uFF09`);
|
|
20234
|
+
return { bytes };
|
|
20235
|
+
}
|
|
20236
|
+
function selfCheck(binPath, expectedVersion) {
|
|
20237
|
+
try {
|
|
20238
|
+
const r = (0, import_node_child_process6.spawnSync)(binPath, ["--version"], {
|
|
20239
|
+
timeout: 2e4,
|
|
20240
|
+
encoding: "utf-8",
|
|
20241
|
+
env: { ...process.env, ZQAGENT_AUTO_UPDATE: "0" }
|
|
20242
|
+
});
|
|
20243
|
+
if (r.error) return { ok: false, error: `\u6267\u884C\u81EA\u68C0\u5931\u8D25\uFF1A${r.error.message}` };
|
|
20244
|
+
if (r.status !== 0) return { ok: false, error: `\u81EA\u68C0\u9000\u51FA\u7801 ${r.status}\uFF1A${(r.stderr || "").trim()}` };
|
|
20245
|
+
const out = `${r.stdout ?? ""}${r.stderr ?? ""}`;
|
|
20246
|
+
if (!out.includes(expectedVersion)) {
|
|
20247
|
+
return { ok: false, error: `\u81EA\u68C0\u7248\u672C\u4E0D\u7B26\uFF08\u671F\u671B ${expectedVersion}\uFF0C\u8F93\u51FA\uFF1A${out.trim().slice(0, 120)}\uFF09` };
|
|
20248
|
+
}
|
|
20249
|
+
return { ok: true };
|
|
20250
|
+
} catch (err) {
|
|
20251
|
+
return { ok: false, error: `\u81EA\u68C0\u5F02\u5E38\uFF1A${err.message}` };
|
|
19726
20252
|
}
|
|
19727
|
-
return { ok: true };
|
|
19728
20253
|
}
|
|
19729
20254
|
|
|
19730
20255
|
// src/update/installer.ts
|
|
19731
20256
|
init_cjs_shims();
|
|
19732
20257
|
var fs29 = __toESM(require("fs"), 1);
|
|
19733
|
-
var
|
|
20258
|
+
var path36 = __toESM(require("path"), 1);
|
|
19734
20259
|
|
|
19735
20260
|
// src/update/state.ts
|
|
19736
20261
|
init_cjs_shims();
|
|
19737
20262
|
var fs28 = __toESM(require("fs"), 1);
|
|
19738
|
-
var
|
|
20263
|
+
var path35 = __toESM(require("path"), 1);
|
|
19739
20264
|
function updatesDir(dataDir) {
|
|
19740
|
-
return
|
|
20265
|
+
return path35.join(dataDir, "updates");
|
|
19741
20266
|
}
|
|
19742
20267
|
function statePath(dataDir) {
|
|
19743
|
-
return
|
|
20268
|
+
return path35.join(updatesDir(dataDir), "state.json");
|
|
19744
20269
|
}
|
|
19745
20270
|
function loadState(dataDir) {
|
|
19746
20271
|
try {
|
|
@@ -19767,12 +20292,12 @@ function patchState(dataDir, patch) {
|
|
|
19767
20292
|
|
|
19768
20293
|
// src/update/installer.ts
|
|
19769
20294
|
function backupDir(dataDir) {
|
|
19770
|
-
return
|
|
20295
|
+
return path36.join(updatesDir(dataDir), "backup");
|
|
19771
20296
|
}
|
|
19772
20297
|
function backupCurrent(dataDir, execPath, version) {
|
|
19773
20298
|
const dir = backupDir(dataDir);
|
|
19774
20299
|
fs29.mkdirSync(dir, { recursive: true });
|
|
19775
|
-
const target =
|
|
20300
|
+
const target = path36.join(dir, `zqagent-${version}${process.platform === "win32" ? ".exe" : ""}`);
|
|
19776
20301
|
fs29.copyFileSync(execPath, target);
|
|
19777
20302
|
fs29.chmodSync(target, 493);
|
|
19778
20303
|
return target;
|
|
@@ -19804,7 +20329,7 @@ function installStaged(opts) {
|
|
|
19804
20329
|
const from = currentVersion();
|
|
19805
20330
|
log(`\u6B63\u5728\u5B89\u88C5 v${opts.version}\uFF08\u5F53\u524D v${from}\uFF09`);
|
|
19806
20331
|
const backupPath = backupCurrent(opts.dataDir, opts.execPath, from);
|
|
19807
|
-
log(`\u5DF2\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5230 ${
|
|
20332
|
+
log(`\u5DF2\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5230 ${path36.basename(backupPath)}`);
|
|
19808
20333
|
replaceExecutable(opts.execPath, opts.stagedPath);
|
|
19809
20334
|
return patchState(opts.dataDir, {
|
|
19810
20335
|
stagedVersion: void 0,
|
|
@@ -19848,7 +20373,7 @@ function rollback(dataDir, execPath, log = () => {
|
|
|
19848
20373
|
}
|
|
19849
20374
|
function readRollbackTarget(dataDir) {
|
|
19850
20375
|
try {
|
|
19851
|
-
const raw = fs29.readFileSync(
|
|
20376
|
+
const raw = fs29.readFileSync(path36.join(updatesDir(dataDir), "state.json"), "utf-8");
|
|
19852
20377
|
const s = JSON.parse(raw);
|
|
19853
20378
|
if (s.backupPath && s.backupVersion) return s;
|
|
19854
20379
|
} catch {
|
|
@@ -20025,7 +20550,7 @@ var UpdateController = class {
|
|
|
20025
20550
|
if (!bin) return `\u6E05\u5355\u6CA1\u6709\u5F53\u524D\u5E73\u53F0\uFF08${platformKey()}\uFF09\u7684\u4EA7\u7269`;
|
|
20026
20551
|
let stagedPath = state.stagedPath;
|
|
20027
20552
|
if (!(state.stagedVersion === manifest.version && stagedPath && fs30.existsSync(stagedPath))) {
|
|
20028
|
-
stagedPath =
|
|
20553
|
+
stagedPath = path37.join(
|
|
20029
20554
|
updatesDir(this.opts.dataDir),
|
|
20030
20555
|
"staged",
|
|
20031
20556
|
`zqagent-${manifest.version}${process.platform === "win32" ? ".exe" : ""}`
|
|
@@ -20200,7 +20725,7 @@ function seedDemoTenant(store) {
|
|
|
20200
20725
|
apiKey: env2("OPENAI_API_KEY"),
|
|
20201
20726
|
baseURL: env2("OPENAI_BASE_URL")
|
|
20202
20727
|
},
|
|
20203
|
-
workspaceRoot: workspace ?
|
|
20728
|
+
workspaceRoot: workspace ? path38.resolve(workspace) : void 0,
|
|
20204
20729
|
allowedCommands: []
|
|
20205
20730
|
};
|
|
20206
20731
|
store.saveTenant(demo);
|
|
@@ -20254,9 +20779,9 @@ function syncTenantModels(store) {
|
|
|
20254
20779
|
tenant.model = model;
|
|
20255
20780
|
changed = true;
|
|
20256
20781
|
}
|
|
20257
|
-
if (workspace && tenant.workspaceRoot !==
|
|
20258
|
-
console.log(`[sync] \u79DF\u6237 ${id} workspaceRoot \u5DF2\u540C\u6B65: ${tenant.workspaceRoot ?? "(\u6C99\u7BB1)"} \u2192 ${
|
|
20259
|
-
tenant.workspaceRoot =
|
|
20782
|
+
if (workspace && tenant.workspaceRoot !== path38.resolve(workspace)) {
|
|
20783
|
+
console.log(`[sync] \u79DF\u6237 ${id} workspaceRoot \u5DF2\u540C\u6B65: ${tenant.workspaceRoot ?? "(\u6C99\u7BB1)"} \u2192 ${path38.resolve(workspace)}`);
|
|
20784
|
+
tenant.workspaceRoot = path38.resolve(workspace);
|
|
20260
20785
|
changed = true;
|
|
20261
20786
|
}
|
|
20262
20787
|
if (apiKey && tenant.provider.apiKey !== apiKey) {
|
|
@@ -20317,7 +20842,7 @@ function listenWithPortFallback(server, startPort, host, dataDir, limit = PORT_F
|
|
|
20317
20842
|
}
|
|
20318
20843
|
try {
|
|
20319
20844
|
fs31.mkdirSync(dataDir, { recursive: true });
|
|
20320
|
-
fs31.writeFileSync(
|
|
20845
|
+
fs31.writeFileSync(path38.join(dataDir, "server-port"), `${actualPort}
|
|
20321
20846
|
`);
|
|
20322
20847
|
} catch {
|
|
20323
20848
|
}
|
|
@@ -20328,7 +20853,7 @@ function listenWithPortFallback(server, startPort, host, dataDir, limit = PORT_F
|
|
|
20328
20853
|
});
|
|
20329
20854
|
}
|
|
20330
20855
|
function startServer(opts = {}) {
|
|
20331
|
-
const dataDir =
|
|
20856
|
+
const dataDir = path38.resolve(opts.dataDir ?? env2("DATA_DIR") ?? DEFAULT_DATA_DIR);
|
|
20332
20857
|
const port = opts.port ?? Number(env2("PORT") ?? 8787);
|
|
20333
20858
|
const host = opts.host ?? env2("HOST") ?? "127.0.0.1";
|
|
20334
20859
|
exitWhenOrphaned();
|
|
@@ -20358,7 +20883,7 @@ function startServer(opts = {}) {
|
|
|
20358
20883
|
}
|
|
20359
20884
|
const adminKey = ensureAdminKey();
|
|
20360
20885
|
const secretKey = env2("SECRET_KEY");
|
|
20361
|
-
const secretBox = secretKey ? SecretBox.fromHex(secretKey) : SecretBox.fromFile(
|
|
20886
|
+
const secretBox = secretKey ? SecretBox.fromHex(secretKey) : SecretBox.fromFile(path38.join(dataDir, "secret.key"));
|
|
20362
20887
|
if (secretKey && !secretBox) {
|
|
20363
20888
|
console.warn("[crypto] SECRET_KEY \u975E\u6CD5\uFF08\u9700 64 \u4F4D hex\uFF09\uFF0C\u901A\u77E5\u51ED\u636E\u5C06\u9000\u5316\u4E3A\u660E\u6587");
|
|
20364
20889
|
}
|
|
@@ -20367,7 +20892,7 @@ function startServer(opts = {}) {
|
|
|
20367
20892
|
let fleet = null;
|
|
20368
20893
|
let fleetCred = null;
|
|
20369
20894
|
function connectFleet(cred) {
|
|
20370
|
-
const localId =
|
|
20895
|
+
const localId = ensureNodeId(store);
|
|
20371
20896
|
const nodeId = (cred.nodeId ?? "").trim() || localId;
|
|
20372
20897
|
if (nodeId !== localId) store.saveNodeId(nodeId);
|
|
20373
20898
|
fleet?.close();
|
|
@@ -20395,7 +20920,7 @@ function startServer(opts = {}) {
|
|
|
20395
20920
|
function fleetStatus() {
|
|
20396
20921
|
return {
|
|
20397
20922
|
linked: fleet !== null,
|
|
20398
|
-
nodeId:
|
|
20923
|
+
nodeId: ensureNodeId(store),
|
|
20399
20924
|
hubUrl: fleetCred?.hubUrl,
|
|
20400
20925
|
gatewayUrl: fleetCred?.gatewayUrl ?? env2("FLEET_GATEWAY_URL"),
|
|
20401
20926
|
online: fleet?.isConnected() ?? false,
|
|
@@ -20407,8 +20932,15 @@ function startServer(opts = {}) {
|
|
|
20407
20932
|
const fleetController = {
|
|
20408
20933
|
status: fleetStatus,
|
|
20409
20934
|
async enroll(input) {
|
|
20410
|
-
const nodeId =
|
|
20411
|
-
const cred = await
|
|
20935
|
+
const nodeId = ensureNodeId(store);
|
|
20936
|
+
const cred = input.account ? await hubEnrollByAccount(input.hubUrl, {
|
|
20937
|
+
email: input.account.email,
|
|
20938
|
+
phone: input.account.phone,
|
|
20939
|
+
password: input.account.password,
|
|
20940
|
+
code: input.account.smsCode,
|
|
20941
|
+
nodeId,
|
|
20942
|
+
label: input.label
|
|
20943
|
+
}) : await hubEnrollByCode(input.hubUrl, {
|
|
20412
20944
|
code: input.code,
|
|
20413
20945
|
nodeId,
|
|
20414
20946
|
label: input.label
|
|
@@ -20434,7 +20966,7 @@ function startServer(opts = {}) {
|
|
|
20434
20966
|
gatewayUrl: fleetCred.gatewayUrl ?? env2("FLEET_GATEWAY_URL"),
|
|
20435
20967
|
fleetToken: fleetCred.fleetToken,
|
|
20436
20968
|
fleetSecret: fleetCred.fleetSecret,
|
|
20437
|
-
nodeId:
|
|
20969
|
+
nodeId: ensureNodeId(store)
|
|
20438
20970
|
};
|
|
20439
20971
|
}
|
|
20440
20972
|
};
|
|
@@ -20587,7 +21119,7 @@ function printReady(info, qq) {
|
|
|
20587
21119
|
`zqagent server \u76D1\u542C http://${info.host}:${info.port}`,
|
|
20588
21120
|
`\u6570\u636E\u76EE\u5F55: ${info.dataDir}`,
|
|
20589
21121
|
`\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`,
|
|
20590
|
-
env2("ZQAGENT_LOG_ADMIN_KEY") === "0" ? `\u7BA1\u7406\u5458\u5BC6\u94A5: ${maskKey(info.adminKey)}\uFF08\u5DF2\u8131\u654F\uFF0C\u5B8C\u6574\u503C\u89C1 ${
|
|
21122
|
+
env2("ZQAGENT_LOG_ADMIN_KEY") === "0" ? `\u7BA1\u7406\u5458\u5BC6\u94A5: ${maskKey(info.adminKey)}\uFF08\u5DF2\u8131\u654F\uFF0C\u5B8C\u6574\u503C\u89C1 ${path38.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`
|
|
20591
21123
|
];
|
|
20592
21124
|
if (info.fleetNodeId) {
|
|
20593
21125
|
lines.push(
|
|
@@ -20606,152 +21138,6 @@ function printReady(info, qq) {
|
|
|
20606
21138
|
for (const l of lines) console.log(l);
|
|
20607
21139
|
}
|
|
20608
21140
|
|
|
20609
|
-
// src/cli/account-enroll.ts
|
|
20610
|
-
init_cjs_shims();
|
|
20611
|
-
var path38 = __toESM(require("path"), 1);
|
|
20612
|
-
var readline = __toESM(require("readline/promises"), 1);
|
|
20613
|
-
var SKIP_ANSWERS = /* @__PURE__ */ new Set(["-", "skip", "none", "no"]);
|
|
20614
|
-
function resolveDefaultHub(hubUrl, env3 = process.env) {
|
|
20615
|
-
return (hubUrl ?? env3.HUB_URL ?? DEFAULT_HUB_URL).trim().replace(/\/$/, "");
|
|
20616
|
-
}
|
|
20617
|
-
function parseHubAnswer(answer, fallback) {
|
|
20618
|
-
const a = answer.trim();
|
|
20619
|
-
if (SKIP_ANSWERS.has(a.toLowerCase())) return null;
|
|
20620
|
-
return (a || fallback).replace(/\/$/, "");
|
|
20621
|
-
}
|
|
20622
|
-
function resolveDataDir2(dataDir) {
|
|
20623
|
-
return path38.resolve(dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
|
|
20624
|
-
}
|
|
20625
|
-
async function maybeAccountEnroll(opts = {}) {
|
|
20626
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) return;
|
|
20627
|
-
let store;
|
|
20628
|
-
try {
|
|
20629
|
-
store = new Store(resolveDataDir2(opts.dataDir));
|
|
20630
|
-
if (resolveFleetConfig(store)) return;
|
|
20631
|
-
} catch (e) {
|
|
20632
|
-
cliErr(`\u63A5\u5165\u68C0\u67E5\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
20633
|
-
return;
|
|
20634
|
-
}
|
|
20635
|
-
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
20636
|
-
try {
|
|
20637
|
-
await runWizard(rl2, store, opts);
|
|
20638
|
-
} catch (e) {
|
|
20639
|
-
cliErr(`\u63A5\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
20640
|
-
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>");
|
|
20641
|
-
} finally {
|
|
20642
|
-
rl2.close();
|
|
20643
|
-
}
|
|
20644
|
-
}
|
|
20645
|
-
async function runWizard(rl2, store, opts) {
|
|
20646
|
-
cliLog("");
|
|
20647
|
-
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");
|
|
20648
|
-
const fallback = resolveDefaultHub(opts.hubUrl);
|
|
20649
|
-
const answer = await rl2.question(`Hub \u5730\u5740 [${fallback}]\uFF1A`);
|
|
20650
|
-
const hubUrl = parseHubAnswer(answer, fallback);
|
|
20651
|
-
if (!hubUrl) {
|
|
20652
|
-
cliLog("\u5DF2\u8DF3\u8FC7\u63A5\u5165\uFF1A\u8282\u70B9\u4FDD\u6301\u7EAF\u672C\u5730\u8FD0\u884C\u3002");
|
|
20653
|
-
return;
|
|
20654
|
-
}
|
|
20655
|
-
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");
|
|
20656
|
-
const mode = (await rl2.question("\u8BF7\u9009\u62E9 [1]\uFF1A")).trim() || "1";
|
|
20657
|
-
const input = {};
|
|
20658
|
-
if (mode === "1") {
|
|
20659
|
-
input.email = (await rl2.question("\u90AE\u7BB1\uFF1A")).trim();
|
|
20660
|
-
input.password = await askHidden(rl2, "\u5BC6\u7801\uFF1A");
|
|
20661
|
-
if (!input.email || !input.password) {
|
|
20662
|
-
cliErr("\u90AE\u7BB1\u4E0E\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
20663
|
-
return;
|
|
20664
|
-
}
|
|
20665
|
-
} else if (mode === "2") {
|
|
20666
|
-
input.phone = (await rl2.question("\u624B\u673A\u53F7\uFF1A")).trim();
|
|
20667
|
-
input.password = await askHidden(rl2, "\u5BC6\u7801\uFF1A");
|
|
20668
|
-
if (!input.phone || !input.password) {
|
|
20669
|
-
cliErr("\u624B\u673A\u53F7\u4E0E\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
20670
|
-
return;
|
|
20671
|
-
}
|
|
20672
|
-
} else if (mode === "3") {
|
|
20673
|
-
input.phone = (await rl2.question("\u624B\u673A\u53F7\uFF1A")).trim();
|
|
20674
|
-
if (!input.phone) {
|
|
20675
|
-
cliErr("\u624B\u673A\u53F7\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
20676
|
-
return;
|
|
20677
|
-
}
|
|
20678
|
-
try {
|
|
20679
|
-
const sent = await hubSendSms(hubUrl, { phone: input.phone, purpose: "login" });
|
|
20680
|
-
if (sent.debugCode) cliLog(`\uFF08\u8C03\u8BD5\u6A21\u5F0F\u9A8C\u8BC1\u7801\uFF1A${sent.debugCode}\uFF09`);
|
|
20681
|
-
else cliLog("\u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001\uFF0C5 \u5206\u949F\u5185\u6709\u6548\u3002");
|
|
20682
|
-
} catch (e) {
|
|
20683
|
-
cliErr(`\u77ED\u4FE1\u9A8C\u8BC1\u7801\u53D1\u9001\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
20684
|
-
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");
|
|
20685
|
-
cliLog(" zqagent link --hub <Hub\u5730\u5740> --code <\u63A5\u5165\u7801>");
|
|
20686
|
-
return;
|
|
20687
|
-
}
|
|
20688
|
-
input.code = (await rl2.question("\u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF1A")).trim();
|
|
20689
|
-
if (!input.code) {
|
|
20690
|
-
cliErr("\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
20691
|
-
return;
|
|
20692
|
-
}
|
|
20693
|
-
} else {
|
|
20694
|
-
cliErr("\u672A\u77E5\u7684\u767B\u5F55\u65B9\u5F0F\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
20695
|
-
return;
|
|
20696
|
-
}
|
|
20697
|
-
const nodeId = ensureNodeId2(store);
|
|
20698
|
-
const cred = await hubEnrollByAccount(hubUrl, { ...input, nodeId, label: opts.label });
|
|
20699
|
-
store.saveFleetCredential({
|
|
20700
|
-
...cred,
|
|
20701
|
-
label: opts.label ?? cred.label,
|
|
20702
|
-
enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
20703
|
-
});
|
|
20704
|
-
cliLog(`\u2705 \u5DF2\u63A5\u5165 Hub\uFF1A\u8282\u70B9 ${cred.nodeId}\uFF08\u7F51\u5173 ${cred.gatewayUrl ?? "\u672A\u4E0B\u53D1"}\uFF09`);
|
|
20705
|
-
cliLog(" \u51ED\u636E\u5DF2\u4FDD\u5B58\u5230 fleet.json\uFF0C\u672C\u6B21\u542F\u52A8\u5373\u8FDE\u63A5 Hub\u3002");
|
|
20706
|
-
}
|
|
20707
|
-
async function askHidden(rl2, prompt) {
|
|
20708
|
-
if (!process.stdin.isTTY) return (await rl2.question(prompt)).trim();
|
|
20709
|
-
return new Promise((resolve24) => {
|
|
20710
|
-
const saved = process.stdin.listeners("data");
|
|
20711
|
-
process.stdin.removeAllListeners("data");
|
|
20712
|
-
cliWrite(prompt);
|
|
20713
|
-
rl2.pause();
|
|
20714
|
-
process.stdin.setRawMode(true);
|
|
20715
|
-
process.stdin.resume();
|
|
20716
|
-
let buf = "";
|
|
20717
|
-
const cleanup = () => {
|
|
20718
|
-
process.stdin.removeListener("data", onData);
|
|
20719
|
-
for (const listener of saved) {
|
|
20720
|
-
process.stdin.on("data", listener);
|
|
20721
|
-
}
|
|
20722
|
-
process.stdin.setRawMode(true);
|
|
20723
|
-
rl2.resume();
|
|
20724
|
-
};
|
|
20725
|
-
const onData = (chunk) => {
|
|
20726
|
-
const s = chunk.toString().replace(/\x1b\[[0-9;?]*[A-Za-z~]/g, "").replace(/\x1bO[A-Za-z]/g, "");
|
|
20727
|
-
for (const ch of s) {
|
|
20728
|
-
if (ch === "\r" || ch === "\n") {
|
|
20729
|
-
cleanup();
|
|
20730
|
-
cliWrite("\n");
|
|
20731
|
-
resolve24(buf);
|
|
20732
|
-
return;
|
|
20733
|
-
}
|
|
20734
|
-
if (ch === "") {
|
|
20735
|
-
cleanup();
|
|
20736
|
-
cliWrite("\n");
|
|
20737
|
-
resolve24("");
|
|
20738
|
-
return;
|
|
20739
|
-
}
|
|
20740
|
-
if (ch === "\x7F" || ch === "\b") {
|
|
20741
|
-
if (buf.length > 0) {
|
|
20742
|
-
buf = buf.slice(0, -1);
|
|
20743
|
-
cliWrite("\b \b");
|
|
20744
|
-
}
|
|
20745
|
-
} else if (ch >= " ") {
|
|
20746
|
-
buf += ch;
|
|
20747
|
-
cliWrite("*");
|
|
20748
|
-
}
|
|
20749
|
-
}
|
|
20750
|
-
};
|
|
20751
|
-
process.stdin.on("data", onData);
|
|
20752
|
-
});
|
|
20753
|
-
}
|
|
20754
|
-
|
|
20755
21141
|
// src/cli/serve.ts
|
|
20756
21142
|
function parse2(argv) {
|
|
20757
21143
|
const out = {};
|
|
@@ -20764,6 +21150,21 @@ function parse2(argv) {
|
|
|
20764
21150
|
} else if (a === "--enroll-code" || a === "--code") {
|
|
20765
21151
|
out.code = v;
|
|
20766
21152
|
i++;
|
|
21153
|
+
} else if (a === "--username" || a === "--user") {
|
|
21154
|
+
out.username = v;
|
|
21155
|
+
i++;
|
|
21156
|
+
} else if (a === "--email") {
|
|
21157
|
+
out.email = v;
|
|
21158
|
+
i++;
|
|
21159
|
+
} else if (a === "--phone") {
|
|
21160
|
+
out.phone = v;
|
|
21161
|
+
i++;
|
|
21162
|
+
} else if (a === "--password") {
|
|
21163
|
+
out.password = v;
|
|
21164
|
+
i++;
|
|
21165
|
+
} else if (a === "--sms-code") {
|
|
21166
|
+
out.smsCode = v;
|
|
21167
|
+
i++;
|
|
20767
21168
|
} else if (a === "--label") {
|
|
20768
21169
|
out.label = v;
|
|
20769
21170
|
i++;
|
|
@@ -20784,7 +21185,32 @@ async function runServeCommand(argv) {
|
|
|
20784
21185
|
const args = parse2(argv);
|
|
20785
21186
|
const hubUrl = (args.hubUrl ?? process.env.HUB_URL ?? "").trim();
|
|
20786
21187
|
const code = (args.code ?? process.env.HUB_ENROLL_CODE ?? "").trim();
|
|
20787
|
-
|
|
21188
|
+
const account = buildAccountAuth(args);
|
|
21189
|
+
if (code && account) {
|
|
21190
|
+
cliErr("--enroll-code \u4E0E Hub \u8D26\u53F7\u53C2\u6570\uFF08--username/--password \u7B49\uFF09\u53EA\u80FD\u4E8C\u9009\u4E00\u3002");
|
|
21191
|
+
return;
|
|
21192
|
+
}
|
|
21193
|
+
if (account && !isCompleteAccount(account) && !process.stdin.isTTY) {
|
|
21194
|
+
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");
|
|
21195
|
+
}
|
|
21196
|
+
if (!code && isCompleteAccount(account)) {
|
|
21197
|
+
try {
|
|
21198
|
+
const r = await linkNode({
|
|
21199
|
+
hubUrl: resolveDefaultHub(args.hubUrl || void 0),
|
|
21200
|
+
account,
|
|
21201
|
+
dataDir: args.dataDir,
|
|
21202
|
+
label: args.label,
|
|
21203
|
+
host: args.host,
|
|
21204
|
+
port: args.port
|
|
21205
|
+
});
|
|
21206
|
+
cliLog(
|
|
21207
|
+
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`
|
|
21208
|
+
);
|
|
21209
|
+
} catch (e) {
|
|
21210
|
+
cliErr(`Hub \u8D26\u53F7\u63A5\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
21211
|
+
}
|
|
21212
|
+
}
|
|
21213
|
+
if (!(hubUrl && code) && !isCompleteAccount(account)) {
|
|
20788
21214
|
await maybeAccountEnroll({ dataDir: args.dataDir, hubUrl: args.hubUrl, label: args.label });
|
|
20789
21215
|
}
|
|
20790
21216
|
const handle = startServer({
|
|
@@ -20923,7 +21349,7 @@ function updateSessionMetaFile(stateDir2, sessionId, patch) {
|
|
|
20923
21349
|
// src/cli/debug.ts
|
|
20924
21350
|
init_cjs_shims();
|
|
20925
21351
|
var fs33 = __toESM(require("fs"), 1);
|
|
20926
|
-
var
|
|
21352
|
+
var os10 = __toESM(require("os"), 1);
|
|
20927
21353
|
var path41 = __toESM(require("path"), 1);
|
|
20928
21354
|
var LOG_NAME = "zqagent-debug.log";
|
|
20929
21355
|
var TRUTHY = /^(1|true|yes|on)$/i;
|
|
@@ -20937,7 +21363,7 @@ function resolveLogFile() {
|
|
|
20937
21363
|
const explicit = process.env.ZQAGENT_DEBUG_LOG;
|
|
20938
21364
|
if (explicit) return path41.resolve(explicit);
|
|
20939
21365
|
const dir = process.env.ZQAGENT_DEBUG_DIR;
|
|
20940
|
-
return path41.join(dir ? path41.resolve(dir) :
|
|
21366
|
+
return path41.join(dir ? path41.resolve(dir) : os10.tmpdir(), LOG_NAME);
|
|
20941
21367
|
}
|
|
20942
21368
|
function enableDebug(argv = process.argv) {
|
|
20943
21369
|
if (enabled) return true;
|
|
@@ -21359,7 +21785,7 @@ function cycleMode(engine) {
|
|
|
21359
21785
|
engine.permissions.mode = next;
|
|
21360
21786
|
return next;
|
|
21361
21787
|
}
|
|
21362
|
-
var rl =
|
|
21788
|
+
var rl = readline3.createInterface({
|
|
21363
21789
|
input: process.stdin,
|
|
21364
21790
|
output: process.stdout
|
|
21365
21791
|
});
|
|
@@ -21375,20 +21801,7 @@ var _exitHandler = null;
|
|
|
21375
21801
|
rl.on("SIGINT", () => {
|
|
21376
21802
|
_exitHandler?.();
|
|
21377
21803
|
});
|
|
21378
|
-
|
|
21379
|
-
const iface = rl;
|
|
21380
|
-
const orig = iface._ttyWrite;
|
|
21381
|
-
iface._ttyWrite = function(s, key) {
|
|
21382
|
-
const k = key;
|
|
21383
|
-
if (k && (k.name === "up" || k.name === "down") && !k.ctrl && !k.meta && !k.shift) {
|
|
21384
|
-
if (iface.cursor > 0) {
|
|
21385
|
-
iface._moveCursor(-iface.cursor);
|
|
21386
|
-
}
|
|
21387
|
-
}
|
|
21388
|
-
orig.call(rl, s, key);
|
|
21389
|
-
};
|
|
21390
|
-
}
|
|
21391
|
-
patchReadlineHistoryNav();
|
|
21804
|
+
patchReadlineHistoryNav(rl);
|
|
21392
21805
|
dlog("init", "\u6A21\u5757\u521D\u59CB\u5316\u5B8C\u6210\uFF08readline / \u8F93\u5165\u8DEF\u7531 / \u5386\u53F2\u5BFC\u822A\u5C31\u7EEA\uFF09");
|
|
21393
21806
|
function question(prompt) {
|
|
21394
21807
|
return inputRouter.ask(prompt);
|
|
@@ -21852,7 +22265,7 @@ async function offerTerminalSetup(engine, canUseAgent) {
|
|
|
21852
22265
|
}
|
|
21853
22266
|
var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set(["link", "serve", "update"]);
|
|
21854
22267
|
function cliVersion() {
|
|
21855
|
-
const env3 = "0.2.
|
|
22268
|
+
const env3 = "0.2.12"?.trim();
|
|
21856
22269
|
if (env3) return env3;
|
|
21857
22270
|
try {
|
|
21858
22271
|
const req2 = (0, import_module.createRequire)(importMetaUrl);
|
|
@@ -21870,11 +22283,13 @@ function printCliUsage() {
|
|
|
21870
22283
|
cliLog(" zqagent serve [\u9009\u9879] \u4EE5 headless \u65B9\u5F0F\u5E38\u9A7B\u4E3A\u53EF\u88AB Hub \u7BA1\u7406\u7684\u8282\u70B9");
|
|
21871
22284
|
cliLog(" zqagent update [--status|--check|--now|--rollback]");
|
|
21872
22285
|
cliLog(" \u67E5\u770B/\u624B\u52A8\u89E6\u53D1\u8282\u70B9\u81EA\u52A8\u66F4\u65B0");
|
|
21873
|
-
cliLog(" zqagent link --hub <url> --
|
|
21874
|
-
cliLog("
|
|
22286
|
+
cliLog(" zqagent link [--hub <url>] [--username <\u90AE\u7BB1/\u624B\u673A\u53F7> --password <\u5BC6\u7801>]");
|
|
22287
|
+
cliLog(" [--code <\u63A5\u5165\u7801>] [--label \u540D\u79F0]");
|
|
22288
|
+
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");
|
|
21875
22289
|
cliLog("");
|
|
21876
22290
|
cliLog("serve \u9009\u9879\uFF1A--port <n> --host <addr> --data-dir <dir>");
|
|
21877
22291
|
cliLog(" --hub <url> --enroll-code <\u7801> --label <\u540D\u79F0> \uFF08\u542F\u52A8\u5373\u63A5\u5165\uFF09");
|
|
22292
|
+
cliLog(" --hub <url> --username <\u90AE\u7BB1/\u624B\u673A\u53F7> --password <\u5BC6\u7801>\uFF08\u8D26\u53F7\u63A5\u5165\uFF09");
|
|
21878
22293
|
cliLog("\u5176\u5B83\u9009\u9879\uFF1A--resume <\u4F1A\u8BDDID> --debug --help/-h --version/-v");
|
|
21879
22294
|
}
|
|
21880
22295
|
async function main() {
|
|
@@ -21891,7 +22306,10 @@ async function main() {
|
|
|
21891
22306
|
process.exit(0);
|
|
21892
22307
|
}
|
|
21893
22308
|
if (subcommand === "link") {
|
|
21894
|
-
const ok2 = await runLinkCommand(process.argv.slice(3)
|
|
22309
|
+
const ok2 = await runLinkCommand(process.argv.slice(3), {
|
|
22310
|
+
rl,
|
|
22311
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY)
|
|
22312
|
+
});
|
|
21895
22313
|
rl.close();
|
|
21896
22314
|
process.exit(ok2 ? 0 : 1);
|
|
21897
22315
|
}
|
|
@@ -22792,7 +23210,11 @@ async function main() {
|
|
|
22792
23210
|
case "/link": {
|
|
22793
23211
|
const code = parts[1];
|
|
22794
23212
|
const hub = parts[2] ?? process.env.HUB_URL;
|
|
22795
|
-
if (!code
|
|
23213
|
+
if (!code) {
|
|
23214
|
+
await runLinkCommand([], { rl, interactive: true });
|
|
23215
|
+
break;
|
|
23216
|
+
}
|
|
23217
|
+
if (!hub) {
|
|
22796
23218
|
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");
|
|
22797
23219
|
break;
|
|
22798
23220
|
}
|