@zqagent/core 0.2.8 → 0.2.10

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.
@@ -3741,10 +3741,10 @@ var OpenAIProvider = class {
3741
3741
  let timer;
3742
3742
  try {
3743
3743
  for (; ; ) {
3744
- const idle = new Promise((resolve23) => {
3744
+ const idle = new Promise((resolve24) => {
3745
3745
  timer = setTimeout(() => {
3746
3746
  onIdle();
3747
- resolve23({ timedOut: true });
3747
+ resolve24({ timedOut: true });
3748
3748
  }, idleMs);
3749
3749
  });
3750
3750
  const next = iter.next();
@@ -6065,12 +6065,12 @@ function makeSink(maxBuffer) {
6065
6065
  };
6066
6066
  }
6067
6067
  function execAsync(file, argv, opts = {}) {
6068
- return new Promise((resolve23) => {
6068
+ return new Promise((resolve24) => {
6069
6069
  const maxBuffer = opts.maxBuffer ?? DEFAULT_MAX_BUFFER;
6070
6070
  const out = makeSink(maxBuffer);
6071
6071
  const err = makeSink(maxBuffer);
6072
6072
  if (opts.signal?.aborted) {
6073
- resolve23({
6073
+ resolve24({
6074
6074
  status: null,
6075
6075
  stdout: Buffer.alloc(0),
6076
6076
  stderr: Buffer.alloc(0),
@@ -6091,7 +6091,7 @@ function execAsync(file, argv, opts = {}) {
6091
6091
  windowsHide: true
6092
6092
  });
6093
6093
  } catch (e) {
6094
- resolve23({
6094
+ resolve24({
6095
6095
  status: null,
6096
6096
  stdout: Buffer.alloc(0),
6097
6097
  stderr: Buffer.alloc(0),
@@ -6128,7 +6128,7 @@ function execAsync(file, argv, opts = {}) {
6128
6128
  };
6129
6129
  if (aborted) result.aborted = true;
6130
6130
  if (spawnError) result.error = spawnError;
6131
- resolve23(result);
6131
+ resolve24(result);
6132
6132
  };
6133
6133
  const killAndSettle = () => {
6134
6134
  killTree(child.pid);
@@ -10218,8 +10218,8 @@ var InputRouter = class {
10218
10218
  }
10219
10219
  /** 询问一行:显示 prompt,返回该行内容 */
10220
10220
  ask(prompt) {
10221
- return new Promise((resolve23) => {
10222
- this.pendingAsks.push({ prompt, resolve: resolve23 });
10221
+ return new Promise((resolve24) => {
10222
+ this.pendingAsks.push({ prompt, resolve: resolve24 });
10223
10223
  this.pumpAsks();
10224
10224
  });
10225
10225
  }
@@ -10316,16 +10316,16 @@ var import_chalk2 = __toESM(require("chalk"), 1);
10316
10316
  var BRAND_TEXT = "ZQAGENT";
10317
10317
  var BRAND_TAGLINE = "ZQAgent \xB7 AI Agent CLI";
10318
10318
  var GLYPHS = {
10319
- Z: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u255A\u2550\u2550\u2588\u2588\u2588\u2554\u255D", " \u2588\u2588\u2588\u2554\u255D ", " \u2588\u2588\u2588\u2554\u255D ", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"],
10320
- Q: [" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u2588\u2588\u2551\u2584\u2584 \u2588\u2588\u2551", "\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D", " \u255A\u2550\u2550\u2580\u2580\u2550\u255D "],
10321
- A: [" \u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551", "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2550\u255D \u255A\u2550\u255D"],
10322
- G: [" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D ", "\u2588\u2588\u2551 \u2588\u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D", " \u255A\u2550\u2550\u2550\u2550\u2550\u255D "],
10323
- E: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D", "\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u255D ", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"],
10324
- N: ["\u2588\u2588\u2588\u2557 \u2588\u2588\u2557", "\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551", "\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551", "\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551", "\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551", "\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D"],
10325
- T: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D", " \u2588\u2588\u2551 ", " \u2588\u2588\u2551 ", " \u2588\u2588\u2551 ", " \u255A\u2550\u255D "]
10319
+ Z: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588 ", " \u2588\u2588\u2588 ", " \u2588\u2588\u2588 ", " \u2588\u2588\u2588 ", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588 ", " "],
10320
+ Q: [" \u2588\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2584\u2584 \u2588\u2588", " \u2588\u2588\u2588\u2588\u2588\u2588 ", " \u2580\u2580 "],
10321
+ A: [" \u2588\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588", " "],
10322
+ G: [" \u2588\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 \u2588\u2588\u2588", "\u2588\u2588 \u2588\u2588", " \u2588\u2588\u2588\u2588\u2588\u2588 ", " "],
10323
+ E: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588 ", " "],
10324
+ N: ["\u2588\u2588 \u2588\u2588", "\u2588\u2588\u2588 \u2588\u2588", "\u2588\u2588\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588\u2588\u2588", " "],
10325
+ T: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 ", " "]
10326
10326
  };
10327
10327
  var GLYPH_ROWS = 6;
10328
- var GLYPH_COLS = 8;
10328
+ var GLYPH_COLS = 9;
10329
10329
  var GRADIENT = [
10330
10330
  [34, 211, 238],
10331
10331
  [99, 102, 241],
@@ -10930,15 +10930,36 @@ function parseServeArgs(argv) {
10930
10930
  return { dataDir, host, port };
10931
10931
  }
10932
10932
  function buildHotCandidates(explicitDataDir, discovered, fallback) {
10933
- if (explicitDataDir) {
10934
- return [{ dataDir: path20.resolve(explicitDataDir), ...fallback }];
10935
- }
10936
- const out = [{ dataDir: path20.resolve(DEFAULT_DATA_DIR), ...fallback }];
10933
+ const out = explicitDataDir ? [{ dataDir: path20.resolve(explicitDataDir), ...fallback }] : [{ dataDir: path20.resolve(DEFAULT_DATA_DIR), ...fallback }];
10937
10934
  for (const inst of discovered) {
10938
10935
  if (!out.some((o) => o.dataDir === inst.dataDir)) out.push(inst);
10939
10936
  }
10940
10937
  return out;
10941
10938
  }
10939
+ function isWindowsAbsolute(p) {
10940
+ return /^[A-Za-z]:[\\/]/.test(p) || /^\\\\/.test(p);
10941
+ }
10942
+ function isAbsolutePath(p) {
10943
+ return path20.isAbsolute(p) || isWindowsAbsolute(p);
10944
+ }
10945
+ function normalizePath(p) {
10946
+ return isWindowsAbsolute(p) ? path20.win32.normalize(p) : path20.normalize(p);
10947
+ }
10948
+ function parseServeCommandLine(line) {
10949
+ if (!/(?:^|\s)["']?serve["']?(?=\s|$)/.test(line)) return null;
10950
+ const m = /--data-dir(?:=|\s+)(?:"([^"]+)"|'([^']+)'|(.+?))(?=\s+--\w|\s*$)/.exec(line);
10951
+ const rawDataDir = (m?.[1] ?? m?.[2] ?? m?.[3] ?? "").trim();
10952
+ if (!rawDataDir || !isAbsolutePath(rawDataDir)) return null;
10953
+ const host = /--host(?:=|\s+)(?:"([^"]+)"|'([^']+)'|(\S+))/.exec(line);
10954
+ const rawHost = (host?.[1] ?? host?.[2] ?? host?.[3] ?? DEFAULT_SERVE_HOST).trim();
10955
+ const portMatch = /--port(?:=|\s+)(\d+)/.exec(line);
10956
+ const port = Number(portMatch?.[1] ?? DEFAULT_SERVE_PORT);
10957
+ return {
10958
+ dataDir: normalizePath(rawDataDir),
10959
+ host: rawHost === "0.0.0.0" || rawHost === "::" || rawHost === "" ? DEFAULT_SERVE_HOST : rawHost,
10960
+ port: Number.isFinite(port) && port > 0 ? port : DEFAULT_SERVE_PORT
10961
+ };
10962
+ }
10942
10963
  function processCwd(pid) {
10943
10964
  try {
10944
10965
  return fs18.readlinkSync(`/proc/${pid}/cwd`);
@@ -10994,23 +11015,28 @@ function discoverFromPs() {
10994
11015
  const res = (0, import_node_child_process4.spawnSync)("ps", ["-axo", "command="], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
10995
11016
  if (res.status !== 0 || !res.stdout) return out;
10996
11017
  for (const line of res.stdout.split("\n")) {
10997
- if (!line.includes(" serve")) continue;
10998
- const m = /--data-dir(?:=|\s+)(.+?)(?=\s+--|\s*$)/.exec(line);
10999
- if (!m) continue;
11000
- const raw = m[1].trim();
11001
- if (!raw || !path20.isAbsolute(raw)) continue;
11002
- const host = /--host(?:=|\s+)(\S+)/.exec(line)?.[1] ?? DEFAULT_SERVE_HOST;
11003
- const port = Number(/--port(?:=|\s+)(\d+)/.exec(line)?.[1] ?? DEFAULT_SERVE_PORT);
11004
- out.push({
11005
- dataDir: path20.normalize(raw),
11006
- host: host === "0.0.0.0" || host === "::" ? DEFAULT_SERVE_HOST : host,
11007
- port: Number.isFinite(port) && port > 0 ? port : DEFAULT_SERVE_PORT
11008
- });
11018
+ const inst = parseServeCommandLine(line);
11019
+ if (inst) out.push(inst);
11020
+ }
11021
+ return out;
11022
+ }
11023
+ function discoverFromWindows() {
11024
+ const out = [];
11025
+ const script = `[Console]::OutputEncoding=[Text.Encoding]::UTF8; Get-CimInstance Win32_Process -Filter "Name='zqagent.exe' OR Name='node.exe'" | ForEach-Object { $_.CommandLine }`;
11026
+ const res = (0, import_node_child_process4.spawnSync)(
11027
+ "powershell.exe",
11028
+ ["-NoProfile", "-NonInteractive", "-Command", script],
11029
+ { encoding: "utf-8", timeout: 15e3, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
11030
+ );
11031
+ if (res.status !== 0 || !res.stdout) return out;
11032
+ for (const line of res.stdout.replace(/^\uFEFF/, "").split(/\r?\n/)) {
11033
+ const inst = parseServeCommandLine(line);
11034
+ if (inst) out.push(inst);
11009
11035
  }
11010
11036
  return out;
11011
11037
  }
11012
11038
  function discoverRunningServeInstances() {
11013
- const found = process.platform === "linux" ? discoverFromProc() : discoverFromPs();
11039
+ const found = process.platform === "linux" ? discoverFromProc() : process.platform === "win32" ? discoverFromWindows() : discoverFromPs();
11014
11040
  const seen = /* @__PURE__ */ new Set();
11015
11041
  return found.filter((inst) => {
11016
11042
  if (seen.has(inst.dataDir)) return false;
@@ -11020,6 +11046,18 @@ function discoverRunningServeInstances() {
11020
11046
  }
11021
11047
 
11022
11048
  // src/cli/link.ts
11049
+ function expandHome(p) {
11050
+ const home = process.env.HOME || process.env.USERPROFILE;
11051
+ if (!home) return p;
11052
+ if (p === "~") return home;
11053
+ if (p.startsWith("~/") || p.startsWith("~\\")) return path21.join(home, p.slice(2));
11054
+ return p;
11055
+ }
11056
+ function installDataDirHint() {
11057
+ if (process.platform === "darwin") return "$HOME/Library/Application Support/zqagent";
11058
+ if (process.platform === "win32") return "%LOCALAPPDATA%\\zqagent";
11059
+ return "/var/lib/zqagent\uFF08\u9700 root\uFF1B\u666E\u901A\u7528\u6237\u7528 ~/.zqagent_data\uFF09";
11060
+ }
11023
11061
  function parseLinkArgs(argv) {
11024
11062
  const out = {};
11025
11063
  for (let i = 0; i < argv.length; i++) {
@@ -11093,10 +11131,12 @@ async function enrollViaServer(host, port, adminKey, opts) {
11093
11131
  return payload?.data;
11094
11132
  }
11095
11133
  async function linkNode(opts) {
11096
- const explicitDataDir = opts.dataDir?.trim() || process.env.DATA_DIR?.trim() || void 0;
11134
+ const rawDataDir = opts.dataDir?.trim() || process.env.DATA_DIR?.trim() || void 0;
11135
+ const explicitDataDir = rawDataDir ? expandHome(rawDataDir) : void 0;
11097
11136
  const host = opts.host?.trim() || process.env.HOST?.trim() || DEFAULT_SERVE_HOST;
11098
11137
  const port = opts.port ?? Number(process.env.PORT ?? DEFAULT_SERVE_PORT);
11099
- const candidates = explicitDataDir ? buildHotCandidates(explicitDataDir, [], { host, port }) : buildHotCandidates(void 0, discoverRunningServeInstances(), { host, port });
11138
+ const running = discoverRunningServeInstances();
11139
+ const candidates = buildHotCandidates(explicitDataDir, running, { host, port });
11100
11140
  for (const inst of candidates) {
11101
11141
  const store2 = new Store(inst.dataDir);
11102
11142
  const adminKey = process.env.ADMIN_API_KEY ?? store2.loadAdminKey();
@@ -11113,18 +11153,36 @@ async function linkNode(opts) {
11113
11153
  nodeId,
11114
11154
  label: opts.label
11115
11155
  });
11116
- store.saveFleetCredential({
11117
- ...cred,
11118
- label: opts.label ?? cred.label,
11119
- enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
11120
- });
11156
+ try {
11157
+ store.saveFleetCredential({
11158
+ ...cred,
11159
+ label: opts.label ?? cred.label,
11160
+ enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
11161
+ });
11162
+ } catch (e) {
11163
+ const err = e;
11164
+ if (err.code === "EACCES" || err.code === "EPERM") {
11165
+ throw new Error(
11166
+ `\u65E0\u6CD5\u5199\u5165\u6570\u636E\u76EE\u5F55 ${dataDir}\uFF08${err.code}: ${err.message}\uFF09
11167
+ \u8BE5\u76EE\u5F55\u5F53\u524D\u7528\u6237\u6CA1\u6709\u5199\u6743\u9650\u3002\u4E24\u79CD\u6539\u6CD5\uFF1A
11168
+ 1) \u53BB\u6389 --data-dir\uFF0C\u8BA9 link \u81EA\u52A8\u53D1\u73B0\u672C\u673A\u8FD0\u884C\u7684\u8282\u70B9\uFF08\u63A8\u8350\uFF09\uFF1B
11169
+ 2) \u7528\u5F53\u524D\u7528\u6237\u53EF\u5199\u7684\u76EE\u5F55\uFF0C\u672C\u5E73\u53F0\u5B89\u88C5\u811A\u672C\u9ED8\u8BA4\uFF1A${installDataDirHint()}
11170
+ \uFF08\u63A5\u5165\u7801\u4E00\u6B21\u6027\uFF0C\u9700\u8981\u91CD\u65B0\u751F\u6210\uFF09`
11171
+ );
11172
+ }
11173
+ throw e;
11174
+ }
11175
+ const otherRunningDirs = [
11176
+ ...new Set(running.map((r) => r.dataDir).filter((d) => d !== dataDir))
11177
+ ];
11121
11178
  return {
11122
11179
  mode: "saved",
11123
11180
  nodeId,
11124
11181
  gatewayUrl: cred.gatewayUrl,
11125
11182
  label: opts.label,
11126
11183
  dataDir,
11127
- explicitDataDir: Boolean(explicitDataDir)
11184
+ explicitDataDir: Boolean(explicitDataDir),
11185
+ runningServiceDirs: otherRunningDirs
11128
11186
  };
11129
11187
  }
11130
11188
  function printLinkHelp() {
@@ -11166,13 +11224,21 @@ async function runLinkCommand(argv) {
11166
11224
  cliLog(` \u7F51\u5173: ${r.gatewayUrl ?? "\uFF08\u672A\u4E0B\u53D1\uFF09"}`);
11167
11225
  cliLog(` \u6570\u636E\u76EE\u5F55: ${r.dataDir}`);
11168
11226
  cliLog(" \u4E0B\u6B21\u542F\u52A8 server \u5373\u81EA\u52A8\u63A5\u5165\uFF1B\u6216\u8FD0\u884C zqagent serve \u5E38\u9A7B\u4E3A\u8282\u70B9\u3002");
11169
- if (!r.explicitDataDir) {
11227
+ if (r.runningServiceDirs.length > 0) {
11228
+ cliLog("");
11229
+ 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");
11230
+ cliLog(` \u672C\u6B21\u5199\u5165: ${r.dataDir}`);
11231
+ for (const d of r.runningServiceDirs) cliLog(` \u670D\u52A1\u4F7F\u7528: ${d}`);
11232
+ cliLog(" \u6B63\u5728\u8FD0\u884C\u7684\u670D\u52A1\u8BFB\u4E0D\u5230\u8FD9\u4EFD\u51ED\u636E\uFF0CHub \u4F1A\u4E00\u76F4\u663E\u793A\u672A\u63A5\u5165\u3002");
11233
+ cliLog(" \u8BF7\u786E\u8BA4\u670D\u52A1\u7684\u6570\u636E\u76EE\u5F55\u540E\u91CD\u65B0\u6267\u884C\uFF08\u63A5\u5165\u7801\u4E00\u6B21\u6027\uFF0C\u9700\u8981\u91CD\u65B0\u751F\u6210\uFF09\uFF1A");
11234
+ cliLog(` zqagent link --hub <Hub\u5730\u5740> --code <\u65B0\u63A5\u5165\u7801> --data-dir "${r.runningServiceDirs[0]}"`);
11235
+ } else if (!r.explicitDataDir) {
11170
11236
  cliLog("");
11171
11237
  cliLog("\u26A0\uFE0F \u672A\u6307\u5B9A --data-dir\uFF0C\u51ED\u636E\u5199\u5165\u4E86\u5F53\u524D\u76EE\u5F55\u4E0B\u7684 .zqagent_data\u3002");
11172
11238
  cliLog(" \u82E5\u672C\u673A\u670D\u52A1\u662F\u7531\u5B89\u88C5\u811A\u672C\uFF08systemd / launchd\uFF09\u542F\u52A8\u7684\uFF0C\u5B83\u8BFB\u4E0D\u5230\u8FD9\u4EFD\u51ED\u636E\uFF0C");
11173
11239
  cliLog(" Hub \u4F1A\u4E00\u76F4\u663E\u793A\u672A\u5728\u7EBF\u3002\u8BF7\u7528\u670D\u52A1\u7684\u6570\u636E\u76EE\u5F55\u91CD\u65B0\u6267\u884C\uFF1A");
11174
11240
  cliLog(" zqagent link --hub <Hub\u5730\u5740> --code <\u65B0\u63A5\u5165\u7801> --data-dir <\u670D\u52A1\u6570\u636E\u76EE\u5F55>");
11175
- cliLog(" \uFF08Linux \u5B89\u88C5\u811A\u672C\u9ED8\u8BA4 /var/lib/zqagent\uFF1B\u63A5\u5165\u7801\u4E00\u6B21\u6027\uFF0C\u9700\u8981\u91CD\u65B0\u751F\u6210\uFF09");
11241
+ cliLog(` \uFF08\u672C\u5E73\u53F0\u5B89\u88C5\u811A\u672C\u9ED8\u8BA4\uFF1A${installDataDirHint()}\uFF1B\u63A5\u5165\u7801\u4E00\u6B21\u6027\uFF0C\u9700\u8981\u91CD\u65B0\u751F\u6210\uFF09`);
11176
11242
  }
11177
11243
  }
11178
11244
  return true;
@@ -12023,11 +12089,11 @@ function isAffirmative(answer) {
12023
12089
  return /^(yes|approve|同意|批准|允许|确定|可以|好的|确认)/.test(a);
12024
12090
  }
12025
12091
  function defer() {
12026
- let resolve23;
12092
+ let resolve24;
12027
12093
  const promise = new Promise((r) => {
12028
- resolve23 = r;
12094
+ resolve24 = r;
12029
12095
  });
12030
- return { promise, resolve: resolve23 };
12096
+ return { promise, resolve: resolve24 };
12031
12097
  }
12032
12098
  var SessionManager = class {
12033
12099
  constructor(store, approvalTimeoutMs = APPROVAL_TIMEOUT_MS, opts = {}) {
@@ -12599,11 +12665,11 @@ data: ${JSON.stringify({ sessionId, seq: entry.seq, ts: entry.ts, data: entry.da
12599
12665
  status: "pending",
12600
12666
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
12601
12667
  };
12602
- const { promise, resolve: resolve23 } = defer();
12668
+ const { promise, resolve: resolve24 } = defer();
12603
12669
  const timer = setTimeout(() => {
12604
12670
  this._recycleApproval(rt, id);
12605
12671
  }, this.approvalTimeoutMs);
12606
- rt.pendingApprovals.set(id, { promise, resolve: resolve23, record, timer });
12672
+ rt.pendingApprovals.set(id, { promise, resolve: resolve24, record, timer });
12607
12673
  rt.approvals.set(id, record);
12608
12674
  this._setStatus(rt, "waiting_approval");
12609
12675
  this._persist(rt);
@@ -12681,11 +12747,11 @@ data: ${JSON.stringify({ sessionId, seq: entry.seq, ts: entry.ts, data: entry.da
12681
12747
  status: "pending",
12682
12748
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
12683
12749
  };
12684
- const { promise, resolve: resolve23 } = defer();
12750
+ const { promise, resolve: resolve24 } = defer();
12685
12751
  const timer = setTimeout(() => {
12686
12752
  this._recycleQuestion(rt, qid);
12687
12753
  }, this.approvalTimeoutMs);
12688
- rt.pendingQuestions.set(qid, { promise, resolve: resolve23, record, timer });
12754
+ rt.pendingQuestions.set(qid, { promise, resolve: resolve24, record, timer });
12689
12755
  rt.questions.set(qid, record);
12690
12756
  this._setStatus(rt, "waiting_question");
12691
12757
  this._persist(rt);
@@ -12994,7 +13060,7 @@ data: ${JSON.stringify(entry.data)}
12994
13060
  if (rt.mcpReady) {
12995
13061
  await Promise.race([
12996
13062
  rt.mcpReady,
12997
- new Promise((resolve23) => setTimeout(resolve23, 15e3))
13063
+ new Promise((resolve24) => setTimeout(resolve24, 15e3))
12998
13064
  ]).catch(() => void 0);
12999
13065
  }
13000
13066
  for await (const event of gen) {
@@ -13579,7 +13645,7 @@ function buildNodeInfo(store, opts) {
13579
13645
  nodeId: opts.nodeId ?? ensureNodeId2(store),
13580
13646
  platform: process.platform,
13581
13647
  mode: process.env.NODE_MODE ?? "standalone",
13582
- version: "0.2.8",
13648
+ version: "0.2.10",
13583
13649
  admin: opts.admin,
13584
13650
  projects: opts.projects
13585
13651
  };
@@ -14572,7 +14638,7 @@ function buildNodeHost(store, manager, diskPath) {
14572
14638
  arch: process.arch,
14573
14639
  release: os6.release(),
14574
14640
  uptimeSec: Math.round(os6.uptime()),
14575
- version: "0.2.8",
14641
+ version: "0.2.10",
14576
14642
  mode: process.env.NODE_MODE ?? "standalone",
14577
14643
  cpu: {
14578
14644
  count: cpus2.length,
@@ -14616,7 +14682,7 @@ function saveNotifications(tenant, secretBox, notifications) {
14616
14682
  var API_PREFIX = "/api/v1";
14617
14683
  var MAX_BODY_BYTES = 10 * 1024 * 1024;
14618
14684
  function readBody(req2) {
14619
- return new Promise((resolve23, reject) => {
14685
+ return new Promise((resolve24, reject) => {
14620
14686
  const chunks = [];
14621
14687
  let size = 0;
14622
14688
  req2.on("data", (c) => {
@@ -14629,9 +14695,9 @@ function readBody(req2) {
14629
14695
  chunks.push(c);
14630
14696
  });
14631
14697
  req2.on("end", () => {
14632
- if (chunks.length === 0) return resolve23(void 0);
14698
+ if (chunks.length === 0) return resolve24(void 0);
14633
14699
  try {
14634
- resolve23(JSON.parse(Buffer.concat(chunks).toString("utf-8")));
14700
+ resolve24(JSON.parse(Buffer.concat(chunks).toString("utf-8")));
14635
14701
  } catch {
14636
14702
  reject(new ApiError(400, "bad_request", "\u8BF7\u6C42\u4F53\u4E0D\u662F\u5408\u6CD5 JSON"));
14637
14703
  }
@@ -15147,8 +15213,18 @@ function createApp(store, manager, opts = {}) {
15147
15213
  applyProvidersPatch(tenant, raw);
15148
15214
  if (typeof raw.workspaceRoot === "string") {
15149
15215
  const ws = raw.workspaceRoot.trim();
15150
- if (ws) tenant.workspaceRoot = path29.resolve(ws);
15151
- else delete tenant.workspaceRoot;
15216
+ const next = ws ? path29.resolve(ws) : void 0;
15217
+ if (tenant.workspaceRoot) {
15218
+ if (next !== tenant.workspaceRoot) {
15219
+ throw new ApiError(
15220
+ 409,
15221
+ "workspace_locked",
15222
+ "\u8BE5\u9879\u76EE\u5DF2\u8BBE\u7F6E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u4E0D\u80FD\u518D\u4FEE\u6539"
15223
+ );
15224
+ }
15225
+ } else if (next) {
15226
+ tenant.workspaceRoot = next;
15227
+ }
15152
15228
  }
15153
15229
  if (typeof raw.name === "string" && raw.name.trim()) {
15154
15230
  tenant.name = raw.name.trim();
@@ -16124,7 +16200,7 @@ function createApp(store, manager, opts = {}) {
16124
16200
  json(res, 200, {
16125
16201
  status: "ok",
16126
16202
  // 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
16127
- version: "0.2.8",
16203
+ version: "0.2.10",
16128
16204
  features: { mcp: hasServerMcpConfig() }
16129
16205
  });
16130
16206
  return;
@@ -16240,8 +16316,8 @@ async function cachedFetchModels(baseURL, apiKey) {
16240
16316
  try {
16241
16317
  result = await Promise.race([
16242
16318
  fetchModels(baseURL, apiKey),
16243
- new Promise((resolve23) => {
16244
- const t = setTimeout(() => resolve23(null), MODEL_FETCH_TIMEOUT_MS);
16319
+ new Promise((resolve24) => {
16320
+ const t = setTimeout(() => resolve24(null), MODEL_FETCH_TIMEOUT_MS);
16245
16321
  t.unref?.();
16246
16322
  })
16247
16323
  ]);
@@ -16266,8 +16342,8 @@ async function cachedFetchModelsEnriched(baseURL, apiKey, preferred) {
16266
16342
  if (!target) return r;
16267
16343
  const ctx = await Promise.race([
16268
16344
  fetchModelContext(baseURL, apiKey, target),
16269
- new Promise((resolve23) => {
16270
- const t = setTimeout(() => resolve23(void 0), MODEL_FETCH_TIMEOUT_MS);
16345
+ new Promise((resolve24) => {
16346
+ const t = setTimeout(() => resolve24(void 0), MODEL_FETCH_TIMEOUT_MS);
16271
16347
  t.unref?.();
16272
16348
  })
16273
16349
  ]);
@@ -17396,13 +17472,13 @@ var EVENT_FLUSH_MAX_EVENTS = 60;
17396
17472
  var EVENT_FLUSH_MAX_BYTES = 200 * 1024;
17397
17473
  var LOOP_LAG_WARN_MS = 2e3;
17398
17474
  function withTimeout(p, ms) {
17399
- return new Promise((resolve23, reject) => {
17475
+ return new Promise((resolve24, reject) => {
17400
17476
  const timer = setTimeout(() => reject(new Error(`\u5B50\u6307\u4EE4\u8D85\u65F6\uFF08${ms}ms\uFF09`)), ms);
17401
17477
  timer.unref?.();
17402
17478
  p.then(
17403
17479
  (v) => {
17404
17480
  clearTimeout(timer);
17405
- resolve23(v);
17481
+ resolve24(v);
17406
17482
  },
17407
17483
  (e) => {
17408
17484
  clearTimeout(timer);
@@ -17762,7 +17838,7 @@ var FleetNodeBridge = class {
17762
17838
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
17763
17839
  platform: process.platform,
17764
17840
  mode: process.env.NODE_MODE ?? "standalone",
17765
- version: "0.2.8",
17841
+ version: "0.2.10",
17766
17842
  ip: primaryIp()
17767
17843
  };
17768
17844
  }
@@ -17817,7 +17893,7 @@ var FleetNodeBridge = class {
17817
17893
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
17818
17894
  platform: process.platform,
17819
17895
  mode: process.env.NODE_MODE ?? "standalone",
17820
- version: "0.2.8",
17896
+ version: "0.2.10",
17821
17897
  ip: primaryIp(),
17822
17898
  projects,
17823
17899
  totals,
@@ -19294,8 +19370,10 @@ var PLATFORM_NAMES = {
19294
19370
  linux: "linux",
19295
19371
  win32: "windows"
19296
19372
  };
19373
+ var LIBC_VARIANT = "";
19297
19374
  function platformKey(platform = process.platform, arch = process.arch) {
19298
- return `${PLATFORM_NAMES[platform] ?? platform}-${arch}`;
19375
+ const base = `${PLATFORM_NAMES[platform] ?? platform}-${arch}`;
19376
+ return LIBC_VARIANT ? `${base}-${LIBC_VARIANT}` : base;
19299
19377
  }
19300
19378
  var SHA256_HEX = /^[0-9a-f]{64}$/;
19301
19379
  function isRecord(v) {
@@ -19482,11 +19560,12 @@ function selfCheck(binPath, expectedVersion) {
19482
19560
  // src/update/platform.ts
19483
19561
  init_cjs_shims();
19484
19562
  var fs27 = __toESM(require("fs"), 1);
19563
+ var os8 = __toESM(require("os"), 1);
19485
19564
  var path33 = __toESM(require("path"), 1);
19486
19565
  var import_node_child_process6 = require("child_process");
19487
19566
  var import_node_module3 = require("module");
19488
19567
  function currentVersion() {
19489
- const injected = "0.2.8"?.trim();
19568
+ const injected = "0.2.10"?.trim();
19490
19569
  if (injected) return injected;
19491
19570
  try {
19492
19571
  const req2 = (0, import_node_module3.createRequire)(importMetaUrl);
@@ -19502,6 +19581,7 @@ function isSeaRuntime() {
19502
19581
  return base !== "node" && base !== "nodejs";
19503
19582
  }
19504
19583
  var DEFAULT_SERVICE_NAME = "zqagent";
19584
+ var DEFAULT_SERVICE_LABEL = "com.zqagent.node";
19505
19585
  function serviceManagerFromCgroup(cgroup, serviceName = DEFAULT_SERVICE_NAME) {
19506
19586
  const unitName = `${serviceName}.service`;
19507
19587
  for (const line of cgroup.split("\n")) {
@@ -19512,7 +19592,46 @@ function serviceManagerFromCgroup(cgroup, serviceName = DEFAULT_SERVICE_NAME) {
19512
19592
  }
19513
19593
  return null;
19514
19594
  }
19595
+ function launchdDomain() {
19596
+ const uid = typeof process.getuid === "function" ? process.getuid() : -1;
19597
+ return uid === 0 ? "system" : `gui/${uid}`;
19598
+ }
19599
+ function launchdLabel() {
19600
+ return process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL;
19601
+ }
19602
+ function launchdPlistPath() {
19603
+ const label = launchdLabel();
19604
+ const uid = typeof process.getuid === "function" ? process.getuid() : -1;
19605
+ if (uid === 0) return `/Library/LaunchDaemons/${label}.plist`;
19606
+ return path33.join(os8.homedir(), "Library", "LaunchAgents", `${label}.plist`);
19607
+ }
19608
+ function serviceManagerFromLaunchctl(output, pid, execPath, sea = true) {
19609
+ const pidMatch = /^\s*pid = (\d+)\s*$/m.exec(output);
19610
+ if (pidMatch && Number(pidMatch[1]) === pid) return "launchd";
19611
+ const program = /^\s*program = (.+?)\s*$/m.exec(output);
19612
+ if (program) {
19613
+ const shown = program[1].replace(/^"|"$/g, "");
19614
+ if (path33.resolve(shown) === path33.resolve(execPath)) return "launchd";
19615
+ }
19616
+ if (!sea && /^\s*state = /m.test(output)) return "launchd";
19617
+ return null;
19618
+ }
19619
+ function parseLaunchdEnvironment(xml) {
19620
+ const out = {};
19621
+ const marker = xml.indexOf("<key>EnvironmentVariables</key>");
19622
+ if (marker < 0) return out;
19623
+ const open = xml.indexOf("<dict>", marker);
19624
+ if (open < 0) return out;
19625
+ const close = xml.indexOf("</dict>", open);
19626
+ if (close < 0) return out;
19627
+ const body = xml.slice(open + "<dict>".length, close);
19628
+ for (const m of body.matchAll(/<key>([^<]+)<\/key>\s*<string>([^<]*)<\/string>/g)) {
19629
+ out[m[1]] = m[2];
19630
+ }
19631
+ return out;
19632
+ }
19515
19633
  function detectServiceManager() {
19634
+ if (process.platform === "darwin") return detectLaunchd();
19516
19635
  if (process.platform !== "linux") return null;
19517
19636
  const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
19518
19637
  try {
@@ -19524,6 +19643,24 @@ function detectServiceManager() {
19524
19643
  return null;
19525
19644
  }
19526
19645
  }
19646
+ function detectLaunchd() {
19647
+ try {
19648
+ const res = (0, import_node_child_process6.spawnSync)(
19649
+ "launchctl",
19650
+ ["print", `${launchdDomain()}/${launchdLabel()}`],
19651
+ { encoding: "utf8", timeout: 3e3 }
19652
+ );
19653
+ if (res.status !== 0 || !res.stdout) return null;
19654
+ return serviceManagerFromLaunchctl(
19655
+ res.stdout,
19656
+ process.pid,
19657
+ process.execPath,
19658
+ isSeaRuntime()
19659
+ );
19660
+ } catch {
19661
+ return null;
19662
+ }
19663
+ }
19527
19664
  function serviceManager() {
19528
19665
  const v = process.env.ZQAGENT_SERVICE_MANAGER?.trim().toLowerCase();
19529
19666
  if (v === "systemd" || v === "launchd") return v;
@@ -19553,11 +19690,24 @@ function readServiceEnvironment() {
19553
19690
  }
19554
19691
  }
19555
19692
  function serviceEnvValue(key) {
19693
+ if (process.platform === "darwin") {
19694
+ if (serviceManager() !== "launchd") return void 0;
19695
+ cachedLaunchdEnv ??= readLaunchdEnvironment();
19696
+ return cachedLaunchdEnv[key];
19697
+ }
19556
19698
  if (process.platform !== "linux") return void 0;
19557
19699
  if (serviceManager() !== "systemd") return void 0;
19558
19700
  cachedServiceEnv ??= readServiceEnvironment();
19559
19701
  return cachedServiceEnv[key];
19560
19702
  }
19703
+ var cachedLaunchdEnv = null;
19704
+ function readLaunchdEnvironment() {
19705
+ try {
19706
+ return parseLaunchdEnvironment(fs27.readFileSync(launchdPlistPath(), "utf8"));
19707
+ } catch {
19708
+ return {};
19709
+ }
19710
+ }
19561
19711
  function selfUpdateCapability(hasPublicKey) {
19562
19712
  if (!isSeaRuntime()) {
19563
19713
  return {
@@ -19942,11 +20092,11 @@ var UpdateController = class {
19942
20092
  const minUptime = num("ZQAGENT_UPDATE_MIN_UPTIME_MS", 10 * 60 * 1e3);
19943
20093
  const idleMs = num("ZQAGENT_UPDATE_IDLE_MS", 60 * 1e3);
19944
20094
  let idleSince = null;
19945
- return new Promise((resolve23) => {
20095
+ return new Promise((resolve24) => {
19946
20096
  const timer = setInterval(() => {
19947
20097
  if (this.stopped) {
19948
20098
  clearInterval(timer);
19949
- resolve23(false);
20099
+ resolve24(false);
19950
20100
  return;
19951
20101
  }
19952
20102
  if (Date.now() - this.startedAt < minUptime || !this.opts.isIdle()) {
@@ -19956,7 +20106,7 @@ var UpdateController = class {
19956
20106
  idleSince ??= Date.now();
19957
20107
  if (Date.now() - idleSince >= idleMs) {
19958
20108
  clearInterval(timer);
19959
- resolve23(true);
20109
+ resolve24(true);
19960
20110
  }
19961
20111
  }, 1e3);
19962
20112
  timer.unref();
@@ -20137,6 +20287,46 @@ function exitWhenOrphaned() {
20137
20287
  }, 1500);
20138
20288
  timer.unref();
20139
20289
  }
20290
+ var PORT_FALLBACK_LIMIT = 20;
20291
+ function listenWithPortFallback(server, startPort, host, dataDir, limit = PORT_FALLBACK_LIMIT) {
20292
+ return new Promise((resolve24, reject) => {
20293
+ let attempts = 0;
20294
+ const tryListen = (port) => {
20295
+ server.removeAllListeners("listening");
20296
+ const onError = (err) => {
20297
+ if (err.code === "EADDRINUSE" && attempts < limit) {
20298
+ attempts += 1;
20299
+ const next = port + 1;
20300
+ console.warn(`[server] \u7AEF\u53E3 ${port} \u5DF2\u88AB\u5360\u7528\uFF08EADDRINUSE\uFF09\uFF0C\u5C1D\u8BD5 ${next} \u2026`);
20301
+ tryListen(next);
20302
+ return;
20303
+ }
20304
+ server.removeListener("error", onError);
20305
+ console.error(
20306
+ `[server] \u65E0\u6CD5\u76D1\u542C ${host}:${port}\uFF1A${err.message}` + (err.code === "EADDRINUSE" ? `\uFF08\u5DF2\u5C1D\u8BD5 ${attempts + 1} \u4E2A\u7AEF\u53E3\u5747\u88AB\u5360\u7528\uFF09` : "")
20307
+ );
20308
+ reject(err);
20309
+ };
20310
+ server.once("error", onError);
20311
+ server.listen(port, host, () => {
20312
+ server.removeListener("error", onError);
20313
+ const addr = server.address();
20314
+ const actualPort = typeof addr === "object" && addr !== null ? addr.port : port;
20315
+ if (actualPort !== startPort) {
20316
+ console.warn(`[server] \u5DF2\u6539\u7528\u7AEF\u53E3 ${actualPort}\uFF08\u539F\u5B9A ${startPort} \u88AB\u5360\u7528\uFF09`);
20317
+ }
20318
+ try {
20319
+ fs31.mkdirSync(dataDir, { recursive: true });
20320
+ fs31.writeFileSync(path37.join(dataDir, "server-port"), `${actualPort}
20321
+ `);
20322
+ } catch {
20323
+ }
20324
+ resolve24(actualPort);
20325
+ });
20326
+ };
20327
+ tryListen(startPort);
20328
+ });
20329
+ }
20140
20330
  function startServer(opts = {}) {
20141
20331
  const dataDir = path37.resolve(opts.dataDir ?? env2("DATA_DIR") ?? DEFAULT_DATA_DIR);
20142
20332
  const port = opts.port ?? Number(env2("PORT") ?? 8787);
@@ -20362,11 +20552,11 @@ function startServer(opts = {}) {
20362
20552
  server.timeout = 0;
20363
20553
  server.keepAliveTimeout = 65e3;
20364
20554
  server.headersTimeout = 66e3;
20365
- const ready = new Promise((resolve23) => {
20366
- server.listen(port, host, () => {
20555
+ const ready = new Promise((resolve24, reject) => {
20556
+ listenWithPortFallback(server, port, host, dataDir).then((actualPort) => {
20367
20557
  const info = {
20368
20558
  host,
20369
- port,
20559
+ port: actualPort,
20370
20560
  dataDir,
20371
20561
  adminKey,
20372
20562
  fleetNodeId: fleet ? fleet.getNodeId() : void 0,
@@ -20379,8 +20569,8 @@ function startServer(opts = {}) {
20379
20569
  printReady(info, qq);
20380
20570
  }
20381
20571
  updater?.start();
20382
- resolve23(info);
20383
- });
20572
+ resolve24(info);
20573
+ }, reject);
20384
20574
  });
20385
20575
  return {
20386
20576
  store,
@@ -20516,7 +20706,7 @@ async function runWizard(rl2, store, opts) {
20516
20706
  }
20517
20707
  async function askHidden(rl2, prompt) {
20518
20708
  if (!process.stdin.isTTY) return (await rl2.question(prompt)).trim();
20519
- return new Promise((resolve23) => {
20709
+ return new Promise((resolve24) => {
20520
20710
  const saved = process.stdin.listeners("data");
20521
20711
  process.stdin.removeAllListeners("data");
20522
20712
  cliWrite(prompt);
@@ -20538,13 +20728,13 @@ async function askHidden(rl2, prompt) {
20538
20728
  if (ch === "\r" || ch === "\n") {
20539
20729
  cleanup();
20540
20730
  cliWrite("\n");
20541
- resolve23(buf);
20731
+ resolve24(buf);
20542
20732
  return;
20543
20733
  }
20544
20734
  if (ch === "") {
20545
20735
  cleanup();
20546
20736
  cliWrite("\n");
20547
- resolve23("");
20737
+ resolve24("");
20548
20738
  return;
20549
20739
  }
20550
20740
  if (ch === "\x7F" || ch === "\b") {
@@ -20733,7 +20923,7 @@ function updateSessionMetaFile(stateDir2, sessionId, patch) {
20733
20923
  // src/cli/debug.ts
20734
20924
  init_cjs_shims();
20735
20925
  var fs33 = __toESM(require("fs"), 1);
20736
- var os8 = __toESM(require("os"), 1);
20926
+ var os9 = __toESM(require("os"), 1);
20737
20927
  var path41 = __toESM(require("path"), 1);
20738
20928
  var LOG_NAME = "zqagent-debug.log";
20739
20929
  var TRUTHY = /^(1|true|yes|on)$/i;
@@ -20747,7 +20937,7 @@ function resolveLogFile() {
20747
20937
  const explicit = process.env.ZQAGENT_DEBUG_LOG;
20748
20938
  if (explicit) return path41.resolve(explicit);
20749
20939
  const dir = process.env.ZQAGENT_DEBUG_DIR;
20750
- return path41.join(dir ? path41.resolve(dir) : os8.tmpdir(), LOG_NAME);
20940
+ return path41.join(dir ? path41.resolve(dir) : os9.tmpdir(), LOG_NAME);
20751
20941
  }
20752
20942
  function enableDebug(argv = process.argv) {
20753
20943
  if (enabled) return true;
@@ -21205,7 +21395,7 @@ function question(prompt) {
21205
21395
  }
21206
21396
  function readPassword(prompt) {
21207
21397
  if (!process.stdin.isTTY) return question(prompt);
21208
- return new Promise((resolve23) => {
21398
+ return new Promise((resolve24) => {
21209
21399
  const savedDataListeners = process.stdin.listeners("data");
21210
21400
  process.stdin.removeAllListeners("data");
21211
21401
  cliWrite(prompt);
@@ -21221,13 +21411,13 @@ function readPassword(prompt) {
21221
21411
  if (ch === "\r" || ch === "\n") {
21222
21412
  cleanup();
21223
21413
  cliWrite("\n");
21224
- resolve23(buf);
21414
+ resolve24(buf);
21225
21415
  return;
21226
21416
  }
21227
21417
  if (ch === "") {
21228
21418
  cleanup();
21229
21419
  cliWrite("\n");
21230
- resolve23("");
21420
+ resolve24("");
21231
21421
  return;
21232
21422
  }
21233
21423
  if (ch === "\x7F" || ch === "\b") {
@@ -21662,7 +21852,7 @@ async function offerTerminalSetup(engine, canUseAgent) {
21662
21852
  }
21663
21853
  var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set(["link", "serve", "update"]);
21664
21854
  function cliVersion() {
21665
- const env3 = "0.2.8"?.trim();
21855
+ const env3 = "0.2.10"?.trim();
21666
21856
  if (env3) return env3;
21667
21857
  try {
21668
21858
  const req2 = (0, import_module.createRequire)(importMetaUrl);