@zqagent/core 0.2.10 → 0.2.11

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/dist/cli/index.js CHANGED
@@ -10077,6 +10077,38 @@ function countRawEscapes(chunk) {
10077
10077
  for (const ch of cleaned) if (ch === "\x1B") escCount++;
10078
10078
  return escCount;
10079
10079
  }
10080
+ function patchReadlineHistoryNav(rl2) {
10081
+ const iface = rl2;
10082
+ const orig = iface._ttyWrite;
10083
+ let draft = null;
10084
+ iface._ttyWrite = function(s, key) {
10085
+ const k = key;
10086
+ const name = k?.name;
10087
+ const plainArrow = (name === "up" || name === "down") && !k?.ctrl && !k?.meta && !k?.shift;
10088
+ if (plainArrow) {
10089
+ if (name === "up" && iface.historyIndex === -1) {
10090
+ draft = { line: iface.line, cursor: iface.cursor };
10091
+ }
10092
+ if (iface.cursor > 0) {
10093
+ iface._moveCursor(-iface.cursor);
10094
+ }
10095
+ }
10096
+ const prevHistoryIndex = iface.historyIndex;
10097
+ orig.call(rl2, s, key);
10098
+ if (plainArrow && name === "down" && prevHistoryIndex >= 0 && iface.historyIndex === -1) {
10099
+ const saved = draft;
10100
+ draft = null;
10101
+ if (saved) {
10102
+ iface.line = saved.line;
10103
+ iface.cursor = Math.min(saved.cursor, saved.line.length);
10104
+ iface._refreshLine?.();
10105
+ }
10106
+ }
10107
+ };
10108
+ rl2.on("line", () => {
10109
+ draft = null;
10110
+ });
10111
+ }
10080
10112
  var PASTE_PLACEHOLDER_PREFIX = "\u7C98\u8D34\u6587\u672C #";
10081
10113
  var InputRouter = class {
10082
10114
  rl;
@@ -10464,7 +10496,7 @@ function renderTerminalTutorial() {
10464
10496
 
10465
10497
  // src/cli/link.ts
10466
10498
  init_esm_shims();
10467
- import * as path22 from "path";
10499
+ import * as path23 from "path";
10468
10500
 
10469
10501
  // src/server/store.ts
10470
10502
  init_esm_shims();
@@ -10874,11 +10906,186 @@ async function hubEnrollByAccount(baseUrl, input) {
10874
10906
 
10875
10907
  // src/cli/serve-instances.ts
10876
10908
  init_esm_shims();
10877
- import { spawnSync as spawnSync2 } from "child_process";
10909
+ import { spawnSync as spawnSync3 } from "child_process";
10910
+ import * as fs19 from "fs";
10911
+ import * as os5 from "os";
10912
+ import * as path22 from "path";
10913
+
10914
+ // src/update/platform.ts
10915
+ init_esm_shims();
10878
10916
  import * as fs18 from "fs";
10917
+ import * as os4 from "os";
10879
10918
  import * as path21 from "path";
10919
+ import { spawnSync as spawnSync2 } from "child_process";
10920
+ import { createRequire as createRequire3 } from "module";
10921
+ function currentVersion() {
10922
+ const injected = "0.2.11"?.trim();
10923
+ if (injected) return injected;
10924
+ try {
10925
+ const req2 = createRequire3(import.meta.url);
10926
+ const pkg = req2("../../package.json");
10927
+ if (pkg?.version) return pkg.version;
10928
+ } catch {
10929
+ }
10930
+ return "dev";
10931
+ }
10932
+ function isSeaRuntime() {
10933
+ if (process.env.ZQAGENT_SEA === "1") return true;
10934
+ const base = path21.basename(process.execPath).toLowerCase().replace(/\.exe$/, "");
10935
+ return base !== "node" && base !== "nodejs";
10936
+ }
10937
+ var DEFAULT_SERVICE_NAME = "zqagent";
10938
+ var DEFAULT_SERVICE_LABEL = "com.zqagent.node";
10939
+ function serviceManagerFromCgroup(cgroup, serviceName = DEFAULT_SERVICE_NAME) {
10940
+ const unitName = `${serviceName}.service`;
10941
+ for (const line of cgroup.split("\n")) {
10942
+ const idx = line.lastIndexOf(":");
10943
+ if (idx < 0) continue;
10944
+ const unitPath = line.slice(idx + 1).trim();
10945
+ if (unitPath.split("/").includes(unitName)) return "systemd";
10946
+ }
10947
+ return null;
10948
+ }
10949
+ function launchdDomain() {
10950
+ const uid = typeof process.getuid === "function" ? process.getuid() : -1;
10951
+ return uid === 0 ? "system" : `gui/${uid}`;
10952
+ }
10953
+ function launchdLabel() {
10954
+ return process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL;
10955
+ }
10956
+ function launchdPlistPath() {
10957
+ const label = launchdLabel();
10958
+ const uid = typeof process.getuid === "function" ? process.getuid() : -1;
10959
+ if (uid === 0) return `/Library/LaunchDaemons/${label}.plist`;
10960
+ return path21.join(os4.homedir(), "Library", "LaunchAgents", `${label}.plist`);
10961
+ }
10962
+ function serviceManagerFromLaunchctl(output, pid, execPath, sea = true) {
10963
+ const pidMatch = /^\s*pid = (\d+)\s*$/m.exec(output);
10964
+ if (pidMatch && Number(pidMatch[1]) === pid) return "launchd";
10965
+ const program = /^\s*program = (.+?)\s*$/m.exec(output);
10966
+ if (program) {
10967
+ const shown = program[1].replace(/^"|"$/g, "");
10968
+ if (path21.resolve(shown) === path21.resolve(execPath)) return "launchd";
10969
+ }
10970
+ if (!sea && /^\s*state = /m.test(output)) return "launchd";
10971
+ return null;
10972
+ }
10973
+ function parseLaunchdEnvironment(xml) {
10974
+ const out = {};
10975
+ const marker = xml.indexOf("<key>EnvironmentVariables</key>");
10976
+ if (marker < 0) return out;
10977
+ const open = xml.indexOf("<dict>", marker);
10978
+ if (open < 0) return out;
10979
+ const close = xml.indexOf("</dict>", open);
10980
+ if (close < 0) return out;
10981
+ const body = xml.slice(open + "<dict>".length, close);
10982
+ for (const m of body.matchAll(/<key>([^<]+)<\/key>\s*<string>([^<]*)<\/string>/g)) {
10983
+ out[m[1]] = m[2];
10984
+ }
10985
+ return out;
10986
+ }
10987
+ function detectServiceManager() {
10988
+ if (process.platform === "darwin") return detectLaunchd();
10989
+ if (process.platform !== "linux") return null;
10990
+ const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
10991
+ try {
10992
+ return serviceManagerFromCgroup(
10993
+ fs18.readFileSync("/proc/self/cgroup", "utf8"),
10994
+ serviceName
10995
+ );
10996
+ } catch {
10997
+ return null;
10998
+ }
10999
+ }
11000
+ function detectLaunchd() {
11001
+ try {
11002
+ const res = spawnSync2(
11003
+ "launchctl",
11004
+ ["print", `${launchdDomain()}/${launchdLabel()}`],
11005
+ { encoding: "utf8", timeout: 3e3 }
11006
+ );
11007
+ if (res.status !== 0 || !res.stdout) return null;
11008
+ return serviceManagerFromLaunchctl(
11009
+ res.stdout,
11010
+ process.pid,
11011
+ process.execPath,
11012
+ isSeaRuntime()
11013
+ );
11014
+ } catch {
11015
+ return null;
11016
+ }
11017
+ }
11018
+ function serviceManager() {
11019
+ const v = process.env.ZQAGENT_SERVICE_MANAGER?.trim().toLowerCase();
11020
+ if (v === "systemd" || v === "launchd") return v;
11021
+ return detectServiceManager();
11022
+ }
11023
+ function parseServiceEnvironment(raw) {
11024
+ const out = {};
11025
+ for (const token of raw.trim().split(/\s+/)) {
11026
+ const idx = token.indexOf("=");
11027
+ if (idx > 0) out[token.slice(0, idx)] = token.slice(idx + 1);
11028
+ }
11029
+ return out;
11030
+ }
11031
+ var cachedServiceEnv = null;
11032
+ function readServiceEnvironment() {
11033
+ const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
11034
+ try {
11035
+ const res = spawnSync2(
11036
+ "systemctl",
11037
+ ["show", serviceName, "--property=Environment", "--value", "--no-pager"],
11038
+ { encoding: "utf8", timeout: 3e3 }
11039
+ );
11040
+ if (res.status !== 0 || !res.stdout) return {};
11041
+ return parseServiceEnvironment(res.stdout);
11042
+ } catch {
11043
+ return {};
11044
+ }
11045
+ }
11046
+ function serviceEnvValue(key) {
11047
+ if (process.platform === "darwin") {
11048
+ if (serviceManager() !== "launchd") return void 0;
11049
+ cachedLaunchdEnv ??= readLaunchdEnvironment();
11050
+ return cachedLaunchdEnv[key];
11051
+ }
11052
+ if (process.platform !== "linux") return void 0;
11053
+ if (serviceManager() !== "systemd") return void 0;
11054
+ cachedServiceEnv ??= readServiceEnvironment();
11055
+ return cachedServiceEnv[key];
11056
+ }
11057
+ var cachedLaunchdEnv = null;
11058
+ function readLaunchdEnvironment() {
11059
+ try {
11060
+ return parseLaunchdEnvironment(fs18.readFileSync(launchdPlistPath(), "utf8"));
11061
+ } catch {
11062
+ return {};
11063
+ }
11064
+ }
11065
+ function selfUpdateCapability(hasPublicKey) {
11066
+ if (!isSeaRuntime()) {
11067
+ return {
11068
+ ok: false,
11069
+ 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"
11070
+ };
11071
+ }
11072
+ if (!serviceManager()) {
11073
+ return {
11074
+ ok: false,
11075
+ reason: "\u672A\u88AB systemd/launchd \u6258\u7BA1\uFF1A\u8BF7\u7528 deploy/service/install.sh \u5B89\u88C5\uFF0C\u6216\u624B\u52A8\u5347\u7EA7"
11076
+ };
11077
+ }
11078
+ if (!hasPublicKey) {
11079
+ return { ok: false, reason: "\u672A\u914D\u7F6E ZQAGENT_UPDATE_PUBKEY\uFF0C\u65E0\u6CD5\u9A8C\u7B7E\uFF0C\u5DF2\u7981\u7528\u81EA\u52A8\u66F4\u65B0" };
11080
+ }
11081
+ return { ok: true };
11082
+ }
11083
+
11084
+ // src/cli/serve-instances.ts
10880
11085
  var DEFAULT_SERVE_HOST = "127.0.0.1";
10881
11086
  var DEFAULT_SERVE_PORT = 8787;
11087
+ var DEFAULT_SERVICE_NAME2 = "zqagent";
11088
+ var DEFAULT_SERVICE_LABEL2 = "com.zqagent.node";
10882
11089
  function serveSubcommandIndex(argv) {
10883
11090
  for (let i = 1; i < argv.length; i++) {
10884
11091
  if (argv[i].startsWith("-")) continue;
@@ -10913,20 +11120,24 @@ function parseServeArgs(argv) {
10913
11120
  return { dataDir, host, port };
10914
11121
  }
10915
11122
  function buildHotCandidates(explicitDataDir, discovered, fallback) {
10916
- const out = explicitDataDir ? [{ dataDir: path21.resolve(explicitDataDir), ...fallback }] : [{ dataDir: path21.resolve(DEFAULT_DATA_DIR), ...fallback }];
10917
- for (const inst of discovered) {
11123
+ const out = [];
11124
+ const push = (inst) => {
10918
11125
  if (!out.some((o) => o.dataDir === inst.dataDir)) out.push(inst);
10919
- }
11126
+ };
11127
+ if (explicitDataDir) push({ dataDir: path22.resolve(explicitDataDir), ...fallback });
11128
+ for (const inst of discovered) if (inst.managed) push(inst);
11129
+ for (const inst of discovered) if (!inst.managed) push(inst);
11130
+ if (!explicitDataDir) push({ dataDir: path22.resolve(DEFAULT_DATA_DIR), ...fallback });
10920
11131
  return out;
10921
11132
  }
10922
11133
  function isWindowsAbsolute(p) {
10923
11134
  return /^[A-Za-z]:[\\/]/.test(p) || /^\\\\/.test(p);
10924
11135
  }
10925
11136
  function isAbsolutePath(p) {
10926
- return path21.isAbsolute(p) || isWindowsAbsolute(p);
11137
+ return path22.isAbsolute(p) || isWindowsAbsolute(p);
10927
11138
  }
10928
11139
  function normalizePath(p) {
10929
- return isWindowsAbsolute(p) ? path21.win32.normalize(p) : path21.normalize(p);
11140
+ return isWindowsAbsolute(p) ? path22.win32.normalize(p) : path22.normalize(p);
10930
11141
  }
10931
11142
  function parseServeCommandLine(line) {
10932
11143
  if (!/(?:^|\s)["']?serve["']?(?=\s|$)/.test(line)) return null;
@@ -10945,7 +11156,7 @@ function parseServeCommandLine(line) {
10945
11156
  }
10946
11157
  function processCwd(pid) {
10947
11158
  try {
10948
- return fs18.readlinkSync(`/proc/${pid}/cwd`);
11159
+ return fs19.readlinkSync(`/proc/${pid}/cwd`);
10949
11160
  } catch {
10950
11161
  return null;
10951
11162
  }
@@ -10953,7 +11164,7 @@ function processCwd(pid) {
10953
11164
  function processEnv(pid) {
10954
11165
  const out = {};
10955
11166
  try {
10956
- const raw = fs18.readFileSync(`/proc/${pid}/environ`, "utf-8");
11167
+ const raw = fs19.readFileSync(`/proc/${pid}/environ`, "utf-8");
10957
11168
  for (const entry of raw.split("\0")) {
10958
11169
  const eq = entry.indexOf("=");
10959
11170
  if (eq > 0) out[entry.slice(0, eq)] = entry.slice(eq + 1);
@@ -10964,14 +11175,24 @@ function processEnv(pid) {
10964
11175
  }
10965
11176
  function resolveDataDir(rawDataDir, cwd, env3) {
10966
11177
  const pick = rawDataDir ?? env3.DATA_DIR ?? null;
10967
- if (pick) return path21.isAbsolute(pick) ? path21.normalize(pick) : cwd ? path21.resolve(cwd, pick) : null;
10968
- return cwd ? path21.resolve(cwd, DEFAULT_DATA_DIR) : null;
11178
+ if (pick) return path22.isAbsolute(pick) ? path22.normalize(pick) : cwd ? path22.resolve(cwd, pick) : null;
11179
+ return cwd ? path22.resolve(cwd, DEFAULT_DATA_DIR) : null;
11180
+ }
11181
+ function isManagedBySystemd(pid, env3) {
11182
+ if (env3.ZQAGENT_SERVICE_MANAGER?.trim()) return true;
11183
+ try {
11184
+ const cgroup = fs19.readFileSync(`/proc/${pid}/cgroup`, "utf-8");
11185
+ const serviceName = env3.ZQAGENT_SERVICE_NAME?.trim() || "zqagent";
11186
+ return serviceManagerFromCgroup(cgroup, serviceName) !== null;
11187
+ } catch {
11188
+ return false;
11189
+ }
10969
11190
  }
10970
11191
  function discoverFromProc() {
10971
11192
  const out = [];
10972
11193
  let pids;
10973
11194
  try {
10974
- pids = fs18.readdirSync("/proc");
11195
+ pids = fs19.readdirSync("/proc");
10975
11196
  } catch {
10976
11197
  return out;
10977
11198
  }
@@ -10980,22 +11201,29 @@ function discoverFromProc() {
10980
11201
  const pid = Number(name);
10981
11202
  if (pid === process.pid) continue;
10982
11203
  let argv;
11204
+ let env3;
10983
11205
  try {
10984
- argv = fs18.readFileSync(`/proc/${pid}/cmdline`, "utf-8").split("\0").filter(Boolean);
11206
+ argv = fs19.readFileSync(`/proc/${pid}/cmdline`, "utf-8").split("\0").filter(Boolean);
11207
+ env3 = processEnv(pid);
10985
11208
  } catch {
10986
11209
  continue;
10987
11210
  }
10988
11211
  const parsed = parseServeArgs(argv);
10989
11212
  if (!parsed) continue;
10990
- const dataDir = resolveDataDir(parsed.dataDir, processCwd(pid), processEnv(pid));
11213
+ const dataDir = resolveDataDir(parsed.dataDir, processCwd(pid), env3);
10991
11214
  if (!dataDir) continue;
10992
- out.push({ dataDir, host: parsed.host, port: parsed.port });
11215
+ out.push({
11216
+ dataDir,
11217
+ host: parsed.host,
11218
+ port: parsed.port,
11219
+ managed: isManagedBySystemd(pid, env3)
11220
+ });
10993
11221
  }
10994
11222
  return out;
10995
11223
  }
10996
11224
  function discoverFromPs() {
10997
11225
  const out = [];
10998
- const res = spawnSync2("ps", ["-axo", "command="], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
11226
+ const res = spawnSync3("ps", ["-axo", "command="], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
10999
11227
  if (res.status !== 0 || !res.stdout) return out;
11000
11228
  for (const line of res.stdout.split("\n")) {
11001
11229
  const inst = parseServeCommandLine(line);
@@ -11006,7 +11234,7 @@ function discoverFromPs() {
11006
11234
  function discoverFromWindows() {
11007
11235
  const out = [];
11008
11236
  const script = `[Console]::OutputEncoding=[Text.Encoding]::UTF8; Get-CimInstance Win32_Process -Filter "Name='zqagent.exe' OR Name='node.exe'" | ForEach-Object { $_.CommandLine }`;
11009
- const res = spawnSync2(
11237
+ const res = spawnSync3(
11010
11238
  "powershell.exe",
11011
11239
  ["-NoProfile", "-NonInteractive", "-Command", script],
11012
11240
  { encoding: "utf-8", timeout: 15e3, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
@@ -11018,14 +11246,126 @@ function discoverFromWindows() {
11018
11246
  }
11019
11247
  return out;
11020
11248
  }
11249
+ function decodeXmlEntities(s) {
11250
+ return s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, "&");
11251
+ }
11252
+ function parseLaunchdProgramArguments(xml) {
11253
+ const marker = xml.indexOf("<key>ProgramArguments</key>");
11254
+ if (marker < 0) return [];
11255
+ const open = xml.indexOf("<array>", marker);
11256
+ if (open < 0) return [];
11257
+ const close = xml.indexOf("</array>", open);
11258
+ if (close < 0) return [];
11259
+ return [...xml.slice(open + "<array>".length, close).matchAll(/<string>([^<]*)<\/string>/g)].map(
11260
+ (m) => decodeXmlEntities(m[1])
11261
+ );
11262
+ }
11263
+ function launchdServiceInstances() {
11264
+ if (process.platform !== "darwin") return [];
11265
+ const label = process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL2;
11266
+ const plists = [
11267
+ `/Library/LaunchDaemons/${label}.plist`,
11268
+ path22.join(os5.homedir(), "Library", "LaunchAgents", `${label}.plist`)
11269
+ ];
11270
+ const out = [];
11271
+ for (const plist of plists) {
11272
+ let xml;
11273
+ try {
11274
+ xml = fs19.readFileSync(plist, "utf-8");
11275
+ } catch {
11276
+ continue;
11277
+ }
11278
+ const parsed = parseServeArgs(parseLaunchdProgramArguments(xml));
11279
+ if (!parsed?.dataDir || !isAbsolutePath(parsed.dataDir)) continue;
11280
+ out.push({
11281
+ dataDir: normalizePath(parsed.dataDir),
11282
+ host: parsed.host,
11283
+ port: parsed.port,
11284
+ managed: true
11285
+ });
11286
+ }
11287
+ return out;
11288
+ }
11289
+ function parseSystemdUnit(text) {
11290
+ let dataDir = null;
11291
+ let host = DEFAULT_SERVE_HOST;
11292
+ let port = DEFAULT_SERVE_PORT;
11293
+ for (const line of text.split("\n")) {
11294
+ const trimmed = line.trim();
11295
+ if (trimmed.startsWith("WorkingDirectory=")) {
11296
+ const v = trimmed.slice("WorkingDirectory=".length).trim();
11297
+ if (v && isAbsolutePath(v)) dataDir = v;
11298
+ } else if (trimmed.startsWith("ExecStart=")) {
11299
+ const tokens = trimmed.slice("ExecStart=".length).trim().split(/\s+/).map((t) => t.replace(/^["']|["']$/g, ""));
11300
+ const parsed = parseServeArgs(tokens);
11301
+ if (!parsed) continue;
11302
+ if (parsed.dataDir && isAbsolutePath(parsed.dataDir)) dataDir = parsed.dataDir;
11303
+ host = parsed.host;
11304
+ port = parsed.port;
11305
+ }
11306
+ }
11307
+ if (!dataDir) return null;
11308
+ return { dataDir: normalizePath(dataDir), host, port, managed: true };
11309
+ }
11310
+ function systemdServiceInstances() {
11311
+ if (process.platform !== "linux") return [];
11312
+ const unit = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME2;
11313
+ const configHome = process.env.XDG_CONFIG_HOME?.trim() || path22.join(os5.homedir(), ".config");
11314
+ const units = [
11315
+ `/etc/systemd/system/${unit}.service`,
11316
+ path22.join(configHome, "systemd", "user", `${unit}.service`)
11317
+ ];
11318
+ const out = [];
11319
+ for (const file of units) {
11320
+ let text;
11321
+ try {
11322
+ text = fs19.readFileSync(file, "utf-8");
11323
+ } catch {
11324
+ continue;
11325
+ }
11326
+ const inst = parseSystemdUnit(text);
11327
+ if (inst) out.push(inst);
11328
+ }
11329
+ return out;
11330
+ }
11331
+ function windowsServiceInstances() {
11332
+ if (process.platform !== "win32") return [];
11333
+ const appdata = process.env.APPDATA?.trim();
11334
+ if (!appdata) return [];
11335
+ const base = path22.join(appdata, "zqagent");
11336
+ try {
11337
+ const raw = fs19.readFileSync(path22.join(base, "runtime", "service.json"), "utf-8");
11338
+ const v = JSON.parse(raw);
11339
+ const dataDir = v.dataDir && isAbsolutePath(v.dataDir) ? v.dataDir : base;
11340
+ const port = Number(v.port);
11341
+ return [
11342
+ {
11343
+ dataDir: normalizePath(dataDir),
11344
+ host: DEFAULT_SERVE_HOST,
11345
+ port: Number.isFinite(port) && port > 0 ? port : DEFAULT_SERVE_PORT,
11346
+ managed: true
11347
+ }
11348
+ ];
11349
+ } catch {
11350
+ return [];
11351
+ }
11352
+ }
11353
+ function mergeServeInstances(discovered, managed) {
11354
+ const out = [];
11355
+ const push = (inst) => {
11356
+ if (!out.some((o) => o.dataDir === inst.dataDir)) out.push(inst);
11357
+ };
11358
+ for (const inst of discovered) {
11359
+ const hit = managed.find((m) => m.dataDir === inst.dataDir);
11360
+ push(hit ? { ...inst, managed: true } : inst);
11361
+ }
11362
+ for (const inst of managed) push(inst);
11363
+ return out;
11364
+ }
11021
11365
  function discoverRunningServeInstances() {
11022
11366
  const found = process.platform === "linux" ? discoverFromProc() : process.platform === "win32" ? discoverFromWindows() : discoverFromPs();
11023
- const seen = /* @__PURE__ */ new Set();
11024
- return found.filter((inst) => {
11025
- if (seen.has(inst.dataDir)) return false;
11026
- seen.add(inst.dataDir);
11027
- return true;
11028
- });
11367
+ const declared = process.platform === "linux" ? systemdServiceInstances() : process.platform === "win32" ? windowsServiceInstances() : launchdServiceInstances();
11368
+ return mergeServeInstances(found, declared);
11029
11369
  }
11030
11370
 
11031
11371
  // src/cli/link.ts
@@ -11033,12 +11373,12 @@ function expandHome(p) {
11033
11373
  const home = process.env.HOME || process.env.USERPROFILE;
11034
11374
  if (!home) return p;
11035
11375
  if (p === "~") return home;
11036
- if (p.startsWith("~/") || p.startsWith("~\\")) return path22.join(home, p.slice(2));
11376
+ if (p.startsWith("~/") || p.startsWith("~\\")) return path23.join(home, p.slice(2));
11037
11377
  return p;
11038
11378
  }
11039
11379
  function installDataDirHint() {
11040
11380
  if (process.platform === "darwin") return "$HOME/Library/Application Support/zqagent";
11041
- if (process.platform === "win32") return "%LOCALAPPDATA%\\zqagent";
11381
+ if (process.platform === "win32") return "%APPDATA%\\zqagent";
11042
11382
  return "/var/lib/zqagent\uFF08\u9700 root\uFF1B\u666E\u901A\u7528\u6237\u7528 ~/.zqagent_data\uFF09";
11043
11383
  }
11044
11384
  function parseLinkArgs(argv) {
@@ -11113,6 +11453,23 @@ async function enrollViaServer(host, port, adminKey, opts) {
11113
11453
  }
11114
11454
  return payload?.data;
11115
11455
  }
11456
+ function hotWarnings(inst, running) {
11457
+ const warnings = [];
11458
+ const managed = running.filter((r) => r.managed && r.dataDir !== inst.dataDir);
11459
+ if (!inst.managed && managed.length > 0) {
11460
+ warnings.push(
11461
+ `\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`
11462
+ );
11463
+ warnings.push(
11464
+ "\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"
11465
+ );
11466
+ }
11467
+ const others = [...new Set(running.map((r) => r.dataDir).filter((d) => d !== inst.dataDir))];
11468
+ if (others.length > 0) {
11469
+ 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`);
11470
+ }
11471
+ return warnings;
11472
+ }
11116
11473
  async function linkNode(opts) {
11117
11474
  const rawDataDir = opts.dataDir?.trim() || process.env.DATA_DIR?.trim() || void 0;
11118
11475
  const explicitDataDir = rawDataDir ? expandHome(rawDataDir) : void 0;
@@ -11126,9 +11483,17 @@ async function linkNode(opts) {
11126
11483
  if (!adminKey) continue;
11127
11484
  if (!await probeServer(inst.host, inst.port, adminKey)) continue;
11128
11485
  const status = await enrollViaServer(inst.host, inst.port, adminKey, opts);
11129
- return { mode: "hot", ...status, dataDir: inst.dataDir };
11486
+ return {
11487
+ mode: "hot",
11488
+ ...status,
11489
+ dataDir: inst.dataDir,
11490
+ managed: inst.managed,
11491
+ warnings: hotWarnings(inst, running)
11492
+ };
11130
11493
  }
11131
- const dataDir = path22.resolve(explicitDataDir ?? DEFAULT_DATA_DIR);
11494
+ const managedDir = running.find((r) => r.managed)?.dataDir;
11495
+ const dataDir = path23.resolve(explicitDataDir ?? managedDir ?? DEFAULT_DATA_DIR);
11496
+ const targetedService = !explicitDataDir && Boolean(managedDir) && dataDir === managedDir;
11132
11497
  const store = new Store(dataDir);
11133
11498
  const nodeId = ensureNodeId(store);
11134
11499
  const cred = await hubEnrollByCode(opts.hubUrl, {
@@ -11165,14 +11530,16 @@ async function linkNode(opts) {
11165
11530
  label: opts.label,
11166
11531
  dataDir,
11167
11532
  explicitDataDir: Boolean(explicitDataDir),
11168
- runningServiceDirs: otherRunningDirs
11533
+ runningServiceDirs: otherRunningDirs,
11534
+ targetedService
11169
11535
  };
11170
11536
  }
11171
11537
  function printLinkHelp() {
11172
- cliLog("\u7528\u6CD5: zqagent link --hub <url> --code <\u6CE8\u518C\u7801> [--label \u540D\u79F0] [--data-dir \u76EE\u5F55]");
11538
+ cliLog("\u7528\u6CD5: zqagent link --hub <url> --code <\u6CE8\u518C\u7801> [--label \u540D\u79F0]");
11173
11539
  cliLog(" \u5728 Hub \u7528\u6237\u4E2D\u5FC3\u751F\u6210\u4E00\u6B21\u6027\u6CE8\u518C\u7801\u540E\uFF0C\u4E8E\u8282\u70B9\u673A\u5668\u6267\u884C\u672C\u547D\u4EE4\u5373\u53EF\u63A5\u5165\u3002");
11174
- cliLog(" \u5DF2\u6709\u672C\u673A server \u65F6\u70ED\u63A5\u5165\uFF08\u514D\u91CD\u542F\uFF0C\u4F1A\u81EA\u52A8\u53D1\u73B0\u8FD0\u884C\u4E2D\u670D\u52A1\u7684 --data-dir\uFF09\uFF1B");
11175
- cliLog(" \u5426\u5219\u5199\u5165 <\u6570\u636E\u76EE\u5F55>/fleet.json\uFF0C\u4E0B\u6B21\u542F\u52A8\u81EA\u52A8\u63A5\u5165\u3002");
11540
+ 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");
11541
+ 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");
11542
+ 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");
11176
11543
  }
11177
11544
  async function runLinkCommand(argv) {
11178
11545
  const args = parseLinkArgs(argv);
@@ -11200,14 +11567,23 @@ async function runLinkCommand(argv) {
11200
11567
  cliLog("\u2705 \u5DF2\u63A5\u5165 Hub\uFF08\u70ED\u63A5\u5165\uFF0C\u514D\u91CD\u542F\uFF09");
11201
11568
  cliLog(` \u8282\u70B9: ${r.nodeId}${r.label ? ` (${r.label})` : ""}`);
11202
11569
  cliLog(` \u7F51\u5173: ${r.gatewayUrl ?? "\uFF08\u672A\u4E0B\u53D1\uFF09"} \u5728\u7EBF: ${r.online ? "\u662F" : "\u8FDE\u63A5\u4E2D\u2026"}`);
11203
- cliLog(` \u6570\u636E\u76EE\u5F55: ${r.dataDir}`);
11570
+ cliLog(` \u6570\u636E\u76EE\u5F55: ${r.dataDir}${r.managed ? "\uFF08\u6258\u7BA1\u670D\u52A1\uFF0C\u5F00\u673A\u81EA\u542F\uFF09" : ""}`);
11571
+ if (r.warnings.length > 0) {
11572
+ cliLog("");
11573
+ for (const w of r.warnings) cliLog(`\u26A0\uFE0F ${w}`);
11574
+ }
11204
11575
  } else {
11205
11576
  cliLog("\u2705 \u63A5\u5165\u51ED\u636E\u5DF2\u4FDD\u5B58\uFF08\u672C\u673A\u6682\u65E0\u8FD0\u884C\u4E2D\u7684 server\uFF09");
11206
11577
  cliLog(` \u8282\u70B9: ${r.nodeId}`);
11207
11578
  cliLog(` \u7F51\u5173: ${r.gatewayUrl ?? "\uFF08\u672A\u4E0B\u53D1\uFF09"}`);
11208
11579
  cliLog(` \u6570\u636E\u76EE\u5F55: ${r.dataDir}`);
11209
11580
  cliLog(" \u4E0B\u6B21\u542F\u52A8 server \u5373\u81EA\u52A8\u63A5\u5165\uFF1B\u6216\u8FD0\u884C zqagent serve \u5E38\u9A7B\u4E3A\u8282\u70B9\u3002");
11210
- if (r.runningServiceDirs.length > 0) {
11581
+ if (r.targetedService) {
11582
+ cliLog("");
11583
+ 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");
11584
+ cliLog(" \u7ACB\u5373\u751F\u6548\uFF1A\u91CD\u542F\u8BE5\u670D\u52A1\uFF08Linux: systemctl restart zqagent\uFF1B");
11585
+ cliLog(" macOS: launchctl kickstart -k gui/$(id -u)/com.zqagent.node\uFF09\u3002");
11586
+ } else if (r.runningServiceDirs.length > 0) {
11211
11587
  cliLog("");
11212
11588
  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");
11213
11589
  cliLog(` \u672C\u6B21\u5199\u5165: ${r.dataDir}`);
@@ -11217,11 +11593,10 @@ async function runLinkCommand(argv) {
11217
11593
  cliLog(` zqagent link --hub <Hub\u5730\u5740> --code <\u65B0\u63A5\u5165\u7801> --data-dir "${r.runningServiceDirs[0]}"`);
11218
11594
  } else if (!r.explicitDataDir) {
11219
11595
  cliLog("");
11220
- cliLog("\u26A0\uFE0F \u672A\u6307\u5B9A --data-dir\uFF0C\u51ED\u636E\u5199\u5165\u4E86\u5F53\u524D\u76EE\u5F55\u4E0B\u7684 .zqagent_data\u3002");
11221
- cliLog(" \u82E5\u672C\u673A\u670D\u52A1\u662F\u7531\u5B89\u88C5\u811A\u672C\uFF08systemd / launchd\uFF09\u542F\u52A8\u7684\uFF0C\u5B83\u8BFB\u4E0D\u5230\u8FD9\u4EFD\u51ED\u636E\uFF0C");
11222
- cliLog(" Hub \u4F1A\u4E00\u76F4\u663E\u793A\u672A\u5728\u7EBF\u3002\u8BF7\u7528\u670D\u52A1\u7684\u6570\u636E\u76EE\u5F55\u91CD\u65B0\u6267\u884C\uFF1A");
11223
- cliLog(" zqagent link --hub <Hub\u5730\u5740> --code <\u65B0\u63A5\u5165\u7801> --data-dir <\u670D\u52A1\u6570\u636E\u76EE\u5F55>");
11224
- cliLog(` \uFF08\u672C\u5E73\u53F0\u5B89\u88C5\u811A\u672C\u9ED8\u8BA4\uFF1A${installDataDirHint()}\uFF1B\u63A5\u5165\u7801\u4E00\u6B21\u6027\uFF0C\u9700\u8981\u91CD\u65B0\u751F\u6210\uFF09`);
11596
+ 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");
11597
+ 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");
11598
+ cliLog(" curl -fsSL https://agent.cd-zq.com/install.sh | sh");
11599
+ cliLog(` \uFF08\u670D\u52A1\u9ED8\u8BA4\u6570\u636E\u76EE\u5F55\uFF1A${installDataDirHint()}\uFF09`);
11225
11600
  }
11226
11601
  }
11227
11602
  return true;
@@ -11241,21 +11616,21 @@ import * as path38 from "path";
11241
11616
 
11242
11617
  // src/server/session.ts
11243
11618
  init_esm_shims();
11244
- import * as path25 from "path";
11619
+ import * as path26 from "path";
11245
11620
  import { AsyncLocalStorage } from "async_hooks";
11246
11621
 
11247
11622
  // src/server/mcpConfig.ts
11248
11623
  init_esm_shims();
11249
- import fs19 from "fs";
11250
- import path23 from "path";
11624
+ import fs20 from "fs";
11625
+ import path24 from "path";
11251
11626
  function isValidMcpConfig(v) {
11252
11627
  return !!v && typeof v === "object" && typeof v.name === "string" && (v.type === "stdio" || v.type === "http");
11253
11628
  }
11254
11629
  function readConfigFile(file) {
11255
11630
  if (!file) return [];
11256
11631
  try {
11257
- if (!fs19.existsSync(file)) return [];
11258
- const raw = JSON.parse(fs19.readFileSync(file, "utf8"));
11632
+ if (!fs20.existsSync(file)) return [];
11633
+ const raw = JSON.parse(fs20.readFileSync(file, "utf8"));
11259
11634
  const list = Array.isArray(raw) ? raw : raw && typeof raw === "object" && Array.isArray(raw.servers) ? raw.servers : [];
11260
11635
  return list.filter(isValidMcpConfig);
11261
11636
  } catch (err) {
@@ -11267,7 +11642,7 @@ function hasServerMcpConfig() {
11267
11642
  if (readConfigFile(process.env.MCP_CONFIG_PATH).length > 0) return true;
11268
11643
  const workspace = process.env.WORKSPACE;
11269
11644
  if (!workspace) return false;
11270
- return readConfigFile(path23.join(workspace, ".agent", "mcp.json")).length > 0;
11645
+ return readConfigFile(path24.join(workspace, ".agent", "mcp.json")).length > 0;
11271
11646
  }
11272
11647
  function loadServerMcpConfigs(tenant) {
11273
11648
  const fromEnv = readConfigFile(process.env.MCP_CONFIG_PATH);
@@ -11277,7 +11652,7 @@ function loadServerMcpConfigs(tenant) {
11277
11652
  }
11278
11653
  const workspace = tenant.workspaceRoot ?? process.env.WORKSPACE;
11279
11654
  if (workspace)
11280
- return readConfigFile(path23.join(workspace, ".agent", "mcp.json"));
11655
+ return readConfigFile(path24.join(workspace, ".agent", "mcp.json"));
11281
11656
  return [];
11282
11657
  }
11283
11658
 
@@ -11422,8 +11797,8 @@ function resolveSessionProvider(store, tenant, providerId) {
11422
11797
 
11423
11798
  // src/server/usage.ts
11424
11799
  init_esm_shims();
11425
- import * as fs20 from "fs";
11426
- import * as path24 from "path";
11800
+ import * as fs21 from "fs";
11801
+ import * as path25 from "path";
11427
11802
  var LEDGER_RETENTION_MONTHS = 12;
11428
11803
  var USAGE_SCHEMA = 1;
11429
11804
  var DEFAULT_PRICING = {
@@ -11504,15 +11879,15 @@ function retainedMonths(now = /* @__PURE__ */ new Date()) {
11504
11879
  return out;
11505
11880
  }
11506
11881
  function atomicWrite(file, content) {
11507
- fs20.mkdirSync(path24.dirname(file), { recursive: true });
11882
+ fs21.mkdirSync(path25.dirname(file), { recursive: true });
11508
11883
  const tmp = `${file}.tmp`;
11509
- fs20.writeFileSync(tmp, content, "utf-8");
11510
- fs20.renameSync(tmp, file);
11884
+ fs21.writeFileSync(tmp, content, "utf-8");
11885
+ fs21.renameSync(tmp, file);
11511
11886
  }
11512
11887
  var UsageLedger = class {
11513
11888
  constructor(root) {
11514
11889
  this.root = root;
11515
- this.dir = path24.join(root, "usage");
11890
+ this.dir = path25.join(root, "usage");
11516
11891
  }
11517
11892
  root;
11518
11893
  dir;
@@ -11525,18 +11900,18 @@ var UsageLedger = class {
11525
11900
  return this.dir;
11526
11901
  }
11527
11902
  ledgerFile(month) {
11528
- return path24.join(this.ledgerDir, `ledger-${month}.jsonl`);
11903
+ return path25.join(this.ledgerDir, `ledger-${month}.jsonl`);
11529
11904
  }
11530
11905
  get rollupFile() {
11531
- return path24.join(this.ledgerDir, "rollup.json");
11906
+ return path25.join(this.ledgerDir, "rollup.json");
11532
11907
  }
11533
11908
  get pricingFile() {
11534
- return path24.join(this.ledgerDir, "pricing.json");
11909
+ return path25.join(this.ledgerDir, "pricing.json");
11535
11910
  }
11536
11911
  // ===================== 初始化 =====================
11537
11912
  init(now = /* @__PURE__ */ new Date()) {
11538
11913
  if (this.inited) return;
11539
- fs20.mkdirSync(this.ledgerDir, { recursive: true });
11914
+ fs21.mkdirSync(this.ledgerDir, { recursive: true });
11540
11915
  this.pricing = this.loadPricing();
11541
11916
  this.rollup = this.loadRollup(now);
11542
11917
  this.pruneLedgers(now);
@@ -11544,7 +11919,7 @@ var UsageLedger = class {
11544
11919
  }
11545
11920
  loadPricing() {
11546
11921
  try {
11547
- const raw = fs20.readFileSync(this.pricingFile, "utf-8");
11922
+ const raw = fs21.readFileSync(this.pricingFile, "utf-8");
11548
11923
  const parsed = JSON.parse(raw);
11549
11924
  const vendors = {};
11550
11925
  for (const v of /* @__PURE__ */ new Set([
@@ -11573,7 +11948,7 @@ var UsageLedger = class {
11573
11948
  }
11574
11949
  loadRollup(now) {
11575
11950
  try {
11576
- const raw = fs20.readFileSync(this.rollupFile, "utf-8");
11951
+ const raw = fs21.readFileSync(this.rollupFile, "utf-8");
11577
11952
  const parsed = JSON.parse(raw);
11578
11953
  return {
11579
11954
  schema: USAGE_SCHEMA,
@@ -11600,10 +11975,10 @@ var UsageLedger = class {
11600
11975
  const keep = retainedMonths(now);
11601
11976
  let changed = false;
11602
11977
  try {
11603
- for (const f of fs20.readdirSync(this.ledgerDir)) {
11978
+ for (const f of fs21.readdirSync(this.ledgerDir)) {
11604
11979
  const m = /^ledger-(\d{4}-\d{2})\.jsonl$/.exec(f);
11605
11980
  if (m && !keep.has(m[1])) {
11606
- fs20.unlinkSync(path24.join(this.ledgerDir, f));
11981
+ fs21.unlinkSync(path25.join(this.ledgerDir, f));
11607
11982
  }
11608
11983
  }
11609
11984
  } catch {
@@ -11680,7 +12055,7 @@ var UsageLedger = class {
11680
12055
  };
11681
12056
  const line = JSON.stringify(rec) + "\n";
11682
12057
  try {
11683
- fs20.appendFileSync(this.ledgerFile(monthOf(rec.ts)), line);
12058
+ fs21.appendFileSync(this.ledgerFile(monthOf(rec.ts)), line);
11684
12059
  } catch (e) {
11685
12060
  console.error(`[usage] \u5199\u8D26\u672C\u5931\u8D25: ${String(e)}`);
11686
12061
  }
@@ -11852,10 +12227,10 @@ var UsageLedger = class {
11852
12227
  const rows = [];
11853
12228
  for (const month of months) {
11854
12229
  const file = this.ledgerFile(month);
11855
- if (!fs20.existsSync(file)) continue;
12230
+ if (!fs21.existsSync(file)) continue;
11856
12231
  let content = "";
11857
12232
  try {
11858
- content = fs20.readFileSync(file, "utf-8");
12233
+ content = fs21.readFileSync(file, "utf-8");
11859
12234
  } catch {
11860
12235
  continue;
11861
12236
  }
@@ -11964,10 +12339,10 @@ var UsageLedger = class {
11964
12339
  const seen = /* @__PURE__ */ new Set();
11965
12340
  for (const month of this.monthsInRange("", "")) {
11966
12341
  const file = this.ledgerFile(month);
11967
- if (!fs20.existsSync(file)) continue;
12342
+ if (!fs21.existsSync(file)) continue;
11968
12343
  let content = "";
11969
12344
  try {
11970
- content = fs20.readFileSync(file, "utf-8");
12345
+ content = fs21.readFileSync(file, "utf-8");
11971
12346
  } catch {
11972
12347
  continue;
11973
12348
  }
@@ -13278,7 +13653,7 @@ data: ${JSON.stringify(entry.data)}
13278
13653
  softThresholdPct: parseRatio(process.env.COMPACTION_SOFT_THRESHOLD_PCT),
13279
13654
  capTokens: parseOptionalPositiveNumber(process.env.COMPACTION_CAP_TOKENS) ?? null,
13280
13655
  // 超预算工具结果按租户/工作区隔离落盘(多租户共用一个状态目录会混内容)
13281
- toolResultDir: path25.join(workspace, ".agent", "tool-results")
13656
+ toolResultDir: path26.join(workspace, ".agent", "tool-results")
13282
13657
  });
13283
13658
  engine.setApprover(this._makeApprover(rt));
13284
13659
  const mcpConfigs = loadServerMcpConfigs(tenant);
@@ -13459,11 +13834,11 @@ var ApiError = class extends Error {
13459
13834
  // src/server/routes.ts
13460
13835
  init_esm_shims();
13461
13836
  import { createServer } from "http";
13462
- import * as path30 from "path";
13837
+ import * as path31 from "path";
13463
13838
 
13464
13839
  // src/server/projects.ts
13465
13840
  init_esm_shims();
13466
- import * as path26 from "path";
13841
+ import * as path27 from "path";
13467
13842
  var DEFAULT_MODEL = () => process.env.OPENAI_MODEL || process.env.MODEL || "gpt-4o";
13468
13843
  function toProjectSummary(store, tenant) {
13469
13844
  return {
@@ -13596,9 +13971,9 @@ function createProject(store, input) {
13596
13971
  if (store.loadTenant(id)) {
13597
13972
  throw new ApiError(409, "project_exists", `\u9879\u76EE ${id} \u5DF2\u5B58\u5728`);
13598
13973
  }
13599
- const workspaceRoot = typeof raw.workspaceRoot === "string" && raw.workspaceRoot.trim() ? path26.resolve(raw.workspaceRoot.trim()) : void 0;
13974
+ const workspaceRoot = typeof raw.workspaceRoot === "string" && raw.workspaceRoot.trim() ? path27.resolve(raw.workspaceRoot.trim()) : void 0;
13600
13975
  const explicitName = typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : "";
13601
- const defaultName = workspaceRoot ? path26.basename(workspaceRoot) : id;
13976
+ const defaultName = workspaceRoot ? path27.basename(workspaceRoot) : id;
13602
13977
  const tenant = {
13603
13978
  id,
13604
13979
  name: explicitName || defaultName,
@@ -13628,7 +14003,7 @@ function buildNodeInfo(store, opts) {
13628
14003
  nodeId: opts.nodeId ?? ensureNodeId2(store),
13629
14004
  platform: process.platform,
13630
14005
  mode: process.env.NODE_MODE ?? "standalone",
13631
- version: "0.2.10",
14006
+ version: "0.2.11",
13632
14007
  admin: opts.admin,
13633
14008
  projects: opts.projects
13634
14009
  };
@@ -13807,34 +14182,34 @@ async function handleHubProxy(req2, res) {
13807
14182
 
13808
14183
  // src/server/fsBrowser.ts
13809
14184
  init_esm_shims();
13810
- import * as fs21 from "fs";
13811
- import * as os4 from "os";
13812
- import * as path27 from "path";
14185
+ import * as fs22 from "fs";
14186
+ import * as os6 from "os";
14187
+ import * as path28 from "path";
13813
14188
  var MAX_ENTRIES = 2e3;
13814
14189
  var DEFAULT_SEARCH_LIMIT = 200;
13815
14190
  var MAX_SEARCH_LIMIT = 1e3;
13816
14191
  function listDirs(input) {
13817
- const base = (input ?? "").trim() || os4.homedir();
13818
- const target = path27.resolve(base);
14192
+ const base = (input ?? "").trim() || os6.homedir();
14193
+ const target = path28.resolve(base);
13819
14194
  let st;
13820
14195
  try {
13821
- st = fs21.statSync(target);
14196
+ st = fs22.statSync(target);
13822
14197
  } catch {
13823
14198
  throw new Error(`\u8DEF\u5F84\u4E0D\u5B58\u5728: ${target}`);
13824
14199
  }
13825
14200
  if (!st.isDirectory()) throw new Error(`\u4E0D\u662F\u76EE\u5F55: ${target}`);
13826
14201
  let dirents;
13827
14202
  try {
13828
- dirents = fs21.readdirSync(target, { withFileTypes: true });
14203
+ dirents = fs22.readdirSync(target, { withFileTypes: true });
13829
14204
  } catch {
13830
14205
  throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09: ${target}`);
13831
14206
  }
13832
14207
  const entries = dirents.map((d) => {
13833
- const full = path27.join(target, d.name);
14208
+ const full = path28.join(target, d.name);
13834
14209
  let isDir = d.isDirectory();
13835
14210
  if (d.isSymbolicLink()) {
13836
14211
  try {
13837
- isDir = fs21.statSync(full).isDirectory();
14212
+ isDir = fs22.statSync(full).isDirectory();
13838
14213
  } catch {
13839
14214
  }
13840
14215
  }
@@ -13843,7 +14218,7 @@ function listDirs(input) {
13843
14218
  entries.sort(
13844
14219
  (a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
13845
14220
  );
13846
- const parentDir = path27.dirname(target);
14221
+ const parentDir = path28.dirname(target);
13847
14222
  return {
13848
14223
  path: target,
13849
14224
  parent: parentDir !== target ? parentDir : null,
@@ -13874,7 +14249,7 @@ var NAME_CACHE_MAX_DIRS = 4;
13874
14249
  var NAME_CACHE_MAX_ENTRIES = 5e4;
13875
14250
  var nameCache = /* @__PURE__ */ new Map();
13876
14251
  function invalidateDirNames(target) {
13877
- nameCache.delete(path27.resolve(target));
14252
+ nameCache.delete(path28.resolve(target));
13878
14253
  }
13879
14254
  async function loadDirNames(target) {
13880
14255
  const now = Date.now();
@@ -13886,7 +14261,7 @@ async function loadDirNames(target) {
13886
14261
  }
13887
14262
  let dirents;
13888
14263
  try {
13889
- dirents = await fs21.promises.readdir(target, { withFileTypes: true });
14264
+ dirents = await fs22.promises.readdir(target, { withFileTypes: true });
13890
14265
  } catch {
13891
14266
  throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09: ${target}`);
13892
14267
  }
@@ -13909,22 +14284,22 @@ async function loadDirNames(target) {
13909
14284
  return entries;
13910
14285
  }
13911
14286
  async function toDirEntry(dir, e) {
13912
- const full = path27.join(dir, e.name);
14287
+ const full = path28.join(dir, e.name);
13913
14288
  let isDir = e.isDir;
13914
14289
  if (e.isLink) {
13915
14290
  try {
13916
- isDir = (await fs21.promises.stat(full)).isDirectory();
14291
+ isDir = (await fs22.promises.stat(full)).isDirectory();
13917
14292
  } catch {
13918
14293
  }
13919
14294
  }
13920
14295
  return { name: e.name, path: full, type: isDir ? "dir" : "file" };
13921
14296
  }
13922
14297
  async function searchDirs(input, query, limit) {
13923
- const base = (input ?? "").trim() || os4.homedir();
13924
- const target = path27.resolve(base);
14298
+ const base = (input ?? "").trim() || os6.homedir();
14299
+ const target = path28.resolve(base);
13925
14300
  let st;
13926
14301
  try {
13927
- st = await fs21.promises.stat(target);
14302
+ st = await fs22.promises.stat(target);
13928
14303
  } catch {
13929
14304
  throw new Error(`\u8DEF\u5F84\u4E0D\u5B58\u5728: ${target}`);
13930
14305
  }
@@ -13954,7 +14329,7 @@ async function searchDirs(input, query, limit) {
13954
14329
  );
13955
14330
  const hit = scored.slice(0, max);
13956
14331
  const entries = await Promise.all(hit.map(({ entry }) => toDirEntry(target, entry)));
13957
- const parentDir = path27.dirname(target);
14332
+ const parentDir = path28.dirname(target);
13958
14333
  return {
13959
14334
  path: target,
13960
14335
  parent: parentDir !== target ? parentDir : null,
@@ -13965,52 +14340,52 @@ async function searchDirs(input, query, limit) {
13965
14340
  };
13966
14341
  }
13967
14342
  function makeDirIn(parentInput, name) {
13968
- const parent = path27.resolve((parentInput ?? "").trim() || os4.homedir());
14343
+ const parent = path28.resolve((parentInput ?? "").trim() || os6.homedir());
13969
14344
  const clean = (name ?? "").trim();
13970
14345
  if (!clean) throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u4E3A\u7A7A");
13971
14346
  if (clean === "." || clean === "..") throw new Error("\u76EE\u5F55\u540D\u975E\u6CD5");
13972
- const target = path27.resolve(parent, clean);
13973
- const rel = path27.relative(parent, target);
13974
- if (!rel || rel.startsWith("..") || path27.isAbsolute(rel)) {
14347
+ const target = path28.resolve(parent, clean);
14348
+ const rel = path28.relative(parent, target);
14349
+ if (!rel || rel.startsWith("..") || path28.isAbsolute(rel)) {
13975
14350
  throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u8D8A\u51FA\u5F53\u524D\u76EE\u5F55");
13976
14351
  }
13977
14352
  let st = null;
13978
14353
  try {
13979
- st = fs21.statSync(target);
14354
+ st = fs22.statSync(target);
13980
14355
  } catch {
13981
14356
  st = null;
13982
14357
  }
13983
14358
  if (st && !st.isDirectory()) throw new Error(`\u5DF2\u5B58\u5728\u540C\u540D\u6587\u4EF6: ${target}`);
13984
14359
  try {
13985
- fs21.mkdirSync(target, { recursive: true });
14360
+ fs22.mkdirSync(target, { recursive: true });
13986
14361
  } catch (e) {
13987
14362
  throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
13988
14363
  }
13989
14364
  invalidateDirNames(parent);
13990
- return { name: path27.basename(target), path: target, type: "dir" };
14365
+ return { name: path28.basename(target), path: target, type: "dir" };
13991
14366
  }
13992
14367
 
13993
14368
  // src/server/projectFiles.ts
13994
14369
  init_esm_shims();
13995
- import * as fs22 from "fs";
13996
- import * as path28 from "path";
14370
+ import * as fs23 from "fs";
14371
+ import * as path29 from "path";
13997
14372
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
13998
14373
  var MAX_DOWNLOAD_BYTES = 16 * 1024 * 1024;
13999
14374
  var MAX_ENTRIES2 = 2e3;
14000
14375
  function toPosix(p) {
14001
- return p.split(path28.sep).join("/");
14376
+ return p.split(path29.sep).join("/");
14002
14377
  }
14003
14378
  function projectRoot(workspaceRoot) {
14004
14379
  const r = (workspaceRoot ?? "").trim();
14005
14380
  if (!r) {
14006
14381
  throw new Error("\u9879\u76EE\u672A\u8BBE\u7F6E\u5DE5\u4F5C\u533A\u76EE\u5F55\uFF08workspaceRoot\uFF09\uFF0C\u65E0\u6CD5\u6D4F\u89C8\u6587\u4EF6");
14007
14382
  }
14008
- const abs = path28.resolve(r);
14009
- if (!fs22.existsSync(abs)) {
14383
+ const abs = path29.resolve(r);
14384
+ if (!fs23.existsSync(abs)) {
14010
14385
  throw new Error(`\u5DE5\u4F5C\u533A\u76EE\u5F55\u4E0D\u5B58\u5728: ${abs}`);
14011
14386
  }
14012
14387
  try {
14013
- return fs22.realpathSync(abs);
14388
+ return fs23.realpathSync(abs);
14014
14389
  } catch {
14015
14390
  return abs;
14016
14391
  }
@@ -14028,37 +14403,37 @@ function listProjectFiles(workspaceRoot, relPath) {
14028
14403
  const dir = resolveWithin(base, relPath ?? "");
14029
14404
  let st;
14030
14405
  try {
14031
- st = fs22.statSync(dir);
14406
+ st = fs23.statSync(dir);
14032
14407
  } catch {
14033
- throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(path28.relative(base, dir)) || "/"}`);
14408
+ throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(path29.relative(base, dir)) || "/"}`);
14034
14409
  }
14035
14410
  if (!st.isDirectory()) throw new Error("\u76EE\u6807\u4E0D\u662F\u76EE\u5F55");
14036
14411
  let dirents;
14037
14412
  try {
14038
- dirents = fs22.readdirSync(dir, { withFileTypes: true });
14413
+ dirents = fs23.readdirSync(dir, { withFileTypes: true });
14039
14414
  } catch {
14040
14415
  throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09");
14041
14416
  }
14042
14417
  const entries = dirents.map((d) => {
14043
- const full = path28.join(dir, d.name);
14418
+ const full = path29.join(dir, d.name);
14044
14419
  let isDir = d.isDirectory();
14045
14420
  if (d.isSymbolicLink()) {
14046
14421
  try {
14047
- isDir = fs22.statSync(full).isDirectory();
14422
+ isDir = fs23.statSync(full).isDirectory();
14048
14423
  } catch {
14049
14424
  }
14050
14425
  }
14051
14426
  let size = 0;
14052
14427
  let mtime = "";
14053
14428
  try {
14054
- const s = fs22.statSync(full);
14429
+ const s = fs23.statSync(full);
14055
14430
  size = s.size;
14056
14431
  mtime = s.mtime.toISOString();
14057
14432
  } catch {
14058
14433
  }
14059
14434
  return {
14060
14435
  name: d.name,
14061
- path: toPosix(path28.relative(base, full)),
14436
+ path: toPosix(path29.relative(base, full)),
14062
14437
  type: isDir ? "dir" : "file",
14063
14438
  size,
14064
14439
  mtime
@@ -14067,12 +14442,12 @@ function listProjectFiles(workspaceRoot, relPath) {
14067
14442
  entries.sort(
14068
14443
  (a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
14069
14444
  );
14070
- const relDir = toPosix(path28.relative(base, dir));
14071
- const parentAbs = path28.dirname(dir);
14445
+ const relDir = toPosix(path29.relative(base, dir));
14446
+ const parentAbs = path29.dirname(dir);
14072
14447
  return {
14073
14448
  root: base,
14074
14449
  path: relDir,
14075
- parent: isWithinRoot(base, parentAbs) ? toPosix(path28.relative(base, parentAbs)) : null,
14450
+ parent: isWithinRoot(base, parentAbs) ? toPosix(path29.relative(base, parentAbs)) : null,
14076
14451
  entries: entries.slice(0, MAX_ENTRIES2)
14077
14452
  };
14078
14453
  }
@@ -14081,17 +14456,17 @@ function readProjectFile(workspaceRoot, relPath) {
14081
14456
  const file = resolveWithin(base, relPath ?? "");
14082
14457
  let st;
14083
14458
  try {
14084
- st = fs22.statSync(file);
14459
+ st = fs23.statSync(file);
14085
14460
  } catch {
14086
14461
  throw new Error("\u6587\u4EF6\u4E0D\u5B58\u5728");
14087
14462
  }
14088
14463
  if (!st.isFile()) throw new Error("\u76EE\u6807\u4E0D\u662F\u6587\u4EF6");
14089
- const buf = fs22.readFileSync(file);
14464
+ const buf = fs23.readFileSync(file);
14090
14465
  const binary = isBinary(buf);
14091
14466
  const truncated = buf.length > MAX_FILE_BYTES;
14092
14467
  const slice = truncated ? buf.subarray(0, MAX_FILE_BYTES) : buf;
14093
14468
  return {
14094
- path: toPosix(path28.relative(base, file)),
14469
+ path: toPosix(path29.relative(base, file)),
14095
14470
  size: st.size,
14096
14471
  binary,
14097
14472
  truncated,
@@ -14103,7 +14478,7 @@ function downloadProjectFile(workspaceRoot, relPath) {
14103
14478
  const file = resolveWithin(base, relPath ?? "");
14104
14479
  let st;
14105
14480
  try {
14106
- st = fs22.statSync(file);
14481
+ st = fs23.statSync(file);
14107
14482
  } catch {
14108
14483
  throw new Error("\u6587\u4EF6\u4E0D\u5B58\u5728");
14109
14484
  }
@@ -14111,10 +14486,10 @@ function downloadProjectFile(workspaceRoot, relPath) {
14111
14486
  if (st.size > MAX_DOWNLOAD_BYTES) {
14112
14487
  throw new Error(`\u6587\u4EF6\u8D85\u8FC7\u4E0B\u8F7D\u4E0A\u9650\uFF08${MAX_DOWNLOAD_BYTES / (1024 * 1024)}MB\uFF09`);
14113
14488
  }
14114
- const buf = fs22.readFileSync(file);
14489
+ const buf = fs23.readFileSync(file);
14115
14490
  return {
14116
- path: toPosix(path28.relative(base, file)),
14117
- name: path28.basename(file),
14491
+ path: toPosix(path29.relative(base, file)),
14492
+ name: path29.basename(file),
14118
14493
  size: buf.length,
14119
14494
  base64: buf.toString("base64")
14120
14495
  };
@@ -14136,12 +14511,12 @@ function writeProjectFile(workspaceRoot, relPath, content) {
14136
14511
  throw new Error("\u5185\u5BB9\u8D85\u8FC7 2MB \u4E0A\u9650\uFF0C\u65E0\u6CD5\u4FDD\u5B58");
14137
14512
  }
14138
14513
  try {
14139
- fs22.mkdirSync(path28.dirname(file), { recursive: true });
14140
- fs22.writeFileSync(file, buf);
14514
+ fs23.mkdirSync(path29.dirname(file), { recursive: true });
14515
+ fs23.writeFileSync(file, buf);
14141
14516
  } catch (e) {
14142
14517
  throw new Error(`\u5199\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
14143
14518
  }
14144
- return { path: toPosix(path28.relative(base, file)), size: buf.length };
14519
+ return { path: toPosix(path29.relative(base, file)), size: buf.length };
14145
14520
  }
14146
14521
  function createProjectDir(workspaceRoot, relPath) {
14147
14522
  const base = projectRoot(workspaceRoot);
@@ -14149,26 +14524,26 @@ function createProjectDir(workspaceRoot, relPath) {
14149
14524
  if (!rel) throw new Error("\u76EE\u5F55\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
14150
14525
  const dir = resolveWithin(base, rel);
14151
14526
  try {
14152
- fs22.mkdirSync(dir, { recursive: true });
14527
+ fs23.mkdirSync(dir, { recursive: true });
14153
14528
  } catch (e) {
14154
14529
  throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
14155
14530
  }
14156
- return { path: toPosix(path28.relative(base, dir)) };
14531
+ return { path: toPosix(path29.relative(base, dir)) };
14157
14532
  }
14158
14533
  function createProjectFile(workspaceRoot, relPath, content = "") {
14159
14534
  const base = projectRoot(workspaceRoot);
14160
14535
  const rel = (relPath ?? "").trim();
14161
14536
  if (!rel) throw new Error("\u6587\u4EF6\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
14162
14537
  const file = resolveWithin(base, rel);
14163
- if (fs22.existsSync(file)) throw new Error("\u6587\u4EF6\u5DF2\u5B58\u5728");
14538
+ if (fs23.existsSync(file)) throw new Error("\u6587\u4EF6\u5DF2\u5B58\u5728");
14164
14539
  const buf = Buffer.from(String(content ?? ""), "utf-8");
14165
14540
  try {
14166
- fs22.mkdirSync(path28.dirname(file), { recursive: true });
14167
- fs22.writeFileSync(file, buf);
14541
+ fs23.mkdirSync(path29.dirname(file), { recursive: true });
14542
+ fs23.writeFileSync(file, buf);
14168
14543
  } catch (e) {
14169
14544
  throw new Error(`\u521B\u5EFA\u6587\u4EF6\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
14170
14545
  }
14171
- return { path: toPosix(path28.relative(base, file)), size: buf.length };
14546
+ return { path: toPosix(path29.relative(base, file)), size: buf.length };
14172
14547
  }
14173
14548
  function searchProjectFiles(workspaceRoot, query) {
14174
14549
  const base = projectRoot(workspaceRoot);
@@ -14191,7 +14566,7 @@ function searchProjectFiles(workspaceRoot, query) {
14191
14566
  if (out.length >= LIMIT) return;
14192
14567
  let dirents;
14193
14568
  try {
14194
- dirents = fs22.readdirSync(dir, { withFileTypes: true });
14569
+ dirents = fs23.readdirSync(dir, { withFileTypes: true });
14195
14570
  } catch {
14196
14571
  return;
14197
14572
  }
@@ -14202,7 +14577,7 @@ function searchProjectFiles(workspaceRoot, query) {
14202
14577
  let isDir = d.isDirectory();
14203
14578
  if (d.isSymbolicLink()) {
14204
14579
  try {
14205
- isDir = fs22.statSync(path28.join(dir, d.name)).isDirectory();
14580
+ isDir = fs23.statSync(path29.join(dir, d.name)).isDirectory();
14206
14581
  } catch {
14207
14582
  isDir = false;
14208
14583
  }
@@ -14210,7 +14585,7 @@ function searchProjectFiles(workspaceRoot, query) {
14210
14585
  if (d.name.toLowerCase().includes(q)) {
14211
14586
  out.push({ path: rel, type: isDir ? "dir" : "file" });
14212
14587
  }
14213
- if (isDir) walk(path28.join(dir, d.name), rel);
14588
+ if (isDir) walk(path29.join(dir, d.name), rel);
14214
14589
  }
14215
14590
  };
14216
14591
  walk(base, "");
@@ -14219,8 +14594,8 @@ function searchProjectFiles(workspaceRoot, query) {
14219
14594
 
14220
14595
  // src/server/projectOps.ts
14221
14596
  init_esm_shims();
14222
- import * as os5 from "os";
14223
- import * as path29 from "path";
14597
+ import * as os7 from "os";
14598
+ import * as path30 from "path";
14224
14599
  var MAX_STDOUT2 = 2e4;
14225
14600
  var MAX_STDERR2 = 1e4;
14226
14601
  var MAX_BUFFER3 = 1024 * 1024 * 5;
@@ -14234,7 +14609,7 @@ function resolveInvocation2(spec, prepared) {
14234
14609
  }
14235
14610
  function workRoot(workspaceRoot) {
14236
14611
  const r = (workspaceRoot ?? "").trim();
14237
- return r ? path29.resolve(r) : os5.homedir();
14612
+ return r ? path30.resolve(r) : os7.homedir();
14238
14613
  }
14239
14614
  async function runProjectCommand(workspaceRoot, command, timeoutSeconds) {
14240
14615
  const cmd = String(command ?? "");
@@ -14545,11 +14920,11 @@ function projectStats(manager, tenantId) {
14545
14920
 
14546
14921
  // src/server/nodeHost.ts
14547
14922
  init_esm_shims();
14548
- import * as fs23 from "fs";
14549
- import * as os6 from "os";
14923
+ import * as fs24 from "fs";
14924
+ import * as os8 from "os";
14550
14925
  function diskInfo(pathStr) {
14551
14926
  try {
14552
- const st = fs23.statfsSync(pathStr);
14927
+ const st = fs24.statfsSync(pathStr);
14553
14928
  return {
14554
14929
  path: pathStr,
14555
14930
  total: Number(st.blocks) * Number(st.bsize),
@@ -14561,7 +14936,7 @@ function diskInfo(pathStr) {
14561
14936
  }
14562
14937
  function networkInfo() {
14563
14938
  const out = [];
14564
- const ifaces = os6.networkInterfaces();
14939
+ const ifaces = os8.networkInterfaces();
14565
14940
  for (const [name, list] of Object.entries(ifaces)) {
14566
14941
  for (const info of list ?? []) {
14567
14942
  out.push({
@@ -14612,23 +14987,23 @@ function overview(store, manager) {
14612
14987
  return { projects, sessions: { total, running, waiting, items }, usage: { tokensIn, tokensOut } };
14613
14988
  }
14614
14989
  function buildNodeHost(store, manager, diskPath) {
14615
- const cpus2 = os6.cpus();
14990
+ const cpus2 = os8.cpus();
14616
14991
  const ov = overview(store, manager);
14617
14992
  return {
14618
14993
  nodeId: store.loadNodeId() ?? "",
14619
- hostname: os6.hostname(),
14994
+ hostname: os8.hostname(),
14620
14995
  platform: process.platform,
14621
14996
  arch: process.arch,
14622
- release: os6.release(),
14623
- uptimeSec: Math.round(os6.uptime()),
14624
- version: "0.2.10",
14997
+ release: os8.release(),
14998
+ uptimeSec: Math.round(os8.uptime()),
14999
+ version: "0.2.11",
14625
15000
  mode: process.env.NODE_MODE ?? "standalone",
14626
15001
  cpu: {
14627
15002
  count: cpus2.length,
14628
15003
  model: cpus2[0]?.model ?? "",
14629
- loadAvg: os6.loadavg().map((n) => Math.round(n * 100) / 100)
15004
+ loadAvg: os8.loadavg().map((n) => Math.round(n * 100) / 100)
14630
15005
  },
14631
- memory: { total: os6.totalmem(), free: os6.freemem() },
15006
+ memory: { total: os8.totalmem(), free: os8.freemem() },
14632
15007
  network: networkInfo(),
14633
15008
  disk: diskInfo(diskPath || process.cwd()),
14634
15009
  ...ov
@@ -15196,7 +15571,7 @@ function createApp(store, manager, opts = {}) {
15196
15571
  applyProvidersPatch(tenant, raw);
15197
15572
  if (typeof raw.workspaceRoot === "string") {
15198
15573
  const ws = raw.workspaceRoot.trim();
15199
- const next = ws ? path30.resolve(ws) : void 0;
15574
+ const next = ws ? path31.resolve(ws) : void 0;
15200
15575
  if (tenant.workspaceRoot) {
15201
15576
  if (next !== tenant.workspaceRoot) {
15202
15577
  throw new ApiError(
@@ -16183,7 +16558,7 @@ function createApp(store, manager, opts = {}) {
16183
16558
  json(res, 200, {
16184
16559
  status: "ok",
16185
16560
  // 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
16186
- version: "0.2.10",
16561
+ version: "0.2.11",
16187
16562
  features: { mcp: hasServerMcpConfig() }
16188
16563
  });
16189
16564
  return;
@@ -16278,7 +16653,7 @@ function createApp(store, manager, opts = {}) {
16278
16653
 
16279
16654
  // src/server/fleet/FleetNodeBridge.ts
16280
16655
  init_esm_shims();
16281
- import * as os7 from "os";
16656
+ import * as os9 from "os";
16282
16657
  import { monitorEventLoopDelay } from "perf_hooks";
16283
16658
 
16284
16659
  // src/server/fleet/FleetCommands.ts
@@ -17472,7 +17847,7 @@ function withTimeout(p, ms) {
17472
17847
  }
17473
17848
  function primaryIp() {
17474
17849
  let v6;
17475
- for (const infos of Object.values(os7.networkInterfaces())) {
17850
+ for (const infos of Object.values(os9.networkInterfaces())) {
17476
17851
  for (const info of infos ?? []) {
17477
17852
  if (info.internal) continue;
17478
17853
  if (info.family === "IPv4") return info.address;
@@ -17821,7 +18196,7 @@ var FleetNodeBridge = class {
17821
18196
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
17822
18197
  platform: process.platform,
17823
18198
  mode: process.env.NODE_MODE ?? "standalone",
17824
- version: "0.2.10",
18199
+ version: "0.2.11",
17825
18200
  ip: primaryIp()
17826
18201
  };
17827
18202
  }
@@ -17876,7 +18251,7 @@ var FleetNodeBridge = class {
17876
18251
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
17877
18252
  platform: process.platform,
17878
18253
  mode: process.env.NODE_MODE ?? "standalone",
17879
- version: "0.2.10",
18254
+ version: "0.2.11",
17880
18255
  ip: primaryIp(),
17881
18256
  projects,
17882
18257
  totals,
@@ -18645,8 +19020,8 @@ init_esm_shims();
18645
19020
 
18646
19021
  // src/server/qq/bindings.ts
18647
19022
  init_esm_shims();
18648
- import * as fs24 from "fs";
18649
- import * as path31 from "path";
19023
+ import * as fs25 from "fs";
19024
+ import * as path32 from "path";
18650
19025
  function conversationKey(target) {
18651
19026
  switch (target.kind) {
18652
19027
  case "c2c":
@@ -18685,12 +19060,12 @@ var QqBindingsStore = class _QqBindingsStore {
18685
19060
  cache = null;
18686
19061
  /** 基于 DATA_DIR 构造 */
18687
19062
  static in(dataDir) {
18688
- return new _QqBindingsStore(path31.join(dataDir, "qq", "bindings.json"));
19063
+ return new _QqBindingsStore(path32.join(dataDir, "qq", "bindings.json"));
18689
19064
  }
18690
19065
  load() {
18691
19066
  if (this.cache) return this.cache;
18692
19067
  try {
18693
- const raw = JSON.parse(fs24.readFileSync(this.file, "utf-8"));
19068
+ const raw = JSON.parse(fs25.readFileSync(this.file, "utf-8"));
18694
19069
  this.cache = {
18695
19070
  conversations: raw.conversations ?? {}
18696
19071
  };
@@ -18722,8 +19097,8 @@ var QqBindingsStore = class _QqBindingsStore {
18722
19097
  return null;
18723
19098
  }
18724
19099
  persist() {
18725
- fs24.mkdirSync(path31.dirname(this.file), { recursive: true });
18726
- fs24.writeFileSync(this.file, JSON.stringify(this.cache, null, 2), "utf-8");
19100
+ fs25.mkdirSync(path32.dirname(this.file), { recursive: true });
19101
+ fs25.writeFileSync(this.file, JSON.stringify(this.cache, null, 2), "utf-8");
18727
19102
  }
18728
19103
  };
18729
19104
 
@@ -19135,8 +19510,8 @@ ${lines.join("\n")}`, msgId);
19135
19510
 
19136
19511
  // src/server/qq/QqManager.ts
19137
19512
  init_esm_shims();
19138
- import * as fs25 from "fs";
19139
- import * as path32 from "path";
19513
+ import * as fs26 from "fs";
19514
+ import * as path33 from "path";
19140
19515
  var QqManager = class {
19141
19516
  constructor(opts) {
19142
19517
  this.opts = opts;
@@ -19145,7 +19520,7 @@ var QqManager = class {
19145
19520
  adapter = null;
19146
19521
  config = null;
19147
19522
  get configFile() {
19148
- return path32.join(this.opts.dataDir, "qq", "config.json");
19523
+ return path33.join(this.opts.dataDir, "qq", "config.json");
19149
19524
  }
19150
19525
  /** 启动:读配置(env 优先,其次文件),有则建连接 */
19151
19526
  start() {
@@ -19183,7 +19558,7 @@ var QqManager = class {
19183
19558
  /** 清空配置:删除文件 + 断开 */
19184
19559
  clearConfig() {
19185
19560
  try {
19186
- fs25.rmSync(this.configFile, { force: true });
19561
+ fs26.rmSync(this.configFile, { force: true });
19187
19562
  } catch {
19188
19563
  }
19189
19564
  this.stop();
@@ -19225,7 +19600,7 @@ var QqManager = class {
19225
19600
  }
19226
19601
  _readConfigFile() {
19227
19602
  try {
19228
- const raw = JSON.parse(fs25.readFileSync(this.configFile, "utf-8"));
19603
+ const raw = JSON.parse(fs26.readFileSync(this.configFile, "utf-8"));
19229
19604
  if (raw.appId && raw.appSecret) {
19230
19605
  return {
19231
19606
  appId: raw.appId,
@@ -19238,8 +19613,8 @@ var QqManager = class {
19238
19613
  return null;
19239
19614
  }
19240
19615
  _persistConfig(cfg) {
19241
- fs25.mkdirSync(path32.dirname(this.configFile), { recursive: true });
19242
- fs25.writeFileSync(this.configFile, JSON.stringify(cfg, null, 2), "utf-8");
19616
+ fs26.mkdirSync(path33.dirname(this.configFile), { recursive: true });
19617
+ fs26.writeFileSync(this.configFile, JSON.stringify(cfg, null, 2), "utf-8");
19243
19618
  }
19244
19619
  };
19245
19620
 
@@ -19293,11 +19668,11 @@ import * as path37 from "path";
19293
19668
  // src/update/downloader.ts
19294
19669
  init_esm_shims();
19295
19670
  import { createHash as createHash3 } from "crypto";
19296
- import * as fs26 from "fs";
19671
+ import * as fs27 from "fs";
19297
19672
  import { Readable as Readable2 } from "stream";
19298
19673
  import { pipeline as pipeline2 } from "stream/promises";
19299
- import { spawnSync as spawnSync3 } from "child_process";
19300
- import * as path33 from "path";
19674
+ import { spawnSync as spawnSync4 } from "child_process";
19675
+ import * as path34 from "path";
19301
19676
 
19302
19677
  // src/update/manifest.ts
19303
19678
  init_esm_shims();
@@ -19474,8 +19849,8 @@ async function fetchManifest(url, publicKey, opts = {}) {
19474
19849
  async function downloadBinary(bin, destPath, log = () => {
19475
19850
  }) {
19476
19851
  const partPath = `${destPath}.part`;
19477
- fs26.mkdirSync(path33.dirname(destPath), { recursive: true });
19478
- fs26.rmSync(partPath, { force: true });
19852
+ fs27.mkdirSync(path34.dirname(destPath), { recursive: true });
19853
+ fs27.rmSync(partPath, { force: true });
19479
19854
  let res;
19480
19855
  try {
19481
19856
  res = await fetch(bin.url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS2) });
@@ -19500,30 +19875,30 @@ async function downloadBinary(bin, destPath, log = () => {
19500
19875
  yield chunk;
19501
19876
  }
19502
19877
  },
19503
- fs26.createWriteStream(partPath, { mode: 493 })
19878
+ fs27.createWriteStream(partPath, { mode: 493 })
19504
19879
  );
19505
19880
  } catch (err) {
19506
- fs26.rmSync(partPath, { force: true });
19881
+ fs27.rmSync(partPath, { force: true });
19507
19882
  return { error: `\u4E0B\u8F7D\u4E2D\u65AD\uFF1A${err.message}` };
19508
19883
  }
19509
19884
  const actual = hash.digest("hex");
19510
19885
  if (actual !== bin.sha256) {
19511
- fs26.rmSync(partPath, { force: true });
19886
+ fs27.rmSync(partPath, { force: true });
19512
19887
  return { error: `SHA-256 \u4E0D\u5339\u914D\uFF08\u671F\u671B ${bin.sha256.slice(0, 12)}\u2026\uFF0C\u5B9E\u9645 ${actual.slice(0, 12)}\u2026\uFF09` };
19513
19888
  }
19514
19889
  if (expected && bytes !== expected) {
19515
- fs26.rmSync(partPath, { force: true });
19890
+ fs27.rmSync(partPath, { force: true });
19516
19891
  return { error: `\u4EA7\u7269\u5927\u5C0F\u4E0D\u5339\u914D\uFF08\u671F\u671B ${expected}\uFF0C\u5B9E\u9645 ${bytes}\uFF09` };
19517
19892
  }
19518
- fs26.rmSync(destPath, { force: true });
19519
- fs26.renameSync(partPath, destPath);
19520
- fs26.chmodSync(destPath, 493);
19521
- log(`\u5DF2\u4E0B\u8F7D ${path33.basename(destPath)}\uFF08${Math.round(bytes / 1024 / 1024)}MB\uFF0C\u6821\u9A8C\u901A\u8FC7\uFF09`);
19893
+ fs27.rmSync(destPath, { force: true });
19894
+ fs27.renameSync(partPath, destPath);
19895
+ fs27.chmodSync(destPath, 493);
19896
+ log(`\u5DF2\u4E0B\u8F7D ${path34.basename(destPath)}\uFF08${Math.round(bytes / 1024 / 1024)}MB\uFF0C\u6821\u9A8C\u901A\u8FC7\uFF09`);
19522
19897
  return { bytes };
19523
19898
  }
19524
19899
  function selfCheck(binPath, expectedVersion) {
19525
19900
  try {
19526
- const r = spawnSync3(binPath, ["--version"], {
19901
+ const r = spawnSync4(binPath, ["--version"], {
19527
19902
  timeout: 2e4,
19528
19903
  encoding: "utf-8",
19529
19904
  env: { ...process.env, ZQAGENT_AUTO_UPDATE: "0" }
@@ -19540,176 +19915,6 @@ function selfCheck(binPath, expectedVersion) {
19540
19915
  }
19541
19916
  }
19542
19917
 
19543
- // src/update/platform.ts
19544
- init_esm_shims();
19545
- import * as fs27 from "fs";
19546
- import * as os8 from "os";
19547
- import * as path34 from "path";
19548
- import { spawnSync as spawnSync4 } from "child_process";
19549
- import { createRequire as createRequire3 } from "module";
19550
- function currentVersion() {
19551
- const injected = "0.2.10"?.trim();
19552
- if (injected) return injected;
19553
- try {
19554
- const req2 = createRequire3(import.meta.url);
19555
- const pkg = req2("../../package.json");
19556
- if (pkg?.version) return pkg.version;
19557
- } catch {
19558
- }
19559
- return "dev";
19560
- }
19561
- function isSeaRuntime() {
19562
- if (process.env.ZQAGENT_SEA === "1") return true;
19563
- const base = path34.basename(process.execPath).toLowerCase().replace(/\.exe$/, "");
19564
- return base !== "node" && base !== "nodejs";
19565
- }
19566
- var DEFAULT_SERVICE_NAME = "zqagent";
19567
- var DEFAULT_SERVICE_LABEL = "com.zqagent.node";
19568
- function serviceManagerFromCgroup(cgroup, serviceName = DEFAULT_SERVICE_NAME) {
19569
- const unitName = `${serviceName}.service`;
19570
- for (const line of cgroup.split("\n")) {
19571
- const idx = line.lastIndexOf(":");
19572
- if (idx < 0) continue;
19573
- const unitPath = line.slice(idx + 1).trim();
19574
- if (unitPath.split("/").includes(unitName)) return "systemd";
19575
- }
19576
- return null;
19577
- }
19578
- function launchdDomain() {
19579
- const uid = typeof process.getuid === "function" ? process.getuid() : -1;
19580
- return uid === 0 ? "system" : `gui/${uid}`;
19581
- }
19582
- function launchdLabel() {
19583
- return process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL;
19584
- }
19585
- function launchdPlistPath() {
19586
- const label = launchdLabel();
19587
- const uid = typeof process.getuid === "function" ? process.getuid() : -1;
19588
- if (uid === 0) return `/Library/LaunchDaemons/${label}.plist`;
19589
- return path34.join(os8.homedir(), "Library", "LaunchAgents", `${label}.plist`);
19590
- }
19591
- function serviceManagerFromLaunchctl(output, pid, execPath, sea = true) {
19592
- const pidMatch = /^\s*pid = (\d+)\s*$/m.exec(output);
19593
- if (pidMatch && Number(pidMatch[1]) === pid) return "launchd";
19594
- const program = /^\s*program = (.+?)\s*$/m.exec(output);
19595
- if (program) {
19596
- const shown = program[1].replace(/^"|"$/g, "");
19597
- if (path34.resolve(shown) === path34.resolve(execPath)) return "launchd";
19598
- }
19599
- if (!sea && /^\s*state = /m.test(output)) return "launchd";
19600
- return null;
19601
- }
19602
- function parseLaunchdEnvironment(xml) {
19603
- const out = {};
19604
- const marker = xml.indexOf("<key>EnvironmentVariables</key>");
19605
- if (marker < 0) return out;
19606
- const open = xml.indexOf("<dict>", marker);
19607
- if (open < 0) return out;
19608
- const close = xml.indexOf("</dict>", open);
19609
- if (close < 0) return out;
19610
- const body = xml.slice(open + "<dict>".length, close);
19611
- for (const m of body.matchAll(/<key>([^<]+)<\/key>\s*<string>([^<]*)<\/string>/g)) {
19612
- out[m[1]] = m[2];
19613
- }
19614
- return out;
19615
- }
19616
- function detectServiceManager() {
19617
- if (process.platform === "darwin") return detectLaunchd();
19618
- if (process.platform !== "linux") return null;
19619
- const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
19620
- try {
19621
- return serviceManagerFromCgroup(
19622
- fs27.readFileSync("/proc/self/cgroup", "utf8"),
19623
- serviceName
19624
- );
19625
- } catch {
19626
- return null;
19627
- }
19628
- }
19629
- function detectLaunchd() {
19630
- try {
19631
- const res = spawnSync4(
19632
- "launchctl",
19633
- ["print", `${launchdDomain()}/${launchdLabel()}`],
19634
- { encoding: "utf8", timeout: 3e3 }
19635
- );
19636
- if (res.status !== 0 || !res.stdout) return null;
19637
- return serviceManagerFromLaunchctl(
19638
- res.stdout,
19639
- process.pid,
19640
- process.execPath,
19641
- isSeaRuntime()
19642
- );
19643
- } catch {
19644
- return null;
19645
- }
19646
- }
19647
- function serviceManager() {
19648
- const v = process.env.ZQAGENT_SERVICE_MANAGER?.trim().toLowerCase();
19649
- if (v === "systemd" || v === "launchd") return v;
19650
- return detectServiceManager();
19651
- }
19652
- function parseServiceEnvironment(raw) {
19653
- const out = {};
19654
- for (const token of raw.trim().split(/\s+/)) {
19655
- const idx = token.indexOf("=");
19656
- if (idx > 0) out[token.slice(0, idx)] = token.slice(idx + 1);
19657
- }
19658
- return out;
19659
- }
19660
- var cachedServiceEnv = null;
19661
- function readServiceEnvironment() {
19662
- const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
19663
- try {
19664
- const res = spawnSync4(
19665
- "systemctl",
19666
- ["show", serviceName, "--property=Environment", "--value", "--no-pager"],
19667
- { encoding: "utf8", timeout: 3e3 }
19668
- );
19669
- if (res.status !== 0 || !res.stdout) return {};
19670
- return parseServiceEnvironment(res.stdout);
19671
- } catch {
19672
- return {};
19673
- }
19674
- }
19675
- function serviceEnvValue(key) {
19676
- if (process.platform === "darwin") {
19677
- if (serviceManager() !== "launchd") return void 0;
19678
- cachedLaunchdEnv ??= readLaunchdEnvironment();
19679
- return cachedLaunchdEnv[key];
19680
- }
19681
- if (process.platform !== "linux") return void 0;
19682
- if (serviceManager() !== "systemd") return void 0;
19683
- cachedServiceEnv ??= readServiceEnvironment();
19684
- return cachedServiceEnv[key];
19685
- }
19686
- var cachedLaunchdEnv = null;
19687
- function readLaunchdEnvironment() {
19688
- try {
19689
- return parseLaunchdEnvironment(fs27.readFileSync(launchdPlistPath(), "utf8"));
19690
- } catch {
19691
- return {};
19692
- }
19693
- }
19694
- function selfUpdateCapability(hasPublicKey) {
19695
- if (!isSeaRuntime()) {
19696
- return {
19697
- ok: false,
19698
- reason: "\u5F53\u524D\u4E0D\u662F\u5355\u6587\u4EF6\uFF08SEA\uFF09\u5F62\u6001\uFF1A\u8BF7\u7528 npm \u5347\u7EA7\uFF08npm i -g @zqagent/core@latest\uFF09"
19699
- };
19700
- }
19701
- if (!serviceManager()) {
19702
- return {
19703
- ok: false,
19704
- reason: "\u672A\u88AB systemd/launchd \u6258\u7BA1\uFF1A\u8BF7\u7528 deploy/service/install.sh \u5B89\u88C5\uFF0C\u6216\u624B\u52A8\u5347\u7EA7"
19705
- };
19706
- }
19707
- if (!hasPublicKey) {
19708
- return { ok: false, reason: "\u672A\u914D\u7F6E ZQAGENT_UPDATE_PUBKEY\uFF0C\u65E0\u6CD5\u9A8C\u7B7E\uFF0C\u5DF2\u7981\u7528\u81EA\u52A8\u66F4\u65B0" };
19709
- }
19710
- return { ok: true };
19711
- }
19712
-
19713
19918
  // src/update/installer.ts
19714
19919
  init_esm_shims();
19715
19920
  import * as fs29 from "fs";
@@ -20906,7 +21111,7 @@ function updateSessionMetaFile(stateDir2, sessionId, patch) {
20906
21111
  // src/cli/debug.ts
20907
21112
  init_esm_shims();
20908
21113
  import * as fs33 from "fs";
20909
- import * as os9 from "os";
21114
+ import * as os10 from "os";
20910
21115
  import * as path42 from "path";
20911
21116
  var LOG_NAME = "zqagent-debug.log";
20912
21117
  var TRUTHY = /^(1|true|yes|on)$/i;
@@ -20920,7 +21125,7 @@ function resolveLogFile() {
20920
21125
  const explicit = process.env.ZQAGENT_DEBUG_LOG;
20921
21126
  if (explicit) return path42.resolve(explicit);
20922
21127
  const dir = process.env.ZQAGENT_DEBUG_DIR;
20923
- return path42.join(dir ? path42.resolve(dir) : os9.tmpdir(), LOG_NAME);
21128
+ return path42.join(dir ? path42.resolve(dir) : os10.tmpdir(), LOG_NAME);
20924
21129
  }
20925
21130
  function enableDebug(argv = process.argv) {
20926
21131
  if (enabled) return true;
@@ -21358,20 +21563,7 @@ var _exitHandler = null;
21358
21563
  rl.on("SIGINT", () => {
21359
21564
  _exitHandler?.();
21360
21565
  });
21361
- function patchReadlineHistoryNav() {
21362
- const iface = rl;
21363
- const orig = iface._ttyWrite;
21364
- iface._ttyWrite = function(s, key) {
21365
- const k = key;
21366
- if (k && (k.name === "up" || k.name === "down") && !k.ctrl && !k.meta && !k.shift) {
21367
- if (iface.cursor > 0) {
21368
- iface._moveCursor(-iface.cursor);
21369
- }
21370
- }
21371
- orig.call(rl, s, key);
21372
- };
21373
- }
21374
- patchReadlineHistoryNav();
21566
+ patchReadlineHistoryNav(rl);
21375
21567
  dlog("init", "\u6A21\u5757\u521D\u59CB\u5316\u5B8C\u6210\uFF08readline / \u8F93\u5165\u8DEF\u7531 / \u5386\u53F2\u5BFC\u822A\u5C31\u7EEA\uFF09");
21376
21568
  function question(prompt) {
21377
21569
  return inputRouter.ask(prompt);
@@ -21835,7 +22027,7 @@ async function offerTerminalSetup(engine, canUseAgent) {
21835
22027
  }
21836
22028
  var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set(["link", "serve", "update"]);
21837
22029
  function cliVersion() {
21838
- const env3 = "0.2.10"?.trim();
22030
+ const env3 = "0.2.11"?.trim();
21839
22031
  if (env3) return env3;
21840
22032
  try {
21841
22033
  const req2 = createRequire4(import.meta.url);