@zqagent/core 0.2.11 → 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.
@@ -2180,12 +2180,12 @@ var MUTATING_TOOLS = /* @__PURE__ */ new Set([
2180
2180
  ]);
2181
2181
  function parseReadFileSpan(content) {
2182
2182
  const body = content.replace(/^\[tool output truncated:[^\n]*\]\n\n/, "");
2183
- let path36;
2183
+ let path37;
2184
2184
  let start;
2185
2185
  let end;
2186
2186
  try {
2187
2187
  const obj = JSON.parse(body);
2188
- path36 = obj.path;
2188
+ path37 = obj.path;
2189
2189
  start = obj.start_line;
2190
2190
  end = obj.end_line;
2191
2191
  } catch {
@@ -2194,14 +2194,14 @@ function parseReadFileSpan(content) {
2194
2194
  const m = new RegExp(`"${key}"\\s*:\\s*(\\d+)`).exec(body);
2195
2195
  return m ? Number(m[1]) : void 0;
2196
2196
  };
2197
- path36 = str2("path");
2197
+ path37 = str2("path");
2198
2198
  start = num2("start_line");
2199
2199
  end = num2("end_line");
2200
2200
  }
2201
- if (typeof path36 !== "string" || !path36) return null;
2201
+ if (typeof path37 !== "string" || !path37) return null;
2202
2202
  if (typeof start !== "number" || typeof end !== "number") return null;
2203
2203
  if (!Number.isFinite(start) || !Number.isFinite(end)) return null;
2204
- return { path: path36, start, end };
2204
+ return { path: path37, start, end };
2205
2205
  }
2206
2206
  function addSpan(spans, start, end) {
2207
2207
  spans.push([start, end]);
@@ -3818,9 +3818,9 @@ var TurnEngine = class _TurnEngine {
3818
3818
  return;
3819
3819
  }
3820
3820
  if (result && typeof result === "object") {
3821
- const path36 = result.path;
3822
- if (path36) {
3823
- this._producedFiles.push(path36);
3821
+ const path37 = result.path;
3822
+ if (path37) {
3823
+ this._producedFiles.push(path37);
3824
3824
  return;
3825
3825
  }
3826
3826
  const changed = result.changed_files;
@@ -5147,10 +5147,10 @@ var OpenAIProvider = class {
5147
5147
  let timer;
5148
5148
  try {
5149
5149
  for (; ; ) {
5150
- const idle = new Promise((resolve19) => {
5150
+ const idle = new Promise((resolve20) => {
5151
5151
  timer = setTimeout(() => {
5152
5152
  onIdle();
5153
- resolve19({ timedOut: true });
5153
+ resolve20({ timedOut: true });
5154
5154
  }, idleMs);
5155
5155
  });
5156
5156
  const next = iter.next();
@@ -5778,12 +5778,12 @@ function makeSink(maxBuffer) {
5778
5778
  };
5779
5779
  }
5780
5780
  function execAsync(file, argv, opts = {}) {
5781
- return new Promise((resolve19) => {
5781
+ return new Promise((resolve20) => {
5782
5782
  const maxBuffer = opts.maxBuffer ?? DEFAULT_MAX_BUFFER;
5783
5783
  const out = makeSink(maxBuffer);
5784
5784
  const err = makeSink(maxBuffer);
5785
5785
  if (opts.signal?.aborted) {
5786
- resolve19({
5786
+ resolve20({
5787
5787
  status: null,
5788
5788
  stdout: Buffer.alloc(0),
5789
5789
  stderr: Buffer.alloc(0),
@@ -5804,7 +5804,7 @@ function execAsync(file, argv, opts = {}) {
5804
5804
  windowsHide: true
5805
5805
  });
5806
5806
  } catch (e) {
5807
- resolve19({
5807
+ resolve20({
5808
5808
  status: null,
5809
5809
  stdout: Buffer.alloc(0),
5810
5810
  stderr: Buffer.alloc(0),
@@ -5841,7 +5841,7 @@ function execAsync(file, argv, opts = {}) {
5841
5841
  };
5842
5842
  if (aborted) result.aborted = true;
5843
5843
  if (spawnError) result.error = spawnError;
5844
- resolve19(result);
5844
+ resolve20(result);
5845
5845
  };
5846
5846
  const killAndSettle = () => {
5847
5847
  killTree(child.pid);
@@ -7736,18 +7736,18 @@ function makeApplyPatch(workspace) {
7736
7736
  return { changed_files: changedFiles, added_files: addedFiles, deleted_files: deletedFiles, file_count: fileCount };
7737
7737
  };
7738
7738
  }
7739
- function applyPatchHunks(oldLines, chunks, path36) {
7739
+ function applyPatchHunks(oldLines, chunks, path37) {
7740
7740
  let newLines = [...oldLines];
7741
7741
  let cursor = 0;
7742
7742
  for (const chunk of chunks) {
7743
7743
  const oldBlock = chunk.filter((l) => l[0] === " " || l[0] === "-").map((l) => l.slice(1));
7744
7744
  const newBlock = chunk.filter((l) => l[0] === " " || l[0] === "+").map((l) => l.slice(1));
7745
7745
  if (!oldBlock.length) {
7746
- throw new Error(`\u8865\u4E01 hunk \u5FC5\u987B\u5305\u542B\u4E0A\u4E0B\u6587\u6216\u5220\u9664\u884C: ${path36}`);
7746
+ throw new Error(`\u8865\u4E01 hunk \u5FC5\u987B\u5305\u542B\u4E0A\u4E0B\u6587\u6216\u5220\u9664\u884C: ${path37}`);
7747
7747
  }
7748
7748
  const matchStart = findBlockMatch(newLines, oldBlock, cursor);
7749
7749
  if (matchStart === -1) {
7750
- throw new Error(`\u8865\u4E01\u4E0A\u4E0B\u6587\u4E0D\u5339\u914D: ${path36}`);
7750
+ throw new Error(`\u8865\u4E01\u4E0A\u4E0B\u6587\u4E0D\u5339\u914D: ${path37}`);
7751
7751
  }
7752
7752
  const matchEnd = matchStart + oldBlock.length;
7753
7753
  newLines.splice(matchStart, oldBlock.length, ...newBlock);
@@ -9840,11 +9840,11 @@ function isAffirmative(answer) {
9840
9840
  return /^(yes|approve|同意|批准|允许|确定|可以|好的|确认)/.test(a);
9841
9841
  }
9842
9842
  function defer() {
9843
- let resolve19;
9843
+ let resolve20;
9844
9844
  const promise = new Promise((r) => {
9845
- resolve19 = r;
9845
+ resolve20 = r;
9846
9846
  });
9847
- return { promise, resolve: resolve19 };
9847
+ return { promise, resolve: resolve20 };
9848
9848
  }
9849
9849
  var SessionManager = class {
9850
9850
  constructor(store, approvalTimeoutMs = APPROVAL_TIMEOUT_MS, opts = {}) {
@@ -10416,11 +10416,11 @@ data: ${JSON.stringify({ sessionId, seq: entry.seq, ts: entry.ts, data: entry.da
10416
10416
  status: "pending",
10417
10417
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
10418
10418
  };
10419
- const { promise, resolve: resolve19 } = defer();
10419
+ const { promise, resolve: resolve20 } = defer();
10420
10420
  const timer = setTimeout(() => {
10421
10421
  this._recycleApproval(rt, id);
10422
10422
  }, this.approvalTimeoutMs);
10423
- rt.pendingApprovals.set(id, { promise, resolve: resolve19, record, timer });
10423
+ rt.pendingApprovals.set(id, { promise, resolve: resolve20, record, timer });
10424
10424
  rt.approvals.set(id, record);
10425
10425
  this._setStatus(rt, "waiting_approval");
10426
10426
  this._persist(rt);
@@ -10498,11 +10498,11 @@ data: ${JSON.stringify({ sessionId, seq: entry.seq, ts: entry.ts, data: entry.da
10498
10498
  status: "pending",
10499
10499
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
10500
10500
  };
10501
- const { promise, resolve: resolve19 } = defer();
10501
+ const { promise, resolve: resolve20 } = defer();
10502
10502
  const timer = setTimeout(() => {
10503
10503
  this._recycleQuestion(rt, qid);
10504
10504
  }, this.approvalTimeoutMs);
10505
- rt.pendingQuestions.set(qid, { promise, resolve: resolve19, record, timer });
10505
+ rt.pendingQuestions.set(qid, { promise, resolve: resolve20, record, timer });
10506
10506
  rt.questions.set(qid, record);
10507
10507
  this._setStatus(rt, "waiting_question");
10508
10508
  this._persist(rt);
@@ -10811,7 +10811,7 @@ data: ${JSON.stringify(entry.data)}
10811
10811
  if (rt.mcpReady) {
10812
10812
  await Promise.race([
10813
10813
  rt.mcpReady,
10814
- new Promise((resolve19) => setTimeout(resolve19, 15e3))
10814
+ new Promise((resolve20) => setTimeout(resolve20, 15e3))
10815
10815
  ]).catch(() => void 0);
10816
10816
  }
10817
10817
  for await (const event of gen) {
@@ -11396,7 +11396,7 @@ function buildNodeInfo(store, opts) {
11396
11396
  nodeId: opts.nodeId ?? ensureNodeId(store),
11397
11397
  platform: process.platform,
11398
11398
  mode: process.env.NODE_MODE ?? "standalone",
11399
- version: "0.2.11",
11399
+ version: "0.2.15",
11400
11400
  admin: opts.admin,
11401
11401
  projects: opts.projects
11402
11402
  };
@@ -11480,8 +11480,8 @@ function hubProxyEnabled(host) {
11480
11480
  const h = (host ?? "127.0.0.1").trim();
11481
11481
  return h === "127.0.0.1" || h === "localhost" || h === "::1";
11482
11482
  }
11483
- function isHubProxyPath(path36) {
11484
- return path36.startsWith(HUB_PROXY_PREFIX);
11483
+ function isHubProxyPath(path37) {
11484
+ return path37.startsWith(HUB_PROXY_PREFIX);
11485
11485
  }
11486
11486
  function decodeTarget(enc) {
11487
11487
  try {
@@ -12389,7 +12389,7 @@ function buildNodeHost(store, manager, diskPath) {
12389
12389
  arch: process.arch,
12390
12390
  release: os6.release(),
12391
12391
  uptimeSec: Math.round(os6.uptime()),
12392
- version: "0.2.11",
12392
+ version: "0.2.15",
12393
12393
  mode: process.env.NODE_MODE ?? "standalone",
12394
12394
  cpu: {
12395
12395
  count: cpus2.length,
@@ -12433,7 +12433,7 @@ function saveNotifications(tenant, secretBox, notifications) {
12433
12433
  var API_PREFIX = "/api/v1";
12434
12434
  var MAX_BODY_BYTES = 10 * 1024 * 1024;
12435
12435
  function readBody(req2) {
12436
- return new Promise((resolve19, reject) => {
12436
+ return new Promise((resolve20, reject) => {
12437
12437
  const chunks = [];
12438
12438
  let size = 0;
12439
12439
  req2.on("data", (c) => {
@@ -12446,9 +12446,9 @@ function readBody(req2) {
12446
12446
  chunks.push(c);
12447
12447
  });
12448
12448
  req2.on("end", () => {
12449
- if (chunks.length === 0) return resolve19(void 0);
12449
+ if (chunks.length === 0) return resolve20(void 0);
12450
12450
  try {
12451
- resolve19(JSON.parse(Buffer.concat(chunks).toString("utf-8")));
12451
+ resolve20(JSON.parse(Buffer.concat(chunks).toString("utf-8")));
12452
12452
  } catch {
12453
12453
  reject(new ApiError(400, "bad_request", "\u8BF7\u6C42\u4F53\u4E0D\u662F\u5408\u6CD5 JSON"));
12454
12454
  }
@@ -12759,7 +12759,25 @@ function createApp(store, manager, opts = {}) {
12759
12759
  ok(res, opts.fleet.status());
12760
12760
  }
12761
12761
  },
12762
- // 运行时热接入:凭一次性注册码接入 Hub(落盘 fleet.json + 立即连接,免重启)
12762
+ // 修改本机节点显示名:写本地配置并立即上报;已接入 Hub 时同步 Hub 记录。
12763
+ // `zqagent rename` 在有 server 在跑时走这里(热生效,免重启)。
12764
+ {
12765
+ method: "POST",
12766
+ pattern: ["fleet", "label"],
12767
+ adminOnly: true,
12768
+ fn: async (_req, res, { body }) => {
12769
+ if (!opts.fleet) {
12770
+ throw new ApiError(503, "fleet_disabled", "\u8282\u70B9\u7BA1\u7406\u63A7\u5236\u5668\u672A\u542F\u7528");
12771
+ }
12772
+ const raw = body ?? {};
12773
+ const label2 = typeof raw.label === "string" ? raw.label.trim() : "";
12774
+ if (!label2) {
12775
+ throw new ApiError(400, "bad_request", "label \u4E0D\u80FD\u4E3A\u7A7A");
12776
+ }
12777
+ ok(res, await opts.fleet.rename(label2));
12778
+ }
12779
+ },
12780
+ // 运行时热接入:凭一次性注册码或 Hub 账号接入(落盘 fleet.json + 立即连接,免重启)
12763
12781
  {
12764
12782
  method: "POST",
12765
12783
  pattern: ["fleet", "enroll"],
@@ -12771,15 +12789,42 @@ function createApp(store, manager, opts = {}) {
12771
12789
  const raw = body ?? {};
12772
12790
  const hubUrl2 = String(raw.hubUrl ?? "").trim().replace(/\/$/, "");
12773
12791
  const code = String(raw.code ?? "").trim();
12774
- if (!hubUrl2 || !code) {
12775
- throw new ApiError(400, "bad_request", "hubUrl \u4E0E code \u5FC5\u586B");
12792
+ const email = String(raw.email ?? "").trim();
12793
+ const phone = String(raw.phone ?? "").trim();
12794
+ const password = String(raw.password ?? "");
12795
+ const smsCode = String(raw.smsCode ?? "").trim();
12796
+ const hasAccount = Boolean(email || phone);
12797
+ if (!hubUrl2) {
12798
+ throw new ApiError(400, "bad_request", "hubUrl \u5FC5\u586B");
12799
+ }
12800
+ if (code && hasAccount) {
12801
+ throw new ApiError(400, "bad_request", "code \u4E0E\u8D26\u53F7\u51ED\u636E\u53EA\u80FD\u4E8C\u9009\u4E00");
12802
+ }
12803
+ if (!code && !hasAccount) {
12804
+ throw new ApiError(400, "bad_request", "\u9700\u8981 code\uFF0C\u6216 email/phone + password/smsCode");
12805
+ }
12806
+ if (hasAccount && !password && !smsCode) {
12807
+ throw new ApiError(400, "bad_request", "\u8D26\u53F7\u63A5\u5165\u9700\u8981 password \u6216 smsCode");
12776
12808
  }
12777
12809
  const label2 = typeof raw.label === "string" ? raw.label.trim() : void 0;
12778
12810
  try {
12779
- ok(res, await opts.fleet.enroll({ hubUrl: hubUrl2, code, label: label2 }));
12811
+ ok(
12812
+ res,
12813
+ await opts.fleet.enroll({
12814
+ hubUrl: hubUrl2,
12815
+ code: code || void 0,
12816
+ account: hasAccount ? {
12817
+ email: email || void 0,
12818
+ phone: phone || void 0,
12819
+ password: password || void 0,
12820
+ smsCode: smsCode || void 0
12821
+ } : void 0,
12822
+ label: label2
12823
+ })
12824
+ );
12780
12825
  } catch (e) {
12781
12826
  const code2 = e.code;
12782
- const status = code2 === "code_expired" ? 410 : code2 === "code_used" || code2 === "node_taken" ? 409 : code2 === "not_found" ? 404 : code2 === "plan_limit" || code2 === "subscription_required" ? 402 : 400;
12827
+ const status = code2 === "code_expired" ? 410 : code2 === "unauthorized" ? 401 : code2 === "account_disabled" ? 403 : code2 === "code_used" || code2 === "node_taken" ? 409 : code2 === "not_found" ? 404 : code2 === "plan_limit" || code2 === "subscription_required" ? 402 : 400;
12783
12828
  const msg = e instanceof Error ? e.message : String(e);
12784
12829
  throw new ApiError(
12785
12830
  status,
@@ -13925,10 +13970,10 @@ function createApp(store, manager, opts = {}) {
13925
13970
  function handle(req2, res) {
13926
13971
  const startedAt = Date.now();
13927
13972
  const url = new URL(req2.url ?? "/", "http://localhost");
13928
- const path36 = url.pathname;
13973
+ const path37 = url.pathname;
13929
13974
  const method = req2.method ?? "GET";
13930
13975
  console.log(
13931
- `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2192 ${method} ${path36}${url.search}`
13976
+ `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2192 ${method} ${path37}${url.search}`
13932
13977
  );
13933
13978
  let tenantId = null;
13934
13979
  let logged = false;
@@ -13936,7 +13981,7 @@ function createApp(store, manager, opts = {}) {
13936
13981
  if (logged) return;
13937
13982
  logged = true;
13938
13983
  console.log(
13939
- `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2190 ${method} ${path36} ${extra} (${Date.now() - startedAt}ms) tenant=${tenantId ?? "-"}`
13984
+ `[api] ${(/* @__PURE__ */ new Date()).toISOString()} \u2190 ${method} ${path37} ${extra} (${Date.now() - startedAt}ms) tenant=${tenantId ?? "-"}`
13940
13985
  );
13941
13986
  };
13942
13987
  res.on("finish", () => logDone(`HTTP ${res.statusCode}`));
@@ -13947,16 +13992,16 @@ function createApp(store, manager, opts = {}) {
13947
13992
  res.end();
13948
13993
  return;
13949
13994
  }
13950
- if (req2.method === "GET" && path36 === "/healthz") {
13995
+ if (req2.method === "GET" && path37 === "/healthz") {
13951
13996
  json(res, 200, {
13952
13997
  status: "ok",
13953
13998
  // 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
13954
- version: "0.2.11",
13999
+ version: "0.2.15",
13955
14000
  features: { mcp: hasServerMcpConfig() }
13956
14001
  });
13957
14002
  return;
13958
14003
  }
13959
- if (hubProxyEnabled(opts.host) && isHubProxyPath(path36)) {
14004
+ if (hubProxyEnabled(opts.host) && isHubProxyPath(path37)) {
13960
14005
  void handleHubProxy(req2, res).catch(() => {
13961
14006
  if (!res.headersSent) {
13962
14007
  res.writeHead(502, { "Content-Type": "application/json; charset=utf-8" });
@@ -13967,11 +14012,11 @@ function createApp(store, manager, opts = {}) {
13967
14012
  });
13968
14013
  return;
13969
14014
  }
13970
- if (!path36.startsWith(API_PREFIX)) {
14015
+ if (!path37.startsWith(API_PREFIX)) {
13971
14016
  json(res, 404, { error: { code: "not_found", message: "\u672A\u77E5\u8DEF\u5F84" } });
13972
14017
  return;
13973
14018
  }
13974
- const segs = path36.slice(API_PREFIX.length).split("/").filter(Boolean);
14019
+ const segs = path37.slice(API_PREFIX.length).split("/").filter(Boolean);
13975
14020
  const apiKey = extractApiKey(req2);
13976
14021
  if (!apiKey) {
13977
14022
  json(res, 401, {
@@ -14036,7 +14081,7 @@ function createApp(store, manager, opts = {}) {
14036
14081
  ).catch((err) => {
14037
14082
  const msg = err instanceof Error ? err.message : String(err);
14038
14083
  console.log(
14039
- `[api] ${(/* @__PURE__ */ new Date()).toISOString()} ! ${method} ${path36} ERROR: ${msg}`
14084
+ `[api] ${(/* @__PURE__ */ new Date()).toISOString()} ! ${method} ${path37} ERROR: ${msg}`
14040
14085
  );
14041
14086
  error(res, err);
14042
14087
  });
@@ -14067,8 +14112,8 @@ async function cachedFetchModels(baseURL, apiKey) {
14067
14112
  try {
14068
14113
  result = await Promise.race([
14069
14114
  fetchModels(baseURL, apiKey),
14070
- new Promise((resolve19) => {
14071
- const t = setTimeout(() => resolve19(null), MODEL_FETCH_TIMEOUT_MS);
14115
+ new Promise((resolve20) => {
14116
+ const t = setTimeout(() => resolve20(null), MODEL_FETCH_TIMEOUT_MS);
14072
14117
  t.unref?.();
14073
14118
  })
14074
14119
  ]);
@@ -14093,8 +14138,8 @@ async function cachedFetchModelsEnriched(baseURL, apiKey, preferred) {
14093
14138
  if (!target) return r;
14094
14139
  const ctx = await Promise.race([
14095
14140
  fetchModelContext(baseURL, apiKey, target),
14096
- new Promise((resolve19) => {
14097
- const t = setTimeout(() => resolve19(void 0), MODEL_FETCH_TIMEOUT_MS);
14141
+ new Promise((resolve20) => {
14142
+ const t = setTimeout(() => resolve20(void 0), MODEL_FETCH_TIMEOUT_MS);
14098
14143
  t.unref?.();
14099
14144
  })
14100
14145
  ]);
@@ -15288,13 +15333,13 @@ var EVENT_FLUSH_MAX_EVENTS = 60;
15288
15333
  var EVENT_FLUSH_MAX_BYTES = 200 * 1024;
15289
15334
  var LOOP_LAG_WARN_MS = 2e3;
15290
15335
  function withTimeout(p, ms) {
15291
- return new Promise((resolve19, reject) => {
15336
+ return new Promise((resolve20, reject) => {
15292
15337
  const timer = setTimeout(() => reject(new Error(`\u5B50\u6307\u4EE4\u8D85\u65F6\uFF08${ms}ms\uFF09`)), ms);
15293
15338
  timer.unref?.();
15294
15339
  p.then(
15295
15340
  (v) => {
15296
15341
  clearTimeout(timer);
15297
- resolve19(v);
15342
+ resolve20(v);
15298
15343
  },
15299
15344
  (e) => {
15300
15345
  clearTimeout(timer);
@@ -15645,6 +15690,11 @@ var FleetNodeBridge = class {
15645
15690
  refreshInfo() {
15646
15691
  this._publishInfo();
15647
15692
  }
15693
+ /** 本地改名后把 status(含 label)与 info 立即重发,控制台不必等下一次周期上报 */
15694
+ republishLabel() {
15695
+ this._send({ kind: "status", status: this._status(this.isConnected()) });
15696
+ this._publishInfo();
15697
+ }
15648
15698
  // ===================== 内部 =====================
15649
15699
  _status(online) {
15650
15700
  return {
@@ -15654,7 +15704,7 @@ var FleetNodeBridge = class {
15654
15704
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
15655
15705
  platform: process.platform,
15656
15706
  mode: process.env.NODE_MODE ?? "standalone",
15657
- version: "0.2.11",
15707
+ version: "0.2.15",
15658
15708
  ip: primaryIp()
15659
15709
  };
15660
15710
  }
@@ -15673,7 +15723,23 @@ var FleetNodeBridge = class {
15673
15723
  byDay: days
15674
15724
  };
15675
15725
  }
15726
+ /**
15727
+ * 上报 info(项目/会话快照)。
15728
+ *
15729
+ * 失败必须留痕:这是控制台「项目列表」的唯一数据源,静默失败会表现为
15730
+ * 「这台节点永远没有任何项目」,且只能靠网关 detail=null 才发现。
15731
+ * 同时用 try 包住,避免一次读盘异常中断 `_onUp` 后续的状态通知。
15732
+ */
15676
15733
  _publishInfo() {
15734
+ try {
15735
+ this._publishInfoNow();
15736
+ } catch (e) {
15737
+ console.warn(
15738
+ `[fleet] \u8282\u70B9 ${this.nodeId} \u4E0A\u62A5 info \u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`
15739
+ );
15740
+ }
15741
+ }
15742
+ _publishInfoNow() {
15677
15743
  const totals = { projects: 0, sessions: 0, running: 0, waiting: 0 };
15678
15744
  const sessions = [];
15679
15745
  const projects = allProjectSummaries(this.opts.deps.store).map((p) => {
@@ -15700,7 +15766,15 @@ var FleetNodeBridge = class {
15700
15766
  totals.sessions += p.sessionCount;
15701
15767
  totals.running += running;
15702
15768
  totals.waiting += waiting;
15703
- return { id: p.id, name: p.name, sessionCount: p.sessionCount, running, waiting };
15769
+ return {
15770
+ id: p.id,
15771
+ name: p.name,
15772
+ sessionCount: p.sessionCount,
15773
+ running,
15774
+ waiting,
15775
+ // 控制台项目列表要展示工作目录(Hub 落盘快照后即可离线查看)
15776
+ workspaceRoot: p.workspaceRoot ?? null
15777
+ };
15704
15778
  });
15705
15779
  this._send({
15706
15780
  kind: "info",
@@ -15709,7 +15783,7 @@ var FleetNodeBridge = class {
15709
15783
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
15710
15784
  platform: process.platform,
15711
15785
  mode: process.env.NODE_MODE ?? "standalone",
15712
- version: "0.2.11",
15786
+ version: "0.2.15",
15713
15787
  ip: primaryIp(),
15714
15788
  projects,
15715
15789
  totals,
@@ -15919,6 +15993,14 @@ function resolveFleetConfig(store) {
15919
15993
  return fleetConfigFromEnv(store);
15920
15994
  }
15921
15995
 
15996
+ // src/node-name.ts
15997
+ init_esm_shims();
15998
+ import * as os8 from "os";
15999
+ function defaultNodeLabel() {
16000
+ const name = os8.hostname().trim();
16001
+ return name || "zqagent-node";
16002
+ }
16003
+
15922
16004
  // src/server/notify/index.ts
15923
16005
  init_esm_shims();
15924
16006
 
@@ -17124,13 +17206,13 @@ var baseUrlResolver = null;
17124
17206
  function resolveBase(baseUrl) {
17125
17207
  return baseUrlResolver ? baseUrlResolver(baseUrl) : baseUrl;
17126
17208
  }
17127
- async function req(baseUrl, token, path36, init = {}) {
17209
+ async function req(baseUrl, token, path37, init = {}) {
17128
17210
  const headers = {
17129
17211
  ...init.body ? { "Content-Type": "application/json" } : {},
17130
17212
  ...init.headers ?? {}
17131
17213
  };
17132
17214
  if (token) headers.Authorization = `Bearer ${token}`;
17133
- const res = await fetch(`${resolveBase(baseUrl).replace(/\/$/, "")}${path36}`, {
17215
+ const res = await fetch(`${resolveBase(baseUrl).replace(/\/$/, "")}${path37}`, {
17134
17216
  ...init,
17135
17217
  headers
17136
17218
  });
@@ -17169,6 +17251,12 @@ async function hubEnrollByAccount(baseUrl, input) {
17169
17251
  });
17170
17252
  return { hubUrl: baseUrl.replace(/\/$/, ""), ...data };
17171
17253
  }
17254
+ async function hubUpdateNodeLabelSelf(baseUrl, fleetToken, input) {
17255
+ return await req(baseUrl, fleetToken, "/api/hub/nodes/self/label", {
17256
+ method: "POST",
17257
+ body: JSON.stringify(input)
17258
+ });
17259
+ }
17172
17260
 
17173
17261
  // src/update/controller.ts
17174
17262
  init_esm_shims();
@@ -17428,12 +17516,12 @@ function selfCheck(binPath, expectedVersion) {
17428
17516
  // src/update/platform.ts
17429
17517
  init_esm_shims();
17430
17518
  import * as fs25 from "fs";
17431
- import * as os8 from "os";
17519
+ import * as os9 from "os";
17432
17520
  import * as path30 from "path";
17433
17521
  import { spawnSync as spawnSync3 } from "child_process";
17434
17522
  import { createRequire as createRequire3 } from "module";
17435
17523
  function currentVersion() {
17436
- const injected = "0.2.11"?.trim();
17524
+ const injected = "0.2.15"?.trim();
17437
17525
  if (injected) return injected;
17438
17526
  try {
17439
17527
  const req2 = createRequire3(import.meta.url);
@@ -17471,7 +17559,7 @@ function launchdPlistPath() {
17471
17559
  const label2 = launchdLabel();
17472
17560
  const uid = typeof process.getuid === "function" ? process.getuid() : -1;
17473
17561
  if (uid === 0) return `/Library/LaunchDaemons/${label2}.plist`;
17474
- return path30.join(os8.homedir(), "Library", "LaunchAgents", `${label2}.plist`);
17562
+ return path30.join(os9.homedir(), "Library", "LaunchAgents", `${label2}.plist`);
17475
17563
  }
17476
17564
  function serviceManagerFromLaunchctl(output, pid, execPath, sea = true) {
17477
17565
  const pidMatch = /^\s*pid = (\d+)\s*$/m.exec(output);
@@ -17960,11 +18048,11 @@ var UpdateController = class {
17960
18048
  const minUptime = num("ZQAGENT_UPDATE_MIN_UPTIME_MS", 10 * 60 * 1e3);
17961
18049
  const idleMs = num("ZQAGENT_UPDATE_IDLE_MS", 60 * 1e3);
17962
18050
  let idleSince = null;
17963
- return new Promise((resolve19) => {
18051
+ return new Promise((resolve20) => {
17964
18052
  const timer = setInterval(() => {
17965
18053
  if (this.stopped) {
17966
18054
  clearInterval(timer);
17967
- resolve19(false);
18055
+ resolve20(false);
17968
18056
  return;
17969
18057
  }
17970
18058
  if (Date.now() - this.startedAt < minUptime || !this.opts.isIdle()) {
@@ -17974,7 +18062,7 @@ var UpdateController = class {
17974
18062
  idleSince ??= Date.now();
17975
18063
  if (Date.now() - idleSince >= idleMs) {
17976
18064
  clearInterval(timer);
17977
- resolve19(true);
18065
+ resolve20(true);
17978
18066
  }
17979
18067
  }, 1e3);
17980
18068
  timer.unref();
@@ -18157,7 +18245,7 @@ function exitWhenOrphaned() {
18157
18245
  }
18158
18246
  var PORT_FALLBACK_LIMIT = 20;
18159
18247
  function listenWithPortFallback(server, startPort, host, dataDir, limit = PORT_FALLBACK_LIMIT) {
18160
- return new Promise((resolve19, reject) => {
18248
+ return new Promise((resolve20, reject) => {
18161
18249
  let attempts = 0;
18162
18250
  const tryListen = (port) => {
18163
18251
  server.removeAllListeners("listening");
@@ -18189,7 +18277,7 @@ function listenWithPortFallback(server, startPort, host, dataDir, limit = PORT_F
18189
18277
  `);
18190
18278
  } catch {
18191
18279
  }
18192
- resolve19(actualPort);
18280
+ resolve20(actualPort);
18193
18281
  });
18194
18282
  };
18195
18283
  tryListen(startPort);
@@ -18267,7 +18355,7 @@ function startServer(opts = {}) {
18267
18355
  hubUrl: fleetCred?.hubUrl,
18268
18356
  gatewayUrl: fleetCred?.gatewayUrl ?? env2("FLEET_GATEWAY_URL"),
18269
18357
  online: fleet?.isConnected() ?? false,
18270
- label: fleetCred?.label,
18358
+ label: fleetCred?.label ?? store.loadNodeLabel() ?? void 0,
18271
18359
  lastError: fleet?.getLastError() ?? void 0,
18272
18360
  reconnectCount: fleet?.getErrorCount() ?? 0
18273
18361
  };
@@ -18276,20 +18364,53 @@ function startServer(opts = {}) {
18276
18364
  status: fleetStatus,
18277
18365
  async enroll(input) {
18278
18366
  const nodeId = ensureNodeId(store);
18279
- const cred = await hubEnrollByCode(input.hubUrl, {
18367
+ const label2 = input.label?.trim() || defaultNodeLabel();
18368
+ const cred = input.account ? await hubEnrollByAccount(input.hubUrl, {
18369
+ email: input.account.email,
18370
+ phone: input.account.phone,
18371
+ password: input.account.password,
18372
+ code: input.account.smsCode,
18373
+ nodeId,
18374
+ label: label2
18375
+ }) : await hubEnrollByCode(input.hubUrl, {
18280
18376
  code: input.code,
18281
18377
  nodeId,
18282
- label: input.label
18378
+ label: label2
18283
18379
  });
18284
18380
  const full = {
18285
18381
  ...cred,
18286
- label: input.label ?? cred.label,
18382
+ label: label2,
18287
18383
  enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
18288
18384
  };
18289
18385
  store.saveFleetCredential(full);
18386
+ store.saveNodeLabel(label2);
18290
18387
  connectFleet(full);
18291
18388
  return fleetStatus();
18292
18389
  },
18390
+ async rename(label2) {
18391
+ const name = label2.trim();
18392
+ store.saveNodeLabel(name);
18393
+ if (fleetCred) {
18394
+ fleetCred = { ...fleetCred, label: name };
18395
+ store.saveFleetCredential(fleetCred);
18396
+ }
18397
+ fleet?.republishLabel();
18398
+ let hubSynced = false;
18399
+ let hubError;
18400
+ const cred = fleetCred;
18401
+ if (cred?.hubUrl && cred.fleetToken) {
18402
+ try {
18403
+ await hubUpdateNodeLabelSelf(cred.hubUrl, cred.fleetToken, {
18404
+ nodeId: ensureNodeId(store),
18405
+ label: name
18406
+ });
18407
+ hubSynced = true;
18408
+ } catch (e) {
18409
+ hubError = e instanceof Error ? e.message : String(e);
18410
+ }
18411
+ }
18412
+ return { ...fleetStatus(), hubSynced, hubError };
18413
+ },
18293
18414
  unlink() {
18294
18415
  fleet?.close();
18295
18416
  fleet = null;
@@ -18420,7 +18541,7 @@ function startServer(opts = {}) {
18420
18541
  server.timeout = 0;
18421
18542
  server.keepAliveTimeout = 65e3;
18422
18543
  server.headersTimeout = 66e3;
18423
- const ready = new Promise((resolve19, reject) => {
18544
+ const ready = new Promise((resolve20, reject) => {
18424
18545
  listenWithPortFallback(server, port, host, dataDir).then((actualPort) => {
18425
18546
  const info = {
18426
18547
  host,
@@ -18437,7 +18558,7 @@ function startServer(opts = {}) {
18437
18558
  printReady(info, qq);
18438
18559
  }
18439
18560
  updater?.start();
18440
- resolve19(info);
18561
+ resolve20(info);
18441
18562
  }, reject);
18442
18563
  });
18443
18564
  return {
@@ -18487,39 +18608,12 @@ function parseHubAnswer(answer, fallback) {
18487
18608
  if (SKIP_ANSWERS.has(a.toLowerCase())) return null;
18488
18609
  return (a || fallback).replace(/\/$/, "");
18489
18610
  }
18490
- function resolveDataDir(dataDir) {
18491
- return path35.resolve(dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
18492
- }
18493
- async function maybeAccountEnroll(opts = {}) {
18494
- if (!process.stdin.isTTY || !process.stdout.isTTY) return;
18495
- let store;
18496
- try {
18497
- store = new Store(resolveDataDir(opts.dataDir));
18498
- if (resolveFleetConfig(store)) return;
18499
- } catch (e) {
18500
- cliErr(`\u63A5\u5165\u68C0\u67E5\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
18501
- return;
18502
- }
18503
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
18504
- try {
18505
- await runWizard(rl, store, opts);
18506
- } catch (e) {
18507
- cliErr(`\u63A5\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
18508
- cliLog(" \u53EF\u7A0D\u540E\u5728\u63A7\u5236\u53F0\u751F\u6210\u63A5\u5165\u7801\uFF0C\u518D\u6267\u884C\uFF1Azqagent link --hub <Hub\u5730\u5740> --code <\u63A5\u5165\u7801>");
18509
- } finally {
18510
- rl.close();
18511
- }
18512
- }
18513
- async function runWizard(rl, store, opts) {
18514
- cliLog("");
18515
- cliLog("\u672C\u673A\u5C1A\u672A\u63A5\u5165 Hub\u3002\u53EF\u7528 Hub \u8D26\u53F7\u63A5\u5165\uFF08\u8282\u70B9\u9ED8\u8BA4\u8FDB\u5165\u300C\u672A\u5206\u7EC4\u300D\uFF09\uFF1B\u8F93\u5165 - \u8DF3\u8FC7\u4FDD\u6301\u7EAF\u672C\u5730\u3002");
18516
- const fallback = resolveDefaultHub(opts.hubUrl);
18611
+ async function promptHubUrl(rl, hubUrl2) {
18612
+ const fallback = resolveDefaultHub(hubUrl2);
18517
18613
  const answer = await rl.question(`Hub \u5730\u5740 [${fallback}]\uFF1A`);
18518
- const hubUrl2 = parseHubAnswer(answer, fallback);
18519
- if (!hubUrl2) {
18520
- cliLog("\u5DF2\u8DF3\u8FC7\u63A5\u5165\uFF1A\u8282\u70B9\u4FDD\u6301\u7EAF\u672C\u5730\u8FD0\u884C\u3002");
18521
- return;
18522
- }
18614
+ return parseHubAnswer(answer, fallback);
18615
+ }
18616
+ async function promptAccountLogin(rl, hubUrl2) {
18523
18617
  cliLog("\u767B\u5F55\u65B9\u5F0F\uFF1A1) \u90AE\u7BB1 + \u5BC6\u7801 2) \u624B\u673A\u53F7 + \u5BC6\u7801 3) \u624B\u673A\u53F7 + \u77ED\u4FE1\u9A8C\u8BC1\u7801");
18524
18618
  const mode = (await rl.question("\u8BF7\u9009\u62E9 [1]\uFF1A")).trim() || "1";
18525
18619
  const input = {};
@@ -18528,53 +18622,107 @@ async function runWizard(rl, store, opts) {
18528
18622
  input.password = await askHidden(rl, "\u5BC6\u7801\uFF1A");
18529
18623
  if (!input.email || !input.password) {
18530
18624
  cliErr("\u90AE\u7BB1\u4E0E\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
18531
- return;
18625
+ return null;
18532
18626
  }
18533
18627
  } else if (mode === "2") {
18534
18628
  input.phone = (await rl.question("\u624B\u673A\u53F7\uFF1A")).trim();
18535
18629
  input.password = await askHidden(rl, "\u5BC6\u7801\uFF1A");
18536
18630
  if (!input.phone || !input.password) {
18537
18631
  cliErr("\u624B\u673A\u53F7\u4E0E\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
18538
- return;
18632
+ return null;
18539
18633
  }
18540
18634
  } else if (mode === "3") {
18541
18635
  input.phone = (await rl.question("\u624B\u673A\u53F7\uFF1A")).trim();
18542
18636
  if (!input.phone) {
18543
18637
  cliErr("\u624B\u673A\u53F7\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
18544
- return;
18638
+ return null;
18545
18639
  }
18546
18640
  try {
18547
- const sent = await hubSendSms(hubUrl2, { phone: input.phone, purpose: "login" });
18641
+ const sent = await hubSendSms(resolveDefaultHub(hubUrl2), {
18642
+ phone: input.phone,
18643
+ purpose: "login"
18644
+ });
18548
18645
  if (sent.debugCode) cliLog(`\uFF08\u8C03\u8BD5\u6A21\u5F0F\u9A8C\u8BC1\u7801\uFF1A${sent.debugCode}\uFF09`);
18549
18646
  else cliLog("\u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001\uFF0C5 \u5206\u949F\u5185\u6709\u6548\u3002");
18550
18647
  } catch (e) {
18551
18648
  cliErr(`\u77ED\u4FE1\u9A8C\u8BC1\u7801\u53D1\u9001\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
18552
18649
  cliLog(" \u53EF\u6539\u7528\u65B9\u5F0F 1/2\uFF08\u5BC6\u7801\u767B\u5F55\uFF09\uFF0C\u6216\u5728\u7F51\u9875\u7AEF\u751F\u6210\u63A5\u5165\u7801\u540E\u6267\u884C\uFF1A");
18553
18650
  cliLog(" zqagent link --hub <Hub\u5730\u5740> --code <\u63A5\u5165\u7801>");
18554
- return;
18651
+ return null;
18555
18652
  }
18556
18653
  input.code = (await rl.question("\u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF1A")).trim();
18557
18654
  if (!input.code) {
18558
18655
  cliErr("\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
18559
- return;
18656
+ return null;
18560
18657
  }
18561
18658
  } else {
18562
18659
  cliErr("\u672A\u77E5\u7684\u767B\u5F55\u65B9\u5F0F\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
18660
+ return null;
18661
+ }
18662
+ return input;
18663
+ }
18664
+ async function promptLinkAccount(rl, hubUrl2, opts = {}) {
18665
+ const fallback = resolveDefaultHub(hubUrl2);
18666
+ let resolved = fallback;
18667
+ if (opts.askHub !== false) {
18668
+ const answer = await promptHubUrl(rl, fallback);
18669
+ if (!answer) {
18670
+ cliLog("\u5DF2\u8DF3\u8FC7\u63A5\u5165\uFF1A\u8282\u70B9\u4FDD\u6301\u7EAF\u672C\u5730\u8FD0\u884C\u3002");
18671
+ return null;
18672
+ }
18673
+ resolved = answer;
18674
+ }
18675
+ const auth = await promptAccountLogin(rl, resolved);
18676
+ if (!auth) return null;
18677
+ return { hubUrl: resolved, auth };
18678
+ }
18679
+ function resolveDataDir(dataDir) {
18680
+ return path35.resolve(dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
18681
+ }
18682
+ async function maybeAccountEnroll(opts = {}) {
18683
+ if (!process.stdin.isTTY || !process.stdout.isTTY) return;
18684
+ let store;
18685
+ try {
18686
+ store = new Store(resolveDataDir(opts.dataDir));
18687
+ if (resolveFleetConfig(store)) return;
18688
+ } catch (e) {
18689
+ cliErr(`\u63A5\u5165\u68C0\u67E5\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
18563
18690
  return;
18564
18691
  }
18692
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
18693
+ try {
18694
+ await runWizard(rl, store, opts);
18695
+ } catch (e) {
18696
+ cliErr(`\u63A5\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
18697
+ cliLog(" \u53EF\u7A0D\u540E\u5728\u63A7\u5236\u53F0\u751F\u6210\u63A5\u5165\u7801\uFF0C\u518D\u6267\u884C\uFF1Azqagent link --hub <Hub\u5730\u5740> --code <\u63A5\u5165\u7801>");
18698
+ } finally {
18699
+ rl.close();
18700
+ }
18701
+ }
18702
+ async function runWizard(rl, store, opts) {
18703
+ cliLog("");
18704
+ cliLog("\u672C\u673A\u5C1A\u672A\u63A5\u5165 Hub\u3002\u53EF\u7528 Hub \u8D26\u53F7\u63A5\u5165\uFF08\u8282\u70B9\u9ED8\u8BA4\u8FDB\u5165\u300C\u672A\u5206\u7EC4\u300D\uFF09\uFF1B\u8F93\u5165 - \u8DF3\u8FC7\u4FDD\u6301\u7EAF\u672C\u5730\u3002");
18705
+ const prompted = await promptLinkAccount(rl, opts.hubUrl);
18706
+ if (!prompted) return;
18565
18707
  const nodeId = ensureNodeId(store);
18566
- const cred = await hubEnrollByAccount(hubUrl2, { ...input, nodeId, label: opts.label });
18708
+ const label2 = opts.label?.trim() || defaultNodeLabel();
18709
+ const cred = await hubEnrollByAccount(prompted.hubUrl, {
18710
+ ...prompted.auth,
18711
+ nodeId,
18712
+ label: label2
18713
+ });
18567
18714
  store.saveFleetCredential({
18568
18715
  ...cred,
18569
- label: opts.label ?? cred.label,
18716
+ label: label2,
18570
18717
  enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
18571
18718
  });
18719
+ store.saveNodeLabel(label2);
18572
18720
  cliLog(`\u2705 \u5DF2\u63A5\u5165 Hub\uFF1A\u8282\u70B9 ${cred.nodeId}\uFF08\u7F51\u5173 ${cred.gatewayUrl ?? "\u672A\u4E0B\u53D1"}\uFF09`);
18573
18721
  cliLog(" \u51ED\u636E\u5DF2\u4FDD\u5B58\u5230 fleet.json\uFF0C\u672C\u6B21\u542F\u52A8\u5373\u8FDE\u63A5 Hub\u3002");
18574
18722
  }
18575
18723
  async function askHidden(rl, prompt) {
18576
18724
  if (!process.stdin.isTTY) return (await rl.question(prompt)).trim();
18577
- return new Promise((resolve19) => {
18725
+ return new Promise((resolve20) => {
18578
18726
  const saved = process.stdin.listeners("data");
18579
18727
  process.stdin.removeAllListeners("data");
18580
18728
  cliWrite(prompt);
@@ -18596,13 +18744,13 @@ async function askHidden(rl, prompt) {
18596
18744
  if (ch === "\r" || ch === "\n") {
18597
18745
  cleanup();
18598
18746
  cliWrite("\n");
18599
- resolve19(buf);
18747
+ resolve20(buf);
18600
18748
  return;
18601
18749
  }
18602
18750
  if (ch === "") {
18603
18751
  cleanup();
18604
18752
  cliWrite("\n");
18605
- resolve19("");
18753
+ resolve20("");
18606
18754
  return;
18607
18755
  }
18608
18756
  if (ch === "\x7F" || ch === "\b") {
@@ -18620,6 +18768,40 @@ async function askHidden(rl, prompt) {
18620
18768
  });
18621
18769
  }
18622
18770
 
18771
+ // src/cli/link.ts
18772
+ init_esm_shims();
18773
+ import * as readline2 from "readline";
18774
+
18775
+ // src/cli/serve-instances.ts
18776
+ init_esm_shims();
18777
+ import { spawnSync as spawnSync4 } from "child_process";
18778
+ import * as fs30 from "fs";
18779
+ import * as os10 from "os";
18780
+ import * as path36 from "path";
18781
+
18782
+ // src/cli/link.ts
18783
+ function buildAccountAuth(flags, env3 = process.env) {
18784
+ const username = (flags.username ?? env3.ZQAGENT_HUB_USERNAME ?? "").trim();
18785
+ let email = (flags.email ?? "").trim();
18786
+ let phone = (flags.phone ?? "").trim();
18787
+ if (username && !email && !phone) {
18788
+ if (username.includes("@")) email = username;
18789
+ else phone = username;
18790
+ }
18791
+ if (!email && !phone) return null;
18792
+ const password = flags.password ?? env3.ZQAGENT_HUB_PASSWORD ?? "";
18793
+ const smsCode = (flags.smsCode ?? env3.ZQAGENT_HUB_SMS_CODE ?? "").trim();
18794
+ return {
18795
+ email: email ? email.toLowerCase() : void 0,
18796
+ phone: phone || void 0,
18797
+ password: password || void 0,
18798
+ smsCode: smsCode || void 0
18799
+ };
18800
+ }
18801
+ function isCompleteAccount(account2) {
18802
+ return Boolean(account2 && (account2.password || account2.smsCode));
18803
+ }
18804
+
18623
18805
  // src/server/index.ts
18624
18806
  function arg(name) {
18625
18807
  const i = process.argv.indexOf(`--${name}`);
@@ -18628,13 +18810,22 @@ function arg(name) {
18628
18810
  var hubUrl = (arg("hub") ?? process.env.HUB_URL ?? "").trim();
18629
18811
  var enrollCode = (arg("enroll-code") ?? process.env.HUB_ENROLL_CODE ?? "").trim();
18630
18812
  var label = arg("label")?.trim();
18631
- void maybeAccountEnroll({ dataDir: arg("data-dir"), hubUrl: arg("hub"), label }).finally(() => {
18813
+ var account = buildAccountAuth({
18814
+ username: arg("username") ?? arg("user"),
18815
+ email: arg("email"),
18816
+ phone: arg("phone"),
18817
+ password: arg("password"),
18818
+ smsCode: arg("sms-code")
18819
+ });
18820
+ var autoEnroll = hubUrl && enrollCode ? { hubUrl, code: enrollCode, label } : hubUrl && isCompleteAccount(account) ? { hubUrl, account, label } : null;
18821
+ var beforeStart = autoEnroll ? Promise.resolve() : maybeAccountEnroll({ dataDir: arg("data-dir"), hubUrl: arg("hub"), label });
18822
+ void beforeStart.finally(() => {
18632
18823
  startServer({
18633
18824
  dataDir: arg("data-dir"),
18634
18825
  port: arg("port") ? Number(arg("port")) : void 0,
18635
18826
  host: arg("host"),
18636
- // 仅当两者齐备时启用「启动即接入」;已有 fleet.json 时会在 runtime 内被忽略
18637
- autoEnroll: hubUrl && enrollCode ? { hubUrl, code: enrollCode, label } : null,
18827
+ // 已有 fleet.json 时会在 runtime 内被忽略
18828
+ autoEnroll,
18638
18829
  autoUpdate: true
18639
18830
  });
18640
18831
  });