@zqagent/core 0.2.16 → 0.2.20
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.oss.en.md +13 -0
- package/README.oss.md +11 -0
- package/README.oss.zh-TW.md +11 -0
- package/dist/cli/index.cjs +764 -53
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +764 -53
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +16 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/server/index.cjs +733 -47
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +739 -53
- package/dist/server/index.js.map +1 -1
- package/dist/tools/explore.cjs.map +1 -1
- package/dist/tools/explore.js.map +1 -1
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -566,6 +566,15 @@ import * as path5 from "path";
|
|
|
566
566
|
import * as readline from "readline";
|
|
567
567
|
import { randomUUID } from "crypto";
|
|
568
568
|
|
|
569
|
+
// src/server/llmIds.ts
|
|
570
|
+
init_esm_shims();
|
|
571
|
+
var GLOBAL_PROVIDER_ID = "__env__";
|
|
572
|
+
var BUILTIN_PROVIDER_ID = "__zqai__";
|
|
573
|
+
function isBuiltinProvider(id) {
|
|
574
|
+
return id === BUILTIN_PROVIDER_ID;
|
|
575
|
+
}
|
|
576
|
+
var FALLBACK_MODEL = "gpt-4o";
|
|
577
|
+
|
|
569
578
|
// src/server/dbgTrace.ts
|
|
570
579
|
init_esm_shims();
|
|
571
580
|
var DBG_FLEET = (() => {
|
|
@@ -1703,7 +1712,23 @@ var Store = class {
|
|
|
1703
1712
|
legacyFiles: [path5.join(this.root, "node-llm.json")]
|
|
1704
1713
|
});
|
|
1705
1714
|
const old = new Map(cur.providers.map((p) => [p.id, p]));
|
|
1706
|
-
const
|
|
1715
|
+
const src = [...cfg.providers];
|
|
1716
|
+
const prevBuiltin = cur.providers.find((p) => p.id === BUILTIN_PROVIDER_ID);
|
|
1717
|
+
if (prevBuiltin && !src.some((p) => p.id === BUILTIN_PROVIDER_ID)) {
|
|
1718
|
+
src.unshift({
|
|
1719
|
+
id: prevBuiltin.id,
|
|
1720
|
+
name: prevBuiltin.name,
|
|
1721
|
+
type: prevBuiltin.type,
|
|
1722
|
+
baseURL: prevBuiltin.baseURL,
|
|
1723
|
+
model: prevBuiltin.model,
|
|
1724
|
+
apiKey: decryptKey(prevBuiltin.apiKeyEnc, file) ?? void 0,
|
|
1725
|
+
reasoningEffort: prevBuiltin.reasoningEffort ?? null,
|
|
1726
|
+
...prevBuiltin.models ? { models: prevBuiltin.models } : {},
|
|
1727
|
+
...prevBuiltin.nonChat ? { nonChat: prevBuiltin.nonChat } : {},
|
|
1728
|
+
...prevBuiltin.modelMeta ? { modelMeta: prevBuiltin.modelMeta } : {}
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
const providers = src.map((p) => {
|
|
1707
1732
|
const prev = old.get(p.id);
|
|
1708
1733
|
const apiKeyEnc = p.apiKey ? encryptKey(p.apiKey, file) : prev?.apiKeyEnc ?? "";
|
|
1709
1734
|
return {
|
|
@@ -9231,7 +9256,6 @@ function registerMediaTool(registry, workspace, opts = {}) {
|
|
|
9231
9256
|
|
|
9232
9257
|
// src/server/nodeLlm.ts
|
|
9233
9258
|
init_esm_shims();
|
|
9234
|
-
var GLOBAL_PROVIDER_ID = "__env__";
|
|
9235
9259
|
function envProvider() {
|
|
9236
9260
|
const apiKey = process.env.OPENAI_API_KEY;
|
|
9237
9261
|
if (!apiKey) return null;
|
|
@@ -9274,19 +9298,26 @@ function nodeLlmView(cfg) {
|
|
|
9274
9298
|
global: true
|
|
9275
9299
|
}
|
|
9276
9300
|
] : [],
|
|
9277
|
-
...cfg.providers.map((p) =>
|
|
9278
|
-
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9301
|
+
...cfg.providers.map((p) => {
|
|
9302
|
+
const builtin = isBuiltinProvider(p.id);
|
|
9303
|
+
return {
|
|
9304
|
+
id: p.id,
|
|
9305
|
+
name: p.name,
|
|
9306
|
+
type: p.type ?? "",
|
|
9307
|
+
baseURL: p.baseURL,
|
|
9308
|
+
model: p.model,
|
|
9309
|
+
hasApiKey: Boolean(p.apiKey),
|
|
9310
|
+
models: p.models ?? [],
|
|
9311
|
+
nonChat: p.nonChat ?? [],
|
|
9312
|
+
modelMeta: p.modelMeta ?? [],
|
|
9313
|
+
reasoningEffort: p.reasoningEffort ?? null,
|
|
9314
|
+
global: false,
|
|
9315
|
+
/** 平台内置(接入 Hub 后自动下发,用户不用关心 Key) */
|
|
9316
|
+
builtin,
|
|
9317
|
+
/** 不可编辑的字段:控制台据此把 baseURL / key 显示为只读 */
|
|
9318
|
+
...builtin ? { locked: ["baseURL", "apiKey"] } : {}
|
|
9319
|
+
};
|
|
9320
|
+
})
|
|
9290
9321
|
];
|
|
9291
9322
|
return {
|
|
9292
9323
|
defaultProviderId: cfg.defaultProviderId ?? null,
|
|
@@ -9299,27 +9330,42 @@ function applyNodeLlmPatch(cfg, raw) {
|
|
|
9299
9330
|
const next = { providers: cfg.providers, defaultProviderId: cfg.defaultProviderId };
|
|
9300
9331
|
if (Array.isArray(raw?.providers)) {
|
|
9301
9332
|
const old = new Map(cfg.providers.map((p) => [p.id, p]));
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
9314
|
-
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
|
|
9318
|
-
|
|
9319
|
-
|
|
9320
|
-
|
|
9321
|
-
|
|
9322
|
-
|
|
9333
|
+
const incoming = raw.providers.filter((x) => Boolean(x) && typeof x === "object").filter((x) => x.global !== true && String(x.id ?? "") !== GLOBAL_PROVIDER_ID);
|
|
9334
|
+
const prevBuiltin = cfg.providers.find((p) => isBuiltinProvider(p.id));
|
|
9335
|
+
const builtinPatch = incoming.find((x) => isBuiltinProvider(String(x.id ?? "")));
|
|
9336
|
+
const keptBuiltin = prevBuiltin ? [
|
|
9337
|
+
{
|
|
9338
|
+
...prevBuiltin,
|
|
9339
|
+
...builtinPatch?.model != null ? { model: String(builtinPatch.model).trim() || prevBuiltin.model } : {},
|
|
9340
|
+
...normalizeModelList(builtinPatch?.models) ? { models: normalizeModelList(builtinPatch?.models) } : {},
|
|
9341
|
+
...builtinPatch?.reasoningEffort !== void 0 ? { reasoningEffort: normReasoningEffort(builtinPatch.reasoningEffort) } : {},
|
|
9342
|
+
...typeof builtinPatch?.name === "string" && builtinPatch.name.trim() ? { name: builtinPatch.name.trim() } : {}
|
|
9343
|
+
}
|
|
9344
|
+
] : [];
|
|
9345
|
+
next.providers = [
|
|
9346
|
+
...keptBuiltin,
|
|
9347
|
+
...incoming.filter((x) => !isBuiltinProvider(String(x.id ?? ""))).map((x) => {
|
|
9348
|
+
const id = String(x.id ?? "").trim();
|
|
9349
|
+
if (!id) throw new ApiError(400, "bad_request", "\u4F9B\u5E94\u5546 id \u4E0D\u80FD\u4E3A\u7A7A");
|
|
9350
|
+
const prev = old.get(id);
|
|
9351
|
+
const apiKey = String(x.apiKey ?? "").trim();
|
|
9352
|
+
const models = normalizeModelList(x.models) ?? prev?.models;
|
|
9353
|
+
const nonChat = normalizeModelList(x.nonChat) ?? prev?.nonChat;
|
|
9354
|
+
const modelMeta = normalizeModelMeta(x.modelMeta) ?? prev?.modelMeta;
|
|
9355
|
+
return {
|
|
9356
|
+
id,
|
|
9357
|
+
name: String(x.name ?? prev?.name ?? id).trim(),
|
|
9358
|
+
type: x.type == null ? prev?.type : String(x.type),
|
|
9359
|
+
baseURL: String(x.baseURL ?? prev?.baseURL ?? "").trim(),
|
|
9360
|
+
model: String(x.model ?? prev?.model ?? "").trim(),
|
|
9361
|
+
apiKey: apiKey || prev?.apiKey,
|
|
9362
|
+
reasoningEffort: x.reasoningEffort === void 0 ? prev?.reasoningEffort ?? null : normReasoningEffort(x.reasoningEffort),
|
|
9363
|
+
...models ? { models } : {},
|
|
9364
|
+
...nonChat ? { nonChat } : {},
|
|
9365
|
+
...modelMeta ? { modelMeta } : {}
|
|
9366
|
+
};
|
|
9367
|
+
})
|
|
9368
|
+
];
|
|
9323
9369
|
}
|
|
9324
9370
|
if (typeof raw?.defaultProviderId === "string") {
|
|
9325
9371
|
const id = raw.defaultProviderId.trim();
|
|
@@ -9339,6 +9385,9 @@ function nodeDefaultProvider(store) {
|
|
|
9339
9385
|
if (cfg.providers.length === 0) return null;
|
|
9340
9386
|
return cfg.providers.find((p) => p.id === cfg.defaultProviderId) ?? cfg.providers[0] ?? null;
|
|
9341
9387
|
}
|
|
9388
|
+
function defaultTenantModel(store) {
|
|
9389
|
+
return process.env.OPENAI_MODEL || process.env.MODEL || nodeDefaultProvider(store)?.model || FALLBACK_MODEL;
|
|
9390
|
+
}
|
|
9342
9391
|
function resolveSessionProvider(store, tenant, providerId) {
|
|
9343
9392
|
const own = tenant.provider ?? {};
|
|
9344
9393
|
if (providerId) {
|
|
@@ -9368,6 +9417,208 @@ function resolveSessionProvider(store, tenant, providerId) {
|
|
|
9368
9417
|
return { ...own, model: tenant.model };
|
|
9369
9418
|
}
|
|
9370
9419
|
|
|
9420
|
+
// src/server/builtinLlm.ts
|
|
9421
|
+
init_esm_shims();
|
|
9422
|
+
var FETCH_TIMEOUT_MS = 8e3;
|
|
9423
|
+
var RETRY_AFTER_MS = 5 * 6e4;
|
|
9424
|
+
function hubBase(cred) {
|
|
9425
|
+
return (cred.hubUrl ?? "").replace(/\/+$/, "");
|
|
9426
|
+
}
|
|
9427
|
+
function asProvider(grant) {
|
|
9428
|
+
const baseURL = String(grant.baseURL ?? "").trim();
|
|
9429
|
+
const apiKey = String(grant.apiKey ?? "").trim();
|
|
9430
|
+
const model = String(grant.model ?? "").trim();
|
|
9431
|
+
if (!baseURL || !apiKey) return null;
|
|
9432
|
+
return {
|
|
9433
|
+
id: BUILTIN_PROVIDER_ID,
|
|
9434
|
+
name: String(grant.name ?? "").trim() || "\u5FD7\u524D\u5927\u6A21\u578B\uFF08\u5185\u7F6E\uFF09",
|
|
9435
|
+
type: "builtin",
|
|
9436
|
+
baseURL,
|
|
9437
|
+
model,
|
|
9438
|
+
apiKey
|
|
9439
|
+
};
|
|
9440
|
+
}
|
|
9441
|
+
async function enrichModels(p) {
|
|
9442
|
+
try {
|
|
9443
|
+
const r = await Promise.race([
|
|
9444
|
+
fetchModels(p.baseURL, p.apiKey ?? "", p.model),
|
|
9445
|
+
new Promise((resolve20) => {
|
|
9446
|
+
const t = setTimeout(() => resolve20(null), FETCH_TIMEOUT_MS);
|
|
9447
|
+
t.unref?.();
|
|
9448
|
+
})
|
|
9449
|
+
]);
|
|
9450
|
+
if (!r?.models?.length) return p;
|
|
9451
|
+
return {
|
|
9452
|
+
...p,
|
|
9453
|
+
// 控制面没给默认型号时,取供应商返回的第一个,避免模型为空让用户卡住
|
|
9454
|
+
model: p.model || r.models[0],
|
|
9455
|
+
models: r.models,
|
|
9456
|
+
...r.nonChat?.length ? { nonChat: r.nonChat } : {},
|
|
9457
|
+
...r.modelMeta?.length ? { modelMeta: r.modelMeta } : {}
|
|
9458
|
+
};
|
|
9459
|
+
} catch {
|
|
9460
|
+
return p;
|
|
9461
|
+
}
|
|
9462
|
+
}
|
|
9463
|
+
function saveBuiltin(store, provider) {
|
|
9464
|
+
const cfg = store.loadNodeLlm();
|
|
9465
|
+
const others = cfg.providers.filter((p) => p.id !== BUILTIN_PROVIDER_ID);
|
|
9466
|
+
const prev = cfg.providers.find((p) => p.id === BUILTIN_PROVIDER_ID);
|
|
9467
|
+
const merged = {
|
|
9468
|
+
...provider,
|
|
9469
|
+
// 用户选过的型号/候选列表/推理强度/显示名都保留;只有托管字段(baseURL/key)强制以控制面为准
|
|
9470
|
+
...prev?.model ? { model: prev.model } : {},
|
|
9471
|
+
...prev?.models?.length ? { models: prev.models } : {},
|
|
9472
|
+
...prev?.reasoningEffort != null ? { reasoningEffort: prev.reasoningEffort } : {},
|
|
9473
|
+
...prev?.name ? { name: prev.name } : {}
|
|
9474
|
+
};
|
|
9475
|
+
store.saveNodeLlm({
|
|
9476
|
+
providers: [merged, ...others],
|
|
9477
|
+
// 之前没有默认且用户也没指定时,让内置模型成为默认——「开箱即用」
|
|
9478
|
+
defaultProviderId: cfg.defaultProviderId ?? BUILTIN_PROVIDER_ID
|
|
9479
|
+
});
|
|
9480
|
+
adoptBuiltinModelForTenants(store, merged.model);
|
|
9481
|
+
}
|
|
9482
|
+
var LEGACY_DEFAULT_MODELS = /* @__PURE__ */ new Set([FALLBACK_MODEL, "deepseek-v4-flash"]);
|
|
9483
|
+
function adoptBuiltinModelForTenants(store, model) {
|
|
9484
|
+
if (!model) return;
|
|
9485
|
+
for (const id of store.listTenants()) {
|
|
9486
|
+
const tenant = store.loadTenant(id);
|
|
9487
|
+
if (!tenant || !LEGACY_DEFAULT_MODELS.has(tenant.model)) continue;
|
|
9488
|
+
if (tenant.provider?.apiKey) continue;
|
|
9489
|
+
tenant.model = model;
|
|
9490
|
+
store.saveTenant(tenant);
|
|
9491
|
+
}
|
|
9492
|
+
}
|
|
9493
|
+
async function ensureBuiltinProvider(store, opts = {}) {
|
|
9494
|
+
const cred = store.loadFleetCredential();
|
|
9495
|
+
if (!cred?.fleetToken || !cred.fleetSecret) {
|
|
9496
|
+
return { status: "disabled", reason: "\u8282\u70B9\u672A\u63A5\u5165 Hub" };
|
|
9497
|
+
}
|
|
9498
|
+
const hub = hubBase(cred);
|
|
9499
|
+
if (!hub) return { status: "disabled", reason: "\u7F3A\u5C11 Hub \u5730\u5740" };
|
|
9500
|
+
const local = store.loadNodeLlm().providers.find((p) => p.id === BUILTIN_PROVIDER_ID);
|
|
9501
|
+
if (local && !opts.force) {
|
|
9502
|
+
adoptBuiltinModelForTenants(store, local.model);
|
|
9503
|
+
return { status: "ready", provider: local, refreshed: false };
|
|
9504
|
+
}
|
|
9505
|
+
const cached3 = cred.builtinLlm ? asProvider(cred.builtinLlm) : null;
|
|
9506
|
+
let res;
|
|
9507
|
+
try {
|
|
9508
|
+
res = await fetch(`${hub}/api/hub/node/builtin-llm`, {
|
|
9509
|
+
headers: {
|
|
9510
|
+
Authorization: `Bearer ${cred.fleetToken}`,
|
|
9511
|
+
"X-Fleet-Secret": cred.fleetSecret,
|
|
9512
|
+
"X-Node-Id": cred.nodeId
|
|
9513
|
+
},
|
|
9514
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
9515
|
+
});
|
|
9516
|
+
} catch (e) {
|
|
9517
|
+
if (cached3) {
|
|
9518
|
+
const provider2 = await enrichModels(cached3);
|
|
9519
|
+
saveBuiltin(store, provider2);
|
|
9520
|
+
return { status: "ready", provider: provider2, refreshed: true };
|
|
9521
|
+
}
|
|
9522
|
+
return { status: "error", reason: `\u8FDE\u63A5 Hub \u5931\u8D25\uFF1A${e.message}` };
|
|
9523
|
+
}
|
|
9524
|
+
let body = null;
|
|
9525
|
+
try {
|
|
9526
|
+
body = await res.json();
|
|
9527
|
+
} catch {
|
|
9528
|
+
}
|
|
9529
|
+
if (!res.ok) {
|
|
9530
|
+
const msg = body?.error?.message ?? `HTTP ${res.status}`;
|
|
9531
|
+
if (res.status === 401 || res.status === 403) {
|
|
9532
|
+
return { status: "unavailable", reason: msg };
|
|
9533
|
+
}
|
|
9534
|
+
if (cached3) {
|
|
9535
|
+
const provider2 = await enrichModels(cached3);
|
|
9536
|
+
saveBuiltin(store, provider2);
|
|
9537
|
+
return { status: "ready", provider: provider2, refreshed: true };
|
|
9538
|
+
}
|
|
9539
|
+
return { status: "error", reason: msg };
|
|
9540
|
+
}
|
|
9541
|
+
const grant = body?.data?.builtinLlm;
|
|
9542
|
+
if (!grant) {
|
|
9543
|
+
const why = String(body?.data?.reason ?? "").trim();
|
|
9544
|
+
return { status: "unavailable", reason: why || "\u63A7\u5236\u9762\u672A\u4E0B\u53D1\u5185\u7F6E\u6A21\u578B" };
|
|
9545
|
+
}
|
|
9546
|
+
const parsed = asProvider(grant);
|
|
9547
|
+
if (!parsed) return { status: "unavailable", reason: "\u5185\u7F6E\u6A21\u578B\u914D\u7F6E\u4E0D\u5B8C\u6574" };
|
|
9548
|
+
const provider = await enrichModels(parsed);
|
|
9549
|
+
saveBuiltin(store, provider);
|
|
9550
|
+
return { status: "ready", provider, refreshed: true };
|
|
9551
|
+
}
|
|
9552
|
+
async function fetchLlmBalance(store) {
|
|
9553
|
+
const cred = store.loadFleetCredential();
|
|
9554
|
+
const hub = cred ? hubBase(cred) : "";
|
|
9555
|
+
if (!cred?.fleetToken || !cred.fleetSecret || !hub) {
|
|
9556
|
+
return { available: null, currency: "CNY", reason: "\u8282\u70B9\u672A\u63A5\u5165 Hub" };
|
|
9557
|
+
}
|
|
9558
|
+
try {
|
|
9559
|
+
const res = await fetch(`${hub}/api/hub/node/balance`, {
|
|
9560
|
+
headers: {
|
|
9561
|
+
Authorization: `Bearer ${cred.fleetToken}`,
|
|
9562
|
+
"X-Fleet-Secret": cred.fleetSecret,
|
|
9563
|
+
"X-Node-Id": cred.nodeId
|
|
9564
|
+
},
|
|
9565
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
9566
|
+
});
|
|
9567
|
+
const body = await res.json().catch(() => null);
|
|
9568
|
+
if (!res.ok) {
|
|
9569
|
+
return {
|
|
9570
|
+
available: null,
|
|
9571
|
+
currency: "CNY",
|
|
9572
|
+
reason: body?.data ? "" : `HTTP ${res.status}`
|
|
9573
|
+
};
|
|
9574
|
+
}
|
|
9575
|
+
const d = body?.data ?? {};
|
|
9576
|
+
const available = typeof d.available === "number" ? d.available : null;
|
|
9577
|
+
return {
|
|
9578
|
+
available,
|
|
9579
|
+
currency: typeof d.currency === "string" && d.currency ? d.currency : "CNY",
|
|
9580
|
+
...typeof d.reserved === "number" ? { reserved: d.reserved } : {},
|
|
9581
|
+
// Hub 没配 HUB_PUBLIC_URL 时退回用接入时的 hubUrl
|
|
9582
|
+
topupUrl: typeof d.topupUrl === "string" && d.topupUrl ? d.topupUrl : `${hub}/topup`,
|
|
9583
|
+
...available === null && typeof d.reason === "string" ? { reason: d.reason } : {}
|
|
9584
|
+
};
|
|
9585
|
+
} catch (e) {
|
|
9586
|
+
return {
|
|
9587
|
+
available: null,
|
|
9588
|
+
currency: "CNY",
|
|
9589
|
+
reason: `\u8FDE\u63A5 Hub \u5931\u8D25\uFF1A${e.message}`
|
|
9590
|
+
};
|
|
9591
|
+
}
|
|
9592
|
+
}
|
|
9593
|
+
var AUTH_RETRY_THROTTLE_MS = 6e4;
|
|
9594
|
+
var lastAuthRetryAt = 0;
|
|
9595
|
+
function healBuiltinOnAuthFailure(store, message) {
|
|
9596
|
+
if (!/401|unauthorized|invalid[_\s]*api[_\s]*key|api[\s_-]*key\s*(?:无效|invalid)/i.test(message)) return;
|
|
9597
|
+
if (!store.loadFleetCredential()) return;
|
|
9598
|
+
if (!store.loadNodeLlm().providers.some((p) => p.id === BUILTIN_PROVIDER_ID)) return;
|
|
9599
|
+
if (Date.now() - lastAuthRetryAt < AUTH_RETRY_THROTTLE_MS) return;
|
|
9600
|
+
lastAuthRetryAt = Date.now();
|
|
9601
|
+
void ensureBuiltinProvider(store, { force: true }).catch(() => {
|
|
9602
|
+
});
|
|
9603
|
+
}
|
|
9604
|
+
var lastFailureAt = 0;
|
|
9605
|
+
function scheduleBuiltinProvider(store, log = () => {
|
|
9606
|
+
}) {
|
|
9607
|
+
if (Date.now() - lastFailureAt < RETRY_AFTER_MS) return;
|
|
9608
|
+
void ensureBuiltinProvider(store).then((r) => {
|
|
9609
|
+
if (r.status === "ready") {
|
|
9610
|
+
if (r.refreshed) log(`[builtin-llm] \u5DF2\u4E0B\u53D1\u5185\u7F6E\u6A21\u578B\uFF1A${r.provider.name}\uFF08${r.provider.model}\uFF09`);
|
|
9611
|
+
return;
|
|
9612
|
+
}
|
|
9613
|
+
if (r.status === "disabled") return;
|
|
9614
|
+
lastFailureAt = Date.now();
|
|
9615
|
+
if (r.status === "unavailable") log(`[builtin-llm] \u6682\u65E0\u5185\u7F6E\u6A21\u578B\uFF1A${r.reason}`);
|
|
9616
|
+
else log(`[builtin-llm] \u62C9\u53D6\u5185\u7F6E\u6A21\u578B\u5931\u8D25\uFF1A${r.reason}`);
|
|
9617
|
+
}).catch(() => {
|
|
9618
|
+
lastFailureAt = Date.now();
|
|
9619
|
+
});
|
|
9620
|
+
}
|
|
9621
|
+
|
|
9371
9622
|
// src/server/usage.ts
|
|
9372
9623
|
init_esm_shims();
|
|
9373
9624
|
import * as fs18 from "fs";
|
|
@@ -11429,6 +11680,7 @@ data: ${JSON.stringify(entry.data)}
|
|
|
11429
11680
|
this._setStatus(rt, "error");
|
|
11430
11681
|
this._persist(rt);
|
|
11431
11682
|
this._emitNotify(rt, "error", this._turnEndData(rt, event.data, {}));
|
|
11683
|
+
healBuiltinOnAuthFailure(this.store, String(event.data["error"] ?? ""));
|
|
11432
11684
|
break;
|
|
11433
11685
|
case "interrupted" /* INTERRUPTED */:
|
|
11434
11686
|
this._setStatus(rt, "interrupted");
|
|
@@ -11859,7 +12111,6 @@ import * as path26 from "path";
|
|
|
11859
12111
|
// src/server/projects.ts
|
|
11860
12112
|
init_esm_shims();
|
|
11861
12113
|
import * as path22 from "path";
|
|
11862
|
-
var DEFAULT_MODEL = () => process.env.OPENAI_MODEL || process.env.MODEL || "gpt-4o";
|
|
11863
12114
|
function toProjectSummary(store, tenant) {
|
|
11864
12115
|
return {
|
|
11865
12116
|
id: tenant.id,
|
|
@@ -11999,7 +12250,7 @@ function createProject(store, input) {
|
|
|
11999
12250
|
id,
|
|
12000
12251
|
name: explicitName || defaultName,
|
|
12001
12252
|
apiKey: generateApiKey(),
|
|
12002
|
-
model: typeof raw.model === "string" && raw.model.trim() ? raw.model.trim() :
|
|
12253
|
+
model: typeof raw.model === "string" && raw.model.trim() ? raw.model.trim() : defaultTenantModel(store),
|
|
12003
12254
|
provider: {
|
|
12004
12255
|
apiKey: typeof raw.providerApiKey === "string" && raw.providerApiKey.trim() ? raw.providerApiKey.trim() : void 0,
|
|
12005
12256
|
baseURL: typeof raw.baseURL === "string" && raw.baseURL.trim() ? raw.baseURL.trim() : void 0
|
|
@@ -12024,7 +12275,7 @@ function buildNodeInfo(store, opts) {
|
|
|
12024
12275
|
nodeId: opts.nodeId ?? ensureNodeId(store),
|
|
12025
12276
|
platform: process.platform,
|
|
12026
12277
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
12027
|
-
version: "0.2.
|
|
12278
|
+
version: "0.2.20",
|
|
12028
12279
|
admin: opts.admin,
|
|
12029
12280
|
projects: opts.projects
|
|
12030
12281
|
};
|
|
@@ -12390,10 +12641,133 @@ function makeDirIn(parentInput, name) {
|
|
|
12390
12641
|
init_esm_shims();
|
|
12391
12642
|
import * as fs20 from "fs";
|
|
12392
12643
|
import * as path24 from "path";
|
|
12644
|
+
|
|
12645
|
+
// src/server/zipArchive.ts
|
|
12646
|
+
init_esm_shims();
|
|
12647
|
+
import * as zlib from "zlib";
|
|
12648
|
+
var MAX_ZIP_ENTRIES = 2e4;
|
|
12649
|
+
var LOCAL_SIG = 67324752;
|
|
12650
|
+
var CENTRAL_SIG = 33639248;
|
|
12651
|
+
var EOCD_SIG = 101010256;
|
|
12652
|
+
var FLAG_UTF8 = 2048;
|
|
12653
|
+
var METHOD_STORE = 0;
|
|
12654
|
+
var METHOD_DEFLATE = 8;
|
|
12655
|
+
var CRC_TABLE = (() => {
|
|
12656
|
+
const table = new Int32Array(256);
|
|
12657
|
+
for (let n = 0; n < 256; n++) {
|
|
12658
|
+
let c = n;
|
|
12659
|
+
for (let k = 0; k < 8; k++) {
|
|
12660
|
+
c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
12661
|
+
}
|
|
12662
|
+
table[n] = c;
|
|
12663
|
+
}
|
|
12664
|
+
return table;
|
|
12665
|
+
})();
|
|
12666
|
+
function crc32(buf) {
|
|
12667
|
+
let c = -1;
|
|
12668
|
+
for (let i = 0; i < buf.length; i++) {
|
|
12669
|
+
c = CRC_TABLE[(c ^ buf[i]) & 255] ^ c >>> 8;
|
|
12670
|
+
}
|
|
12671
|
+
return (c ^ -1) >>> 0;
|
|
12672
|
+
}
|
|
12673
|
+
function dosDateTime(d) {
|
|
12674
|
+
const year = Math.max(1980, d.getFullYear());
|
|
12675
|
+
return {
|
|
12676
|
+
time: d.getHours() << 11 | d.getMinutes() << 5 | d.getSeconds() >> 1,
|
|
12677
|
+
date: year - 1980 << 9 | d.getMonth() + 1 << 5 | d.getDate()
|
|
12678
|
+
};
|
|
12679
|
+
}
|
|
12680
|
+
function buildZip(entries) {
|
|
12681
|
+
if (entries.length > MAX_ZIP_ENTRIES) {
|
|
12682
|
+
throw new Error(`\u5F52\u6863\u6761\u76EE\u8FC7\u591A\uFF08${entries.length} > ${MAX_ZIP_ENTRIES}\uFF09`);
|
|
12683
|
+
}
|
|
12684
|
+
const chunks = [];
|
|
12685
|
+
const central = [];
|
|
12686
|
+
let offset = 0;
|
|
12687
|
+
for (const e of entries) {
|
|
12688
|
+
const name = Buffer.from(e.name, "utf-8");
|
|
12689
|
+
const isDir = e.name.endsWith("/");
|
|
12690
|
+
const raw = isDir ? Buffer.alloc(0) : e.data ?? Buffer.alloc(0);
|
|
12691
|
+
let method = METHOD_STORE;
|
|
12692
|
+
let body = raw;
|
|
12693
|
+
if (!isDir && raw.length > 0) {
|
|
12694
|
+
const deflated = zlib.deflateRawSync(raw, { level: 6 });
|
|
12695
|
+
if (deflated.length < raw.length) {
|
|
12696
|
+
method = METHOD_DEFLATE;
|
|
12697
|
+
body = deflated;
|
|
12698
|
+
}
|
|
12699
|
+
}
|
|
12700
|
+
const crc = isDir ? 0 : crc32(raw);
|
|
12701
|
+
const { time, date } = dosDateTime(e.mtime ?? /* @__PURE__ */ new Date());
|
|
12702
|
+
const local = Buffer.alloc(30);
|
|
12703
|
+
local.writeUInt32LE(LOCAL_SIG, 0);
|
|
12704
|
+
local.writeUInt16LE(20, 4);
|
|
12705
|
+
local.writeUInt16LE(FLAG_UTF8, 6);
|
|
12706
|
+
local.writeUInt16LE(method, 8);
|
|
12707
|
+
local.writeUInt16LE(time, 10);
|
|
12708
|
+
local.writeUInt16LE(date, 12);
|
|
12709
|
+
local.writeUInt32LE(crc, 14);
|
|
12710
|
+
local.writeUInt32LE(body.length, 18);
|
|
12711
|
+
local.writeUInt32LE(raw.length, 22);
|
|
12712
|
+
local.writeUInt16LE(name.length, 26);
|
|
12713
|
+
local.writeUInt16LE(0, 28);
|
|
12714
|
+
chunks.push(local, name);
|
|
12715
|
+
if (body.length > 0) chunks.push(body);
|
|
12716
|
+
central.push({
|
|
12717
|
+
name,
|
|
12718
|
+
method,
|
|
12719
|
+
crc,
|
|
12720
|
+
csize: body.length,
|
|
12721
|
+
usize: raw.length,
|
|
12722
|
+
offset,
|
|
12723
|
+
time,
|
|
12724
|
+
date,
|
|
12725
|
+
isDir
|
|
12726
|
+
});
|
|
12727
|
+
offset += local.length + name.length + body.length;
|
|
12728
|
+
}
|
|
12729
|
+
const cdStart = offset;
|
|
12730
|
+
for (const c of central) {
|
|
12731
|
+
const head = Buffer.alloc(46);
|
|
12732
|
+
head.writeUInt32LE(CENTRAL_SIG, 0);
|
|
12733
|
+
head.writeUInt16LE(20, 4);
|
|
12734
|
+
head.writeUInt16LE(20, 6);
|
|
12735
|
+
head.writeUInt16LE(FLAG_UTF8, 8);
|
|
12736
|
+
head.writeUInt16LE(c.method, 10);
|
|
12737
|
+
head.writeUInt16LE(c.time, 12);
|
|
12738
|
+
head.writeUInt16LE(c.date, 14);
|
|
12739
|
+
head.writeUInt32LE(c.crc, 16);
|
|
12740
|
+
head.writeUInt32LE(c.csize, 20);
|
|
12741
|
+
head.writeUInt32LE(c.usize, 24);
|
|
12742
|
+
head.writeUInt16LE(c.name.length, 28);
|
|
12743
|
+
head.writeUInt16LE(0, 30);
|
|
12744
|
+
head.writeUInt16LE(0, 32);
|
|
12745
|
+
head.writeUInt16LE(0, 34);
|
|
12746
|
+
head.writeUInt16LE(0, 36);
|
|
12747
|
+
head.writeUInt32LE(c.isDir ? 16 : 0, 38);
|
|
12748
|
+
head.writeUInt32LE(c.offset, 42);
|
|
12749
|
+
chunks.push(head, c.name);
|
|
12750
|
+
offset += head.length + c.name.length;
|
|
12751
|
+
}
|
|
12752
|
+
const eocd = Buffer.alloc(22);
|
|
12753
|
+
eocd.writeUInt32LE(EOCD_SIG, 0);
|
|
12754
|
+
eocd.writeUInt16LE(0, 4);
|
|
12755
|
+
eocd.writeUInt16LE(0, 6);
|
|
12756
|
+
eocd.writeUInt16LE(central.length, 8);
|
|
12757
|
+
eocd.writeUInt16LE(central.length, 10);
|
|
12758
|
+
eocd.writeUInt32LE(offset - cdStart, 12);
|
|
12759
|
+
eocd.writeUInt32LE(cdStart, 16);
|
|
12760
|
+
eocd.writeUInt16LE(0, 20);
|
|
12761
|
+
chunks.push(eocd);
|
|
12762
|
+
return Buffer.concat(chunks);
|
|
12763
|
+
}
|
|
12764
|
+
|
|
12765
|
+
// src/server/projectFiles.ts
|
|
12393
12766
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
12394
12767
|
var MAX_DOWNLOAD_BYTES = 16 * 1024 * 1024;
|
|
12395
12768
|
var MAX_BINARY_BYTES = 2.5 * 1024 * 1024;
|
|
12396
12769
|
var MAX_ENTRIES2 = 2e3;
|
|
12770
|
+
var MAX_ZIP_BYTES = 100 * 1024 * 1024;
|
|
12397
12771
|
function toPosix(p) {
|
|
12398
12772
|
return p.split(path24.sep).join("/");
|
|
12399
12773
|
}
|
|
@@ -12669,6 +13043,134 @@ function deleteProjectPaths(workspaceRoot, relPaths) {
|
|
|
12669
13043
|
}
|
|
12670
13044
|
return out;
|
|
12671
13045
|
}
|
|
13046
|
+
function formatBytes(n) {
|
|
13047
|
+
if (n >= 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MB`;
|
|
13048
|
+
if (n >= 1024) return `${(n / 1024).toFixed(1)} KB`;
|
|
13049
|
+
return `${n} B`;
|
|
13050
|
+
}
|
|
13051
|
+
function renameProjectPath(workspaceRoot, relPath, newName) {
|
|
13052
|
+
const base = projectRoot(workspaceRoot);
|
|
13053
|
+
const rel = (relPath ?? "").trim().replace(/^[/\\]+/, "");
|
|
13054
|
+
if (!rel) throw new Error("\u4E0D\u80FD\u91CD\u547D\u540D\u9879\u76EE\u6839\u76EE\u5F55");
|
|
13055
|
+
const abs = resolveWithin(base, rel);
|
|
13056
|
+
const name = (newName ?? "").trim();
|
|
13057
|
+
if (!name) throw new Error("\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
|
|
13058
|
+
if (name === "." || name === "..") throw new Error("\u540D\u79F0\u975E\u6CD5");
|
|
13059
|
+
if (/[/\\]/.test(name)) throw new Error("\u540D\u79F0\u4E0D\u80FD\u5305\u542B\u8DEF\u5F84\u5206\u9694\u7B26");
|
|
13060
|
+
if (!fs20.existsSync(abs)) throw new Error("\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
13061
|
+
const parent = path24.dirname(abs);
|
|
13062
|
+
const target = path24.join(parent, name);
|
|
13063
|
+
if (!isWithinRoot(base, target)) throw new Error("\u8DEF\u5F84\u8D8A\u754C\uFF08\u8D85\u51FA\u9879\u76EE\u5DE5\u4F5C\u533A\uFF09");
|
|
13064
|
+
if (fs20.existsSync(target)) {
|
|
13065
|
+
let same = false;
|
|
13066
|
+
try {
|
|
13067
|
+
const a = fs20.statSync(target);
|
|
13068
|
+
const b = fs20.statSync(abs);
|
|
13069
|
+
same = a.ino === b.ino && a.dev === b.dev;
|
|
13070
|
+
} catch {
|
|
13071
|
+
same = false;
|
|
13072
|
+
}
|
|
13073
|
+
if (!same) throw new Error(`\u5DF2\u5B58\u5728\u540C\u540D\u6587\u4EF6\u6216\u76EE\u5F55: ${name}`);
|
|
13074
|
+
}
|
|
13075
|
+
if (path24.resolve(target) === path24.resolve(abs)) {
|
|
13076
|
+
return { from: toPosix(path24.relative(base, abs)), path: toPosix(path24.relative(base, abs)) };
|
|
13077
|
+
}
|
|
13078
|
+
try {
|
|
13079
|
+
fs20.renameSync(abs, target);
|
|
13080
|
+
} catch (e) {
|
|
13081
|
+
throw new Error(`\u91CD\u547D\u540D\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
13082
|
+
}
|
|
13083
|
+
return { from: toPosix(path24.relative(base, abs)), path: toPosix(path24.relative(base, target)) };
|
|
13084
|
+
}
|
|
13085
|
+
function zipProjectPaths(workspaceRoot, relPaths, opts = {}) {
|
|
13086
|
+
const base = projectRoot(workspaceRoot);
|
|
13087
|
+
const maxBytes = opts.maxBytes && opts.maxBytes > 0 ? opts.maxBytes : MAX_ZIP_BYTES;
|
|
13088
|
+
const rels = (relPaths ?? []).map((x) => (x ?? "").trim().replace(/^[/\\]+/, ""));
|
|
13089
|
+
if (rels.length === 0) throw new Error("\u8BF7\u9009\u62E9\u8981\u538B\u7F29\u7684\u6587\u4EF6\u6216\u76EE\u5F55");
|
|
13090
|
+
if (rels.some((r) => !r)) throw new Error("\u4E0D\u80FD\u538B\u7F29\u9879\u76EE\u6839\u76EE\u5F55");
|
|
13091
|
+
const targets = rels.map((rel) => ({ rel, abs: resolveWithin(base, rel) }));
|
|
13092
|
+
const single = targets.length === 1 ? targets[0].abs : "";
|
|
13093
|
+
const items = [];
|
|
13094
|
+
let total = 0;
|
|
13095
|
+
const overLimit = () => new Error(
|
|
13096
|
+
`\u5171 ${formatBytes(total)}\uFF0C\u8D85\u8FC7 ${formatBytes(maxBytes)} \u4E0A\u9650\uFF0C\u4E0D\u652F\u6301\u538B\u7F29\u4E0B\u8F7D`
|
|
13097
|
+
);
|
|
13098
|
+
const walk = (absDir) => {
|
|
13099
|
+
let dirents;
|
|
13100
|
+
try {
|
|
13101
|
+
dirents = fs20.readdirSync(absDir, { withFileTypes: true });
|
|
13102
|
+
} catch {
|
|
13103
|
+
return 0;
|
|
13104
|
+
}
|
|
13105
|
+
dirents.sort((a, b) => a.name.localeCompare(b.name));
|
|
13106
|
+
let files = 0;
|
|
13107
|
+
for (const d of dirents) {
|
|
13108
|
+
if (d.isSymbolicLink()) continue;
|
|
13109
|
+
const child = path24.join(absDir, d.name);
|
|
13110
|
+
if (d.isDirectory()) {
|
|
13111
|
+
files += walk(child);
|
|
13112
|
+
continue;
|
|
13113
|
+
}
|
|
13114
|
+
if (!d.isFile()) continue;
|
|
13115
|
+
let st;
|
|
13116
|
+
try {
|
|
13117
|
+
st = fs20.statSync(child);
|
|
13118
|
+
} catch {
|
|
13119
|
+
continue;
|
|
13120
|
+
}
|
|
13121
|
+
total += st.size;
|
|
13122
|
+
if (total > maxBytes) throw overLimit();
|
|
13123
|
+
if (items.length >= MAX_ZIP_ENTRIES) {
|
|
13124
|
+
throw new Error(`\u5F52\u6863\u6761\u76EE\u8FC7\u591A\uFF08\u8D85\u8FC7 ${MAX_ZIP_ENTRIES} \u9879\uFF09\uFF0C\u8BF7\u7F29\u5C0F\u8303\u56F4\u540E\u518D\u8BD5`);
|
|
13125
|
+
}
|
|
13126
|
+
items.push({ abs: child, dir: false, size: st.size, mtime: st.mtime });
|
|
13127
|
+
files++;
|
|
13128
|
+
}
|
|
13129
|
+
if (files === 0) {
|
|
13130
|
+
let mtime = /* @__PURE__ */ new Date();
|
|
13131
|
+
try {
|
|
13132
|
+
mtime = fs20.statSync(absDir).mtime;
|
|
13133
|
+
} catch {
|
|
13134
|
+
}
|
|
13135
|
+
items.push({ abs: absDir, dir: true, size: 0, mtime });
|
|
13136
|
+
}
|
|
13137
|
+
return files;
|
|
13138
|
+
};
|
|
13139
|
+
for (const t of targets) {
|
|
13140
|
+
let st;
|
|
13141
|
+
try {
|
|
13142
|
+
st = fs20.statSync(t.abs);
|
|
13143
|
+
} catch {
|
|
13144
|
+
throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${t.rel}`);
|
|
13145
|
+
}
|
|
13146
|
+
if (st.isDirectory()) {
|
|
13147
|
+
walk(t.abs);
|
|
13148
|
+
continue;
|
|
13149
|
+
}
|
|
13150
|
+
total += st.size;
|
|
13151
|
+
if (total > maxBytes) throw overLimit();
|
|
13152
|
+
items.push({ abs: t.abs, dir: false, size: st.size, mtime: st.mtime });
|
|
13153
|
+
}
|
|
13154
|
+
const nameOf = (abs) => {
|
|
13155
|
+
const rel = toPosix(path24.relative(single || base, abs));
|
|
13156
|
+
return rel || path24.posix.basename(toPosix(abs));
|
|
13157
|
+
};
|
|
13158
|
+
const zipEntries = items.map((it) => {
|
|
13159
|
+
const name2 = nameOf(it.abs);
|
|
13160
|
+
if (it.dir) return { name: `${name2}/`, mtime: it.mtime };
|
|
13161
|
+
return { name: name2, data: fs20.readFileSync(it.abs), mtime: it.mtime };
|
|
13162
|
+
});
|
|
13163
|
+
const buf = buildZip(zipEntries);
|
|
13164
|
+
const first = targets[0].rel;
|
|
13165
|
+
const name = single ? `${path24.posix.basename(toPosix(first))}.zip` : "archive.zip";
|
|
13166
|
+
return {
|
|
13167
|
+
name,
|
|
13168
|
+
size: buf.length,
|
|
13169
|
+
total,
|
|
13170
|
+
entries: zipEntries.length,
|
|
13171
|
+
base64: buf.toString("base64")
|
|
13172
|
+
};
|
|
13173
|
+
}
|
|
12672
13174
|
|
|
12673
13175
|
// src/server/projectOps.ts
|
|
12674
13176
|
init_esm_shims();
|
|
@@ -12998,6 +13500,7 @@ function projectStats(manager, tenantId) {
|
|
|
12998
13500
|
|
|
12999
13501
|
// src/server/nodeHost.ts
|
|
13000
13502
|
init_esm_shims();
|
|
13503
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
13001
13504
|
import * as fs21 from "fs";
|
|
13002
13505
|
import * as os6 from "os";
|
|
13003
13506
|
function diskInfo(pathStr) {
|
|
@@ -13012,6 +13515,64 @@ function diskInfo(pathStr) {
|
|
|
13012
13515
|
return null;
|
|
13013
13516
|
}
|
|
13014
13517
|
}
|
|
13518
|
+
var PSEUDO_FS = /^(devfs|tmpfs|devtmpfs|proc|procfs|sysfs|none|udev|shm|mqueue|devpts|hugetlbfs|debugfs|tracefs|securityfs|pstore|bpf|configfs|fusectl|nsfs|autofs|efivarfs|ramfs|map)$/;
|
|
13519
|
+
function isInternalMount(mount) {
|
|
13520
|
+
if (mount === "/") return false;
|
|
13521
|
+
const prefixes = ["/proc", "/sys", "/run", "/snap"];
|
|
13522
|
+
if (process.platform === "darwin") prefixes.push("/System/Volumes");
|
|
13523
|
+
return prefixes.some((p) => mount === p || mount.startsWith(`${p}/`));
|
|
13524
|
+
}
|
|
13525
|
+
function readOnlyVolumes() {
|
|
13526
|
+
const out = /* @__PURE__ */ new Set();
|
|
13527
|
+
const res = spawnSync2("mount", [], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
|
|
13528
|
+
if (res.error || res.status !== 0 || !res.stdout) return out;
|
|
13529
|
+
for (const line of res.stdout.split("\n")) {
|
|
13530
|
+
const m = line.match(/^.+? on (.+?) \(([^)]*)\)$/);
|
|
13531
|
+
if (!m || m[1] === "/") continue;
|
|
13532
|
+
if (m[2].split(",").some((opt) => opt.trim() === "read-only")) out.add(m[1]);
|
|
13533
|
+
}
|
|
13534
|
+
return out;
|
|
13535
|
+
}
|
|
13536
|
+
function diskList(workspacePath) {
|
|
13537
|
+
const out = [];
|
|
13538
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13539
|
+
const push = (path37, total, free) => {
|
|
13540
|
+
if (!path37 || seen.has(path37) || !Number.isFinite(total) || total <= 0) return;
|
|
13541
|
+
seen.add(path37);
|
|
13542
|
+
out.push({ path: path37, total, free });
|
|
13543
|
+
};
|
|
13544
|
+
if (process.platform === "win32") {
|
|
13545
|
+
for (const letter of "CDEFGHIJKLMNOPQRSTUVWXYZ") {
|
|
13546
|
+
const root = `${letter}:\\`;
|
|
13547
|
+
const d = diskInfo(root);
|
|
13548
|
+
if (d) push(root, d.total, d.free);
|
|
13549
|
+
}
|
|
13550
|
+
} else {
|
|
13551
|
+
const readonly = process.platform === "darwin" ? readOnlyVolumes() : /* @__PURE__ */ new Set();
|
|
13552
|
+
const res = spawnSync2("df", ["-kP"], {
|
|
13553
|
+
encoding: "utf-8",
|
|
13554
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
13555
|
+
});
|
|
13556
|
+
if (!res.error && res.status === 0 && res.stdout) {
|
|
13557
|
+
for (const line of res.stdout.split("\n").slice(1)) {
|
|
13558
|
+
const m = line.trim().match(/^(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+\d+%\s+(.+)$/);
|
|
13559
|
+
if (!m || PSEUDO_FS.test(m[1])) continue;
|
|
13560
|
+
if (/^\/dev\/loop\d+$/.test(m[1])) continue;
|
|
13561
|
+
if (isInternalMount(m[5]) || readonly.has(m[5])) continue;
|
|
13562
|
+
push(m[5], Number(m[2]) * 1024, Number(m[4]) * 1024);
|
|
13563
|
+
}
|
|
13564
|
+
}
|
|
13565
|
+
}
|
|
13566
|
+
const primary = diskInfo(workspacePath);
|
|
13567
|
+
if (primary) {
|
|
13568
|
+
const covered = out.some((d) => {
|
|
13569
|
+
const root = d.path.endsWith("/") || d.path.endsWith("\\") ? d.path : `${d.path}/`;
|
|
13570
|
+
return workspacePath === d.path || workspacePath.startsWith(root);
|
|
13571
|
+
});
|
|
13572
|
+
if (!covered) push(primary.path, primary.total, primary.free);
|
|
13573
|
+
}
|
|
13574
|
+
return out.sort((a, b) => b.total - a.total);
|
|
13575
|
+
}
|
|
13015
13576
|
function networkInfo() {
|
|
13016
13577
|
const out = [];
|
|
13017
13578
|
const ifaces = os6.networkInterfaces();
|
|
@@ -13067,6 +13628,7 @@ function overview(store, manager) {
|
|
|
13067
13628
|
function buildNodeHost(store, manager, diskPath) {
|
|
13068
13629
|
const cpus2 = os6.cpus();
|
|
13069
13630
|
const ov = overview(store, manager);
|
|
13631
|
+
const disks = diskList(diskPath || process.cwd());
|
|
13070
13632
|
return {
|
|
13071
13633
|
nodeId: store.loadNodeId() ?? "",
|
|
13072
13634
|
hostname: os6.hostname(),
|
|
@@ -13074,7 +13636,7 @@ function buildNodeHost(store, manager, diskPath) {
|
|
|
13074
13636
|
arch: process.arch,
|
|
13075
13637
|
release: os6.release(),
|
|
13076
13638
|
uptimeSec: Math.round(os6.uptime()),
|
|
13077
|
-
version: "0.2.
|
|
13639
|
+
version: "0.2.20",
|
|
13078
13640
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
13079
13641
|
cpu: {
|
|
13080
13642
|
count: cpus2.length,
|
|
@@ -13084,6 +13646,7 @@ function buildNodeHost(store, manager, diskPath) {
|
|
|
13084
13646
|
memory: { total: os6.totalmem(), free: os6.freemem() },
|
|
13085
13647
|
network: networkInfo(),
|
|
13086
13648
|
disk: diskInfo(diskPath || process.cwd()),
|
|
13649
|
+
disks,
|
|
13087
13650
|
...ov
|
|
13088
13651
|
};
|
|
13089
13652
|
}
|
|
@@ -14309,6 +14872,41 @@ function createApp(store, manager, opts = {}) {
|
|
|
14309
14872
|
}
|
|
14310
14873
|
}
|
|
14311
14874
|
},
|
|
14875
|
+
{
|
|
14876
|
+
method: "POST",
|
|
14877
|
+
pattern: ["files", "rename"],
|
|
14878
|
+
// 重命名(只改同目录下的名字)
|
|
14879
|
+
fn: (_req, res, { tenant, body }) => {
|
|
14880
|
+
const raw = body ?? {};
|
|
14881
|
+
try {
|
|
14882
|
+
ok(
|
|
14883
|
+
res,
|
|
14884
|
+
renameProjectPath(
|
|
14885
|
+
tenant.workspaceRoot ?? null,
|
|
14886
|
+
String(raw.path ?? ""),
|
|
14887
|
+
String(raw.name ?? "")
|
|
14888
|
+
)
|
|
14889
|
+
);
|
|
14890
|
+
} catch (e) {
|
|
14891
|
+
throw new ApiError(400, "bad_request", e instanceof Error ? e.message : String(e));
|
|
14892
|
+
}
|
|
14893
|
+
}
|
|
14894
|
+
},
|
|
14895
|
+
{
|
|
14896
|
+
method: "POST",
|
|
14897
|
+
pattern: ["files", "zip"],
|
|
14898
|
+
// 压缩下载(多选一起打包;超上限由实现拒绝)
|
|
14899
|
+
fn: (_req, res, { tenant, body }) => {
|
|
14900
|
+
const raw = body ?? {};
|
|
14901
|
+
const paths = Array.isArray(raw.paths) ? raw.paths.map((x) => String(x)) : [];
|
|
14902
|
+
if (paths.length === 0) throw new ApiError(400, "bad_request", "paths \u4E0D\u80FD\u4E3A\u7A7A");
|
|
14903
|
+
try {
|
|
14904
|
+
ok(res, zipProjectPaths(tenant.workspaceRoot ?? null, paths));
|
|
14905
|
+
} catch (e) {
|
|
14906
|
+
throw new ApiError(400, "bad_request", e instanceof Error ? e.message : String(e));
|
|
14907
|
+
}
|
|
14908
|
+
}
|
|
14909
|
+
},
|
|
14312
14910
|
// ---------- 项目(= 租户)管理:控制台多项目视图 ----------
|
|
14313
14911
|
// 仅管理员密钥可用;项目级与会话级接口仍用项目自己的 tenant API Key
|
|
14314
14912
|
// (或管理员密钥 + X-Project-Id 头),互不暴露明文密钥。
|
|
@@ -14367,6 +14965,29 @@ function createApp(store, manager, opts = {}) {
|
|
|
14367
14965
|
ok(res, nodeLlmView(next));
|
|
14368
14966
|
}
|
|
14369
14967
|
},
|
|
14968
|
+
// 大模型账户余额(控制台「余额不足 → 查看余额并充值」用;由节点向 Hub 代查)
|
|
14969
|
+
{
|
|
14970
|
+
method: "GET",
|
|
14971
|
+
pattern: ["node", "llm", "balance"],
|
|
14972
|
+
adminOnly: true,
|
|
14973
|
+
fn: async (_req, res) => {
|
|
14974
|
+
ok(res, await fetchLlmBalance(store));
|
|
14975
|
+
}
|
|
14976
|
+
},
|
|
14977
|
+
// 重新拉取平台内置模型凭据(用户点了「刷新内置模型」,或 Key 在控制台被重置)
|
|
14978
|
+
{
|
|
14979
|
+
method: "POST",
|
|
14980
|
+
pattern: ["node", "llm", "builtin-refresh"],
|
|
14981
|
+
adminOnly: true,
|
|
14982
|
+
fn: async (_req, res) => {
|
|
14983
|
+
const r = await ensureBuiltinProvider(store, { force: true });
|
|
14984
|
+
if (r.status !== "ready") {
|
|
14985
|
+
ok(res, { ok: false, reason: r.reason });
|
|
14986
|
+
return;
|
|
14987
|
+
}
|
|
14988
|
+
ok(res, { ok: true, view: nodeLlmView(store.loadNodeLlm()) });
|
|
14989
|
+
}
|
|
14990
|
+
},
|
|
14370
14991
|
// ---------- 用量(账本 + 汇总 + 价格) ----------
|
|
14371
14992
|
{
|
|
14372
14993
|
method: "GET",
|
|
@@ -14793,7 +15414,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
14793
15414
|
json(res, 200, {
|
|
14794
15415
|
status: "ok",
|
|
14795
15416
|
// 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
|
|
14796
|
-
version: "0.2.
|
|
15417
|
+
version: "0.2.20",
|
|
14797
15418
|
features: { mcp: hasServerMcpConfig() }
|
|
14798
15419
|
});
|
|
14799
15420
|
return;
|
|
@@ -15133,6 +15754,22 @@ async function dispatchFleetCommand(deps, env3) {
|
|
|
15133
15754
|
store.saveNodeLlm(next);
|
|
15134
15755
|
return ok2(nodeLlmView(next));
|
|
15135
15756
|
}
|
|
15757
|
+
/*
|
|
15758
|
+
* 重新拉取平台内置模型(志前 API)。
|
|
15759
|
+
*
|
|
15760
|
+
* 用途:用户在控制台点了「刷新」、或内置模型的 Key 在控制台被重置后需要换新。
|
|
15761
|
+
* 走写链串行——它会改写 connections.json,不能与 update_node_llm 并发。
|
|
15762
|
+
*/
|
|
15763
|
+
// 余额查询:只读、幂等,可进只读并发池
|
|
15764
|
+
case "get_llm_balance":
|
|
15765
|
+
return ok2(await fetchLlmBalance(store));
|
|
15766
|
+
case "refresh_builtin_llm": {
|
|
15767
|
+
const r = await ensureBuiltinProvider(store, { force: true });
|
|
15768
|
+
if (r.status !== "ready") {
|
|
15769
|
+
return ok2({ ok: false, reason: r.reason });
|
|
15770
|
+
}
|
|
15771
|
+
return ok2({ ok: true, view: nodeLlmView(store.loadNodeLlm()) });
|
|
15772
|
+
}
|
|
15136
15773
|
case "get_usage_summary": {
|
|
15137
15774
|
const ledger = manager.usageLedger();
|
|
15138
15775
|
if (!ledger) return ok2({ total: null, groups: [] });
|
|
@@ -15317,6 +15954,24 @@ async function dispatchFleetCommand(deps, env3) {
|
|
|
15317
15954
|
const t = project();
|
|
15318
15955
|
return ok2(searchProjectFiles(t.workspaceRoot ?? null, String(payload.query ?? "")));
|
|
15319
15956
|
}
|
|
15957
|
+
case "rename_path": {
|
|
15958
|
+
const t = project();
|
|
15959
|
+
return ok2(
|
|
15960
|
+
renameProjectPath(
|
|
15961
|
+
t.workspaceRoot ?? null,
|
|
15962
|
+
String(payload.path ?? ""),
|
|
15963
|
+
String(payload.name ?? "")
|
|
15964
|
+
)
|
|
15965
|
+
);
|
|
15966
|
+
}
|
|
15967
|
+
case "zip_download": {
|
|
15968
|
+
const t = project();
|
|
15969
|
+
const raw = payload.paths;
|
|
15970
|
+
const paths = Array.isArray(raw) ? raw.map((x) => String(x)) : [];
|
|
15971
|
+
if (paths.length === 0) throw new ApiError(400, "bad_request", "paths \u4E0D\u80FD\u4E3A\u7A7A");
|
|
15972
|
+
const maxBytes = typeof payload.maxBytes === "number" ? payload.maxBytes : void 0;
|
|
15973
|
+
return ok2(zipProjectPaths(t.workspaceRoot ?? null, paths, { maxBytes }));
|
|
15974
|
+
}
|
|
15320
15975
|
case "list_tools": {
|
|
15321
15976
|
const t = project();
|
|
15322
15977
|
return ok2(buildToolCatalog(t.workspaceRoot ?? process.cwd()));
|
|
@@ -15669,6 +16324,22 @@ function toWireAck(ack) {
|
|
|
15669
16324
|
data: ack.data === void 0 ? void 0 : utf8Encode(JSON.stringify(ack.data))
|
|
15670
16325
|
};
|
|
15671
16326
|
}
|
|
16327
|
+
var ACK_JSON_MAX_BYTES = MAX_FRAME_BYTES - 64 * 1024;
|
|
16328
|
+
function mb(bytes) {
|
|
16329
|
+
return (bytes / (1024 * 1024)).toFixed(1);
|
|
16330
|
+
}
|
|
16331
|
+
function guardAckSize(ack, json2) {
|
|
16332
|
+
if (!ack.ok || ack.data === void 0) return ack;
|
|
16333
|
+
const bytes = Buffer.byteLength(json2, "utf8");
|
|
16334
|
+
if (bytes <= ACK_JSON_MAX_BYTES) return ack;
|
|
16335
|
+
return {
|
|
16336
|
+
reqId: ack.reqId,
|
|
16337
|
+
type: ack.type,
|
|
16338
|
+
ok: false,
|
|
16339
|
+
// 带上实际大小:用户据此能判断「差一点」还是「差很多」,而不是只看到「失败」
|
|
16340
|
+
error: `\u7ED3\u679C\u8FC7\u5927\uFF08${mb(bytes)} MB\uFF09\uFF0C\u8D85\u8FC7\u5355\u5E27\u4F20\u8F93\u4E0A\u9650\uFF08${mb(ACK_JSON_MAX_BYTES)} MB\uFF09\uFF0C\u8BF7\u7F29\u5C0F\u8303\u56F4\u540E\u91CD\u8BD5`
|
|
16341
|
+
};
|
|
16342
|
+
}
|
|
15672
16343
|
function fromWireCommand(env3) {
|
|
15673
16344
|
let payload = {};
|
|
15674
16345
|
if (env3.payload && env3.payload.length > 0) {
|
|
@@ -16139,6 +16810,7 @@ var READONLY_CMD_TYPES = /* @__PURE__ */ new Set([
|
|
|
16139
16810
|
"get_node_llm",
|
|
16140
16811
|
"list_node_llm_models",
|
|
16141
16812
|
"get_usage_summary",
|
|
16813
|
+
"get_llm_balance",
|
|
16142
16814
|
"get_usage_records",
|
|
16143
16815
|
"get_usage_pricing",
|
|
16144
16816
|
"list_projects",
|
|
@@ -16563,7 +17235,7 @@ var FleetNodeBridge = class {
|
|
|
16563
17235
|
label: this.opts.deps.store.loadNodeLabel() ?? void 0,
|
|
16564
17236
|
platform: process.platform,
|
|
16565
17237
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
16566
|
-
version: "0.2.
|
|
17238
|
+
version: "0.2.20",
|
|
16567
17239
|
ip: primaryIp()
|
|
16568
17240
|
};
|
|
16569
17241
|
}
|
|
@@ -16661,7 +17333,7 @@ var FleetNodeBridge = class {
|
|
|
16661
17333
|
label: this.opts.deps.store.loadNodeLabel() ?? void 0,
|
|
16662
17334
|
platform: process.platform,
|
|
16663
17335
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
16664
|
-
version: "0.2.
|
|
17336
|
+
version: "0.2.20",
|
|
16665
17337
|
ip: primaryIp(),
|
|
16666
17338
|
projects,
|
|
16667
17339
|
totals,
|
|
@@ -16823,7 +17495,13 @@ var FleetNodeBridge = class {
|
|
|
16823
17495
|
const stamped = { ...ack, reqId: env3.reqId, type: env3.type };
|
|
16824
17496
|
const json2 = JSON.stringify(stamped);
|
|
16825
17497
|
const __t1 = dbgNow();
|
|
16826
|
-
|
|
17498
|
+
const payload = guardAckSize(stamped, json2);
|
|
17499
|
+
if (payload !== stamped) {
|
|
17500
|
+
console.warn(
|
|
17501
|
+
`[fleet] ${env3.type} \u56DE\u6267 ${(json2.length / 1024 / 1024).toFixed(1)}MB \u8D85\u8FC7\u5355\u5E27\u4E0A\u9650\uFF0C\u5DF2\u964D\u7EA7\u4E3A\u9519\u8BEF\u56DE\u6267`
|
|
17502
|
+
);
|
|
17503
|
+
}
|
|
17504
|
+
this._send({ kind: "ack", clientId: env3.clientId, ack: payload });
|
|
16827
17505
|
dbgMs(
|
|
16828
17506
|
"publishAck",
|
|
16829
17507
|
__t0,
|
|
@@ -18147,7 +18825,7 @@ import { createHash as createHash3 } from "crypto";
|
|
|
18147
18825
|
import * as fs24 from "fs";
|
|
18148
18826
|
import { Readable as Readable2 } from "stream";
|
|
18149
18827
|
import { pipeline as pipeline2 } from "stream/promises";
|
|
18150
|
-
import { spawnSync as
|
|
18828
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
18151
18829
|
import * as path29 from "path";
|
|
18152
18830
|
|
|
18153
18831
|
// src/update/manifest.ts
|
|
@@ -18374,7 +19052,7 @@ async function downloadBinary(bin, destPath, log = () => {
|
|
|
18374
19052
|
}
|
|
18375
19053
|
function selfCheck(binPath, expectedVersion) {
|
|
18376
19054
|
try {
|
|
18377
|
-
const r =
|
|
19055
|
+
const r = spawnSync3(binPath, ["--version"], {
|
|
18378
19056
|
timeout: 2e4,
|
|
18379
19057
|
encoding: "utf-8",
|
|
18380
19058
|
env: { ...process.env, ZQAGENT_AUTO_UPDATE: "0" }
|
|
@@ -18396,10 +19074,10 @@ init_esm_shims();
|
|
|
18396
19074
|
import * as fs25 from "fs";
|
|
18397
19075
|
import * as os9 from "os";
|
|
18398
19076
|
import * as path30 from "path";
|
|
18399
|
-
import { spawnSync as
|
|
19077
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
18400
19078
|
import { createRequire as createRequire3 } from "module";
|
|
18401
19079
|
function currentVersion() {
|
|
18402
|
-
const injected = "0.2.
|
|
19080
|
+
const injected = "0.2.20"?.trim();
|
|
18403
19081
|
if (injected) return injected;
|
|
18404
19082
|
try {
|
|
18405
19083
|
const req2 = createRequire3(import.meta.url);
|
|
@@ -18479,7 +19157,7 @@ function detectServiceManager() {
|
|
|
18479
19157
|
}
|
|
18480
19158
|
function detectLaunchd() {
|
|
18481
19159
|
try {
|
|
18482
|
-
const res =
|
|
19160
|
+
const res = spawnSync4(
|
|
18483
19161
|
"launchctl",
|
|
18484
19162
|
["print", `${launchdDomain()}/${launchdLabel()}`],
|
|
18485
19163
|
{ encoding: "utf8", timeout: 3e3 }
|
|
@@ -18512,7 +19190,7 @@ var cachedServiceEnv = null;
|
|
|
18512
19190
|
function readServiceEnvironment() {
|
|
18513
19191
|
const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
|
|
18514
19192
|
try {
|
|
18515
|
-
const res =
|
|
19193
|
+
const res = spawnSync4(
|
|
18516
19194
|
"systemctl",
|
|
18517
19195
|
["show", serviceName, "--property=Environment", "--value", "--no-pager"],
|
|
18518
19196
|
{ encoding: "utf8", timeout: 3e3 }
|
|
@@ -19125,7 +19803,9 @@ function seedDemoTenant(store) {
|
|
|
19125
19803
|
// 未显式指定时随机生成:固定默认密钥一旦随 HOST=0.0.0.0 暴露到公网,等于公开凭据。
|
|
19126
19804
|
// 只在首次创建时生成并落盘,后续启动沿用磁盘上的值(启动日志会打印完整密钥)。
|
|
19127
19805
|
apiKey: env2("TENANT_API_KEY") ?? generateApiKey(),
|
|
19128
|
-
|
|
19806
|
+
// 不再硬编码具体厂商型号:志前 API 只认 deepseek-flash,写死 deepseek-v4-flash
|
|
19807
|
+
// 会让新装节点的第一次请求 404。默认值统一走 defaultTenantModel(见 nodeLlm.ts)。
|
|
19808
|
+
model: defaultTenantModel(store),
|
|
19129
19809
|
provider: {
|
|
19130
19810
|
apiKey: env2("OPENAI_API_KEY"),
|
|
19131
19811
|
baseURL: env2("OPENAI_BASE_URL")
|
|
@@ -19265,6 +19945,8 @@ function startServer(opts = {}) {
|
|
|
19265
19945
|
const store = new Store(dataDir);
|
|
19266
19946
|
const demo = seedDemoTenant(store);
|
|
19267
19947
|
syncTenantModels(store);
|
|
19948
|
+
const nodeModel = nodeDefaultProvider(store)?.model;
|
|
19949
|
+
if (nodeModel) adoptBuiltinModelForTenants(store, nodeModel);
|
|
19268
19950
|
const usageLedger = new UsageLedger(dataDir);
|
|
19269
19951
|
usageLedger.init();
|
|
19270
19952
|
const manager = new SessionManager(store, void 0, { usage: usageLedger });
|
|
@@ -19408,8 +20090,12 @@ function startServer(opts = {}) {
|
|
|
19408
20090
|
if (initialCred) {
|
|
19409
20091
|
connectFleet(initialCred);
|
|
19410
20092
|
} else if (opts.autoEnroll) {
|
|
19411
|
-
void fleetController.enroll(opts.autoEnroll).then((st) =>
|
|
20093
|
+
void fleetController.enroll(opts.autoEnroll).then((st) => {
|
|
20094
|
+
console.log(`[fleet] \u5DF2\u81EA\u52A8\u63A5\u5165\uFF0C\u8282\u70B9 ${st.nodeId}\uFF08${st.gatewayUrl}\uFF09`);
|
|
20095
|
+
scheduleBuiltinProvider(store, (m) => console.log(m));
|
|
20096
|
+
}).catch((e) => console.warn(`[fleet] \u81EA\u52A8\u63A5\u5165\u5931\u8D25\uFF08\u53EF\u7A0D\u540E /link \u91CD\u8BD5\uFF09: ${e instanceof Error ? e.message : e}`));
|
|
19412
20097
|
}
|
|
20098
|
+
if (initialCred) scheduleBuiltinProvider(store, (m) => console.log(m));
|
|
19413
20099
|
const pairingCodes = new PairingCodeStore();
|
|
19414
20100
|
const qq = new QqManager({
|
|
19415
20101
|
store,
|
|
@@ -19749,7 +20435,7 @@ import * as readline3 from "readline";
|
|
|
19749
20435
|
|
|
19750
20436
|
// src/cli/serve-instances.ts
|
|
19751
20437
|
init_esm_shims();
|
|
19752
|
-
import { spawnSync as
|
|
20438
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
19753
20439
|
import * as fs30 from "fs";
|
|
19754
20440
|
import * as os10 from "os";
|
|
19755
20441
|
import * as path36 from "path";
|