@zqagent/core 0.2.12 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -554,7 +554,7 @@ init_esm_shims();
554
554
  import "dotenv/config";
555
555
  import * as fs34 from "fs";
556
556
  import * as readline3 from "readline";
557
- import * as path43 from "path";
557
+ import * as path44 from "path";
558
558
  import { exec } from "child_process";
559
559
  import { promisify } from "util";
560
560
 
@@ -1360,12 +1360,12 @@ var MUTATING_TOOLS = /* @__PURE__ */ new Set([
1360
1360
  ]);
1361
1361
  function parseReadFileSpan(content) {
1362
1362
  const body = content.replace(/^\[tool output truncated:[^\n]*\]\n\n/, "");
1363
- let path44;
1363
+ let path45;
1364
1364
  let start;
1365
1365
  let end;
1366
1366
  try {
1367
1367
  const obj = JSON.parse(body);
1368
- path44 = obj.path;
1368
+ path45 = obj.path;
1369
1369
  start = obj.start_line;
1370
1370
  end = obj.end_line;
1371
1371
  } catch {
@@ -1374,14 +1374,14 @@ function parseReadFileSpan(content) {
1374
1374
  const m = new RegExp(`"${key}"\\s*:\\s*(\\d+)`).exec(body);
1375
1375
  return m ? Number(m[1]) : void 0;
1376
1376
  };
1377
- path44 = str2("path");
1377
+ path45 = str2("path");
1378
1378
  start = num2("start_line");
1379
1379
  end = num2("end_line");
1380
1380
  }
1381
- if (typeof path44 !== "string" || !path44) return null;
1381
+ if (typeof path45 !== "string" || !path45) return null;
1382
1382
  if (typeof start !== "number" || typeof end !== "number") return null;
1383
1383
  if (!Number.isFinite(start) || !Number.isFinite(end)) return null;
1384
- return { path: path44, start, end };
1384
+ return { path: path45, start, end };
1385
1385
  }
1386
1386
  function addSpan(spans, start, end) {
1387
1387
  spans.push([start, end]);
@@ -3020,9 +3020,9 @@ var TurnEngine = class _TurnEngine {
3020
3020
  return;
3021
3021
  }
3022
3022
  if (result && typeof result === "object") {
3023
- const path44 = result.path;
3024
- if (path44) {
3025
- this._producedFiles.push(path44);
3023
+ const path45 = result.path;
3024
+ if (path45) {
3025
+ this._producedFiles.push(path45);
3026
3026
  return;
3027
3027
  }
3028
3028
  const changed = result.changed_files;
@@ -3724,10 +3724,10 @@ var OpenAIProvider = class {
3724
3724
  let timer;
3725
3725
  try {
3726
3726
  for (; ; ) {
3727
- const idle = new Promise((resolve24) => {
3727
+ const idle = new Promise((resolve25) => {
3728
3728
  timer = setTimeout(() => {
3729
3729
  onIdle();
3730
- resolve24({ timedOut: true });
3730
+ resolve25({ timedOut: true });
3731
3731
  }, idleMs);
3732
3732
  });
3733
3733
  const next = iter.next();
@@ -6048,12 +6048,12 @@ function makeSink(maxBuffer) {
6048
6048
  };
6049
6049
  }
6050
6050
  function execAsync(file, argv, opts = {}) {
6051
- return new Promise((resolve24) => {
6051
+ return new Promise((resolve25) => {
6052
6052
  const maxBuffer = opts.maxBuffer ?? DEFAULT_MAX_BUFFER;
6053
6053
  const out = makeSink(maxBuffer);
6054
6054
  const err = makeSink(maxBuffer);
6055
6055
  if (opts.signal?.aborted) {
6056
- resolve24({
6056
+ resolve25({
6057
6057
  status: null,
6058
6058
  stdout: Buffer.alloc(0),
6059
6059
  stderr: Buffer.alloc(0),
@@ -6074,7 +6074,7 @@ function execAsync(file, argv, opts = {}) {
6074
6074
  windowsHide: true
6075
6075
  });
6076
6076
  } catch (e) {
6077
- resolve24({
6077
+ resolve25({
6078
6078
  status: null,
6079
6079
  stdout: Buffer.alloc(0),
6080
6080
  stderr: Buffer.alloc(0),
@@ -6111,7 +6111,7 @@ function execAsync(file, argv, opts = {}) {
6111
6111
  };
6112
6112
  if (aborted) result.aborted = true;
6113
6113
  if (spawnError) result.error = spawnError;
6114
- resolve24(result);
6114
+ resolve25(result);
6115
6115
  };
6116
6116
  const killAndSettle = () => {
6117
6117
  killTree(child.pid);
@@ -8006,18 +8006,18 @@ function makeApplyPatch(workspace) {
8006
8006
  return { changed_files: changedFiles, added_files: addedFiles, deleted_files: deletedFiles, file_count: fileCount };
8007
8007
  };
8008
8008
  }
8009
- function applyPatchHunks(oldLines, chunks, path44) {
8009
+ function applyPatchHunks(oldLines, chunks, path45) {
8010
8010
  let newLines = [...oldLines];
8011
8011
  let cursor = 0;
8012
8012
  for (const chunk of chunks) {
8013
8013
  const oldBlock = chunk.filter((l) => l[0] === " " || l[0] === "-").map((l) => l.slice(1));
8014
8014
  const newBlock = chunk.filter((l) => l[0] === " " || l[0] === "+").map((l) => l.slice(1));
8015
8015
  if (!oldBlock.length) {
8016
- throw new Error(`\u8865\u4E01 hunk \u5FC5\u987B\u5305\u542B\u4E0A\u4E0B\u6587\u6216\u5220\u9664\u884C: ${path44}`);
8016
+ throw new Error(`\u8865\u4E01 hunk \u5FC5\u987B\u5305\u542B\u4E0A\u4E0B\u6587\u6216\u5220\u9664\u884C: ${path45}`);
8017
8017
  }
8018
8018
  const matchStart = findBlockMatch(newLines, oldBlock, cursor);
8019
8019
  if (matchStart === -1) {
8020
- throw new Error(`\u8865\u4E01\u4E0A\u4E0B\u6587\u4E0D\u5339\u914D: ${path44}`);
8020
+ throw new Error(`\u8865\u4E01\u4E0A\u4E0B\u6587\u4E0D\u5339\u914D: ${path45}`);
8021
8021
  }
8022
8022
  const matchEnd = matchStart + oldBlock.length;
8023
8023
  newLines.splice(matchStart, oldBlock.length, ...newBlock);
@@ -10233,8 +10233,8 @@ var InputRouter = class {
10233
10233
  }
10234
10234
  /** 询问一行:显示 prompt,返回该行内容 */
10235
10235
  ask(prompt) {
10236
- return new Promise((resolve24) => {
10237
- this.pendingAsks.push({ prompt, resolve: resolve24 });
10236
+ return new Promise((resolve25) => {
10237
+ this.pendingAsks.push({ prompt, resolve: resolve25 });
10238
10238
  this.pumpAsks();
10239
10239
  });
10240
10240
  }
@@ -10859,13 +10859,13 @@ var baseUrlResolver = null;
10859
10859
  function resolveBase(baseUrl) {
10860
10860
  return baseUrlResolver ? baseUrlResolver(baseUrl) : baseUrl;
10861
10861
  }
10862
- async function req(baseUrl, token, path44, init = {}) {
10862
+ async function req(baseUrl, token, path45, init = {}) {
10863
10863
  const headers = {
10864
10864
  ...init.body ? { "Content-Type": "application/json" } : {},
10865
10865
  ...init.headers ?? {}
10866
10866
  };
10867
10867
  if (token) headers.Authorization = `Bearer ${token}`;
10868
- const res = await fetch(`${resolveBase(baseUrl).replace(/\/$/, "")}${path44}`, {
10868
+ const res = await fetch(`${resolveBase(baseUrl).replace(/\/$/, "")}${path45}`, {
10869
10869
  ...init,
10870
10870
  headers
10871
10871
  });
@@ -10904,6 +10904,20 @@ async function hubEnrollByAccount(baseUrl, input) {
10904
10904
  });
10905
10905
  return { hubUrl: baseUrl.replace(/\/$/, ""), ...data };
10906
10906
  }
10907
+ async function hubUpdateNodeLabelSelf(baseUrl, fleetToken, input) {
10908
+ return await req(baseUrl, fleetToken, "/api/hub/nodes/self/label", {
10909
+ method: "POST",
10910
+ body: JSON.stringify(input)
10911
+ });
10912
+ }
10913
+
10914
+ // src/node-name.ts
10915
+ init_esm_shims();
10916
+ import * as os4 from "os";
10917
+ function defaultNodeLabel() {
10918
+ const name = os4.hostname().trim();
10919
+ return name || "zqagent-node";
10920
+ }
10907
10921
 
10908
10922
  // src/cli/account-enroll.ts
10909
10923
  init_esm_shims();
@@ -11747,11 +11761,11 @@ function isAffirmative(answer) {
11747
11761
  return /^(yes|approve|同意|批准|允许|确定|可以|好的|确认)/.test(a);
11748
11762
  }
11749
11763
  function defer() {
11750
- let resolve24;
11764
+ let resolve25;
11751
11765
  const promise = new Promise((r) => {
11752
- resolve24 = r;
11766
+ resolve25 = r;
11753
11767
  });
11754
- return { promise, resolve: resolve24 };
11768
+ return { promise, resolve: resolve25 };
11755
11769
  }
11756
11770
  var SessionManager = class {
11757
11771
  constructor(store, approvalTimeoutMs = APPROVAL_TIMEOUT_MS, opts = {}) {
@@ -12323,11 +12337,11 @@ data: ${JSON.stringify({ sessionId, seq: entry.seq, ts: entry.ts, data: entry.da
12323
12337
  status: "pending",
12324
12338
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
12325
12339
  };
12326
- const { promise, resolve: resolve24 } = defer();
12340
+ const { promise, resolve: resolve25 } = defer();
12327
12341
  const timer = setTimeout(() => {
12328
12342
  this._recycleApproval(rt, id);
12329
12343
  }, this.approvalTimeoutMs);
12330
- rt.pendingApprovals.set(id, { promise, resolve: resolve24, record, timer });
12344
+ rt.pendingApprovals.set(id, { promise, resolve: resolve25, record, timer });
12331
12345
  rt.approvals.set(id, record);
12332
12346
  this._setStatus(rt, "waiting_approval");
12333
12347
  this._persist(rt);
@@ -12405,11 +12419,11 @@ data: ${JSON.stringify({ sessionId, seq: entry.seq, ts: entry.ts, data: entry.da
12405
12419
  status: "pending",
12406
12420
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
12407
12421
  };
12408
- const { promise, resolve: resolve24 } = defer();
12422
+ const { promise, resolve: resolve25 } = defer();
12409
12423
  const timer = setTimeout(() => {
12410
12424
  this._recycleQuestion(rt, qid);
12411
12425
  }, this.approvalTimeoutMs);
12412
- rt.pendingQuestions.set(qid, { promise, resolve: resolve24, record, timer });
12426
+ rt.pendingQuestions.set(qid, { promise, resolve: resolve25, record, timer });
12413
12427
  rt.questions.set(qid, record);
12414
12428
  this._setStatus(rt, "waiting_question");
12415
12429
  this._persist(rt);
@@ -12718,7 +12732,7 @@ data: ${JSON.stringify(entry.data)}
12718
12732
  if (rt.mcpReady) {
12719
12733
  await Promise.race([
12720
12734
  rt.mcpReady,
12721
- new Promise((resolve24) => setTimeout(resolve24, 15e3))
12735
+ new Promise((resolve25) => setTimeout(resolve25, 15e3))
12722
12736
  ]).catch(() => void 0);
12723
12737
  }
12724
12738
  for await (const event of gen) {
@@ -13296,7 +13310,7 @@ function buildNodeInfo(store, opts) {
13296
13310
  nodeId: opts.nodeId ?? ensureNodeId(store),
13297
13311
  platform: process.platform,
13298
13312
  mode: process.env.NODE_MODE ?? "standalone",
13299
- version: "0.2.12",
13313
+ version: "0.2.14",
13300
13314
  admin: opts.admin,
13301
13315
  projects: opts.projects
13302
13316
  };
@@ -13434,22 +13448,24 @@ async function runWizard(rl2, store, opts) {
13434
13448
  const prompted = await promptLinkAccount(rl2, opts.hubUrl);
13435
13449
  if (!prompted) return;
13436
13450
  const nodeId = ensureNodeId(store);
13451
+ const label = opts.label?.trim() || defaultNodeLabel();
13437
13452
  const cred = await hubEnrollByAccount(prompted.hubUrl, {
13438
13453
  ...prompted.auth,
13439
13454
  nodeId,
13440
- label: opts.label
13455
+ label
13441
13456
  });
13442
13457
  store.saveFleetCredential({
13443
13458
  ...cred,
13444
- label: opts.label ?? cred.label,
13459
+ label,
13445
13460
  enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
13446
13461
  });
13462
+ store.saveNodeLabel(label);
13447
13463
  cliLog(`\u2705 \u5DF2\u63A5\u5165 Hub\uFF1A\u8282\u70B9 ${cred.nodeId}\uFF08\u7F51\u5173 ${cred.gatewayUrl ?? "\u672A\u4E0B\u53D1"}\uFF09`);
13448
13464
  cliLog(" \u51ED\u636E\u5DF2\u4FDD\u5B58\u5230 fleet.json\uFF0C\u672C\u6B21\u542F\u52A8\u5373\u8FDE\u63A5 Hub\u3002");
13449
13465
  }
13450
13466
  async function askHidden(rl2, prompt) {
13451
13467
  if (!process.stdin.isTTY) return (await rl2.question(prompt)).trim();
13452
- return new Promise((resolve24) => {
13468
+ return new Promise((resolve25) => {
13453
13469
  const saved = process.stdin.listeners("data");
13454
13470
  process.stdin.removeAllListeners("data");
13455
13471
  cliWrite(prompt);
@@ -13471,13 +13487,13 @@ async function askHidden(rl2, prompt) {
13471
13487
  if (ch === "\r" || ch === "\n") {
13472
13488
  cleanup();
13473
13489
  cliWrite("\n");
13474
- resolve24(buf);
13490
+ resolve25(buf);
13475
13491
  return;
13476
13492
  }
13477
13493
  if (ch === "") {
13478
13494
  cleanup();
13479
13495
  cliWrite("\n");
13480
- resolve24("");
13496
+ resolve25("");
13481
13497
  return;
13482
13498
  }
13483
13499
  if (ch === "\x7F" || ch === "\b") {
@@ -13499,18 +13515,18 @@ async function askHidden(rl2, prompt) {
13499
13515
  init_esm_shims();
13500
13516
  import { spawnSync as spawnSync3 } from "child_process";
13501
13517
  import * as fs21 from "fs";
13502
- import * as os5 from "os";
13518
+ import * as os6 from "os";
13503
13519
  import * as path27 from "path";
13504
13520
 
13505
13521
  // src/update/platform.ts
13506
13522
  init_esm_shims();
13507
13523
  import * as fs20 from "fs";
13508
- import * as os4 from "os";
13524
+ import * as os5 from "os";
13509
13525
  import * as path26 from "path";
13510
13526
  import { spawnSync as spawnSync2 } from "child_process";
13511
13527
  import { createRequire as createRequire3 } from "module";
13512
13528
  function currentVersion() {
13513
- const injected = "0.2.12"?.trim();
13529
+ const injected = "0.2.14"?.trim();
13514
13530
  if (injected) return injected;
13515
13531
  try {
13516
13532
  const req2 = createRequire3(import.meta.url);
@@ -13548,7 +13564,7 @@ function launchdPlistPath() {
13548
13564
  const label = launchdLabel();
13549
13565
  const uid = typeof process.getuid === "function" ? process.getuid() : -1;
13550
13566
  if (uid === 0) return `/Library/LaunchDaemons/${label}.plist`;
13551
- return path26.join(os4.homedir(), "Library", "LaunchAgents", `${label}.plist`);
13567
+ return path26.join(os5.homedir(), "Library", "LaunchAgents", `${label}.plist`);
13552
13568
  }
13553
13569
  function serviceManagerFromLaunchctl(output, pid, execPath, sea = true) {
13554
13570
  const pidMatch = /^\s*pid = (\d+)\s*$/m.exec(output);
@@ -13856,7 +13872,7 @@ function launchdServiceInstances() {
13856
13872
  const label = process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL2;
13857
13873
  const plists = [
13858
13874
  `/Library/LaunchDaemons/${label}.plist`,
13859
- path27.join(os5.homedir(), "Library", "LaunchAgents", `${label}.plist`)
13875
+ path27.join(os6.homedir(), "Library", "LaunchAgents", `${label}.plist`)
13860
13876
  ];
13861
13877
  const out = [];
13862
13878
  for (const plist of plists) {
@@ -13901,7 +13917,7 @@ function parseSystemdUnit(text) {
13901
13917
  function systemdServiceInstances() {
13902
13918
  if (process.platform !== "linux") return [];
13903
13919
  const unit = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME2;
13904
- const configHome = process.env.XDG_CONFIG_HOME?.trim() || path27.join(os5.homedir(), ".config");
13920
+ const configHome = process.env.XDG_CONFIG_HOME?.trim() || path27.join(os6.homedir(), ".config");
13905
13921
  const units = [
13906
13922
  `/etc/systemd/system/${unit}.service`,
13907
13923
  path27.join(configHome, "systemd", "user", `${unit}.service`)
@@ -14136,6 +14152,7 @@ async function linkNode(opts) {
14136
14152
  const targetedService = !explicitDataDir && Boolean(managedDir) && dataDir === managedDir;
14137
14153
  const store = new Store(dataDir);
14138
14154
  const nodeId = ensureNodeId2(store);
14155
+ const label = opts.label?.trim() || defaultNodeLabel();
14139
14156
  const account = opts.account;
14140
14157
  const cred = account && isCompleteAccount(account) ? await hubEnrollByAccount(hubUrl, {
14141
14158
  email: account.email,
@@ -14143,18 +14160,19 @@ async function linkNode(opts) {
14143
14160
  password: account.password,
14144
14161
  code: account.smsCode,
14145
14162
  nodeId,
14146
- label: opts.label
14163
+ label
14147
14164
  }) : await hubEnrollByCode(hubUrl, {
14148
14165
  code: opts.code,
14149
14166
  nodeId,
14150
- label: opts.label
14167
+ label
14151
14168
  });
14152
14169
  try {
14153
14170
  store.saveFleetCredential({
14154
14171
  ...cred,
14155
- label: opts.label ?? cred.label,
14172
+ label,
14156
14173
  enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
14157
14174
  });
14175
+ store.saveNodeLabel(label);
14158
14176
  } catch (e) {
14159
14177
  const err = e;
14160
14178
  if (err.code === "EACCES" || err.code === "EPERM") {
@@ -14216,7 +14234,7 @@ async function runLinkCommand(argv, ctx = {}) {
14216
14234
  return false;
14217
14235
  }
14218
14236
  const asPrompter = (rl2) => ({
14219
- question: (q) => new Promise((resolve24) => rl2.question(q, resolve24)),
14237
+ question: (q) => new Promise((resolve25) => rl2.question(q, resolve25)),
14220
14238
  pause: () => rl2.pause(),
14221
14239
  resume: () => rl2.resume()
14222
14240
  });
@@ -14311,18 +14329,178 @@ async function runLinkCommand(argv, ctx = {}) {
14311
14329
  }
14312
14330
  }
14313
14331
 
14332
+ // src/cli/rename.ts
14333
+ init_esm_shims();
14334
+ import * as path29 from "path";
14335
+ function parseArgs(argv) {
14336
+ const out = {};
14337
+ for (let i = 0; i < argv.length; i++) {
14338
+ const a = argv[i];
14339
+ if (a === "--data-dir") {
14340
+ out.dataDir = argv[++i];
14341
+ } else if (a === "--host") {
14342
+ out.host = argv[++i];
14343
+ } else if (a === "--port") {
14344
+ out.port = Number(argv[++i]);
14345
+ } else if (a === "-h" || a === "--help") {
14346
+ out.help = true;
14347
+ } else if (!a.startsWith("-") && out.label === void 0) {
14348
+ out.label = a;
14349
+ }
14350
+ }
14351
+ return out;
14352
+ }
14353
+ function printRenameHelp() {
14354
+ cliLog("\u7528\u6CD5: zqagent rename <\u540D\u79F0> [--data-dir <dir>]");
14355
+ 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");
14356
+ 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");
14357
+ 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");
14358
+ cliLog(" \u793A\u4F8B: zqagent rename ten004-dev");
14359
+ }
14360
+ async function probeServer2(host, port, adminKey) {
14361
+ const ctrl = new AbortController();
14362
+ const timer = setTimeout(() => ctrl.abort(), 1500);
14363
+ try {
14364
+ const res = await fetch(`http://${host}:${port}/api/v1/fleet/status`, {
14365
+ headers: { Authorization: `Bearer ${adminKey}` },
14366
+ signal: ctrl.signal
14367
+ });
14368
+ return res.ok;
14369
+ } catch {
14370
+ return false;
14371
+ } finally {
14372
+ clearTimeout(timer);
14373
+ }
14374
+ }
14375
+ async function renameViaServer(host, port, adminKey, label) {
14376
+ const res = await fetch(`http://${host}:${port}/api/v1/fleet/label`, {
14377
+ method: "POST",
14378
+ headers: {
14379
+ "Content-Type": "application/json",
14380
+ Authorization: `Bearer ${adminKey}`
14381
+ },
14382
+ body: JSON.stringify({ label })
14383
+ });
14384
+ const text = await res.text();
14385
+ let payload = null;
14386
+ try {
14387
+ payload = text ? JSON.parse(text) : null;
14388
+ } catch {
14389
+ }
14390
+ if (!res.ok) {
14391
+ throw new Error(payload?.error?.message ?? `HTTP ${res.status}`);
14392
+ }
14393
+ const data = payload?.data;
14394
+ return { hubSynced: Boolean(data?.hubSynced), hubError: data?.hubError };
14395
+ }
14396
+ async function runRenameCommand(argv) {
14397
+ const args = parseArgs(argv);
14398
+ if (args.help) {
14399
+ printRenameHelp();
14400
+ return true;
14401
+ }
14402
+ const label = (args.label ?? "").trim();
14403
+ if (!label) {
14404
+ cliErr("\u7F3A\u5C11\u65B0\u7684\u8282\u70B9\u540D\u79F0\u3002");
14405
+ printRenameHelp();
14406
+ return false;
14407
+ }
14408
+ const host = args.host?.trim() || process.env.HOST?.trim() || DEFAULT_SERVE_HOST;
14409
+ const port = args.port ?? Number(process.env.PORT ?? DEFAULT_SERVE_PORT);
14410
+ const explicitDataDir = args.dataDir?.trim() ? expandHome(args.dataDir.trim()) : void 0;
14411
+ const running = discoverRunningServeInstances();
14412
+ const candidates = explicitDataDir ? [
14413
+ running.find((r) => path29.resolve(r.dataDir) === path29.resolve(explicitDataDir)) ?? {
14414
+ dataDir: path29.resolve(explicitDataDir),
14415
+ host,
14416
+ port
14417
+ }
14418
+ ] : buildHotCandidates(void 0, running, { host, port });
14419
+ for (const inst of candidates) {
14420
+ const store2 = new Store(inst.dataDir);
14421
+ const adminKey = process.env.ADMIN_API_KEY ?? store2.loadAdminKey();
14422
+ if (!adminKey) continue;
14423
+ if (!await probeServer2(inst.host, inst.port, adminKey)) continue;
14424
+ try {
14425
+ const r = await renameViaServer(inst.host, inst.port, adminKey, label);
14426
+ cliLog(`\u2705 \u8282\u70B9\u540D\u79F0\u5DF2\u66F4\u65B0\u4E3A\u300C${label}\u300D\uFF08\u5DF2\u70ED\u751F\u6548\uFF0C\u65E0\u9700\u91CD\u542F\uFF09`);
14427
+ cliLog(` \u6570\u636E\u76EE\u5F55: ${inst.dataDir}`);
14428
+ if (r.hubSynced) {
14429
+ cliLog(" Hub \u8BB0\u5F55\u5DF2\u540C\u6B65\uFF0C\u5237\u65B0\u63A7\u5236\u53F0\u5373\u53EF\u770B\u5230\u65B0\u540D\u79F0\u3002");
14430
+ } else if (r.hubError) {
14431
+ cliLog(`\u26A0\uFE0F \u672C\u5730\u5DF2\u66F4\u65B0\uFF0C\u4F46\u540C\u6B65 Hub \u5931\u8D25\uFF1A${r.hubError}`);
14432
+ cliLog(" \u53EF\u7A0D\u540E\u91CD\u8BD5\u540C\u4E00\u547D\u4EE4\uFF0C\u6216\u76F4\u63A5\u5728 Hub \u754C\u9762\u6539\u540D\u3002");
14433
+ } else {
14434
+ cliLog(" \u672C\u673A\u672A\u63A5\u5165 Hub\uFF0CHub \u754C\u9762\u4E0D\u4F1A\u663E\u793A\u8BE5\u540D\u79F0\u3002");
14435
+ }
14436
+ return true;
14437
+ } catch (e) {
14438
+ const msg = e instanceof Error ? e.message : String(e);
14439
+ if (/未知路由|HTTP 404/.test(msg)) {
14440
+ 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");
14441
+ break;
14442
+ }
14443
+ cliErr(`\u6539\u540D\u5931\u8D25: ${msg}`);
14444
+ return false;
14445
+ }
14446
+ }
14447
+ const dataDir = path29.resolve(
14448
+ explicitDataDir ?? running.find((r) => r.managed)?.dataDir ?? DEFAULT_DATA_DIR
14449
+ );
14450
+ const store = new Store(dataDir);
14451
+ try {
14452
+ store.saveNodeLabel(label);
14453
+ } catch (e) {
14454
+ const err = e;
14455
+ cliErr(
14456
+ `\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`
14457
+ );
14458
+ return false;
14459
+ }
14460
+ const cred = store.loadFleetCredential();
14461
+ if (!cred) {
14462
+ cliLog(`\u2705 \u8282\u70B9\u540D\u79F0\u5DF2\u4FDD\u5B58\u4E3A\u300C${label}\u300D\uFF08${dataDir}\uFF09`);
14463
+ cliLog(" \u672C\u673A\u672A\u63A5\u5165 Hub\uFF0C\u4E0B\u6B21\u542F\u52A8 serve \u540E\u751F\u6548\u3002");
14464
+ return true;
14465
+ }
14466
+ store.saveFleetCredential({ ...cred, label });
14467
+ let hubSynced = false;
14468
+ let hubError;
14469
+ if (cred.hubUrl && cred.fleetToken) {
14470
+ try {
14471
+ await hubUpdateNodeLabelSelf(cred.hubUrl, cred.fleetToken, {
14472
+ nodeId: cred.nodeId,
14473
+ label
14474
+ });
14475
+ hubSynced = true;
14476
+ } catch (e) {
14477
+ hubError = e instanceof Error ? e.message : String(e);
14478
+ }
14479
+ }
14480
+ cliLog(`\u2705 \u8282\u70B9\u540D\u79F0\u5DF2\u4FDD\u5B58\u4E3A\u300C${label}\u300D\uFF08${dataDir}\uFF0C\u4E0B\u6B21\u542F\u52A8 serve \u751F\u6548\uFF09`);
14481
+ if (hubSynced) {
14482
+ cliLog(" Hub \u8BB0\u5F55\u5DF2\u540C\u6B65\uFF0C\u5237\u65B0\u63A7\u5236\u53F0\u5373\u53EF\u770B\u5230\u65B0\u540D\u79F0\u3002");
14483
+ } else if (hubError) {
14484
+ cliLog(`\u26A0\uFE0F \u672C\u5730\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u540C\u6B65 Hub \u5931\u8D25\uFF1A${hubError}`);
14485
+ cliLog(" \u53EF\u7A0D\u540E\u91CD\u8BD5\u540C\u4E00\u547D\u4EE4\uFF0C\u6216\u76F4\u63A5\u5728 Hub \u754C\u9762\u6539\u540D\u3002");
14486
+ } else {
14487
+ 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");
14488
+ }
14489
+ return true;
14490
+ }
14491
+
14314
14492
  // src/cli/serve.ts
14315
14493
  init_esm_shims();
14316
14494
 
14317
14495
  // src/server/runtime.ts
14318
14496
  init_esm_shims();
14319
14497
  import * as fs31 from "fs";
14320
- import * as path39 from "path";
14498
+ import * as path40 from "path";
14321
14499
 
14322
14500
  // src/server/routes.ts
14323
14501
  init_esm_shims();
14324
14502
  import { createServer } from "http";
14325
- import * as path32 from "path";
14503
+ import * as path33 from "path";
14326
14504
 
14327
14505
  // src/server/auth.ts
14328
14506
  init_esm_shims();
@@ -14402,8 +14580,8 @@ function hubProxyEnabled(host) {
14402
14580
  const h = (host ?? "127.0.0.1").trim();
14403
14581
  return h === "127.0.0.1" || h === "localhost" || h === "::1";
14404
14582
  }
14405
- function isHubProxyPath(path44) {
14406
- return path44.startsWith(HUB_PROXY_PREFIX);
14583
+ function isHubProxyPath(path45) {
14584
+ return path45.startsWith(HUB_PROXY_PREFIX);
14407
14585
  }
14408
14586
  function decodeTarget(enc) {
14409
14587
  try {
@@ -14498,14 +14676,14 @@ async function handleHubProxy(req2, res) {
14498
14676
  // src/server/fsBrowser.ts
14499
14677
  init_esm_shims();
14500
14678
  import * as fs22 from "fs";
14501
- import * as os6 from "os";
14502
- import * as path29 from "path";
14679
+ import * as os7 from "os";
14680
+ import * as path30 from "path";
14503
14681
  var MAX_ENTRIES = 2e3;
14504
14682
  var DEFAULT_SEARCH_LIMIT = 200;
14505
14683
  var MAX_SEARCH_LIMIT = 1e3;
14506
14684
  function listDirs(input) {
14507
- const base = (input ?? "").trim() || os6.homedir();
14508
- const target = path29.resolve(base);
14685
+ const base = (input ?? "").trim() || os7.homedir();
14686
+ const target = path30.resolve(base);
14509
14687
  let st;
14510
14688
  try {
14511
14689
  st = fs22.statSync(target);
@@ -14520,7 +14698,7 @@ function listDirs(input) {
14520
14698
  throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09: ${target}`);
14521
14699
  }
14522
14700
  const entries = dirents.map((d) => {
14523
- const full = path29.join(target, d.name);
14701
+ const full = path30.join(target, d.name);
14524
14702
  let isDir = d.isDirectory();
14525
14703
  if (d.isSymbolicLink()) {
14526
14704
  try {
@@ -14533,7 +14711,7 @@ function listDirs(input) {
14533
14711
  entries.sort(
14534
14712
  (a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
14535
14713
  );
14536
- const parentDir = path29.dirname(target);
14714
+ const parentDir = path30.dirname(target);
14537
14715
  return {
14538
14716
  path: target,
14539
14717
  parent: parentDir !== target ? parentDir : null,
@@ -14564,7 +14742,7 @@ var NAME_CACHE_MAX_DIRS = 4;
14564
14742
  var NAME_CACHE_MAX_ENTRIES = 5e4;
14565
14743
  var nameCache = /* @__PURE__ */ new Map();
14566
14744
  function invalidateDirNames(target) {
14567
- nameCache.delete(path29.resolve(target));
14745
+ nameCache.delete(path30.resolve(target));
14568
14746
  }
14569
14747
  async function loadDirNames(target) {
14570
14748
  const now = Date.now();
@@ -14599,7 +14777,7 @@ async function loadDirNames(target) {
14599
14777
  return entries;
14600
14778
  }
14601
14779
  async function toDirEntry(dir, e) {
14602
- const full = path29.join(dir, e.name);
14780
+ const full = path30.join(dir, e.name);
14603
14781
  let isDir = e.isDir;
14604
14782
  if (e.isLink) {
14605
14783
  try {
@@ -14610,8 +14788,8 @@ async function toDirEntry(dir, e) {
14610
14788
  return { name: e.name, path: full, type: isDir ? "dir" : "file" };
14611
14789
  }
14612
14790
  async function searchDirs(input, query, limit) {
14613
- const base = (input ?? "").trim() || os6.homedir();
14614
- const target = path29.resolve(base);
14791
+ const base = (input ?? "").trim() || os7.homedir();
14792
+ const target = path30.resolve(base);
14615
14793
  let st;
14616
14794
  try {
14617
14795
  st = await fs22.promises.stat(target);
@@ -14644,7 +14822,7 @@ async function searchDirs(input, query, limit) {
14644
14822
  );
14645
14823
  const hit = scored.slice(0, max);
14646
14824
  const entries = await Promise.all(hit.map(({ entry }) => toDirEntry(target, entry)));
14647
- const parentDir = path29.dirname(target);
14825
+ const parentDir = path30.dirname(target);
14648
14826
  return {
14649
14827
  path: target,
14650
14828
  parent: parentDir !== target ? parentDir : null,
@@ -14655,13 +14833,13 @@ async function searchDirs(input, query, limit) {
14655
14833
  };
14656
14834
  }
14657
14835
  function makeDirIn(parentInput, name) {
14658
- const parent = path29.resolve((parentInput ?? "").trim() || os6.homedir());
14836
+ const parent = path30.resolve((parentInput ?? "").trim() || os7.homedir());
14659
14837
  const clean = (name ?? "").trim();
14660
14838
  if (!clean) throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u4E3A\u7A7A");
14661
14839
  if (clean === "." || clean === "..") throw new Error("\u76EE\u5F55\u540D\u975E\u6CD5");
14662
- const target = path29.resolve(parent, clean);
14663
- const rel = path29.relative(parent, target);
14664
- if (!rel || rel.startsWith("..") || path29.isAbsolute(rel)) {
14840
+ const target = path30.resolve(parent, clean);
14841
+ const rel = path30.relative(parent, target);
14842
+ if (!rel || rel.startsWith("..") || path30.isAbsolute(rel)) {
14665
14843
  throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u8D8A\u51FA\u5F53\u524D\u76EE\u5F55");
14666
14844
  }
14667
14845
  let st = null;
@@ -14677,25 +14855,25 @@ function makeDirIn(parentInput, name) {
14677
14855
  throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
14678
14856
  }
14679
14857
  invalidateDirNames(parent);
14680
- return { name: path29.basename(target), path: target, type: "dir" };
14858
+ return { name: path30.basename(target), path: target, type: "dir" };
14681
14859
  }
14682
14860
 
14683
14861
  // src/server/projectFiles.ts
14684
14862
  init_esm_shims();
14685
14863
  import * as fs23 from "fs";
14686
- import * as path30 from "path";
14864
+ import * as path31 from "path";
14687
14865
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
14688
14866
  var MAX_DOWNLOAD_BYTES = 16 * 1024 * 1024;
14689
14867
  var MAX_ENTRIES2 = 2e3;
14690
14868
  function toPosix(p) {
14691
- return p.split(path30.sep).join("/");
14869
+ return p.split(path31.sep).join("/");
14692
14870
  }
14693
14871
  function projectRoot(workspaceRoot) {
14694
14872
  const r = (workspaceRoot ?? "").trim();
14695
14873
  if (!r) {
14696
14874
  throw new Error("\u9879\u76EE\u672A\u8BBE\u7F6E\u5DE5\u4F5C\u533A\u76EE\u5F55\uFF08workspaceRoot\uFF09\uFF0C\u65E0\u6CD5\u6D4F\u89C8\u6587\u4EF6");
14697
14875
  }
14698
- const abs = path30.resolve(r);
14876
+ const abs = path31.resolve(r);
14699
14877
  if (!fs23.existsSync(abs)) {
14700
14878
  throw new Error(`\u5DE5\u4F5C\u533A\u76EE\u5F55\u4E0D\u5B58\u5728: ${abs}`);
14701
14879
  }
@@ -14720,7 +14898,7 @@ function listProjectFiles(workspaceRoot, relPath) {
14720
14898
  try {
14721
14899
  st = fs23.statSync(dir);
14722
14900
  } catch {
14723
- throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(path30.relative(base, dir)) || "/"}`);
14901
+ throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(path31.relative(base, dir)) || "/"}`);
14724
14902
  }
14725
14903
  if (!st.isDirectory()) throw new Error("\u76EE\u6807\u4E0D\u662F\u76EE\u5F55");
14726
14904
  let dirents;
@@ -14730,7 +14908,7 @@ function listProjectFiles(workspaceRoot, relPath) {
14730
14908
  throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09");
14731
14909
  }
14732
14910
  const entries = dirents.map((d) => {
14733
- const full = path30.join(dir, d.name);
14911
+ const full = path31.join(dir, d.name);
14734
14912
  let isDir = d.isDirectory();
14735
14913
  if (d.isSymbolicLink()) {
14736
14914
  try {
@@ -14748,7 +14926,7 @@ function listProjectFiles(workspaceRoot, relPath) {
14748
14926
  }
14749
14927
  return {
14750
14928
  name: d.name,
14751
- path: toPosix(path30.relative(base, full)),
14929
+ path: toPosix(path31.relative(base, full)),
14752
14930
  type: isDir ? "dir" : "file",
14753
14931
  size,
14754
14932
  mtime
@@ -14757,12 +14935,12 @@ function listProjectFiles(workspaceRoot, relPath) {
14757
14935
  entries.sort(
14758
14936
  (a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
14759
14937
  );
14760
- const relDir = toPosix(path30.relative(base, dir));
14761
- const parentAbs = path30.dirname(dir);
14938
+ const relDir = toPosix(path31.relative(base, dir));
14939
+ const parentAbs = path31.dirname(dir);
14762
14940
  return {
14763
14941
  root: base,
14764
14942
  path: relDir,
14765
- parent: isWithinRoot(base, parentAbs) ? toPosix(path30.relative(base, parentAbs)) : null,
14943
+ parent: isWithinRoot(base, parentAbs) ? toPosix(path31.relative(base, parentAbs)) : null,
14766
14944
  entries: entries.slice(0, MAX_ENTRIES2)
14767
14945
  };
14768
14946
  }
@@ -14781,7 +14959,7 @@ function readProjectFile(workspaceRoot, relPath) {
14781
14959
  const truncated = buf.length > MAX_FILE_BYTES;
14782
14960
  const slice = truncated ? buf.subarray(0, MAX_FILE_BYTES) : buf;
14783
14961
  return {
14784
- path: toPosix(path30.relative(base, file)),
14962
+ path: toPosix(path31.relative(base, file)),
14785
14963
  size: st.size,
14786
14964
  binary,
14787
14965
  truncated,
@@ -14803,8 +14981,8 @@ function downloadProjectFile(workspaceRoot, relPath) {
14803
14981
  }
14804
14982
  const buf = fs23.readFileSync(file);
14805
14983
  return {
14806
- path: toPosix(path30.relative(base, file)),
14807
- name: path30.basename(file),
14984
+ path: toPosix(path31.relative(base, file)),
14985
+ name: path31.basename(file),
14808
14986
  size: buf.length,
14809
14987
  base64: buf.toString("base64")
14810
14988
  };
@@ -14826,12 +15004,12 @@ function writeProjectFile(workspaceRoot, relPath, content) {
14826
15004
  throw new Error("\u5185\u5BB9\u8D85\u8FC7 2MB \u4E0A\u9650\uFF0C\u65E0\u6CD5\u4FDD\u5B58");
14827
15005
  }
14828
15006
  try {
14829
- fs23.mkdirSync(path30.dirname(file), { recursive: true });
15007
+ fs23.mkdirSync(path31.dirname(file), { recursive: true });
14830
15008
  fs23.writeFileSync(file, buf);
14831
15009
  } catch (e) {
14832
15010
  throw new Error(`\u5199\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
14833
15011
  }
14834
- return { path: toPosix(path30.relative(base, file)), size: buf.length };
15012
+ return { path: toPosix(path31.relative(base, file)), size: buf.length };
14835
15013
  }
14836
15014
  function createProjectDir(workspaceRoot, relPath) {
14837
15015
  const base = projectRoot(workspaceRoot);
@@ -14843,7 +15021,7 @@ function createProjectDir(workspaceRoot, relPath) {
14843
15021
  } catch (e) {
14844
15022
  throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
14845
15023
  }
14846
- return { path: toPosix(path30.relative(base, dir)) };
15024
+ return { path: toPosix(path31.relative(base, dir)) };
14847
15025
  }
14848
15026
  function createProjectFile(workspaceRoot, relPath, content = "") {
14849
15027
  const base = projectRoot(workspaceRoot);
@@ -14853,12 +15031,12 @@ function createProjectFile(workspaceRoot, relPath, content = "") {
14853
15031
  if (fs23.existsSync(file)) throw new Error("\u6587\u4EF6\u5DF2\u5B58\u5728");
14854
15032
  const buf = Buffer.from(String(content ?? ""), "utf-8");
14855
15033
  try {
14856
- fs23.mkdirSync(path30.dirname(file), { recursive: true });
15034
+ fs23.mkdirSync(path31.dirname(file), { recursive: true });
14857
15035
  fs23.writeFileSync(file, buf);
14858
15036
  } catch (e) {
14859
15037
  throw new Error(`\u521B\u5EFA\u6587\u4EF6\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
14860
15038
  }
14861
- return { path: toPosix(path30.relative(base, file)), size: buf.length };
15039
+ return { path: toPosix(path31.relative(base, file)), size: buf.length };
14862
15040
  }
14863
15041
  function searchProjectFiles(workspaceRoot, query) {
14864
15042
  const base = projectRoot(workspaceRoot);
@@ -14892,7 +15070,7 @@ function searchProjectFiles(workspaceRoot, query) {
14892
15070
  let isDir = d.isDirectory();
14893
15071
  if (d.isSymbolicLink()) {
14894
15072
  try {
14895
- isDir = fs23.statSync(path30.join(dir, d.name)).isDirectory();
15073
+ isDir = fs23.statSync(path31.join(dir, d.name)).isDirectory();
14896
15074
  } catch {
14897
15075
  isDir = false;
14898
15076
  }
@@ -14900,7 +15078,7 @@ function searchProjectFiles(workspaceRoot, query) {
14900
15078
  if (d.name.toLowerCase().includes(q)) {
14901
15079
  out.push({ path: rel, type: isDir ? "dir" : "file" });
14902
15080
  }
14903
- if (isDir) walk(path30.join(dir, d.name), rel);
15081
+ if (isDir) walk(path31.join(dir, d.name), rel);
14904
15082
  }
14905
15083
  };
14906
15084
  walk(base, "");
@@ -14909,8 +15087,8 @@ function searchProjectFiles(workspaceRoot, query) {
14909
15087
 
14910
15088
  // src/server/projectOps.ts
14911
15089
  init_esm_shims();
14912
- import * as os7 from "os";
14913
- import * as path31 from "path";
15090
+ import * as os8 from "os";
15091
+ import * as path32 from "path";
14914
15092
  var MAX_STDOUT2 = 2e4;
14915
15093
  var MAX_STDERR2 = 1e4;
14916
15094
  var MAX_BUFFER3 = 1024 * 1024 * 5;
@@ -14924,7 +15102,7 @@ function resolveInvocation2(spec, prepared) {
14924
15102
  }
14925
15103
  function workRoot(workspaceRoot) {
14926
15104
  const r = (workspaceRoot ?? "").trim();
14927
- return r ? path31.resolve(r) : os7.homedir();
15105
+ return r ? path32.resolve(r) : os8.homedir();
14928
15106
  }
14929
15107
  async function runProjectCommand(workspaceRoot, command, timeoutSeconds) {
14930
15108
  const cmd = String(command ?? "");
@@ -15236,7 +15414,7 @@ function projectStats(manager, tenantId) {
15236
15414
  // src/server/nodeHost.ts
15237
15415
  init_esm_shims();
15238
15416
  import * as fs24 from "fs";
15239
- import * as os8 from "os";
15417
+ import * as os9 from "os";
15240
15418
  function diskInfo(pathStr) {
15241
15419
  try {
15242
15420
  const st = fs24.statfsSync(pathStr);
@@ -15251,7 +15429,7 @@ function diskInfo(pathStr) {
15251
15429
  }
15252
15430
  function networkInfo() {
15253
15431
  const out = [];
15254
- const ifaces = os8.networkInterfaces();
15432
+ const ifaces = os9.networkInterfaces();
15255
15433
  for (const [name, list] of Object.entries(ifaces)) {
15256
15434
  for (const info of list ?? []) {
15257
15435
  out.push({
@@ -15302,23 +15480,23 @@ function overview(store, manager) {
15302
15480
  return { projects, sessions: { total, running, waiting, items }, usage: { tokensIn, tokensOut } };
15303
15481
  }
15304
15482
  function buildNodeHost(store, manager, diskPath) {
15305
- const cpus2 = os8.cpus();
15483
+ const cpus2 = os9.cpus();
15306
15484
  const ov = overview(store, manager);
15307
15485
  return {
15308
15486
  nodeId: store.loadNodeId() ?? "",
15309
- hostname: os8.hostname(),
15487
+ hostname: os9.hostname(),
15310
15488
  platform: process.platform,
15311
15489
  arch: process.arch,
15312
- release: os8.release(),
15313
- uptimeSec: Math.round(os8.uptime()),
15314
- version: "0.2.12",
15490
+ release: os9.release(),
15491
+ uptimeSec: Math.round(os9.uptime()),
15492
+ version: "0.2.14",
15315
15493
  mode: process.env.NODE_MODE ?? "standalone",
15316
15494
  cpu: {
15317
15495
  count: cpus2.length,
15318
15496
  model: cpus2[0]?.model ?? "",
15319
- loadAvg: os8.loadavg().map((n) => Math.round(n * 100) / 100)
15497
+ loadAvg: os9.loadavg().map((n) => Math.round(n * 100) / 100)
15320
15498
  },
15321
- memory: { total: os8.totalmem(), free: os8.freemem() },
15499
+ memory: { total: os9.totalmem(), free: os9.freemem() },
15322
15500
  network: networkInfo(),
15323
15501
  disk: diskInfo(diskPath || process.cwd()),
15324
15502
  ...ov
@@ -15355,7 +15533,7 @@ function saveNotifications(tenant, secretBox, notifications) {
15355
15533
  var API_PREFIX = "/api/v1";
15356
15534
  var MAX_BODY_BYTES = 10 * 1024 * 1024;
15357
15535
  function readBody(req2) {
15358
- return new Promise((resolve24, reject) => {
15536
+ return new Promise((resolve25, reject) => {
15359
15537
  const chunks = [];
15360
15538
  let size = 0;
15361
15539
  req2.on("data", (c) => {
@@ -15368,9 +15546,9 @@ function readBody(req2) {
15368
15546
  chunks.push(c);
15369
15547
  });
15370
15548
  req2.on("end", () => {
15371
- if (chunks.length === 0) return resolve24(void 0);
15549
+ if (chunks.length === 0) return resolve25(void 0);
15372
15550
  try {
15373
- resolve24(JSON.parse(Buffer.concat(chunks).toString("utf-8")));
15551
+ resolve25(JSON.parse(Buffer.concat(chunks).toString("utf-8")));
15374
15552
  } catch {
15375
15553
  reject(new ApiError(400, "bad_request", "\u8BF7\u6C42\u4F53\u4E0D\u662F\u5408\u6CD5 JSON"));
15376
15554
  }
@@ -15681,6 +15859,24 @@ function createApp(store, manager, opts = {}) {
15681
15859
  ok(res, opts.fleet.status());
15682
15860
  }
15683
15861
  },
15862
+ // 修改本机节点显示名:写本地配置并立即上报;已接入 Hub 时同步 Hub 记录。
15863
+ // `zqagent rename` 在有 server 在跑时走这里(热生效,免重启)。
15864
+ {
15865
+ method: "POST",
15866
+ pattern: ["fleet", "label"],
15867
+ adminOnly: true,
15868
+ fn: async (_req, res, { body }) => {
15869
+ if (!opts.fleet) {
15870
+ throw new ApiError(503, "fleet_disabled", "\u8282\u70B9\u7BA1\u7406\u63A7\u5236\u5668\u672A\u542F\u7528");
15871
+ }
15872
+ const raw = body ?? {};
15873
+ const label = typeof raw.label === "string" ? raw.label.trim() : "";
15874
+ if (!label) {
15875
+ throw new ApiError(400, "bad_request", "label \u4E0D\u80FD\u4E3A\u7A7A");
15876
+ }
15877
+ ok(res, await opts.fleet.rename(label));
15878
+ }
15879
+ },
15684
15880
  // 运行时热接入:凭一次性注册码或 Hub 账号接入(落盘 fleet.json + 立即连接,免重启)
15685
15881
  {
15686
15882
  method: "POST",
@@ -15913,7 +16109,7 @@ function createApp(store, manager, opts = {}) {
15913
16109
  applyProvidersPatch(tenant, raw);
15914
16110
  if (typeof raw.workspaceRoot === "string") {
15915
16111
  const ws = raw.workspaceRoot.trim();
15916
- const next = ws ? path32.resolve(ws) : void 0;
16112
+ const next = ws ? path33.resolve(ws) : void 0;
15917
16113
  if (tenant.workspaceRoot) {
15918
16114
  if (next !== tenant.workspaceRoot) {
15919
16115
  throw new ApiError(
@@ -16874,10 +17070,10 @@ function createApp(store, manager, opts = {}) {
16874
17070
  function handle(req2, res) {
16875
17071
  const startedAt2 = Date.now();
16876
17072
  const url = new URL(req2.url ?? "/", "http://localhost");
16877
- const path44 = url.pathname;
17073
+ const path45 = url.pathname;
16878
17074
  const method = req2.method ?? "GET";
16879
17075
  console.log(
16880
- `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2192 ${method} ${path44}${url.search}`
17076
+ `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2192 ${method} ${path45}${url.search}`
16881
17077
  );
16882
17078
  let tenantId = null;
16883
17079
  let logged = false;
@@ -16885,7 +17081,7 @@ function createApp(store, manager, opts = {}) {
16885
17081
  if (logged) return;
16886
17082
  logged = true;
16887
17083
  console.log(
16888
- `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2190 ${method} ${path44} ${extra} (${Date.now() - startedAt2}ms) tenant=${tenantId ?? "-"}`
17084
+ `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2190 ${method} ${path45} ${extra} (${Date.now() - startedAt2}ms) tenant=${tenantId ?? "-"}`
16889
17085
  );
16890
17086
  };
16891
17087
  res.on("finish", () => logDone(`HTTP ${res.statusCode}`));
@@ -16896,16 +17092,16 @@ function createApp(store, manager, opts = {}) {
16896
17092
  res.end();
16897
17093
  return;
16898
17094
  }
16899
- if (req2.method === "GET" && path44 === "/healthz") {
17095
+ if (req2.method === "GET" && path45 === "/healthz") {
16900
17096
  json(res, 200, {
16901
17097
  status: "ok",
16902
17098
  // 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
16903
- version: "0.2.12",
17099
+ version: "0.2.14",
16904
17100
  features: { mcp: hasServerMcpConfig() }
16905
17101
  });
16906
17102
  return;
16907
17103
  }
16908
- if (hubProxyEnabled(opts.host) && isHubProxyPath(path44)) {
17104
+ if (hubProxyEnabled(opts.host) && isHubProxyPath(path45)) {
16909
17105
  void handleHubProxy(req2, res).catch(() => {
16910
17106
  if (!res.headersSent) {
16911
17107
  res.writeHead(502, { "Content-Type": "application/json; charset=utf-8" });
@@ -16916,11 +17112,11 @@ function createApp(store, manager, opts = {}) {
16916
17112
  });
16917
17113
  return;
16918
17114
  }
16919
- if (!path44.startsWith(API_PREFIX)) {
17115
+ if (!path45.startsWith(API_PREFIX)) {
16920
17116
  json(res, 404, { error: { code: "not_found", message: "\u672A\u77E5\u8DEF\u5F84" } });
16921
17117
  return;
16922
17118
  }
16923
- const segs = path44.slice(API_PREFIX.length).split("/").filter(Boolean);
17119
+ const segs = path45.slice(API_PREFIX.length).split("/").filter(Boolean);
16924
17120
  const apiKey = extractApiKey(req2);
16925
17121
  if (!apiKey) {
16926
17122
  json(res, 401, {
@@ -16985,7 +17181,7 @@ function createApp(store, manager, opts = {}) {
16985
17181
  ).catch((err) => {
16986
17182
  const msg = err instanceof Error ? err.message : String(err);
16987
17183
  console.log(
16988
- `[api] ${(/* @__PURE__ */ new Date()).toISOString()} ! ${method} ${path44} ERROR: ${msg}`
17184
+ `[api] ${(/* @__PURE__ */ new Date()).toISOString()} ! ${method} ${path45} ERROR: ${msg}`
16989
17185
  );
16990
17186
  error(res, err);
16991
17187
  });
@@ -16995,7 +17191,7 @@ function createApp(store, manager, opts = {}) {
16995
17191
 
16996
17192
  // src/server/fleet/FleetNodeBridge.ts
16997
17193
  init_esm_shims();
16998
- import * as os9 from "os";
17194
+ import * as os10 from "os";
16999
17195
  import { monitorEventLoopDelay } from "perf_hooks";
17000
17196
 
17001
17197
  // src/server/fleet/FleetCommands.ts
@@ -17016,8 +17212,8 @@ async function cachedFetchModels(baseURL, apiKey) {
17016
17212
  try {
17017
17213
  result = await Promise.race([
17018
17214
  fetchModels(baseURL, apiKey),
17019
- new Promise((resolve24) => {
17020
- const t = setTimeout(() => resolve24(null), MODEL_FETCH_TIMEOUT_MS);
17215
+ new Promise((resolve25) => {
17216
+ const t = setTimeout(() => resolve25(null), MODEL_FETCH_TIMEOUT_MS);
17021
17217
  t.unref?.();
17022
17218
  })
17023
17219
  ]);
@@ -17042,8 +17238,8 @@ async function cachedFetchModelsEnriched(baseURL, apiKey, preferred) {
17042
17238
  if (!target) return r;
17043
17239
  const ctx = await Promise.race([
17044
17240
  fetchModelContext(baseURL, apiKey, target),
17045
- new Promise((resolve24) => {
17046
- const t = setTimeout(() => resolve24(void 0), MODEL_FETCH_TIMEOUT_MS);
17241
+ new Promise((resolve25) => {
17242
+ const t = setTimeout(() => resolve25(void 0), MODEL_FETCH_TIMEOUT_MS);
17047
17243
  t.unref?.();
17048
17244
  })
17049
17245
  ]);
@@ -18172,13 +18368,13 @@ var EVENT_FLUSH_MAX_EVENTS = 60;
18172
18368
  var EVENT_FLUSH_MAX_BYTES = 200 * 1024;
18173
18369
  var LOOP_LAG_WARN_MS = 2e3;
18174
18370
  function withTimeout(p, ms) {
18175
- return new Promise((resolve24, reject) => {
18371
+ return new Promise((resolve25, reject) => {
18176
18372
  const timer = setTimeout(() => reject(new Error(`\u5B50\u6307\u4EE4\u8D85\u65F6\uFF08${ms}ms\uFF09`)), ms);
18177
18373
  timer.unref?.();
18178
18374
  p.then(
18179
18375
  (v) => {
18180
18376
  clearTimeout(timer);
18181
- resolve24(v);
18377
+ resolve25(v);
18182
18378
  },
18183
18379
  (e) => {
18184
18380
  clearTimeout(timer);
@@ -18189,7 +18385,7 @@ function withTimeout(p, ms) {
18189
18385
  }
18190
18386
  function primaryIp() {
18191
18387
  let v6;
18192
- for (const infos of Object.values(os9.networkInterfaces())) {
18388
+ for (const infos of Object.values(os10.networkInterfaces())) {
18193
18389
  for (const info of infos ?? []) {
18194
18390
  if (info.internal) continue;
18195
18391
  if (info.family === "IPv4") return info.address;
@@ -18529,6 +18725,11 @@ var FleetNodeBridge = class {
18529
18725
  refreshInfo() {
18530
18726
  this._publishInfo();
18531
18727
  }
18728
+ /** 本地改名后把 status(含 label)与 info 立即重发,控制台不必等下一次周期上报 */
18729
+ republishLabel() {
18730
+ this._send({ kind: "status", status: this._status(this.isConnected()) });
18731
+ this._publishInfo();
18732
+ }
18532
18733
  // ===================== 内部 =====================
18533
18734
  _status(online) {
18534
18735
  return {
@@ -18538,7 +18739,7 @@ var FleetNodeBridge = class {
18538
18739
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
18539
18740
  platform: process.platform,
18540
18741
  mode: process.env.NODE_MODE ?? "standalone",
18541
- version: "0.2.12",
18742
+ version: "0.2.14",
18542
18743
  ip: primaryIp()
18543
18744
  };
18544
18745
  }
@@ -18557,7 +18758,23 @@ var FleetNodeBridge = class {
18557
18758
  byDay: days
18558
18759
  };
18559
18760
  }
18761
+ /**
18762
+ * 上报 info(项目/会话快照)。
18763
+ *
18764
+ * 失败必须留痕:这是控制台「项目列表」的唯一数据源,静默失败会表现为
18765
+ * 「这台节点永远没有任何项目」,且只能靠网关 detail=null 才发现。
18766
+ * 同时用 try 包住,避免一次读盘异常中断 `_onUp` 后续的状态通知。
18767
+ */
18560
18768
  _publishInfo() {
18769
+ try {
18770
+ this._publishInfoNow();
18771
+ } catch (e) {
18772
+ console.warn(
18773
+ `[fleet] \u8282\u70B9 ${this.nodeId} \u4E0A\u62A5 info \u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`
18774
+ );
18775
+ }
18776
+ }
18777
+ _publishInfoNow() {
18561
18778
  const totals = { projects: 0, sessions: 0, running: 0, waiting: 0 };
18562
18779
  const sessions = [];
18563
18780
  const projects = allProjectSummaries(this.opts.deps.store).map((p) => {
@@ -18584,7 +18801,15 @@ var FleetNodeBridge = class {
18584
18801
  totals.sessions += p.sessionCount;
18585
18802
  totals.running += running;
18586
18803
  totals.waiting += waiting;
18587
- return { id: p.id, name: p.name, sessionCount: p.sessionCount, running, waiting };
18804
+ return {
18805
+ id: p.id,
18806
+ name: p.name,
18807
+ sessionCount: p.sessionCount,
18808
+ running,
18809
+ waiting,
18810
+ // 控制台项目列表要展示工作目录(Hub 落盘快照后即可离线查看)
18811
+ workspaceRoot: p.workspaceRoot ?? null
18812
+ };
18588
18813
  });
18589
18814
  this._send({
18590
18815
  kind: "info",
@@ -18593,7 +18818,7 @@ var FleetNodeBridge = class {
18593
18818
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
18594
18819
  platform: process.platform,
18595
18820
  mode: process.env.NODE_MODE ?? "standalone",
18596
- version: "0.2.12",
18821
+ version: "0.2.14",
18597
18822
  ip: primaryIp(),
18598
18823
  projects,
18599
18824
  totals,
@@ -19341,7 +19566,7 @@ init_esm_shims();
19341
19566
  // src/server/qq/bindings.ts
19342
19567
  init_esm_shims();
19343
19568
  import * as fs25 from "fs";
19344
- import * as path33 from "path";
19569
+ import * as path34 from "path";
19345
19570
  function conversationKey(target) {
19346
19571
  switch (target.kind) {
19347
19572
  case "c2c":
@@ -19380,7 +19605,7 @@ var QqBindingsStore = class _QqBindingsStore {
19380
19605
  cache = null;
19381
19606
  /** 基于 DATA_DIR 构造 */
19382
19607
  static in(dataDir) {
19383
- return new _QqBindingsStore(path33.join(dataDir, "qq", "bindings.json"));
19608
+ return new _QqBindingsStore(path34.join(dataDir, "qq", "bindings.json"));
19384
19609
  }
19385
19610
  load() {
19386
19611
  if (this.cache) return this.cache;
@@ -19417,7 +19642,7 @@ var QqBindingsStore = class _QqBindingsStore {
19417
19642
  return null;
19418
19643
  }
19419
19644
  persist() {
19420
- fs25.mkdirSync(path33.dirname(this.file), { recursive: true });
19645
+ fs25.mkdirSync(path34.dirname(this.file), { recursive: true });
19421
19646
  fs25.writeFileSync(this.file, JSON.stringify(this.cache, null, 2), "utf-8");
19422
19647
  }
19423
19648
  };
@@ -19831,7 +20056,7 @@ ${lines.join("\n")}`, msgId);
19831
20056
  // src/server/qq/QqManager.ts
19832
20057
  init_esm_shims();
19833
20058
  import * as fs26 from "fs";
19834
- import * as path34 from "path";
20059
+ import * as path35 from "path";
19835
20060
  var QqManager = class {
19836
20061
  constructor(opts) {
19837
20062
  this.opts = opts;
@@ -19840,7 +20065,7 @@ var QqManager = class {
19840
20065
  adapter = null;
19841
20066
  config = null;
19842
20067
  get configFile() {
19843
- return path34.join(this.opts.dataDir, "qq", "config.json");
20068
+ return path35.join(this.opts.dataDir, "qq", "config.json");
19844
20069
  }
19845
20070
  /** 启动:读配置(env 优先,其次文件),有则建连接 */
19846
20071
  start() {
@@ -19933,7 +20158,7 @@ var QqManager = class {
19933
20158
  return null;
19934
20159
  }
19935
20160
  _persistConfig(cfg) {
19936
- fs26.mkdirSync(path34.dirname(this.configFile), { recursive: true });
20161
+ fs26.mkdirSync(path35.dirname(this.configFile), { recursive: true });
19937
20162
  fs26.writeFileSync(this.configFile, JSON.stringify(cfg, null, 2), "utf-8");
19938
20163
  }
19939
20164
  };
@@ -19983,7 +20208,7 @@ var PairingCodeStore = class {
19983
20208
  // src/update/controller.ts
19984
20209
  init_esm_shims();
19985
20210
  import * as fs30 from "fs";
19986
- import * as path38 from "path";
20211
+ import * as path39 from "path";
19987
20212
 
19988
20213
  // src/update/downloader.ts
19989
20214
  init_esm_shims();
@@ -19992,7 +20217,7 @@ import * as fs27 from "fs";
19992
20217
  import { Readable as Readable2 } from "stream";
19993
20218
  import { pipeline as pipeline2 } from "stream/promises";
19994
20219
  import { spawnSync as spawnSync4 } from "child_process";
19995
- import * as path35 from "path";
20220
+ import * as path36 from "path";
19996
20221
 
19997
20222
  // src/update/manifest.ts
19998
20223
  init_esm_shims();
@@ -20169,7 +20394,7 @@ async function fetchManifest(url, publicKey, opts = {}) {
20169
20394
  async function downloadBinary(bin, destPath, log = () => {
20170
20395
  }) {
20171
20396
  const partPath = `${destPath}.part`;
20172
- fs27.mkdirSync(path35.dirname(destPath), { recursive: true });
20397
+ fs27.mkdirSync(path36.dirname(destPath), { recursive: true });
20173
20398
  fs27.rmSync(partPath, { force: true });
20174
20399
  let res;
20175
20400
  try {
@@ -20213,7 +20438,7 @@ async function downloadBinary(bin, destPath, log = () => {
20213
20438
  fs27.rmSync(destPath, { force: true });
20214
20439
  fs27.renameSync(partPath, destPath);
20215
20440
  fs27.chmodSync(destPath, 493);
20216
- log(`\u5DF2\u4E0B\u8F7D ${path35.basename(destPath)}\uFF08${Math.round(bytes / 1024 / 1024)}MB\uFF0C\u6821\u9A8C\u901A\u8FC7\uFF09`);
20441
+ log(`\u5DF2\u4E0B\u8F7D ${path36.basename(destPath)}\uFF08${Math.round(bytes / 1024 / 1024)}MB\uFF0C\u6821\u9A8C\u901A\u8FC7\uFF09`);
20217
20442
  return { bytes };
20218
20443
  }
20219
20444
  function selfCheck(binPath, expectedVersion) {
@@ -20238,17 +20463,17 @@ function selfCheck(binPath, expectedVersion) {
20238
20463
  // src/update/installer.ts
20239
20464
  init_esm_shims();
20240
20465
  import * as fs29 from "fs";
20241
- import * as path37 from "path";
20466
+ import * as path38 from "path";
20242
20467
 
20243
20468
  // src/update/state.ts
20244
20469
  init_esm_shims();
20245
20470
  import * as fs28 from "fs";
20246
- import * as path36 from "path";
20471
+ import * as path37 from "path";
20247
20472
  function updatesDir(dataDir) {
20248
- return path36.join(dataDir, "updates");
20473
+ return path37.join(dataDir, "updates");
20249
20474
  }
20250
20475
  function statePath(dataDir) {
20251
- return path36.join(updatesDir(dataDir), "state.json");
20476
+ return path37.join(updatesDir(dataDir), "state.json");
20252
20477
  }
20253
20478
  function loadState(dataDir) {
20254
20479
  try {
@@ -20275,12 +20500,12 @@ function patchState(dataDir, patch) {
20275
20500
 
20276
20501
  // src/update/installer.ts
20277
20502
  function backupDir(dataDir) {
20278
- return path37.join(updatesDir(dataDir), "backup");
20503
+ return path38.join(updatesDir(dataDir), "backup");
20279
20504
  }
20280
20505
  function backupCurrent(dataDir, execPath, version) {
20281
20506
  const dir = backupDir(dataDir);
20282
20507
  fs29.mkdirSync(dir, { recursive: true });
20283
- const target = path37.join(dir, `zqagent-${version}${process.platform === "win32" ? ".exe" : ""}`);
20508
+ const target = path38.join(dir, `zqagent-${version}${process.platform === "win32" ? ".exe" : ""}`);
20284
20509
  fs29.copyFileSync(execPath, target);
20285
20510
  fs29.chmodSync(target, 493);
20286
20511
  return target;
@@ -20312,7 +20537,7 @@ function installStaged(opts) {
20312
20537
  const from = currentVersion();
20313
20538
  log(`\u6B63\u5728\u5B89\u88C5 v${opts.version}\uFF08\u5F53\u524D v${from}\uFF09`);
20314
20539
  const backupPath = backupCurrent(opts.dataDir, opts.execPath, from);
20315
- log(`\u5DF2\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5230 ${path37.basename(backupPath)}`);
20540
+ log(`\u5DF2\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5230 ${path38.basename(backupPath)}`);
20316
20541
  replaceExecutable(opts.execPath, opts.stagedPath);
20317
20542
  return patchState(opts.dataDir, {
20318
20543
  stagedVersion: void 0,
@@ -20356,7 +20581,7 @@ function rollback(dataDir, execPath, log = () => {
20356
20581
  }
20357
20582
  function readRollbackTarget(dataDir) {
20358
20583
  try {
20359
- const raw = fs29.readFileSync(path37.join(updatesDir(dataDir), "state.json"), "utf-8");
20584
+ const raw = fs29.readFileSync(path38.join(updatesDir(dataDir), "state.json"), "utf-8");
20360
20585
  const s = JSON.parse(raw);
20361
20586
  if (s.backupPath && s.backupVersion) return s;
20362
20587
  } catch {
@@ -20533,7 +20758,7 @@ var UpdateController = class {
20533
20758
  if (!bin) return `\u6E05\u5355\u6CA1\u6709\u5F53\u524D\u5E73\u53F0\uFF08${platformKey()}\uFF09\u7684\u4EA7\u7269`;
20534
20759
  let stagedPath = state.stagedPath;
20535
20760
  if (!(state.stagedVersion === manifest.version && stagedPath && fs30.existsSync(stagedPath))) {
20536
- stagedPath = path38.join(
20761
+ stagedPath = path39.join(
20537
20762
  updatesDir(this.opts.dataDir),
20538
20763
  "staged",
20539
20764
  `zqagent-${manifest.version}${process.platform === "win32" ? ".exe" : ""}`
@@ -20600,11 +20825,11 @@ var UpdateController = class {
20600
20825
  const minUptime = num("ZQAGENT_UPDATE_MIN_UPTIME_MS", 10 * 60 * 1e3);
20601
20826
  const idleMs = num("ZQAGENT_UPDATE_IDLE_MS", 60 * 1e3);
20602
20827
  let idleSince = null;
20603
- return new Promise((resolve24) => {
20828
+ return new Promise((resolve25) => {
20604
20829
  const timer = setInterval(() => {
20605
20830
  if (this.stopped) {
20606
20831
  clearInterval(timer);
20607
- resolve24(false);
20832
+ resolve25(false);
20608
20833
  return;
20609
20834
  }
20610
20835
  if (Date.now() - this.startedAt < minUptime || !this.opts.isIdle()) {
@@ -20614,7 +20839,7 @@ var UpdateController = class {
20614
20839
  idleSince ??= Date.now();
20615
20840
  if (Date.now() - idleSince >= idleMs) {
20616
20841
  clearInterval(timer);
20617
- resolve24(true);
20842
+ resolve25(true);
20618
20843
  }
20619
20844
  }, 1e3);
20620
20845
  timer.unref();
@@ -20708,7 +20933,7 @@ function seedDemoTenant(store) {
20708
20933
  apiKey: env2("OPENAI_API_KEY"),
20709
20934
  baseURL: env2("OPENAI_BASE_URL")
20710
20935
  },
20711
- workspaceRoot: workspace ? path39.resolve(workspace) : void 0,
20936
+ workspaceRoot: workspace ? path40.resolve(workspace) : void 0,
20712
20937
  allowedCommands: []
20713
20938
  };
20714
20939
  store.saveTenant(demo);
@@ -20762,9 +20987,9 @@ function syncTenantModels(store) {
20762
20987
  tenant.model = model;
20763
20988
  changed = true;
20764
20989
  }
20765
- if (workspace && tenant.workspaceRoot !== path39.resolve(workspace)) {
20766
- console.log(`[sync] \u79DF\u6237 ${id} workspaceRoot \u5DF2\u540C\u6B65: ${tenant.workspaceRoot ?? "(\u6C99\u7BB1)"} \u2192 ${path39.resolve(workspace)}`);
20767
- tenant.workspaceRoot = path39.resolve(workspace);
20990
+ if (workspace && tenant.workspaceRoot !== path40.resolve(workspace)) {
20991
+ console.log(`[sync] \u79DF\u6237 ${id} workspaceRoot \u5DF2\u540C\u6B65: ${tenant.workspaceRoot ?? "(\u6C99\u7BB1)"} \u2192 ${path40.resolve(workspace)}`);
20992
+ tenant.workspaceRoot = path40.resolve(workspace);
20768
20993
  changed = true;
20769
20994
  }
20770
20995
  if (apiKey && tenant.provider.apiKey !== apiKey) {
@@ -20797,7 +21022,7 @@ function exitWhenOrphaned() {
20797
21022
  }
20798
21023
  var PORT_FALLBACK_LIMIT = 20;
20799
21024
  function listenWithPortFallback(server, startPort, host, dataDir, limit = PORT_FALLBACK_LIMIT) {
20800
- return new Promise((resolve24, reject) => {
21025
+ return new Promise((resolve25, reject) => {
20801
21026
  let attempts = 0;
20802
21027
  const tryListen = (port) => {
20803
21028
  server.removeAllListeners("listening");
@@ -20825,18 +21050,18 @@ function listenWithPortFallback(server, startPort, host, dataDir, limit = PORT_F
20825
21050
  }
20826
21051
  try {
20827
21052
  fs31.mkdirSync(dataDir, { recursive: true });
20828
- fs31.writeFileSync(path39.join(dataDir, "server-port"), `${actualPort}
21053
+ fs31.writeFileSync(path40.join(dataDir, "server-port"), `${actualPort}
20829
21054
  `);
20830
21055
  } catch {
20831
21056
  }
20832
- resolve24(actualPort);
21057
+ resolve25(actualPort);
20833
21058
  });
20834
21059
  };
20835
21060
  tryListen(startPort);
20836
21061
  });
20837
21062
  }
20838
21063
  function startServer(opts = {}) {
20839
- const dataDir = path39.resolve(opts.dataDir ?? env2("DATA_DIR") ?? DEFAULT_DATA_DIR);
21064
+ const dataDir = path40.resolve(opts.dataDir ?? env2("DATA_DIR") ?? DEFAULT_DATA_DIR);
20840
21065
  const port = opts.port ?? Number(env2("PORT") ?? 8787);
20841
21066
  const host = opts.host ?? env2("HOST") ?? "127.0.0.1";
20842
21067
  exitWhenOrphaned();
@@ -20866,7 +21091,7 @@ function startServer(opts = {}) {
20866
21091
  }
20867
21092
  const adminKey = ensureAdminKey();
20868
21093
  const secretKey = env2("SECRET_KEY");
20869
- const secretBox = secretKey ? SecretBox.fromHex(secretKey) : SecretBox.fromFile(path39.join(dataDir, "secret.key"));
21094
+ const secretBox = secretKey ? SecretBox.fromHex(secretKey) : SecretBox.fromFile(path40.join(dataDir, "secret.key"));
20870
21095
  if (secretKey && !secretBox) {
20871
21096
  console.warn("[crypto] SECRET_KEY \u975E\u6CD5\uFF08\u9700 64 \u4F4D hex\uFF09\uFF0C\u901A\u77E5\u51ED\u636E\u5C06\u9000\u5316\u4E3A\u660E\u6587");
20872
21097
  }
@@ -20907,7 +21132,7 @@ function startServer(opts = {}) {
20907
21132
  hubUrl: fleetCred?.hubUrl,
20908
21133
  gatewayUrl: fleetCred?.gatewayUrl ?? env2("FLEET_GATEWAY_URL"),
20909
21134
  online: fleet?.isConnected() ?? false,
20910
- label: fleetCred?.label,
21135
+ label: fleetCred?.label ?? store.loadNodeLabel() ?? void 0,
20911
21136
  lastError: fleet?.getLastError() ?? void 0,
20912
21137
  reconnectCount: fleet?.getErrorCount() ?? 0
20913
21138
  };
@@ -20916,27 +21141,53 @@ function startServer(opts = {}) {
20916
21141
  status: fleetStatus,
20917
21142
  async enroll(input) {
20918
21143
  const nodeId = ensureNodeId(store);
21144
+ const label = input.label?.trim() || defaultNodeLabel();
20919
21145
  const cred = input.account ? await hubEnrollByAccount(input.hubUrl, {
20920
21146
  email: input.account.email,
20921
21147
  phone: input.account.phone,
20922
21148
  password: input.account.password,
20923
21149
  code: input.account.smsCode,
20924
21150
  nodeId,
20925
- label: input.label
21151
+ label
20926
21152
  }) : await hubEnrollByCode(input.hubUrl, {
20927
21153
  code: input.code,
20928
21154
  nodeId,
20929
- label: input.label
21155
+ label
20930
21156
  });
20931
21157
  const full = {
20932
21158
  ...cred,
20933
- label: input.label ?? cred.label,
21159
+ label,
20934
21160
  enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
20935
21161
  };
20936
21162
  store.saveFleetCredential(full);
21163
+ store.saveNodeLabel(label);
20937
21164
  connectFleet(full);
20938
21165
  return fleetStatus();
20939
21166
  },
21167
+ async rename(label) {
21168
+ const name = label.trim();
21169
+ store.saveNodeLabel(name);
21170
+ if (fleetCred) {
21171
+ fleetCred = { ...fleetCred, label: name };
21172
+ store.saveFleetCredential(fleetCred);
21173
+ }
21174
+ fleet?.republishLabel();
21175
+ let hubSynced = false;
21176
+ let hubError;
21177
+ const cred = fleetCred;
21178
+ if (cred?.hubUrl && cred.fleetToken) {
21179
+ try {
21180
+ await hubUpdateNodeLabelSelf(cred.hubUrl, cred.fleetToken, {
21181
+ nodeId: ensureNodeId(store),
21182
+ label: name
21183
+ });
21184
+ hubSynced = true;
21185
+ } catch (e) {
21186
+ hubError = e instanceof Error ? e.message : String(e);
21187
+ }
21188
+ }
21189
+ return { ...fleetStatus(), hubSynced, hubError };
21190
+ },
20940
21191
  unlink() {
20941
21192
  fleet?.close();
20942
21193
  fleet = null;
@@ -21067,7 +21318,7 @@ function startServer(opts = {}) {
21067
21318
  server.timeout = 0;
21068
21319
  server.keepAliveTimeout = 65e3;
21069
21320
  server.headersTimeout = 66e3;
21070
- const ready = new Promise((resolve24, reject) => {
21321
+ const ready = new Promise((resolve25, reject) => {
21071
21322
  listenWithPortFallback(server, port, host, dataDir).then((actualPort) => {
21072
21323
  const info = {
21073
21324
  host,
@@ -21084,7 +21335,7 @@ function startServer(opts = {}) {
21084
21335
  printReady(info, qq);
21085
21336
  }
21086
21337
  updater?.start();
21087
- resolve24(info);
21338
+ resolve25(info);
21088
21339
  }, reject);
21089
21340
  });
21090
21341
  return {
@@ -21102,7 +21353,7 @@ function printReady(info, qq) {
21102
21353
  `zqagent server \u76D1\u542C http://${info.host}:${info.port}`,
21103
21354
  `\u6570\u636E\u76EE\u5F55: ${info.dataDir}`,
21104
21355
  `\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`,
21105
- 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`
21356
+ env2("ZQAGENT_LOG_ADMIN_KEY") === "0" ? `\u7BA1\u7406\u5458\u5BC6\u94A5: ${maskKey(info.adminKey)}\uFF08\u5DF2\u8131\u654F\uFF0C\u5B8C\u6574\u503C\u89C1 ${path40.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`
21106
21357
  ];
21107
21358
  if (info.fleetNodeId) {
21108
21359
  lines.push(
@@ -21235,7 +21486,7 @@ async function runServeCommand(argv) {
21235
21486
 
21236
21487
  // src/cli/update.ts
21237
21488
  init_esm_shims();
21238
- import * as path40 from "path";
21489
+ import * as path41 from "path";
21239
21490
  function parse3(argv) {
21240
21491
  const out = { status: false, check: false, now: false, rollback: false };
21241
21492
  for (let i = 0; i < argv.length; i++) {
@@ -21264,7 +21515,7 @@ function restartHint() {
21264
21515
  }
21265
21516
  async function runUpdateCommand(argv) {
21266
21517
  const args = parse3(argv);
21267
- const dataDir = path40.resolve(args.dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
21518
+ const dataDir = path41.resolve(args.dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
21268
21519
  const controller = new UpdateController({ dataDir, isIdle: () => true });
21269
21520
  if (args.rollback) {
21270
21521
  const restored = controller.rollbackNow();
@@ -21313,9 +21564,9 @@ async function runUpdateCommand(argv) {
21313
21564
  // src/cli/sessionMeta.ts
21314
21565
  init_esm_shims();
21315
21566
  import * as fs32 from "fs";
21316
- import * as path41 from "path";
21567
+ import * as path42 from "path";
21317
21568
  function updateSessionMetaFile(stateDir2, sessionId, patch) {
21318
- const file = path41.join(stateDir2, `${sessionId}_state.json`);
21569
+ const file = path42.join(stateDir2, `${sessionId}_state.json`);
21319
21570
  try {
21320
21571
  const raw = fs32.readFileSync(file, "utf8");
21321
21572
  const state = JSON.parse(raw);
@@ -21332,8 +21583,8 @@ function updateSessionMetaFile(stateDir2, sessionId, patch) {
21332
21583
  // src/cli/debug.ts
21333
21584
  init_esm_shims();
21334
21585
  import * as fs33 from "fs";
21335
- import * as os10 from "os";
21336
- import * as path42 from "path";
21586
+ import * as os11 from "os";
21587
+ import * as path43 from "path";
21337
21588
  var LOG_NAME = "zqagent-debug.log";
21338
21589
  var TRUTHY = /^(1|true|yes|on)$/i;
21339
21590
  function bootRef() {
@@ -21344,9 +21595,9 @@ var logFile = null;
21344
21595
  var startedAt = Date.now();
21345
21596
  function resolveLogFile() {
21346
21597
  const explicit = process.env.ZQAGENT_DEBUG_LOG;
21347
- if (explicit) return path42.resolve(explicit);
21598
+ if (explicit) return path43.resolve(explicit);
21348
21599
  const dir = process.env.ZQAGENT_DEBUG_DIR;
21349
- return path42.join(dir ? path42.resolve(dir) : os10.tmpdir(), LOG_NAME);
21600
+ return path43.join(dir ? path43.resolve(dir) : os11.tmpdir(), LOG_NAME);
21350
21601
  }
21351
21602
  function enableDebug(argv = process.argv) {
21352
21603
  if (enabled) return true;
@@ -21362,7 +21613,7 @@ function enableDebug(argv = process.argv) {
21362
21613
  enabled = true;
21363
21614
  logFile = resolveLogFile();
21364
21615
  try {
21365
- fs33.mkdirSync(path42.dirname(logFile), { recursive: true });
21616
+ fs33.mkdirSync(path43.dirname(logFile), { recursive: true });
21366
21617
  fs33.writeFileSync(logFile, "");
21367
21618
  } catch {
21368
21619
  logFile = null;
@@ -21540,7 +21791,7 @@ if (enableDebug(process.argv)) {
21540
21791
  logEnvironment();
21541
21792
  }
21542
21793
  var MODEL = process.env.OPENAI_MODEL ?? "gpt-4o";
21543
- var WORKSPACE = path43.resolve(process.env.WORKSPACE ?? ".");
21794
+ var WORKSPACE = path44.resolve(process.env.WORKSPACE ?? ".");
21544
21795
  var MAX_ITERATIONS = parseMaxIterations(process.env.MAX_ITERATIONS, 300);
21545
21796
  var STATE_DIR = stateDir();
21546
21797
  function listSessions() {
@@ -21551,7 +21802,7 @@ function listSessions() {
21551
21802
  if (!f.endsWith("_state.json")) continue;
21552
21803
  try {
21553
21804
  const parsed = JSON.parse(
21554
- fs34.readFileSync(path43.join(STATE_DIR, f), "utf8")
21805
+ fs34.readFileSync(path44.join(STATE_DIR, f), "utf8")
21555
21806
  );
21556
21807
  if (parsed && typeof parsed.sessionId === "string") {
21557
21808
  sessions.push(parsed);
@@ -21585,7 +21836,7 @@ function printLastAssistantMessage(messages) {
21585
21836
  out += renderer.flush();
21586
21837
  cliWrite(out + "\n");
21587
21838
  }
21588
- var AGENTS_FILE = path43.join(WORKSPACE, ".agent", "agents.json");
21839
+ var AGENTS_FILE = path44.join(WORKSPACE, ".agent", "agents.json");
21589
21840
  function loadAgentsFromFile() {
21590
21841
  try {
21591
21842
  if (!fs34.existsSync(AGENTS_FILE)) return [];
@@ -21601,7 +21852,7 @@ function loadAgentsFromFile() {
21601
21852
  }
21602
21853
  function saveAgentsToFile(defs) {
21603
21854
  try {
21604
- fs34.mkdirSync(path43.dirname(AGENTS_FILE), { recursive: true });
21855
+ fs34.mkdirSync(path44.dirname(AGENTS_FILE), { recursive: true });
21605
21856
  fs34.writeFileSync(AGENTS_FILE, JSON.stringify(defs, null, 2) + "\n", "utf8");
21606
21857
  } catch (err) {
21607
21858
  cliErr(`\u26A0\uFE0F \u4FDD\u5B58 agents \u914D\u7F6E\u5931\u8D25: ${err}`);
@@ -21611,8 +21862,8 @@ var agentRegistry = new AgentRegistry([
21611
21862
  ...BUILTIN_AGENTS,
21612
21863
  ...loadAgentsFromFile()
21613
21864
  ]);
21614
- var MCP_FILE = path43.join(WORKSPACE, ".agent", "mcp.json");
21615
- var COMMAND_TOOLS_FILE = path43.join(WORKSPACE, ".agent", "tools.json");
21865
+ var MCP_FILE = path44.join(WORKSPACE, ".agent", "mcp.json");
21866
+ var COMMAND_TOOLS_FILE = path44.join(WORKSPACE, ".agent", "tools.json");
21616
21867
  function loadJsonArray(file, validate) {
21617
21868
  try {
21618
21869
  if (!fs34.existsSync(file)) return [];
@@ -21626,7 +21877,7 @@ function loadJsonArray(file, validate) {
21626
21877
  }
21627
21878
  function saveJsonFile(file, data) {
21628
21879
  try {
21629
- fs34.mkdirSync(path43.dirname(file), { recursive: true });
21880
+ fs34.mkdirSync(path44.dirname(file), { recursive: true });
21630
21881
  fs34.writeFileSync(file, JSON.stringify(data, null, 2) + "\n", "utf8");
21631
21882
  } catch (err) {
21632
21883
  cliErr(`\u26A0\uFE0F \u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${err}`);
@@ -21699,7 +21950,7 @@ ${stderr}` : ""
21699
21950
  }
21700
21951
  }
21701
21952
  var mcpManager = null;
21702
- function parseArgs(argv) {
21953
+ function parseArgs2(argv) {
21703
21954
  const result = {};
21704
21955
  for (let i = 0; i < argv.length; i++) {
21705
21956
  if (argv[i] === "--resume" || argv[i] === "--r") {
@@ -21728,13 +21979,13 @@ function pruneEmptySessions(keepSessionId) {
21728
21979
  if (!isEmptySession(s) || s.sessionId === keepSessionId) continue;
21729
21980
  for (const suffix of ["_state.json", ".jsonl"]) {
21730
21981
  try {
21731
- fs34.unlinkSync(path43.join(STATE_DIR, `${s.sessionId}${suffix}`));
21982
+ fs34.unlinkSync(path44.join(STATE_DIR, `${s.sessionId}${suffix}`));
21732
21983
  } catch {
21733
21984
  }
21734
21985
  }
21735
21986
  }
21736
21987
  }
21737
- var cliArgs = parseArgs(process.argv.slice(2));
21988
+ var cliArgs = parseArgs2(process.argv.slice(2));
21738
21989
  var resumeId = cliArgs["resume"];
21739
21990
  var SESSION_ID = resolveInitialSessionId(resumeId);
21740
21991
  if (!resumeId) pruneEmptySessions(SESSION_ID);
@@ -21791,7 +22042,7 @@ function question(prompt) {
21791
22042
  }
21792
22043
  function readPassword(prompt) {
21793
22044
  if (!process.stdin.isTTY) return question(prompt);
21794
- return new Promise((resolve24) => {
22045
+ return new Promise((resolve25) => {
21795
22046
  const savedDataListeners = process.stdin.listeners("data");
21796
22047
  process.stdin.removeAllListeners("data");
21797
22048
  cliWrite(prompt);
@@ -21807,13 +22058,13 @@ function readPassword(prompt) {
21807
22058
  if (ch === "\r" || ch === "\n") {
21808
22059
  cleanup();
21809
22060
  cliWrite("\n");
21810
- resolve24(buf);
22061
+ resolve25(buf);
21811
22062
  return;
21812
22063
  }
21813
22064
  if (ch === "") {
21814
22065
  cleanup();
21815
22066
  cliWrite("\n");
21816
- resolve24("");
22067
+ resolve25("");
21817
22068
  return;
21818
22069
  }
21819
22070
  if (ch === "\x7F" || ch === "\b") {
@@ -22246,9 +22497,9 @@ async function offerTerminalSetup(engine, canUseAgent) {
22246
22497
  cliLog("");
22247
22498
  }
22248
22499
  }
22249
- var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set(["link", "serve", "update"]);
22500
+ var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set(["link", "serve", "update", "rename"]);
22250
22501
  function cliVersion() {
22251
- const env3 = "0.2.12"?.trim();
22502
+ const env3 = "0.2.14"?.trim();
22252
22503
  if (env3) return env3;
22253
22504
  try {
22254
22505
  const req2 = createRequire4(import.meta.url);
@@ -22269,6 +22520,7 @@ function printCliUsage() {
22269
22520
  cliLog(" zqagent link [--hub <url>] [--username <\u90AE\u7BB1/\u624B\u673A\u53F7> --password <\u5BC6\u7801>]");
22270
22521
  cliLog(" [--code <\u63A5\u5165\u7801>] [--label \u540D\u79F0]");
22271
22522
  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");
22523
+ 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");
22272
22524
  cliLog("");
22273
22525
  cliLog("serve \u9009\u9879\uFF1A--port <n> --host <addr> --data-dir <dir>");
22274
22526
  cliLog(" --hub <url> --enroll-code <\u7801> --label <\u540D\u79F0> \uFF08\u542F\u52A8\u5373\u63A5\u5165\uFF09");
@@ -22296,6 +22548,11 @@ async function main() {
22296
22548
  rl.close();
22297
22549
  process.exit(ok2 ? 0 : 1);
22298
22550
  }
22551
+ if (subcommand === "rename") {
22552
+ const ok2 = await runRenameCommand(process.argv.slice(3));
22553
+ rl.close();
22554
+ process.exit(ok2 ? 0 : 1);
22555
+ }
22299
22556
  if (subcommand === "serve") {
22300
22557
  rl.close();
22301
22558
  await runServeCommand(process.argv.slice(3));
@@ -22457,7 +22714,7 @@ async function main() {
22457
22714
  }
22458
22715
  });
22459
22716
  const savedState = resumeId ? FileLogHook.loadState(resumeId, STATE_DIR) : null;
22460
- const metaStateFile = path43.join(STATE_DIR, `${SESSION_ID}_state.json`);
22717
+ const metaStateFile = path44.join(STATE_DIR, `${SESSION_ID}_state.json`);
22461
22718
  const stateForMeta = savedState ?? (fs34.existsSync(metaStateFile) ? FileLogHook.loadState(SESSION_ID, STATE_DIR) : null);
22462
22719
  sessionMeta = {
22463
22720
  sessionId: SESSION_ID,