@zqagent/core 0.2.12 → 0.2.15

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.
@@ -571,7 +571,7 @@ init_cjs_shims();
571
571
  var import_config = require("dotenv/config");
572
572
  var fs34 = __toESM(require("fs"), 1);
573
573
  var readline3 = __toESM(require("readline"), 1);
574
- var path42 = __toESM(require("path"), 1);
574
+ var path43 = __toESM(require("path"), 1);
575
575
  var import_child_process = require("child_process");
576
576
  var import_util = require("util");
577
577
 
@@ -1377,12 +1377,12 @@ var MUTATING_TOOLS = /* @__PURE__ */ new Set([
1377
1377
  ]);
1378
1378
  function parseReadFileSpan(content) {
1379
1379
  const body = content.replace(/^\[tool output truncated:[^\n]*\]\n\n/, "");
1380
- let path43;
1380
+ let path44;
1381
1381
  let start;
1382
1382
  let end;
1383
1383
  try {
1384
1384
  const obj = JSON.parse(body);
1385
- path43 = obj.path;
1385
+ path44 = obj.path;
1386
1386
  start = obj.start_line;
1387
1387
  end = obj.end_line;
1388
1388
  } catch {
@@ -1391,14 +1391,14 @@ function parseReadFileSpan(content) {
1391
1391
  const m = new RegExp(`"${key}"\\s*:\\s*(\\d+)`).exec(body);
1392
1392
  return m ? Number(m[1]) : void 0;
1393
1393
  };
1394
- path43 = str2("path");
1394
+ path44 = str2("path");
1395
1395
  start = num2("start_line");
1396
1396
  end = num2("end_line");
1397
1397
  }
1398
- if (typeof path43 !== "string" || !path43) return null;
1398
+ if (typeof path44 !== "string" || !path44) return null;
1399
1399
  if (typeof start !== "number" || typeof end !== "number") return null;
1400
1400
  if (!Number.isFinite(start) || !Number.isFinite(end)) return null;
1401
- return { path: path43, start, end };
1401
+ return { path: path44, start, end };
1402
1402
  }
1403
1403
  function addSpan(spans, start, end) {
1404
1404
  spans.push([start, end]);
@@ -3037,9 +3037,9 @@ var TurnEngine = class _TurnEngine {
3037
3037
  return;
3038
3038
  }
3039
3039
  if (result && typeof result === "object") {
3040
- const path43 = result.path;
3041
- if (path43) {
3042
- this._producedFiles.push(path43);
3040
+ const path44 = result.path;
3041
+ if (path44) {
3042
+ this._producedFiles.push(path44);
3043
3043
  return;
3044
3044
  }
3045
3045
  const changed = result.changed_files;
@@ -3741,10 +3741,10 @@ var OpenAIProvider = class {
3741
3741
  let timer;
3742
3742
  try {
3743
3743
  for (; ; ) {
3744
- const idle = new Promise((resolve24) => {
3744
+ const idle = new Promise((resolve25) => {
3745
3745
  timer = setTimeout(() => {
3746
3746
  onIdle();
3747
- resolve24({ timedOut: true });
3747
+ resolve25({ 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((resolve24) => {
6068
+ return new Promise((resolve25) => {
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
- resolve24({
6073
+ resolve25({
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
- resolve24({
6094
+ resolve25({
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
- resolve24(result);
6131
+ resolve25(result);
6132
6132
  };
6133
6133
  const killAndSettle = () => {
6134
6134
  killTree(child.pid);
@@ -8023,18 +8023,18 @@ function makeApplyPatch(workspace) {
8023
8023
  return { changed_files: changedFiles, added_files: addedFiles, deleted_files: deletedFiles, file_count: fileCount };
8024
8024
  };
8025
8025
  }
8026
- function applyPatchHunks(oldLines, chunks, path43) {
8026
+ function applyPatchHunks(oldLines, chunks, path44) {
8027
8027
  let newLines = [...oldLines];
8028
8028
  let cursor = 0;
8029
8029
  for (const chunk of chunks) {
8030
8030
  const oldBlock = chunk.filter((l) => l[0] === " " || l[0] === "-").map((l) => l.slice(1));
8031
8031
  const newBlock = chunk.filter((l) => l[0] === " " || l[0] === "+").map((l) => l.slice(1));
8032
8032
  if (!oldBlock.length) {
8033
- throw new Error(`\u8865\u4E01 hunk \u5FC5\u987B\u5305\u542B\u4E0A\u4E0B\u6587\u6216\u5220\u9664\u884C: ${path43}`);
8033
+ throw new Error(`\u8865\u4E01 hunk \u5FC5\u987B\u5305\u542B\u4E0A\u4E0B\u6587\u6216\u5220\u9664\u884C: ${path44}`);
8034
8034
  }
8035
8035
  const matchStart = findBlockMatch(newLines, oldBlock, cursor);
8036
8036
  if (matchStart === -1) {
8037
- throw new Error(`\u8865\u4E01\u4E0A\u4E0B\u6587\u4E0D\u5339\u914D: ${path43}`);
8037
+ throw new Error(`\u8865\u4E01\u4E0A\u4E0B\u6587\u4E0D\u5339\u914D: ${path44}`);
8038
8038
  }
8039
8039
  const matchEnd = matchStart + oldBlock.length;
8040
8040
  newLines.splice(matchStart, oldBlock.length, ...newBlock);
@@ -10250,8 +10250,8 @@ var InputRouter = class {
10250
10250
  }
10251
10251
  /** 询问一行:显示 prompt,返回该行内容 */
10252
10252
  ask(prompt) {
10253
- return new Promise((resolve24) => {
10254
- this.pendingAsks.push({ prompt, resolve: resolve24 });
10253
+ return new Promise((resolve25) => {
10254
+ this.pendingAsks.push({ prompt, resolve: resolve25 });
10255
10255
  this.pumpAsks();
10256
10256
  });
10257
10257
  }
@@ -10876,13 +10876,13 @@ var baseUrlResolver = null;
10876
10876
  function resolveBase(baseUrl) {
10877
10877
  return baseUrlResolver ? baseUrlResolver(baseUrl) : baseUrl;
10878
10878
  }
10879
- async function req(baseUrl, token, path43, init = {}) {
10879
+ async function req(baseUrl, token, path44, init = {}) {
10880
10880
  const headers = {
10881
10881
  ...init.body ? { "Content-Type": "application/json" } : {},
10882
10882
  ...init.headers ?? {}
10883
10883
  };
10884
10884
  if (token) headers.Authorization = `Bearer ${token}`;
10885
- const res = await fetch(`${resolveBase(baseUrl).replace(/\/$/, "")}${path43}`, {
10885
+ const res = await fetch(`${resolveBase(baseUrl).replace(/\/$/, "")}${path44}`, {
10886
10886
  ...init,
10887
10887
  headers
10888
10888
  });
@@ -10921,6 +10921,20 @@ async function hubEnrollByAccount(baseUrl, input) {
10921
10921
  });
10922
10922
  return { hubUrl: baseUrl.replace(/\/$/, ""), ...data };
10923
10923
  }
10924
+ async function hubUpdateNodeLabelSelf(baseUrl, fleetToken, input) {
10925
+ return await req(baseUrl, fleetToken, "/api/hub/nodes/self/label", {
10926
+ method: "POST",
10927
+ body: JSON.stringify(input)
10928
+ });
10929
+ }
10930
+
10931
+ // src/node-name.ts
10932
+ init_cjs_shims();
10933
+ var os4 = __toESM(require("os"), 1);
10934
+ function defaultNodeLabel() {
10935
+ const name = os4.hostname().trim();
10936
+ return name || "zqagent-node";
10937
+ }
10924
10938
 
10925
10939
  // src/cli/account-enroll.ts
10926
10940
  init_cjs_shims();
@@ -11764,11 +11778,11 @@ function isAffirmative(answer) {
11764
11778
  return /^(yes|approve|同意|批准|允许|确定|可以|好的|确认)/.test(a);
11765
11779
  }
11766
11780
  function defer() {
11767
- let resolve24;
11781
+ let resolve25;
11768
11782
  const promise = new Promise((r) => {
11769
- resolve24 = r;
11783
+ resolve25 = r;
11770
11784
  });
11771
- return { promise, resolve: resolve24 };
11785
+ return { promise, resolve: resolve25 };
11772
11786
  }
11773
11787
  var SessionManager = class {
11774
11788
  constructor(store, approvalTimeoutMs = APPROVAL_TIMEOUT_MS, opts = {}) {
@@ -12340,11 +12354,11 @@ data: ${JSON.stringify({ sessionId, seq: entry.seq, ts: entry.ts, data: entry.da
12340
12354
  status: "pending",
12341
12355
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
12342
12356
  };
12343
- const { promise, resolve: resolve24 } = defer();
12357
+ const { promise, resolve: resolve25 } = defer();
12344
12358
  const timer = setTimeout(() => {
12345
12359
  this._recycleApproval(rt, id);
12346
12360
  }, this.approvalTimeoutMs);
12347
- rt.pendingApprovals.set(id, { promise, resolve: resolve24, record, timer });
12361
+ rt.pendingApprovals.set(id, { promise, resolve: resolve25, record, timer });
12348
12362
  rt.approvals.set(id, record);
12349
12363
  this._setStatus(rt, "waiting_approval");
12350
12364
  this._persist(rt);
@@ -12422,11 +12436,11 @@ data: ${JSON.stringify({ sessionId, seq: entry.seq, ts: entry.ts, data: entry.da
12422
12436
  status: "pending",
12423
12437
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
12424
12438
  };
12425
- const { promise, resolve: resolve24 } = defer();
12439
+ const { promise, resolve: resolve25 } = defer();
12426
12440
  const timer = setTimeout(() => {
12427
12441
  this._recycleQuestion(rt, qid);
12428
12442
  }, this.approvalTimeoutMs);
12429
- rt.pendingQuestions.set(qid, { promise, resolve: resolve24, record, timer });
12443
+ rt.pendingQuestions.set(qid, { promise, resolve: resolve25, record, timer });
12430
12444
  rt.questions.set(qid, record);
12431
12445
  this._setStatus(rt, "waiting_question");
12432
12446
  this._persist(rt);
@@ -12735,7 +12749,7 @@ data: ${JSON.stringify(entry.data)}
12735
12749
  if (rt.mcpReady) {
12736
12750
  await Promise.race([
12737
12751
  rt.mcpReady,
12738
- new Promise((resolve24) => setTimeout(resolve24, 15e3))
12752
+ new Promise((resolve25) => setTimeout(resolve25, 15e3))
12739
12753
  ]).catch(() => void 0);
12740
12754
  }
12741
12755
  for await (const event of gen) {
@@ -13313,7 +13327,7 @@ function buildNodeInfo(store, opts) {
13313
13327
  nodeId: opts.nodeId ?? ensureNodeId(store),
13314
13328
  platform: process.platform,
13315
13329
  mode: process.env.NODE_MODE ?? "standalone",
13316
- version: "0.2.12",
13330
+ version: "0.2.15",
13317
13331
  admin: opts.admin,
13318
13332
  projects: opts.projects
13319
13333
  };
@@ -13451,22 +13465,24 @@ async function runWizard(rl2, store, opts) {
13451
13465
  const prompted = await promptLinkAccount(rl2, opts.hubUrl);
13452
13466
  if (!prompted) return;
13453
13467
  const nodeId = ensureNodeId(store);
13468
+ const label = opts.label?.trim() || defaultNodeLabel();
13454
13469
  const cred = await hubEnrollByAccount(prompted.hubUrl, {
13455
13470
  ...prompted.auth,
13456
13471
  nodeId,
13457
- label: opts.label
13472
+ label
13458
13473
  });
13459
13474
  store.saveFleetCredential({
13460
13475
  ...cred,
13461
- label: opts.label ?? cred.label,
13476
+ label,
13462
13477
  enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
13463
13478
  });
13479
+ store.saveNodeLabel(label);
13464
13480
  cliLog(`\u2705 \u5DF2\u63A5\u5165 Hub\uFF1A\u8282\u70B9 ${cred.nodeId}\uFF08\u7F51\u5173 ${cred.gatewayUrl ?? "\u672A\u4E0B\u53D1"}\uFF09`);
13465
13481
  cliLog(" \u51ED\u636E\u5DF2\u4FDD\u5B58\u5230 fleet.json\uFF0C\u672C\u6B21\u542F\u52A8\u5373\u8FDE\u63A5 Hub\u3002");
13466
13482
  }
13467
13483
  async function askHidden(rl2, prompt) {
13468
13484
  if (!process.stdin.isTTY) return (await rl2.question(prompt)).trim();
13469
- return new Promise((resolve24) => {
13485
+ return new Promise((resolve25) => {
13470
13486
  const saved = process.stdin.listeners("data");
13471
13487
  process.stdin.removeAllListeners("data");
13472
13488
  cliWrite(prompt);
@@ -13488,13 +13504,13 @@ async function askHidden(rl2, prompt) {
13488
13504
  if (ch === "\r" || ch === "\n") {
13489
13505
  cleanup();
13490
13506
  cliWrite("\n");
13491
- resolve24(buf);
13507
+ resolve25(buf);
13492
13508
  return;
13493
13509
  }
13494
13510
  if (ch === "") {
13495
13511
  cleanup();
13496
13512
  cliWrite("\n");
13497
- resolve24("");
13513
+ resolve25("");
13498
13514
  return;
13499
13515
  }
13500
13516
  if (ch === "\x7F" || ch === "\b") {
@@ -13516,18 +13532,18 @@ async function askHidden(rl2, prompt) {
13516
13532
  init_cjs_shims();
13517
13533
  var import_node_child_process5 = require("child_process");
13518
13534
  var fs21 = __toESM(require("fs"), 1);
13519
- var os5 = __toESM(require("os"), 1);
13535
+ var os6 = __toESM(require("os"), 1);
13520
13536
  var path26 = __toESM(require("path"), 1);
13521
13537
 
13522
13538
  // src/update/platform.ts
13523
13539
  init_cjs_shims();
13524
13540
  var fs20 = __toESM(require("fs"), 1);
13525
- var os4 = __toESM(require("os"), 1);
13541
+ var os5 = __toESM(require("os"), 1);
13526
13542
  var path25 = __toESM(require("path"), 1);
13527
13543
  var import_node_child_process4 = require("child_process");
13528
13544
  var import_node_module3 = require("module");
13529
13545
  function currentVersion() {
13530
- const injected = "0.2.12"?.trim();
13546
+ const injected = "0.2.15"?.trim();
13531
13547
  if (injected) return injected;
13532
13548
  try {
13533
13549
  const req2 = (0, import_node_module3.createRequire)(importMetaUrl);
@@ -13565,7 +13581,7 @@ function launchdPlistPath() {
13565
13581
  const label = launchdLabel();
13566
13582
  const uid = typeof process.getuid === "function" ? process.getuid() : -1;
13567
13583
  if (uid === 0) return `/Library/LaunchDaemons/${label}.plist`;
13568
- return path25.join(os4.homedir(), "Library", "LaunchAgents", `${label}.plist`);
13584
+ return path25.join(os5.homedir(), "Library", "LaunchAgents", `${label}.plist`);
13569
13585
  }
13570
13586
  function serviceManagerFromLaunchctl(output, pid, execPath, sea = true) {
13571
13587
  const pidMatch = /^\s*pid = (\d+)\s*$/m.exec(output);
@@ -13873,7 +13889,7 @@ function launchdServiceInstances() {
13873
13889
  const label = process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL2;
13874
13890
  const plists = [
13875
13891
  `/Library/LaunchDaemons/${label}.plist`,
13876
- path26.join(os5.homedir(), "Library", "LaunchAgents", `${label}.plist`)
13892
+ path26.join(os6.homedir(), "Library", "LaunchAgents", `${label}.plist`)
13877
13893
  ];
13878
13894
  const out = [];
13879
13895
  for (const plist of plists) {
@@ -13918,7 +13934,7 @@ function parseSystemdUnit(text) {
13918
13934
  function systemdServiceInstances() {
13919
13935
  if (process.platform !== "linux") return [];
13920
13936
  const unit = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME2;
13921
- const configHome = process.env.XDG_CONFIG_HOME?.trim() || path26.join(os5.homedir(), ".config");
13937
+ const configHome = process.env.XDG_CONFIG_HOME?.trim() || path26.join(os6.homedir(), ".config");
13922
13938
  const units = [
13923
13939
  `/etc/systemd/system/${unit}.service`,
13924
13940
  path26.join(configHome, "systemd", "user", `${unit}.service`)
@@ -14153,6 +14169,7 @@ async function linkNode(opts) {
14153
14169
  const targetedService = !explicitDataDir && Boolean(managedDir) && dataDir === managedDir;
14154
14170
  const store = new Store(dataDir);
14155
14171
  const nodeId = ensureNodeId2(store);
14172
+ const label = opts.label?.trim() || defaultNodeLabel();
14156
14173
  const account = opts.account;
14157
14174
  const cred = account && isCompleteAccount(account) ? await hubEnrollByAccount(hubUrl, {
14158
14175
  email: account.email,
@@ -14160,18 +14177,19 @@ async function linkNode(opts) {
14160
14177
  password: account.password,
14161
14178
  code: account.smsCode,
14162
14179
  nodeId,
14163
- label: opts.label
14180
+ label
14164
14181
  }) : await hubEnrollByCode(hubUrl, {
14165
14182
  code: opts.code,
14166
14183
  nodeId,
14167
- label: opts.label
14184
+ label
14168
14185
  });
14169
14186
  try {
14170
14187
  store.saveFleetCredential({
14171
14188
  ...cred,
14172
- label: opts.label ?? cred.label,
14189
+ label,
14173
14190
  enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
14174
14191
  });
14192
+ store.saveNodeLabel(label);
14175
14193
  } catch (e) {
14176
14194
  const err = e;
14177
14195
  if (err.code === "EACCES" || err.code === "EPERM") {
@@ -14233,7 +14251,7 @@ async function runLinkCommand(argv, ctx = {}) {
14233
14251
  return false;
14234
14252
  }
14235
14253
  const asPrompter = (rl2) => ({
14236
- question: (q) => new Promise((resolve24) => rl2.question(q, resolve24)),
14254
+ question: (q) => new Promise((resolve25) => rl2.question(q, resolve25)),
14237
14255
  pause: () => rl2.pause(),
14238
14256
  resume: () => rl2.resume()
14239
14257
  });
@@ -14328,18 +14346,178 @@ async function runLinkCommand(argv, ctx = {}) {
14328
14346
  }
14329
14347
  }
14330
14348
 
14349
+ // src/cli/rename.ts
14350
+ init_cjs_shims();
14351
+ var path28 = __toESM(require("path"), 1);
14352
+ function parseArgs(argv) {
14353
+ const out = {};
14354
+ for (let i = 0; i < argv.length; i++) {
14355
+ const a = argv[i];
14356
+ if (a === "--data-dir") {
14357
+ out.dataDir = argv[++i];
14358
+ } else if (a === "--host") {
14359
+ out.host = argv[++i];
14360
+ } else if (a === "--port") {
14361
+ out.port = Number(argv[++i]);
14362
+ } else if (a === "-h" || a === "--help") {
14363
+ out.help = true;
14364
+ } else if (!a.startsWith("-") && out.label === void 0) {
14365
+ out.label = a;
14366
+ }
14367
+ }
14368
+ return out;
14369
+ }
14370
+ function printRenameHelp() {
14371
+ cliLog("\u7528\u6CD5: zqagent rename <\u540D\u79F0> [--data-dir <dir>]");
14372
+ cliLog(" \u4FEE\u6539\u672C\u673A\u8282\u70B9\u5728 Hub \u663E\u793A\u7684\u540D\u79F0\u3002\u672C\u673A\u6709 server \u5728\u8DD1\u65F6\u70ED\u751F\u6548\uFF08\u514D\u91CD\u542F\uFF09\uFF0C");
14373
+ cliLog(" \u5426\u5219\u5199\u5165\u6570\u636E\u76EE\u5F55\uFF0C\u4E0B\u6B21\u542F\u52A8\u751F\u6548\uFF1B\u5DF2\u63A5\u5165 Hub \u65F6\u540C\u65F6\u66F4\u65B0 Hub \u7684\u8282\u70B9\u8BB0\u5F55\u3002");
14374
+ cliLog(" \u63A5\u5165\u65F6\u672A\u6307\u5B9A\u540D\u79F0\u7684\u8282\u70B9\u9ED8\u8BA4\u7528\u4E3B\u673A\u540D\uFF0C\u4E5F\u53EF\u5728 Hub \u754C\u9762\u76F4\u63A5\u6539\u540D\u3002");
14375
+ cliLog(" \u793A\u4F8B: zqagent rename ten004-dev");
14376
+ }
14377
+ async function probeServer2(host, port, adminKey) {
14378
+ const ctrl = new AbortController();
14379
+ const timer = setTimeout(() => ctrl.abort(), 1500);
14380
+ try {
14381
+ const res = await fetch(`http://${host}:${port}/api/v1/fleet/status`, {
14382
+ headers: { Authorization: `Bearer ${adminKey}` },
14383
+ signal: ctrl.signal
14384
+ });
14385
+ return res.ok;
14386
+ } catch {
14387
+ return false;
14388
+ } finally {
14389
+ clearTimeout(timer);
14390
+ }
14391
+ }
14392
+ async function renameViaServer(host, port, adminKey, label) {
14393
+ const res = await fetch(`http://${host}:${port}/api/v1/fleet/label`, {
14394
+ method: "POST",
14395
+ headers: {
14396
+ "Content-Type": "application/json",
14397
+ Authorization: `Bearer ${adminKey}`
14398
+ },
14399
+ body: JSON.stringify({ label })
14400
+ });
14401
+ const text = await res.text();
14402
+ let payload = null;
14403
+ try {
14404
+ payload = text ? JSON.parse(text) : null;
14405
+ } catch {
14406
+ }
14407
+ if (!res.ok) {
14408
+ throw new Error(payload?.error?.message ?? `HTTP ${res.status}`);
14409
+ }
14410
+ const data = payload?.data;
14411
+ return { hubSynced: Boolean(data?.hubSynced), hubError: data?.hubError };
14412
+ }
14413
+ async function runRenameCommand(argv) {
14414
+ const args = parseArgs(argv);
14415
+ if (args.help) {
14416
+ printRenameHelp();
14417
+ return true;
14418
+ }
14419
+ const label = (args.label ?? "").trim();
14420
+ if (!label) {
14421
+ cliErr("\u7F3A\u5C11\u65B0\u7684\u8282\u70B9\u540D\u79F0\u3002");
14422
+ printRenameHelp();
14423
+ return false;
14424
+ }
14425
+ const host = args.host?.trim() || process.env.HOST?.trim() || DEFAULT_SERVE_HOST;
14426
+ const port = args.port ?? Number(process.env.PORT ?? DEFAULT_SERVE_PORT);
14427
+ const explicitDataDir = args.dataDir?.trim() ? expandHome(args.dataDir.trim()) : void 0;
14428
+ const running = discoverRunningServeInstances();
14429
+ const candidates = explicitDataDir ? [
14430
+ running.find((r) => path28.resolve(r.dataDir) === path28.resolve(explicitDataDir)) ?? {
14431
+ dataDir: path28.resolve(explicitDataDir),
14432
+ host,
14433
+ port
14434
+ }
14435
+ ] : buildHotCandidates(void 0, running, { host, port });
14436
+ for (const inst of candidates) {
14437
+ const store2 = new Store(inst.dataDir);
14438
+ const adminKey = process.env.ADMIN_API_KEY ?? store2.loadAdminKey();
14439
+ if (!adminKey) continue;
14440
+ if (!await probeServer2(inst.host, inst.port, adminKey)) continue;
14441
+ try {
14442
+ const r = await renameViaServer(inst.host, inst.port, adminKey, label);
14443
+ cliLog(`\u2705 \u8282\u70B9\u540D\u79F0\u5DF2\u66F4\u65B0\u4E3A\u300C${label}\u300D\uFF08\u5DF2\u70ED\u751F\u6548\uFF0C\u65E0\u9700\u91CD\u542F\uFF09`);
14444
+ cliLog(` \u6570\u636E\u76EE\u5F55: ${inst.dataDir}`);
14445
+ if (r.hubSynced) {
14446
+ cliLog(" Hub \u8BB0\u5F55\u5DF2\u540C\u6B65\uFF0C\u5237\u65B0\u63A7\u5236\u53F0\u5373\u53EF\u770B\u5230\u65B0\u540D\u79F0\u3002");
14447
+ } else if (r.hubError) {
14448
+ cliLog(`\u26A0\uFE0F \u672C\u5730\u5DF2\u66F4\u65B0\uFF0C\u4F46\u540C\u6B65 Hub \u5931\u8D25\uFF1A${r.hubError}`);
14449
+ cliLog(" \u53EF\u7A0D\u540E\u91CD\u8BD5\u540C\u4E00\u547D\u4EE4\uFF0C\u6216\u76F4\u63A5\u5728 Hub \u754C\u9762\u6539\u540D\u3002");
14450
+ } else {
14451
+ cliLog(" \u672C\u673A\u672A\u63A5\u5165 Hub\uFF0CHub \u754C\u9762\u4E0D\u4F1A\u663E\u793A\u8BE5\u540D\u79F0\u3002");
14452
+ }
14453
+ return true;
14454
+ } catch (e) {
14455
+ const msg = e instanceof Error ? e.message : String(e);
14456
+ if (/未知路由|HTTP 404/.test(msg)) {
14457
+ cliLog("\u26A0\uFE0F \u8FD0\u884C\u4E2D\u7684\u8282\u70B9\u670D\u52A1\u7248\u672C\u8F83\u65E7\uFF0C\u6539\u540D\u6539\u4E3A\u76F4\u63A5\u5199\u5165\u6570\u636E\u76EE\u5F55\uFF0C\u91CD\u542F\u540E\u751F\u6548\u3002");
14458
+ break;
14459
+ }
14460
+ cliErr(`\u6539\u540D\u5931\u8D25: ${msg}`);
14461
+ return false;
14462
+ }
14463
+ }
14464
+ const dataDir = path28.resolve(
14465
+ explicitDataDir ?? running.find((r) => r.managed)?.dataDir ?? DEFAULT_DATA_DIR
14466
+ );
14467
+ const store = new Store(dataDir);
14468
+ try {
14469
+ store.saveNodeLabel(label);
14470
+ } catch (e) {
14471
+ const err = e;
14472
+ cliErr(
14473
+ `\u65E0\u6CD5\u5199\u5165\u6570\u636E\u76EE\u5F55 ${dataDir}\uFF08${err.code ?? "EACCES"}\uFF09\u3002\u82E5\u8282\u70B9\u7531\u7CFB\u7EDF\u670D\u52A1\u6258\u7BA1\uFF0C\u8BF7\u7528 sudo \u6267\u884C\uFF0C\u6216\u7528 --data-dir \u6307\u5B9A\u76EE\u5F55\u3002`
14474
+ );
14475
+ return false;
14476
+ }
14477
+ const cred = store.loadFleetCredential();
14478
+ if (!cred) {
14479
+ cliLog(`\u2705 \u8282\u70B9\u540D\u79F0\u5DF2\u4FDD\u5B58\u4E3A\u300C${label}\u300D\uFF08${dataDir}\uFF09`);
14480
+ cliLog(" \u672C\u673A\u672A\u63A5\u5165 Hub\uFF0C\u4E0B\u6B21\u542F\u52A8 serve \u540E\u751F\u6548\u3002");
14481
+ return true;
14482
+ }
14483
+ store.saveFleetCredential({ ...cred, label });
14484
+ let hubSynced = false;
14485
+ let hubError;
14486
+ if (cred.hubUrl && cred.fleetToken) {
14487
+ try {
14488
+ await hubUpdateNodeLabelSelf(cred.hubUrl, cred.fleetToken, {
14489
+ nodeId: cred.nodeId,
14490
+ label
14491
+ });
14492
+ hubSynced = true;
14493
+ } catch (e) {
14494
+ hubError = e instanceof Error ? e.message : String(e);
14495
+ }
14496
+ }
14497
+ cliLog(`\u2705 \u8282\u70B9\u540D\u79F0\u5DF2\u4FDD\u5B58\u4E3A\u300C${label}\u300D\uFF08${dataDir}\uFF0C\u4E0B\u6B21\u542F\u52A8 serve \u751F\u6548\uFF09`);
14498
+ if (hubSynced) {
14499
+ cliLog(" Hub \u8BB0\u5F55\u5DF2\u540C\u6B65\uFF0C\u5237\u65B0\u63A7\u5236\u53F0\u5373\u53EF\u770B\u5230\u65B0\u540D\u79F0\u3002");
14500
+ } else if (hubError) {
14501
+ cliLog(`\u26A0\uFE0F \u672C\u5730\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u540C\u6B65 Hub \u5931\u8D25\uFF1A${hubError}`);
14502
+ cliLog(" \u53EF\u7A0D\u540E\u91CD\u8BD5\u540C\u4E00\u547D\u4EE4\uFF0C\u6216\u76F4\u63A5\u5728 Hub \u754C\u9762\u6539\u540D\u3002");
14503
+ } else {
14504
+ cliLog(" \u8282\u70B9\u51ED\u636E\u4E0D\u5B8C\u6574\uFF08\u7F3A\u5C11 Hub \u5730\u5740\u6216\u4EE4\u724C\uFF09\uFF0CHub \u8BB0\u5F55\u672A\u66F4\u65B0\u3002");
14505
+ }
14506
+ return true;
14507
+ }
14508
+
14331
14509
  // src/cli/serve.ts
14332
14510
  init_cjs_shims();
14333
14511
 
14334
14512
  // src/server/runtime.ts
14335
14513
  init_cjs_shims();
14336
14514
  var fs31 = __toESM(require("fs"), 1);
14337
- var path38 = __toESM(require("path"), 1);
14515
+ var path39 = __toESM(require("path"), 1);
14338
14516
 
14339
14517
  // src/server/routes.ts
14340
14518
  init_cjs_shims();
14341
14519
  var import_http = require("http");
14342
- var path31 = __toESM(require("path"), 1);
14520
+ var path32 = __toESM(require("path"), 1);
14343
14521
 
14344
14522
  // src/server/auth.ts
14345
14523
  init_cjs_shims();
@@ -14419,8 +14597,8 @@ function hubProxyEnabled(host) {
14419
14597
  const h = (host ?? "127.0.0.1").trim();
14420
14598
  return h === "127.0.0.1" || h === "localhost" || h === "::1";
14421
14599
  }
14422
- function isHubProxyPath(path43) {
14423
- return path43.startsWith(HUB_PROXY_PREFIX);
14600
+ function isHubProxyPath(path44) {
14601
+ return path44.startsWith(HUB_PROXY_PREFIX);
14424
14602
  }
14425
14603
  function decodeTarget(enc) {
14426
14604
  try {
@@ -14515,14 +14693,14 @@ async function handleHubProxy(req2, res) {
14515
14693
  // src/server/fsBrowser.ts
14516
14694
  init_cjs_shims();
14517
14695
  var fs22 = __toESM(require("fs"), 1);
14518
- var os6 = __toESM(require("os"), 1);
14519
- var path28 = __toESM(require("path"), 1);
14696
+ var os7 = __toESM(require("os"), 1);
14697
+ var path29 = __toESM(require("path"), 1);
14520
14698
  var MAX_ENTRIES = 2e3;
14521
14699
  var DEFAULT_SEARCH_LIMIT = 200;
14522
14700
  var MAX_SEARCH_LIMIT = 1e3;
14523
14701
  function listDirs(input) {
14524
- const base = (input ?? "").trim() || os6.homedir();
14525
- const target = path28.resolve(base);
14702
+ const base = (input ?? "").trim() || os7.homedir();
14703
+ const target = path29.resolve(base);
14526
14704
  let st;
14527
14705
  try {
14528
14706
  st = fs22.statSync(target);
@@ -14537,7 +14715,7 @@ function listDirs(input) {
14537
14715
  throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09: ${target}`);
14538
14716
  }
14539
14717
  const entries = dirents.map((d) => {
14540
- const full = path28.join(target, d.name);
14718
+ const full = path29.join(target, d.name);
14541
14719
  let isDir = d.isDirectory();
14542
14720
  if (d.isSymbolicLink()) {
14543
14721
  try {
@@ -14550,7 +14728,7 @@ function listDirs(input) {
14550
14728
  entries.sort(
14551
14729
  (a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
14552
14730
  );
14553
- const parentDir = path28.dirname(target);
14731
+ const parentDir = path29.dirname(target);
14554
14732
  return {
14555
14733
  path: target,
14556
14734
  parent: parentDir !== target ? parentDir : null,
@@ -14581,7 +14759,7 @@ var NAME_CACHE_MAX_DIRS = 4;
14581
14759
  var NAME_CACHE_MAX_ENTRIES = 5e4;
14582
14760
  var nameCache = /* @__PURE__ */ new Map();
14583
14761
  function invalidateDirNames(target) {
14584
- nameCache.delete(path28.resolve(target));
14762
+ nameCache.delete(path29.resolve(target));
14585
14763
  }
14586
14764
  async function loadDirNames(target) {
14587
14765
  const now = Date.now();
@@ -14616,7 +14794,7 @@ async function loadDirNames(target) {
14616
14794
  return entries;
14617
14795
  }
14618
14796
  async function toDirEntry(dir, e) {
14619
- const full = path28.join(dir, e.name);
14797
+ const full = path29.join(dir, e.name);
14620
14798
  let isDir = e.isDir;
14621
14799
  if (e.isLink) {
14622
14800
  try {
@@ -14627,8 +14805,8 @@ async function toDirEntry(dir, e) {
14627
14805
  return { name: e.name, path: full, type: isDir ? "dir" : "file" };
14628
14806
  }
14629
14807
  async function searchDirs(input, query, limit) {
14630
- const base = (input ?? "").trim() || os6.homedir();
14631
- const target = path28.resolve(base);
14808
+ const base = (input ?? "").trim() || os7.homedir();
14809
+ const target = path29.resolve(base);
14632
14810
  let st;
14633
14811
  try {
14634
14812
  st = await fs22.promises.stat(target);
@@ -14661,7 +14839,7 @@ async function searchDirs(input, query, limit) {
14661
14839
  );
14662
14840
  const hit = scored.slice(0, max);
14663
14841
  const entries = await Promise.all(hit.map(({ entry }) => toDirEntry(target, entry)));
14664
- const parentDir = path28.dirname(target);
14842
+ const parentDir = path29.dirname(target);
14665
14843
  return {
14666
14844
  path: target,
14667
14845
  parent: parentDir !== target ? parentDir : null,
@@ -14672,13 +14850,13 @@ async function searchDirs(input, query, limit) {
14672
14850
  };
14673
14851
  }
14674
14852
  function makeDirIn(parentInput, name) {
14675
- const parent = path28.resolve((parentInput ?? "").trim() || os6.homedir());
14853
+ const parent = path29.resolve((parentInput ?? "").trim() || os7.homedir());
14676
14854
  const clean = (name ?? "").trim();
14677
14855
  if (!clean) throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u4E3A\u7A7A");
14678
14856
  if (clean === "." || clean === "..") throw new Error("\u76EE\u5F55\u540D\u975E\u6CD5");
14679
- const target = path28.resolve(parent, clean);
14680
- const rel = path28.relative(parent, target);
14681
- if (!rel || rel.startsWith("..") || path28.isAbsolute(rel)) {
14857
+ const target = path29.resolve(parent, clean);
14858
+ const rel = path29.relative(parent, target);
14859
+ if (!rel || rel.startsWith("..") || path29.isAbsolute(rel)) {
14682
14860
  throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u8D8A\u51FA\u5F53\u524D\u76EE\u5F55");
14683
14861
  }
14684
14862
  let st = null;
@@ -14694,25 +14872,25 @@ function makeDirIn(parentInput, name) {
14694
14872
  throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
14695
14873
  }
14696
14874
  invalidateDirNames(parent);
14697
- return { name: path28.basename(target), path: target, type: "dir" };
14875
+ return { name: path29.basename(target), path: target, type: "dir" };
14698
14876
  }
14699
14877
 
14700
14878
  // src/server/projectFiles.ts
14701
14879
  init_cjs_shims();
14702
14880
  var fs23 = __toESM(require("fs"), 1);
14703
- var path29 = __toESM(require("path"), 1);
14881
+ var path30 = __toESM(require("path"), 1);
14704
14882
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
14705
14883
  var MAX_DOWNLOAD_BYTES = 16 * 1024 * 1024;
14706
14884
  var MAX_ENTRIES2 = 2e3;
14707
14885
  function toPosix(p) {
14708
- return p.split(path29.sep).join("/");
14886
+ return p.split(path30.sep).join("/");
14709
14887
  }
14710
14888
  function projectRoot(workspaceRoot) {
14711
14889
  const r = (workspaceRoot ?? "").trim();
14712
14890
  if (!r) {
14713
14891
  throw new Error("\u9879\u76EE\u672A\u8BBE\u7F6E\u5DE5\u4F5C\u533A\u76EE\u5F55\uFF08workspaceRoot\uFF09\uFF0C\u65E0\u6CD5\u6D4F\u89C8\u6587\u4EF6");
14714
14892
  }
14715
- const abs = path29.resolve(r);
14893
+ const abs = path30.resolve(r);
14716
14894
  if (!fs23.existsSync(abs)) {
14717
14895
  throw new Error(`\u5DE5\u4F5C\u533A\u76EE\u5F55\u4E0D\u5B58\u5728: ${abs}`);
14718
14896
  }
@@ -14737,7 +14915,7 @@ function listProjectFiles(workspaceRoot, relPath) {
14737
14915
  try {
14738
14916
  st = fs23.statSync(dir);
14739
14917
  } catch {
14740
- throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(path29.relative(base, dir)) || "/"}`);
14918
+ throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(path30.relative(base, dir)) || "/"}`);
14741
14919
  }
14742
14920
  if (!st.isDirectory()) throw new Error("\u76EE\u6807\u4E0D\u662F\u76EE\u5F55");
14743
14921
  let dirents;
@@ -14747,7 +14925,7 @@ function listProjectFiles(workspaceRoot, relPath) {
14747
14925
  throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09");
14748
14926
  }
14749
14927
  const entries = dirents.map((d) => {
14750
- const full = path29.join(dir, d.name);
14928
+ const full = path30.join(dir, d.name);
14751
14929
  let isDir = d.isDirectory();
14752
14930
  if (d.isSymbolicLink()) {
14753
14931
  try {
@@ -14765,7 +14943,7 @@ function listProjectFiles(workspaceRoot, relPath) {
14765
14943
  }
14766
14944
  return {
14767
14945
  name: d.name,
14768
- path: toPosix(path29.relative(base, full)),
14946
+ path: toPosix(path30.relative(base, full)),
14769
14947
  type: isDir ? "dir" : "file",
14770
14948
  size,
14771
14949
  mtime
@@ -14774,12 +14952,12 @@ function listProjectFiles(workspaceRoot, relPath) {
14774
14952
  entries.sort(
14775
14953
  (a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
14776
14954
  );
14777
- const relDir = toPosix(path29.relative(base, dir));
14778
- const parentAbs = path29.dirname(dir);
14955
+ const relDir = toPosix(path30.relative(base, dir));
14956
+ const parentAbs = path30.dirname(dir);
14779
14957
  return {
14780
14958
  root: base,
14781
14959
  path: relDir,
14782
- parent: isWithinRoot(base, parentAbs) ? toPosix(path29.relative(base, parentAbs)) : null,
14960
+ parent: isWithinRoot(base, parentAbs) ? toPosix(path30.relative(base, parentAbs)) : null,
14783
14961
  entries: entries.slice(0, MAX_ENTRIES2)
14784
14962
  };
14785
14963
  }
@@ -14798,7 +14976,7 @@ function readProjectFile(workspaceRoot, relPath) {
14798
14976
  const truncated = buf.length > MAX_FILE_BYTES;
14799
14977
  const slice = truncated ? buf.subarray(0, MAX_FILE_BYTES) : buf;
14800
14978
  return {
14801
- path: toPosix(path29.relative(base, file)),
14979
+ path: toPosix(path30.relative(base, file)),
14802
14980
  size: st.size,
14803
14981
  binary,
14804
14982
  truncated,
@@ -14820,8 +14998,8 @@ function downloadProjectFile(workspaceRoot, relPath) {
14820
14998
  }
14821
14999
  const buf = fs23.readFileSync(file);
14822
15000
  return {
14823
- path: toPosix(path29.relative(base, file)),
14824
- name: path29.basename(file),
15001
+ path: toPosix(path30.relative(base, file)),
15002
+ name: path30.basename(file),
14825
15003
  size: buf.length,
14826
15004
  base64: buf.toString("base64")
14827
15005
  };
@@ -14843,12 +15021,12 @@ function writeProjectFile(workspaceRoot, relPath, content) {
14843
15021
  throw new Error("\u5185\u5BB9\u8D85\u8FC7 2MB \u4E0A\u9650\uFF0C\u65E0\u6CD5\u4FDD\u5B58");
14844
15022
  }
14845
15023
  try {
14846
- fs23.mkdirSync(path29.dirname(file), { recursive: true });
15024
+ fs23.mkdirSync(path30.dirname(file), { recursive: true });
14847
15025
  fs23.writeFileSync(file, buf);
14848
15026
  } catch (e) {
14849
15027
  throw new Error(`\u5199\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
14850
15028
  }
14851
- return { path: toPosix(path29.relative(base, file)), size: buf.length };
15029
+ return { path: toPosix(path30.relative(base, file)), size: buf.length };
14852
15030
  }
14853
15031
  function createProjectDir(workspaceRoot, relPath) {
14854
15032
  const base = projectRoot(workspaceRoot);
@@ -14860,7 +15038,7 @@ function createProjectDir(workspaceRoot, relPath) {
14860
15038
  } catch (e) {
14861
15039
  throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
14862
15040
  }
14863
- return { path: toPosix(path29.relative(base, dir)) };
15041
+ return { path: toPosix(path30.relative(base, dir)) };
14864
15042
  }
14865
15043
  function createProjectFile(workspaceRoot, relPath, content = "") {
14866
15044
  const base = projectRoot(workspaceRoot);
@@ -14870,12 +15048,12 @@ function createProjectFile(workspaceRoot, relPath, content = "") {
14870
15048
  if (fs23.existsSync(file)) throw new Error("\u6587\u4EF6\u5DF2\u5B58\u5728");
14871
15049
  const buf = Buffer.from(String(content ?? ""), "utf-8");
14872
15050
  try {
14873
- fs23.mkdirSync(path29.dirname(file), { recursive: true });
15051
+ fs23.mkdirSync(path30.dirname(file), { recursive: true });
14874
15052
  fs23.writeFileSync(file, buf);
14875
15053
  } catch (e) {
14876
15054
  throw new Error(`\u521B\u5EFA\u6587\u4EF6\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
14877
15055
  }
14878
- return { path: toPosix(path29.relative(base, file)), size: buf.length };
15056
+ return { path: toPosix(path30.relative(base, file)), size: buf.length };
14879
15057
  }
14880
15058
  function searchProjectFiles(workspaceRoot, query) {
14881
15059
  const base = projectRoot(workspaceRoot);
@@ -14909,7 +15087,7 @@ function searchProjectFiles(workspaceRoot, query) {
14909
15087
  let isDir = d.isDirectory();
14910
15088
  if (d.isSymbolicLink()) {
14911
15089
  try {
14912
- isDir = fs23.statSync(path29.join(dir, d.name)).isDirectory();
15090
+ isDir = fs23.statSync(path30.join(dir, d.name)).isDirectory();
14913
15091
  } catch {
14914
15092
  isDir = false;
14915
15093
  }
@@ -14917,7 +15095,7 @@ function searchProjectFiles(workspaceRoot, query) {
14917
15095
  if (d.name.toLowerCase().includes(q)) {
14918
15096
  out.push({ path: rel, type: isDir ? "dir" : "file" });
14919
15097
  }
14920
- if (isDir) walk(path29.join(dir, d.name), rel);
15098
+ if (isDir) walk(path30.join(dir, d.name), rel);
14921
15099
  }
14922
15100
  };
14923
15101
  walk(base, "");
@@ -14926,8 +15104,8 @@ function searchProjectFiles(workspaceRoot, query) {
14926
15104
 
14927
15105
  // src/server/projectOps.ts
14928
15106
  init_cjs_shims();
14929
- var os7 = __toESM(require("os"), 1);
14930
- var path30 = __toESM(require("path"), 1);
15107
+ var os8 = __toESM(require("os"), 1);
15108
+ var path31 = __toESM(require("path"), 1);
14931
15109
  var MAX_STDOUT2 = 2e4;
14932
15110
  var MAX_STDERR2 = 1e4;
14933
15111
  var MAX_BUFFER3 = 1024 * 1024 * 5;
@@ -14941,7 +15119,7 @@ function resolveInvocation2(spec, prepared) {
14941
15119
  }
14942
15120
  function workRoot(workspaceRoot) {
14943
15121
  const r = (workspaceRoot ?? "").trim();
14944
- return r ? path30.resolve(r) : os7.homedir();
15122
+ return r ? path31.resolve(r) : os8.homedir();
14945
15123
  }
14946
15124
  async function runProjectCommand(workspaceRoot, command, timeoutSeconds) {
14947
15125
  const cmd = String(command ?? "");
@@ -15253,7 +15431,7 @@ function projectStats(manager, tenantId) {
15253
15431
  // src/server/nodeHost.ts
15254
15432
  init_cjs_shims();
15255
15433
  var fs24 = __toESM(require("fs"), 1);
15256
- var os8 = __toESM(require("os"), 1);
15434
+ var os9 = __toESM(require("os"), 1);
15257
15435
  function diskInfo(pathStr) {
15258
15436
  try {
15259
15437
  const st = fs24.statfsSync(pathStr);
@@ -15268,7 +15446,7 @@ function diskInfo(pathStr) {
15268
15446
  }
15269
15447
  function networkInfo() {
15270
15448
  const out = [];
15271
- const ifaces = os8.networkInterfaces();
15449
+ const ifaces = os9.networkInterfaces();
15272
15450
  for (const [name, list] of Object.entries(ifaces)) {
15273
15451
  for (const info of list ?? []) {
15274
15452
  out.push({
@@ -15319,23 +15497,23 @@ function overview(store, manager) {
15319
15497
  return { projects, sessions: { total, running, waiting, items }, usage: { tokensIn, tokensOut } };
15320
15498
  }
15321
15499
  function buildNodeHost(store, manager, diskPath) {
15322
- const cpus2 = os8.cpus();
15500
+ const cpus2 = os9.cpus();
15323
15501
  const ov = overview(store, manager);
15324
15502
  return {
15325
15503
  nodeId: store.loadNodeId() ?? "",
15326
- hostname: os8.hostname(),
15504
+ hostname: os9.hostname(),
15327
15505
  platform: process.platform,
15328
15506
  arch: process.arch,
15329
- release: os8.release(),
15330
- uptimeSec: Math.round(os8.uptime()),
15331
- version: "0.2.12",
15507
+ release: os9.release(),
15508
+ uptimeSec: Math.round(os9.uptime()),
15509
+ version: "0.2.15",
15332
15510
  mode: process.env.NODE_MODE ?? "standalone",
15333
15511
  cpu: {
15334
15512
  count: cpus2.length,
15335
15513
  model: cpus2[0]?.model ?? "",
15336
- loadAvg: os8.loadavg().map((n) => Math.round(n * 100) / 100)
15514
+ loadAvg: os9.loadavg().map((n) => Math.round(n * 100) / 100)
15337
15515
  },
15338
- memory: { total: os8.totalmem(), free: os8.freemem() },
15516
+ memory: { total: os9.totalmem(), free: os9.freemem() },
15339
15517
  network: networkInfo(),
15340
15518
  disk: diskInfo(diskPath || process.cwd()),
15341
15519
  ...ov
@@ -15372,7 +15550,7 @@ function saveNotifications(tenant, secretBox, notifications) {
15372
15550
  var API_PREFIX = "/api/v1";
15373
15551
  var MAX_BODY_BYTES = 10 * 1024 * 1024;
15374
15552
  function readBody(req2) {
15375
- return new Promise((resolve24, reject) => {
15553
+ return new Promise((resolve25, reject) => {
15376
15554
  const chunks = [];
15377
15555
  let size = 0;
15378
15556
  req2.on("data", (c) => {
@@ -15385,9 +15563,9 @@ function readBody(req2) {
15385
15563
  chunks.push(c);
15386
15564
  });
15387
15565
  req2.on("end", () => {
15388
- if (chunks.length === 0) return resolve24(void 0);
15566
+ if (chunks.length === 0) return resolve25(void 0);
15389
15567
  try {
15390
- resolve24(JSON.parse(Buffer.concat(chunks).toString("utf-8")));
15568
+ resolve25(JSON.parse(Buffer.concat(chunks).toString("utf-8")));
15391
15569
  } catch {
15392
15570
  reject(new ApiError(400, "bad_request", "\u8BF7\u6C42\u4F53\u4E0D\u662F\u5408\u6CD5 JSON"));
15393
15571
  }
@@ -15698,6 +15876,24 @@ function createApp(store, manager, opts = {}) {
15698
15876
  ok(res, opts.fleet.status());
15699
15877
  }
15700
15878
  },
15879
+ // 修改本机节点显示名:写本地配置并立即上报;已接入 Hub 时同步 Hub 记录。
15880
+ // `zqagent rename` 在有 server 在跑时走这里(热生效,免重启)。
15881
+ {
15882
+ method: "POST",
15883
+ pattern: ["fleet", "label"],
15884
+ adminOnly: true,
15885
+ fn: async (_req, res, { body }) => {
15886
+ if (!opts.fleet) {
15887
+ throw new ApiError(503, "fleet_disabled", "\u8282\u70B9\u7BA1\u7406\u63A7\u5236\u5668\u672A\u542F\u7528");
15888
+ }
15889
+ const raw = body ?? {};
15890
+ const label = typeof raw.label === "string" ? raw.label.trim() : "";
15891
+ if (!label) {
15892
+ throw new ApiError(400, "bad_request", "label \u4E0D\u80FD\u4E3A\u7A7A");
15893
+ }
15894
+ ok(res, await opts.fleet.rename(label));
15895
+ }
15896
+ },
15701
15897
  // 运行时热接入:凭一次性注册码或 Hub 账号接入(落盘 fleet.json + 立即连接,免重启)
15702
15898
  {
15703
15899
  method: "POST",
@@ -15930,7 +16126,7 @@ function createApp(store, manager, opts = {}) {
15930
16126
  applyProvidersPatch(tenant, raw);
15931
16127
  if (typeof raw.workspaceRoot === "string") {
15932
16128
  const ws = raw.workspaceRoot.trim();
15933
- const next = ws ? path31.resolve(ws) : void 0;
16129
+ const next = ws ? path32.resolve(ws) : void 0;
15934
16130
  if (tenant.workspaceRoot) {
15935
16131
  if (next !== tenant.workspaceRoot) {
15936
16132
  throw new ApiError(
@@ -16891,10 +17087,10 @@ function createApp(store, manager, opts = {}) {
16891
17087
  function handle(req2, res) {
16892
17088
  const startedAt2 = Date.now();
16893
17089
  const url = new URL(req2.url ?? "/", "http://localhost");
16894
- const path43 = url.pathname;
17090
+ const path44 = url.pathname;
16895
17091
  const method = req2.method ?? "GET";
16896
17092
  console.log(
16897
- `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2192 ${method} ${path43}${url.search}`
17093
+ `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2192 ${method} ${path44}${url.search}`
16898
17094
  );
16899
17095
  let tenantId = null;
16900
17096
  let logged = false;
@@ -16902,7 +17098,7 @@ function createApp(store, manager, opts = {}) {
16902
17098
  if (logged) return;
16903
17099
  logged = true;
16904
17100
  console.log(
16905
- `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2190 ${method} ${path43} ${extra} (${Date.now() - startedAt2}ms) tenant=${tenantId ?? "-"}`
17101
+ `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2190 ${method} ${path44} ${extra} (${Date.now() - startedAt2}ms) tenant=${tenantId ?? "-"}`
16906
17102
  );
16907
17103
  };
16908
17104
  res.on("finish", () => logDone(`HTTP ${res.statusCode}`));
@@ -16913,16 +17109,16 @@ function createApp(store, manager, opts = {}) {
16913
17109
  res.end();
16914
17110
  return;
16915
17111
  }
16916
- if (req2.method === "GET" && path43 === "/healthz") {
17112
+ if (req2.method === "GET" && path44 === "/healthz") {
16917
17113
  json(res, 200, {
16918
17114
  status: "ok",
16919
17115
  // 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
16920
- version: "0.2.12",
17116
+ version: "0.2.15",
16921
17117
  features: { mcp: hasServerMcpConfig() }
16922
17118
  });
16923
17119
  return;
16924
17120
  }
16925
- if (hubProxyEnabled(opts.host) && isHubProxyPath(path43)) {
17121
+ if (hubProxyEnabled(opts.host) && isHubProxyPath(path44)) {
16926
17122
  void handleHubProxy(req2, res).catch(() => {
16927
17123
  if (!res.headersSent) {
16928
17124
  res.writeHead(502, { "Content-Type": "application/json; charset=utf-8" });
@@ -16933,11 +17129,11 @@ function createApp(store, manager, opts = {}) {
16933
17129
  });
16934
17130
  return;
16935
17131
  }
16936
- if (!path43.startsWith(API_PREFIX)) {
17132
+ if (!path44.startsWith(API_PREFIX)) {
16937
17133
  json(res, 404, { error: { code: "not_found", message: "\u672A\u77E5\u8DEF\u5F84" } });
16938
17134
  return;
16939
17135
  }
16940
- const segs = path43.slice(API_PREFIX.length).split("/").filter(Boolean);
17136
+ const segs = path44.slice(API_PREFIX.length).split("/").filter(Boolean);
16941
17137
  const apiKey = extractApiKey(req2);
16942
17138
  if (!apiKey) {
16943
17139
  json(res, 401, {
@@ -17002,7 +17198,7 @@ function createApp(store, manager, opts = {}) {
17002
17198
  ).catch((err) => {
17003
17199
  const msg = err instanceof Error ? err.message : String(err);
17004
17200
  console.log(
17005
- `[api] ${(/* @__PURE__ */ new Date()).toISOString()} ! ${method} ${path43} ERROR: ${msg}`
17201
+ `[api] ${(/* @__PURE__ */ new Date()).toISOString()} ! ${method} ${path44} ERROR: ${msg}`
17006
17202
  );
17007
17203
  error(res, err);
17008
17204
  });
@@ -17012,7 +17208,7 @@ function createApp(store, manager, opts = {}) {
17012
17208
 
17013
17209
  // src/server/fleet/FleetNodeBridge.ts
17014
17210
  init_cjs_shims();
17015
- var os9 = __toESM(require("os"), 1);
17211
+ var os10 = __toESM(require("os"), 1);
17016
17212
  var import_node_perf_hooks = require("perf_hooks");
17017
17213
 
17018
17214
  // src/server/fleet/FleetCommands.ts
@@ -17033,8 +17229,8 @@ async function cachedFetchModels(baseURL, apiKey) {
17033
17229
  try {
17034
17230
  result = await Promise.race([
17035
17231
  fetchModels(baseURL, apiKey),
17036
- new Promise((resolve24) => {
17037
- const t = setTimeout(() => resolve24(null), MODEL_FETCH_TIMEOUT_MS);
17232
+ new Promise((resolve25) => {
17233
+ const t = setTimeout(() => resolve25(null), MODEL_FETCH_TIMEOUT_MS);
17038
17234
  t.unref?.();
17039
17235
  })
17040
17236
  ]);
@@ -17059,8 +17255,8 @@ async function cachedFetchModelsEnriched(baseURL, apiKey, preferred) {
17059
17255
  if (!target) return r;
17060
17256
  const ctx = await Promise.race([
17061
17257
  fetchModelContext(baseURL, apiKey, target),
17062
- new Promise((resolve24) => {
17063
- const t = setTimeout(() => resolve24(void 0), MODEL_FETCH_TIMEOUT_MS);
17258
+ new Promise((resolve25) => {
17259
+ const t = setTimeout(() => resolve25(void 0), MODEL_FETCH_TIMEOUT_MS);
17064
17260
  t.unref?.();
17065
17261
  })
17066
17262
  ]);
@@ -18189,13 +18385,13 @@ var EVENT_FLUSH_MAX_EVENTS = 60;
18189
18385
  var EVENT_FLUSH_MAX_BYTES = 200 * 1024;
18190
18386
  var LOOP_LAG_WARN_MS = 2e3;
18191
18387
  function withTimeout(p, ms) {
18192
- return new Promise((resolve24, reject) => {
18388
+ return new Promise((resolve25, reject) => {
18193
18389
  const timer = setTimeout(() => reject(new Error(`\u5B50\u6307\u4EE4\u8D85\u65F6\uFF08${ms}ms\uFF09`)), ms);
18194
18390
  timer.unref?.();
18195
18391
  p.then(
18196
18392
  (v) => {
18197
18393
  clearTimeout(timer);
18198
- resolve24(v);
18394
+ resolve25(v);
18199
18395
  },
18200
18396
  (e) => {
18201
18397
  clearTimeout(timer);
@@ -18206,7 +18402,7 @@ function withTimeout(p, ms) {
18206
18402
  }
18207
18403
  function primaryIp() {
18208
18404
  let v6;
18209
- for (const infos of Object.values(os9.networkInterfaces())) {
18405
+ for (const infos of Object.values(os10.networkInterfaces())) {
18210
18406
  for (const info of infos ?? []) {
18211
18407
  if (info.internal) continue;
18212
18408
  if (info.family === "IPv4") return info.address;
@@ -18546,6 +18742,11 @@ var FleetNodeBridge = class {
18546
18742
  refreshInfo() {
18547
18743
  this._publishInfo();
18548
18744
  }
18745
+ /** 本地改名后把 status(含 label)与 info 立即重发,控制台不必等下一次周期上报 */
18746
+ republishLabel() {
18747
+ this._send({ kind: "status", status: this._status(this.isConnected()) });
18748
+ this._publishInfo();
18749
+ }
18549
18750
  // ===================== 内部 =====================
18550
18751
  _status(online) {
18551
18752
  return {
@@ -18555,7 +18756,7 @@ var FleetNodeBridge = class {
18555
18756
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
18556
18757
  platform: process.platform,
18557
18758
  mode: process.env.NODE_MODE ?? "standalone",
18558
- version: "0.2.12",
18759
+ version: "0.2.15",
18559
18760
  ip: primaryIp()
18560
18761
  };
18561
18762
  }
@@ -18574,7 +18775,23 @@ var FleetNodeBridge = class {
18574
18775
  byDay: days
18575
18776
  };
18576
18777
  }
18778
+ /**
18779
+ * 上报 info(项目/会话快照)。
18780
+ *
18781
+ * 失败必须留痕:这是控制台「项目列表」的唯一数据源,静默失败会表现为
18782
+ * 「这台节点永远没有任何项目」,且只能靠网关 detail=null 才发现。
18783
+ * 同时用 try 包住,避免一次读盘异常中断 `_onUp` 后续的状态通知。
18784
+ */
18577
18785
  _publishInfo() {
18786
+ try {
18787
+ this._publishInfoNow();
18788
+ } catch (e) {
18789
+ console.warn(
18790
+ `[fleet] \u8282\u70B9 ${this.nodeId} \u4E0A\u62A5 info \u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`
18791
+ );
18792
+ }
18793
+ }
18794
+ _publishInfoNow() {
18578
18795
  const totals = { projects: 0, sessions: 0, running: 0, waiting: 0 };
18579
18796
  const sessions = [];
18580
18797
  const projects = allProjectSummaries(this.opts.deps.store).map((p) => {
@@ -18601,7 +18818,15 @@ var FleetNodeBridge = class {
18601
18818
  totals.sessions += p.sessionCount;
18602
18819
  totals.running += running;
18603
18820
  totals.waiting += waiting;
18604
- return { id: p.id, name: p.name, sessionCount: p.sessionCount, running, waiting };
18821
+ return {
18822
+ id: p.id,
18823
+ name: p.name,
18824
+ sessionCount: p.sessionCount,
18825
+ running,
18826
+ waiting,
18827
+ // 控制台项目列表要展示工作目录(Hub 落盘快照后即可离线查看)
18828
+ workspaceRoot: p.workspaceRoot ?? null
18829
+ };
18605
18830
  });
18606
18831
  this._send({
18607
18832
  kind: "info",
@@ -18610,7 +18835,7 @@ var FleetNodeBridge = class {
18610
18835
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
18611
18836
  platform: process.platform,
18612
18837
  mode: process.env.NODE_MODE ?? "standalone",
18613
- version: "0.2.12",
18838
+ version: "0.2.15",
18614
18839
  ip: primaryIp(),
18615
18840
  projects,
18616
18841
  totals,
@@ -19358,7 +19583,7 @@ init_cjs_shims();
19358
19583
  // src/server/qq/bindings.ts
19359
19584
  init_cjs_shims();
19360
19585
  var fs25 = __toESM(require("fs"), 1);
19361
- var path32 = __toESM(require("path"), 1);
19586
+ var path33 = __toESM(require("path"), 1);
19362
19587
  function conversationKey(target) {
19363
19588
  switch (target.kind) {
19364
19589
  case "c2c":
@@ -19397,7 +19622,7 @@ var QqBindingsStore = class _QqBindingsStore {
19397
19622
  cache = null;
19398
19623
  /** 基于 DATA_DIR 构造 */
19399
19624
  static in(dataDir) {
19400
- return new _QqBindingsStore(path32.join(dataDir, "qq", "bindings.json"));
19625
+ return new _QqBindingsStore(path33.join(dataDir, "qq", "bindings.json"));
19401
19626
  }
19402
19627
  load() {
19403
19628
  if (this.cache) return this.cache;
@@ -19434,7 +19659,7 @@ var QqBindingsStore = class _QqBindingsStore {
19434
19659
  return null;
19435
19660
  }
19436
19661
  persist() {
19437
- fs25.mkdirSync(path32.dirname(this.file), { recursive: true });
19662
+ fs25.mkdirSync(path33.dirname(this.file), { recursive: true });
19438
19663
  fs25.writeFileSync(this.file, JSON.stringify(this.cache, null, 2), "utf-8");
19439
19664
  }
19440
19665
  };
@@ -19848,7 +20073,7 @@ ${lines.join("\n")}`, msgId);
19848
20073
  // src/server/qq/QqManager.ts
19849
20074
  init_cjs_shims();
19850
20075
  var fs26 = __toESM(require("fs"), 1);
19851
- var path33 = __toESM(require("path"), 1);
20076
+ var path34 = __toESM(require("path"), 1);
19852
20077
  var QqManager = class {
19853
20078
  constructor(opts) {
19854
20079
  this.opts = opts;
@@ -19857,7 +20082,7 @@ var QqManager = class {
19857
20082
  adapter = null;
19858
20083
  config = null;
19859
20084
  get configFile() {
19860
- return path33.join(this.opts.dataDir, "qq", "config.json");
20085
+ return path34.join(this.opts.dataDir, "qq", "config.json");
19861
20086
  }
19862
20087
  /** 启动:读配置(env 优先,其次文件),有则建连接 */
19863
20088
  start() {
@@ -19950,7 +20175,7 @@ var QqManager = class {
19950
20175
  return null;
19951
20176
  }
19952
20177
  _persistConfig(cfg) {
19953
- fs26.mkdirSync(path33.dirname(this.configFile), { recursive: true });
20178
+ fs26.mkdirSync(path34.dirname(this.configFile), { recursive: true });
19954
20179
  fs26.writeFileSync(this.configFile, JSON.stringify(cfg, null, 2), "utf-8");
19955
20180
  }
19956
20181
  };
@@ -20000,7 +20225,7 @@ var PairingCodeStore = class {
20000
20225
  // src/update/controller.ts
20001
20226
  init_cjs_shims();
20002
20227
  var fs30 = __toESM(require("fs"), 1);
20003
- var path37 = __toESM(require("path"), 1);
20228
+ var path38 = __toESM(require("path"), 1);
20004
20229
 
20005
20230
  // src/update/downloader.ts
20006
20231
  init_cjs_shims();
@@ -20009,7 +20234,7 @@ var fs27 = __toESM(require("fs"), 1);
20009
20234
  var import_node_stream2 = require("stream");
20010
20235
  var import_promises2 = require("stream/promises");
20011
20236
  var import_node_child_process6 = require("child_process");
20012
- var path34 = __toESM(require("path"), 1);
20237
+ var path35 = __toESM(require("path"), 1);
20013
20238
 
20014
20239
  // src/update/manifest.ts
20015
20240
  init_cjs_shims();
@@ -20186,7 +20411,7 @@ async function fetchManifest(url, publicKey, opts = {}) {
20186
20411
  async function downloadBinary(bin, destPath, log = () => {
20187
20412
  }) {
20188
20413
  const partPath = `${destPath}.part`;
20189
- fs27.mkdirSync(path34.dirname(destPath), { recursive: true });
20414
+ fs27.mkdirSync(path35.dirname(destPath), { recursive: true });
20190
20415
  fs27.rmSync(partPath, { force: true });
20191
20416
  let res;
20192
20417
  try {
@@ -20230,7 +20455,7 @@ async function downloadBinary(bin, destPath, log = () => {
20230
20455
  fs27.rmSync(destPath, { force: true });
20231
20456
  fs27.renameSync(partPath, destPath);
20232
20457
  fs27.chmodSync(destPath, 493);
20233
- log(`\u5DF2\u4E0B\u8F7D ${path34.basename(destPath)}\uFF08${Math.round(bytes / 1024 / 1024)}MB\uFF0C\u6821\u9A8C\u901A\u8FC7\uFF09`);
20458
+ log(`\u5DF2\u4E0B\u8F7D ${path35.basename(destPath)}\uFF08${Math.round(bytes / 1024 / 1024)}MB\uFF0C\u6821\u9A8C\u901A\u8FC7\uFF09`);
20234
20459
  return { bytes };
20235
20460
  }
20236
20461
  function selfCheck(binPath, expectedVersion) {
@@ -20255,17 +20480,17 @@ function selfCheck(binPath, expectedVersion) {
20255
20480
  // src/update/installer.ts
20256
20481
  init_cjs_shims();
20257
20482
  var fs29 = __toESM(require("fs"), 1);
20258
- var path36 = __toESM(require("path"), 1);
20483
+ var path37 = __toESM(require("path"), 1);
20259
20484
 
20260
20485
  // src/update/state.ts
20261
20486
  init_cjs_shims();
20262
20487
  var fs28 = __toESM(require("fs"), 1);
20263
- var path35 = __toESM(require("path"), 1);
20488
+ var path36 = __toESM(require("path"), 1);
20264
20489
  function updatesDir(dataDir) {
20265
- return path35.join(dataDir, "updates");
20490
+ return path36.join(dataDir, "updates");
20266
20491
  }
20267
20492
  function statePath(dataDir) {
20268
- return path35.join(updatesDir(dataDir), "state.json");
20493
+ return path36.join(updatesDir(dataDir), "state.json");
20269
20494
  }
20270
20495
  function loadState(dataDir) {
20271
20496
  try {
@@ -20292,12 +20517,12 @@ function patchState(dataDir, patch) {
20292
20517
 
20293
20518
  // src/update/installer.ts
20294
20519
  function backupDir(dataDir) {
20295
- return path36.join(updatesDir(dataDir), "backup");
20520
+ return path37.join(updatesDir(dataDir), "backup");
20296
20521
  }
20297
20522
  function backupCurrent(dataDir, execPath, version) {
20298
20523
  const dir = backupDir(dataDir);
20299
20524
  fs29.mkdirSync(dir, { recursive: true });
20300
- const target = path36.join(dir, `zqagent-${version}${process.platform === "win32" ? ".exe" : ""}`);
20525
+ const target = path37.join(dir, `zqagent-${version}${process.platform === "win32" ? ".exe" : ""}`);
20301
20526
  fs29.copyFileSync(execPath, target);
20302
20527
  fs29.chmodSync(target, 493);
20303
20528
  return target;
@@ -20329,7 +20554,7 @@ function installStaged(opts) {
20329
20554
  const from = currentVersion();
20330
20555
  log(`\u6B63\u5728\u5B89\u88C5 v${opts.version}\uFF08\u5F53\u524D v${from}\uFF09`);
20331
20556
  const backupPath = backupCurrent(opts.dataDir, opts.execPath, from);
20332
- log(`\u5DF2\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5230 ${path36.basename(backupPath)}`);
20557
+ log(`\u5DF2\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5230 ${path37.basename(backupPath)}`);
20333
20558
  replaceExecutable(opts.execPath, opts.stagedPath);
20334
20559
  return patchState(opts.dataDir, {
20335
20560
  stagedVersion: void 0,
@@ -20373,7 +20598,7 @@ function rollback(dataDir, execPath, log = () => {
20373
20598
  }
20374
20599
  function readRollbackTarget(dataDir) {
20375
20600
  try {
20376
- const raw = fs29.readFileSync(path36.join(updatesDir(dataDir), "state.json"), "utf-8");
20601
+ const raw = fs29.readFileSync(path37.join(updatesDir(dataDir), "state.json"), "utf-8");
20377
20602
  const s = JSON.parse(raw);
20378
20603
  if (s.backupPath && s.backupVersion) return s;
20379
20604
  } catch {
@@ -20550,7 +20775,7 @@ var UpdateController = class {
20550
20775
  if (!bin) return `\u6E05\u5355\u6CA1\u6709\u5F53\u524D\u5E73\u53F0\uFF08${platformKey()}\uFF09\u7684\u4EA7\u7269`;
20551
20776
  let stagedPath = state.stagedPath;
20552
20777
  if (!(state.stagedVersion === manifest.version && stagedPath && fs30.existsSync(stagedPath))) {
20553
- stagedPath = path37.join(
20778
+ stagedPath = path38.join(
20554
20779
  updatesDir(this.opts.dataDir),
20555
20780
  "staged",
20556
20781
  `zqagent-${manifest.version}${process.platform === "win32" ? ".exe" : ""}`
@@ -20617,11 +20842,11 @@ var UpdateController = class {
20617
20842
  const minUptime = num("ZQAGENT_UPDATE_MIN_UPTIME_MS", 10 * 60 * 1e3);
20618
20843
  const idleMs = num("ZQAGENT_UPDATE_IDLE_MS", 60 * 1e3);
20619
20844
  let idleSince = null;
20620
- return new Promise((resolve24) => {
20845
+ return new Promise((resolve25) => {
20621
20846
  const timer = setInterval(() => {
20622
20847
  if (this.stopped) {
20623
20848
  clearInterval(timer);
20624
- resolve24(false);
20849
+ resolve25(false);
20625
20850
  return;
20626
20851
  }
20627
20852
  if (Date.now() - this.startedAt < minUptime || !this.opts.isIdle()) {
@@ -20631,7 +20856,7 @@ var UpdateController = class {
20631
20856
  idleSince ??= Date.now();
20632
20857
  if (Date.now() - idleSince >= idleMs) {
20633
20858
  clearInterval(timer);
20634
- resolve24(true);
20859
+ resolve25(true);
20635
20860
  }
20636
20861
  }, 1e3);
20637
20862
  timer.unref();
@@ -20725,7 +20950,7 @@ function seedDemoTenant(store) {
20725
20950
  apiKey: env2("OPENAI_API_KEY"),
20726
20951
  baseURL: env2("OPENAI_BASE_URL")
20727
20952
  },
20728
- workspaceRoot: workspace ? path38.resolve(workspace) : void 0,
20953
+ workspaceRoot: workspace ? path39.resolve(workspace) : void 0,
20729
20954
  allowedCommands: []
20730
20955
  };
20731
20956
  store.saveTenant(demo);
@@ -20779,9 +21004,9 @@ function syncTenantModels(store) {
20779
21004
  tenant.model = model;
20780
21005
  changed = true;
20781
21006
  }
20782
- if (workspace && tenant.workspaceRoot !== path38.resolve(workspace)) {
20783
- console.log(`[sync] \u79DF\u6237 ${id} workspaceRoot \u5DF2\u540C\u6B65: ${tenant.workspaceRoot ?? "(\u6C99\u7BB1)"} \u2192 ${path38.resolve(workspace)}`);
20784
- tenant.workspaceRoot = path38.resolve(workspace);
21007
+ if (workspace && tenant.workspaceRoot !== path39.resolve(workspace)) {
21008
+ console.log(`[sync] \u79DF\u6237 ${id} workspaceRoot \u5DF2\u540C\u6B65: ${tenant.workspaceRoot ?? "(\u6C99\u7BB1)"} \u2192 ${path39.resolve(workspace)}`);
21009
+ tenant.workspaceRoot = path39.resolve(workspace);
20785
21010
  changed = true;
20786
21011
  }
20787
21012
  if (apiKey && tenant.provider.apiKey !== apiKey) {
@@ -20814,7 +21039,7 @@ function exitWhenOrphaned() {
20814
21039
  }
20815
21040
  var PORT_FALLBACK_LIMIT = 20;
20816
21041
  function listenWithPortFallback(server, startPort, host, dataDir, limit = PORT_FALLBACK_LIMIT) {
20817
- return new Promise((resolve24, reject) => {
21042
+ return new Promise((resolve25, reject) => {
20818
21043
  let attempts = 0;
20819
21044
  const tryListen = (port) => {
20820
21045
  server.removeAllListeners("listening");
@@ -20842,18 +21067,18 @@ function listenWithPortFallback(server, startPort, host, dataDir, limit = PORT_F
20842
21067
  }
20843
21068
  try {
20844
21069
  fs31.mkdirSync(dataDir, { recursive: true });
20845
- fs31.writeFileSync(path38.join(dataDir, "server-port"), `${actualPort}
21070
+ fs31.writeFileSync(path39.join(dataDir, "server-port"), `${actualPort}
20846
21071
  `);
20847
21072
  } catch {
20848
21073
  }
20849
- resolve24(actualPort);
21074
+ resolve25(actualPort);
20850
21075
  });
20851
21076
  };
20852
21077
  tryListen(startPort);
20853
21078
  });
20854
21079
  }
20855
21080
  function startServer(opts = {}) {
20856
- const dataDir = path38.resolve(opts.dataDir ?? env2("DATA_DIR") ?? DEFAULT_DATA_DIR);
21081
+ const dataDir = path39.resolve(opts.dataDir ?? env2("DATA_DIR") ?? DEFAULT_DATA_DIR);
20857
21082
  const port = opts.port ?? Number(env2("PORT") ?? 8787);
20858
21083
  const host = opts.host ?? env2("HOST") ?? "127.0.0.1";
20859
21084
  exitWhenOrphaned();
@@ -20883,7 +21108,7 @@ function startServer(opts = {}) {
20883
21108
  }
20884
21109
  const adminKey = ensureAdminKey();
20885
21110
  const secretKey = env2("SECRET_KEY");
20886
- const secretBox = secretKey ? SecretBox.fromHex(secretKey) : SecretBox.fromFile(path38.join(dataDir, "secret.key"));
21111
+ const secretBox = secretKey ? SecretBox.fromHex(secretKey) : SecretBox.fromFile(path39.join(dataDir, "secret.key"));
20887
21112
  if (secretKey && !secretBox) {
20888
21113
  console.warn("[crypto] SECRET_KEY \u975E\u6CD5\uFF08\u9700 64 \u4F4D hex\uFF09\uFF0C\u901A\u77E5\u51ED\u636E\u5C06\u9000\u5316\u4E3A\u660E\u6587");
20889
21114
  }
@@ -20924,7 +21149,7 @@ function startServer(opts = {}) {
20924
21149
  hubUrl: fleetCred?.hubUrl,
20925
21150
  gatewayUrl: fleetCred?.gatewayUrl ?? env2("FLEET_GATEWAY_URL"),
20926
21151
  online: fleet?.isConnected() ?? false,
20927
- label: fleetCred?.label,
21152
+ label: fleetCred?.label ?? store.loadNodeLabel() ?? void 0,
20928
21153
  lastError: fleet?.getLastError() ?? void 0,
20929
21154
  reconnectCount: fleet?.getErrorCount() ?? 0
20930
21155
  };
@@ -20933,27 +21158,53 @@ function startServer(opts = {}) {
20933
21158
  status: fleetStatus,
20934
21159
  async enroll(input) {
20935
21160
  const nodeId = ensureNodeId(store);
21161
+ const label = input.label?.trim() || defaultNodeLabel();
20936
21162
  const cred = input.account ? await hubEnrollByAccount(input.hubUrl, {
20937
21163
  email: input.account.email,
20938
21164
  phone: input.account.phone,
20939
21165
  password: input.account.password,
20940
21166
  code: input.account.smsCode,
20941
21167
  nodeId,
20942
- label: input.label
21168
+ label
20943
21169
  }) : await hubEnrollByCode(input.hubUrl, {
20944
21170
  code: input.code,
20945
21171
  nodeId,
20946
- label: input.label
21172
+ label
20947
21173
  });
20948
21174
  const full = {
20949
21175
  ...cred,
20950
- label: input.label ?? cred.label,
21176
+ label,
20951
21177
  enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
20952
21178
  };
20953
21179
  store.saveFleetCredential(full);
21180
+ store.saveNodeLabel(label);
20954
21181
  connectFleet(full);
20955
21182
  return fleetStatus();
20956
21183
  },
21184
+ async rename(label) {
21185
+ const name = label.trim();
21186
+ store.saveNodeLabel(name);
21187
+ if (fleetCred) {
21188
+ fleetCred = { ...fleetCred, label: name };
21189
+ store.saveFleetCredential(fleetCred);
21190
+ }
21191
+ fleet?.republishLabel();
21192
+ let hubSynced = false;
21193
+ let hubError;
21194
+ const cred = fleetCred;
21195
+ if (cred?.hubUrl && cred.fleetToken) {
21196
+ try {
21197
+ await hubUpdateNodeLabelSelf(cred.hubUrl, cred.fleetToken, {
21198
+ nodeId: ensureNodeId(store),
21199
+ label: name
21200
+ });
21201
+ hubSynced = true;
21202
+ } catch (e) {
21203
+ hubError = e instanceof Error ? e.message : String(e);
21204
+ }
21205
+ }
21206
+ return { ...fleetStatus(), hubSynced, hubError };
21207
+ },
20957
21208
  unlink() {
20958
21209
  fleet?.close();
20959
21210
  fleet = null;
@@ -21084,7 +21335,7 @@ function startServer(opts = {}) {
21084
21335
  server.timeout = 0;
21085
21336
  server.keepAliveTimeout = 65e3;
21086
21337
  server.headersTimeout = 66e3;
21087
- const ready = new Promise((resolve24, reject) => {
21338
+ const ready = new Promise((resolve25, reject) => {
21088
21339
  listenWithPortFallback(server, port, host, dataDir).then((actualPort) => {
21089
21340
  const info = {
21090
21341
  host,
@@ -21101,7 +21352,7 @@ function startServer(opts = {}) {
21101
21352
  printReady(info, qq);
21102
21353
  }
21103
21354
  updater?.start();
21104
- resolve24(info);
21355
+ resolve25(info);
21105
21356
  }, reject);
21106
21357
  });
21107
21358
  return {
@@ -21119,7 +21370,7 @@ function printReady(info, qq) {
21119
21370
  `zqagent server \u76D1\u542C http://${info.host}:${info.port}`,
21120
21371
  `\u6570\u636E\u76EE\u5F55: ${info.dataDir}`,
21121
21372
  `\u5BA1\u6279\u6302\u8D77\u8D85\u65F6: ${env2("APPROVAL_TIMEOUT_SECONDS") ?? 900}s\uFF08\u8D85\u65F6\u540E\u56DE\u6536\u5185\u5B58\u4EFB\u52A1\uFF0C\u53EF\u7ECF resume \u6062\u590D\uFF09`,
21122
- env2("ZQAGENT_LOG_ADMIN_KEY") === "0" ? `\u7BA1\u7406\u5458\u5BC6\u94A5: ${maskKey(info.adminKey)}\uFF08\u5DF2\u8131\u654F\uFF0C\u5B8C\u6574\u503C\u89C1 ${path38.join(info.dataDir, "admin.json")}\uFF09` : `\u7BA1\u7406\u5458\u5BC6\u94A5: ${info.adminKey}\uFF08\u63A7\u5236\u53F0\u591A\u9879\u76EE\u5165\u53E3\uFF1A/api/v1/projects\uFF1B\u9879\u76EE\u7EA7\u63A5\u53E3\u52A0 X-Project-Id \u5934\uFF09`
21373
+ env2("ZQAGENT_LOG_ADMIN_KEY") === "0" ? `\u7BA1\u7406\u5458\u5BC6\u94A5: ${maskKey(info.adminKey)}\uFF08\u5DF2\u8131\u654F\uFF0C\u5B8C\u6574\u503C\u89C1 ${path39.join(info.dataDir, "admin.json")}\uFF09` : `\u7BA1\u7406\u5458\u5BC6\u94A5: ${info.adminKey}\uFF08\u63A7\u5236\u53F0\u591A\u9879\u76EE\u5165\u53E3\uFF1A/api/v1/projects\uFF1B\u9879\u76EE\u7EA7\u63A5\u53E3\u52A0 X-Project-Id \u5934\uFF09`
21123
21374
  ];
21124
21375
  if (info.fleetNodeId) {
21125
21376
  lines.push(
@@ -21252,7 +21503,7 @@ async function runServeCommand(argv) {
21252
21503
 
21253
21504
  // src/cli/update.ts
21254
21505
  init_cjs_shims();
21255
- var path39 = __toESM(require("path"), 1);
21506
+ var path40 = __toESM(require("path"), 1);
21256
21507
  function parse3(argv) {
21257
21508
  const out = { status: false, check: false, now: false, rollback: false };
21258
21509
  for (let i = 0; i < argv.length; i++) {
@@ -21281,7 +21532,7 @@ function restartHint() {
21281
21532
  }
21282
21533
  async function runUpdateCommand(argv) {
21283
21534
  const args = parse3(argv);
21284
- const dataDir = path39.resolve(args.dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
21535
+ const dataDir = path40.resolve(args.dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
21285
21536
  const controller = new UpdateController({ dataDir, isIdle: () => true });
21286
21537
  if (args.rollback) {
21287
21538
  const restored = controller.rollbackNow();
@@ -21330,9 +21581,9 @@ async function runUpdateCommand(argv) {
21330
21581
  // src/cli/sessionMeta.ts
21331
21582
  init_cjs_shims();
21332
21583
  var fs32 = __toESM(require("fs"), 1);
21333
- var path40 = __toESM(require("path"), 1);
21584
+ var path41 = __toESM(require("path"), 1);
21334
21585
  function updateSessionMetaFile(stateDir2, sessionId, patch) {
21335
- const file = path40.join(stateDir2, `${sessionId}_state.json`);
21586
+ const file = path41.join(stateDir2, `${sessionId}_state.json`);
21336
21587
  try {
21337
21588
  const raw = fs32.readFileSync(file, "utf8");
21338
21589
  const state = JSON.parse(raw);
@@ -21349,8 +21600,8 @@ function updateSessionMetaFile(stateDir2, sessionId, patch) {
21349
21600
  // src/cli/debug.ts
21350
21601
  init_cjs_shims();
21351
21602
  var fs33 = __toESM(require("fs"), 1);
21352
- var os10 = __toESM(require("os"), 1);
21353
- var path41 = __toESM(require("path"), 1);
21603
+ var os11 = __toESM(require("os"), 1);
21604
+ var path42 = __toESM(require("path"), 1);
21354
21605
  var LOG_NAME = "zqagent-debug.log";
21355
21606
  var TRUTHY = /^(1|true|yes|on)$/i;
21356
21607
  function bootRef() {
@@ -21361,9 +21612,9 @@ var logFile = null;
21361
21612
  var startedAt = Date.now();
21362
21613
  function resolveLogFile() {
21363
21614
  const explicit = process.env.ZQAGENT_DEBUG_LOG;
21364
- if (explicit) return path41.resolve(explicit);
21615
+ if (explicit) return path42.resolve(explicit);
21365
21616
  const dir = process.env.ZQAGENT_DEBUG_DIR;
21366
- return path41.join(dir ? path41.resolve(dir) : os10.tmpdir(), LOG_NAME);
21617
+ return path42.join(dir ? path42.resolve(dir) : os11.tmpdir(), LOG_NAME);
21367
21618
  }
21368
21619
  function enableDebug(argv = process.argv) {
21369
21620
  if (enabled) return true;
@@ -21379,7 +21630,7 @@ function enableDebug(argv = process.argv) {
21379
21630
  enabled = true;
21380
21631
  logFile = resolveLogFile();
21381
21632
  try {
21382
- fs33.mkdirSync(path41.dirname(logFile), { recursive: true });
21633
+ fs33.mkdirSync(path42.dirname(logFile), { recursive: true });
21383
21634
  fs33.writeFileSync(logFile, "");
21384
21635
  } catch {
21385
21636
  logFile = null;
@@ -21557,7 +21808,7 @@ if (enableDebug(process.argv)) {
21557
21808
  logEnvironment();
21558
21809
  }
21559
21810
  var MODEL = process.env.OPENAI_MODEL ?? "gpt-4o";
21560
- var WORKSPACE = path42.resolve(process.env.WORKSPACE ?? ".");
21811
+ var WORKSPACE = path43.resolve(process.env.WORKSPACE ?? ".");
21561
21812
  var MAX_ITERATIONS = parseMaxIterations(process.env.MAX_ITERATIONS, 300);
21562
21813
  var STATE_DIR = stateDir();
21563
21814
  function listSessions() {
@@ -21568,7 +21819,7 @@ function listSessions() {
21568
21819
  if (!f.endsWith("_state.json")) continue;
21569
21820
  try {
21570
21821
  const parsed = JSON.parse(
21571
- fs34.readFileSync(path42.join(STATE_DIR, f), "utf8")
21822
+ fs34.readFileSync(path43.join(STATE_DIR, f), "utf8")
21572
21823
  );
21573
21824
  if (parsed && typeof parsed.sessionId === "string") {
21574
21825
  sessions.push(parsed);
@@ -21602,7 +21853,7 @@ function printLastAssistantMessage(messages) {
21602
21853
  out += renderer.flush();
21603
21854
  cliWrite(out + "\n");
21604
21855
  }
21605
- var AGENTS_FILE = path42.join(WORKSPACE, ".agent", "agents.json");
21856
+ var AGENTS_FILE = path43.join(WORKSPACE, ".agent", "agents.json");
21606
21857
  function loadAgentsFromFile() {
21607
21858
  try {
21608
21859
  if (!fs34.existsSync(AGENTS_FILE)) return [];
@@ -21618,7 +21869,7 @@ function loadAgentsFromFile() {
21618
21869
  }
21619
21870
  function saveAgentsToFile(defs) {
21620
21871
  try {
21621
- fs34.mkdirSync(path42.dirname(AGENTS_FILE), { recursive: true });
21872
+ fs34.mkdirSync(path43.dirname(AGENTS_FILE), { recursive: true });
21622
21873
  fs34.writeFileSync(AGENTS_FILE, JSON.stringify(defs, null, 2) + "\n", "utf8");
21623
21874
  } catch (err) {
21624
21875
  cliErr(`\u26A0\uFE0F \u4FDD\u5B58 agents \u914D\u7F6E\u5931\u8D25: ${err}`);
@@ -21628,8 +21879,8 @@ var agentRegistry = new AgentRegistry([
21628
21879
  ...BUILTIN_AGENTS,
21629
21880
  ...loadAgentsFromFile()
21630
21881
  ]);
21631
- var MCP_FILE = path42.join(WORKSPACE, ".agent", "mcp.json");
21632
- var COMMAND_TOOLS_FILE = path42.join(WORKSPACE, ".agent", "tools.json");
21882
+ var MCP_FILE = path43.join(WORKSPACE, ".agent", "mcp.json");
21883
+ var COMMAND_TOOLS_FILE = path43.join(WORKSPACE, ".agent", "tools.json");
21633
21884
  function loadJsonArray(file, validate) {
21634
21885
  try {
21635
21886
  if (!fs34.existsSync(file)) return [];
@@ -21643,7 +21894,7 @@ function loadJsonArray(file, validate) {
21643
21894
  }
21644
21895
  function saveJsonFile(file, data) {
21645
21896
  try {
21646
- fs34.mkdirSync(path42.dirname(file), { recursive: true });
21897
+ fs34.mkdirSync(path43.dirname(file), { recursive: true });
21647
21898
  fs34.writeFileSync(file, JSON.stringify(data, null, 2) + "\n", "utf8");
21648
21899
  } catch (err) {
21649
21900
  cliErr(`\u26A0\uFE0F \u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${err}`);
@@ -21716,7 +21967,7 @@ ${stderr}` : ""
21716
21967
  }
21717
21968
  }
21718
21969
  var mcpManager = null;
21719
- function parseArgs(argv) {
21970
+ function parseArgs2(argv) {
21720
21971
  const result = {};
21721
21972
  for (let i = 0; i < argv.length; i++) {
21722
21973
  if (argv[i] === "--resume" || argv[i] === "--r") {
@@ -21745,13 +21996,13 @@ function pruneEmptySessions(keepSessionId) {
21745
21996
  if (!isEmptySession(s) || s.sessionId === keepSessionId) continue;
21746
21997
  for (const suffix of ["_state.json", ".jsonl"]) {
21747
21998
  try {
21748
- fs34.unlinkSync(path42.join(STATE_DIR, `${s.sessionId}${suffix}`));
21999
+ fs34.unlinkSync(path43.join(STATE_DIR, `${s.sessionId}${suffix}`));
21749
22000
  } catch {
21750
22001
  }
21751
22002
  }
21752
22003
  }
21753
22004
  }
21754
- var cliArgs = parseArgs(process.argv.slice(2));
22005
+ var cliArgs = parseArgs2(process.argv.slice(2));
21755
22006
  var resumeId = cliArgs["resume"];
21756
22007
  var SESSION_ID = resolveInitialSessionId(resumeId);
21757
22008
  if (!resumeId) pruneEmptySessions(SESSION_ID);
@@ -21808,7 +22059,7 @@ function question(prompt) {
21808
22059
  }
21809
22060
  function readPassword(prompt) {
21810
22061
  if (!process.stdin.isTTY) return question(prompt);
21811
- return new Promise((resolve24) => {
22062
+ return new Promise((resolve25) => {
21812
22063
  const savedDataListeners = process.stdin.listeners("data");
21813
22064
  process.stdin.removeAllListeners("data");
21814
22065
  cliWrite(prompt);
@@ -21824,13 +22075,13 @@ function readPassword(prompt) {
21824
22075
  if (ch === "\r" || ch === "\n") {
21825
22076
  cleanup();
21826
22077
  cliWrite("\n");
21827
- resolve24(buf);
22078
+ resolve25(buf);
21828
22079
  return;
21829
22080
  }
21830
22081
  if (ch === "") {
21831
22082
  cleanup();
21832
22083
  cliWrite("\n");
21833
- resolve24("");
22084
+ resolve25("");
21834
22085
  return;
21835
22086
  }
21836
22087
  if (ch === "\x7F" || ch === "\b") {
@@ -22263,9 +22514,9 @@ async function offerTerminalSetup(engine, canUseAgent) {
22263
22514
  cliLog("");
22264
22515
  }
22265
22516
  }
22266
- var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set(["link", "serve", "update"]);
22517
+ var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set(["link", "serve", "update", "rename"]);
22267
22518
  function cliVersion() {
22268
- const env3 = "0.2.12"?.trim();
22519
+ const env3 = "0.2.15"?.trim();
22269
22520
  if (env3) return env3;
22270
22521
  try {
22271
22522
  const req2 = (0, import_module.createRequire)(importMetaUrl);
@@ -22286,6 +22537,7 @@ function printCliUsage() {
22286
22537
  cliLog(" zqagent link [--hub <url>] [--username <\u90AE\u7BB1/\u624B\u673A\u53F7> --password <\u5BC6\u7801>]");
22287
22538
  cliLog(" [--code <\u63A5\u5165\u7801>] [--label \u540D\u79F0]");
22288
22539
  cliLog(" \u628A\u672C\u673A\u8282\u70B9\u63A5\u5165 Hub\uFF08\u8D26\u53F7\u76F4\u8FDE\u6216\u63A5\u5165\u7801\uFF1B\u672C\u673A\u6709 server \u65F6\u70ED\u63A5\u5165\uFF09");
22540
+ cliLog(" zqagent rename <\u540D\u79F0> \u4FEE\u6539\u8282\u70B9\u5728 Hub \u663E\u793A\u7684\u540D\u79F0\uFF08\u672C\u673A\u4E0E Hub \u8BB0\u5F55\u4E00\u8D77\u66F4\u65B0\uFF09");
22289
22541
  cliLog("");
22290
22542
  cliLog("serve \u9009\u9879\uFF1A--port <n> --host <addr> --data-dir <dir>");
22291
22543
  cliLog(" --hub <url> --enroll-code <\u7801> --label <\u540D\u79F0> \uFF08\u542F\u52A8\u5373\u63A5\u5165\uFF09");
@@ -22313,6 +22565,11 @@ async function main() {
22313
22565
  rl.close();
22314
22566
  process.exit(ok2 ? 0 : 1);
22315
22567
  }
22568
+ if (subcommand === "rename") {
22569
+ const ok2 = await runRenameCommand(process.argv.slice(3));
22570
+ rl.close();
22571
+ process.exit(ok2 ? 0 : 1);
22572
+ }
22316
22573
  if (subcommand === "serve") {
22317
22574
  rl.close();
22318
22575
  await runServeCommand(process.argv.slice(3));
@@ -22474,7 +22731,7 @@ async function main() {
22474
22731
  }
22475
22732
  });
22476
22733
  const savedState = resumeId ? FileLogHook.loadState(resumeId, STATE_DIR) : null;
22477
- const metaStateFile = path42.join(STATE_DIR, `${SESSION_ID}_state.json`);
22734
+ const metaStateFile = path43.join(STATE_DIR, `${SESSION_ID}_state.json`);
22478
22735
  const stateForMeta = savedState ?? (fs34.existsSync(metaStateFile) ? FileLogHook.loadState(SESSION_ID, STATE_DIR) : null);
22479
22736
  sessionMeta = {
22480
22737
  sessionId: SESSION_ID,