@clawos-dev/clawd 0.2.351 → 0.2.353

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.cjs CHANGED
@@ -450,8 +450,8 @@ var init_parseUtil = __esm({
450
450
  init_errors();
451
451
  init_en();
452
452
  makeIssue = (params) => {
453
- const { data, path: path81, errorMaps, issueData } = params;
454
- const fullPath = [...path81, ...issueData.path || []];
453
+ const { data, path: path82, errorMaps, issueData } = params;
454
+ const fullPath = [...path82, ...issueData.path || []];
455
455
  const fullIssue = {
456
456
  ...issueData,
457
457
  path: fullPath
@@ -762,11 +762,11 @@ var init_types = __esm({
762
762
  init_parseUtil();
763
763
  init_util();
764
764
  ParseInputLazyPath = class {
765
- constructor(parent, value, path81, key) {
765
+ constructor(parent, value, path82, key) {
766
766
  this._cachedPath = [];
767
767
  this.parent = parent;
768
768
  this.data = value;
769
- this._path = path81;
769
+ this._path = path82;
770
770
  this._key = key;
771
771
  }
772
772
  get path() {
@@ -6139,7 +6139,13 @@ var init_feishu_auth = __esm({
6139
6139
  * 设备属性,与登录态无关、登录登出不变。UI"我的设备标识"用它拼
6140
6140
  * clawos://device/<deviceId>(替代旧的 unionId——不再向外暴露人的身份标识)。
6141
6141
  */
6142
- deviceId: external_exports.string().min(1)
6142
+ deviceId: external_exports.string().min(1),
6143
+ /**
6144
+ * TTC JWT 过期时间(unix ms)。null = 登录回调未携带 expires_at;字段缺省 = 老 daemon。
6145
+ * 仅时间戳——token 本体永不出 ws(spec §9 不变)。UI 据此派生 过期/临期 提示
6146
+ * (见 spec 2026-08-17-ttc-jwt-expiry-ux-design §2)。
6147
+ */
6148
+ ttcTokenExpiresAt: external_exports.number().nullable().optional()
6143
6149
  });
6144
6150
  AuthLogoutResponseSchema = external_exports.object({
6145
6151
  type: external_exports.literal("auth:logout:ok")
@@ -7012,6 +7018,10 @@ var init_schemas = __esm({
7012
7018
  effort: external_exports.string().optional(),
7013
7019
  // 归一化运行时观测字段(daemon 独立计算,session:update 不接受;meta_update 事件投递)
7014
7020
  ...sessionMetaShape,
7021
+ // daemon 生成智能标题的防重标记:reducer 在 meta_update.aiLabel 真变化时自动盖章
7022
+ // (observer ai-title 回灌与 daemon 自产两个生产者同路)。为空 = 还没生成过 →
7023
+ // manager.send 首条消息触发生成。session:update(外部 RPC)zod strip 不接受此字段。
7024
+ aiLabelGeneratedAt: external_exports.string().optional(),
7015
7025
  permissionRules: external_exports.array(AllowRuleSchema).optional(),
7016
7026
  // Sidebar 置顶时间戳;null/undefined 表示未置顶
7017
7027
  pinnedAt: external_exports.number().int().nonnegative().nullable().optional(),
@@ -8954,8 +8964,8 @@ var require_req = __commonJS({
8954
8964
  if (req.originalUrl) {
8955
8965
  _req.url = req.originalUrl;
8956
8966
  } else {
8957
- const path81 = req.path;
8958
- _req.url = typeof path81 === "string" ? path81 : req.url ? req.url.path || req.url : void 0;
8967
+ const path82 = req.path;
8968
+ _req.url = typeof path82 === "string" ? path82 : req.url ? req.url.path || req.url : void 0;
8959
8969
  }
8960
8970
  if (req.query) {
8961
8971
  _req.query = req.query;
@@ -9120,14 +9130,14 @@ var require_redact = __commonJS({
9120
9130
  }
9121
9131
  return obj;
9122
9132
  }
9123
- function parsePath(path81) {
9133
+ function parsePath(path82) {
9124
9134
  const parts = [];
9125
9135
  let current = "";
9126
9136
  let inBrackets = false;
9127
9137
  let inQuotes = false;
9128
9138
  let quoteChar = "";
9129
- for (let i = 0; i < path81.length; i++) {
9130
- const char = path81[i];
9139
+ for (let i = 0; i < path82.length; i++) {
9140
+ const char = path82[i];
9131
9141
  if (!inBrackets && char === ".") {
9132
9142
  if (current) {
9133
9143
  parts.push(current);
@@ -9258,10 +9268,10 @@ var require_redact = __commonJS({
9258
9268
  return current;
9259
9269
  }
9260
9270
  function redactPaths(obj, paths, censor, remove = false) {
9261
- for (const path81 of paths) {
9262
- const parts = parsePath(path81);
9271
+ for (const path82 of paths) {
9272
+ const parts = parsePath(path82);
9263
9273
  if (parts.includes("*")) {
9264
- redactWildcardPath(obj, parts, censor, path81, remove);
9274
+ redactWildcardPath(obj, parts, censor, path82, remove);
9265
9275
  } else {
9266
9276
  if (remove) {
9267
9277
  removeKey(obj, parts);
@@ -9346,8 +9356,8 @@ var require_redact = __commonJS({
9346
9356
  }
9347
9357
  } else {
9348
9358
  if (afterWildcard.includes("*")) {
9349
- const wrappedCensor = typeof censor === "function" ? (value, path81) => {
9350
- const fullPath = [...pathArray.slice(0, pathLength), ...path81];
9359
+ const wrappedCensor = typeof censor === "function" ? (value, path82) => {
9360
+ const fullPath = [...pathArray.slice(0, pathLength), ...path82];
9351
9361
  return censor(value, fullPath);
9352
9362
  } : censor;
9353
9363
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -9382,8 +9392,8 @@ var require_redact = __commonJS({
9382
9392
  return null;
9383
9393
  }
9384
9394
  const pathStructure = /* @__PURE__ */ new Map();
9385
- for (const path81 of pathsToClone) {
9386
- const parts = parsePath(path81);
9395
+ for (const path82 of pathsToClone) {
9396
+ const parts = parsePath(path82);
9387
9397
  let current = pathStructure;
9388
9398
  for (let i = 0; i < parts.length; i++) {
9389
9399
  const part = parts[i];
@@ -9435,24 +9445,24 @@ var require_redact = __commonJS({
9435
9445
  }
9436
9446
  return cloneSelectively(obj, pathStructure);
9437
9447
  }
9438
- function validatePath(path81) {
9439
- if (typeof path81 !== "string") {
9448
+ function validatePath(path82) {
9449
+ if (typeof path82 !== "string") {
9440
9450
  throw new Error("Paths must be (non-empty) strings");
9441
9451
  }
9442
- if (path81 === "") {
9452
+ if (path82 === "") {
9443
9453
  throw new Error("Invalid redaction path ()");
9444
9454
  }
9445
- if (path81.includes("..")) {
9446
- throw new Error(`Invalid redaction path (${path81})`);
9455
+ if (path82.includes("..")) {
9456
+ throw new Error(`Invalid redaction path (${path82})`);
9447
9457
  }
9448
- if (path81.includes(",")) {
9449
- throw new Error(`Invalid redaction path (${path81})`);
9458
+ if (path82.includes(",")) {
9459
+ throw new Error(`Invalid redaction path (${path82})`);
9450
9460
  }
9451
9461
  let bracketCount = 0;
9452
9462
  let inQuotes = false;
9453
9463
  let quoteChar = "";
9454
- for (let i = 0; i < path81.length; i++) {
9455
- const char = path81[i];
9464
+ for (let i = 0; i < path82.length; i++) {
9465
+ const char = path82[i];
9456
9466
  if ((char === '"' || char === "'") && bracketCount > 0) {
9457
9467
  if (!inQuotes) {
9458
9468
  inQuotes = true;
@@ -9466,20 +9476,20 @@ var require_redact = __commonJS({
9466
9476
  } else if (char === "]" && !inQuotes) {
9467
9477
  bracketCount--;
9468
9478
  if (bracketCount < 0) {
9469
- throw new Error(`Invalid redaction path (${path81})`);
9479
+ throw new Error(`Invalid redaction path (${path82})`);
9470
9480
  }
9471
9481
  }
9472
9482
  }
9473
9483
  if (bracketCount !== 0) {
9474
- throw new Error(`Invalid redaction path (${path81})`);
9484
+ throw new Error(`Invalid redaction path (${path82})`);
9475
9485
  }
9476
9486
  }
9477
9487
  function validatePaths(paths) {
9478
9488
  if (!Array.isArray(paths)) {
9479
9489
  throw new TypeError("paths must be an array");
9480
9490
  }
9481
- for (const path81 of paths) {
9482
- validatePath(path81);
9491
+ for (const path82 of paths) {
9492
+ validatePath(path82);
9483
9493
  }
9484
9494
  }
9485
9495
  function slowRedact(options = {}) {
@@ -9647,8 +9657,8 @@ var require_redaction = __commonJS({
9647
9657
  if (shape[k2] === null) {
9648
9658
  o[k2] = (value) => topCensor(value, [k2]);
9649
9659
  } else {
9650
- const wrappedCensor = typeof censor === "function" ? (value, path81) => {
9651
- return censor(value, [k2, ...path81]);
9660
+ const wrappedCensor = typeof censor === "function" ? (value, path82) => {
9661
+ return censor(value, [k2, ...path82]);
9652
9662
  } : censor;
9653
9663
  o[k2] = Redact({
9654
9664
  paths: shape[k2],
@@ -9866,10 +9876,10 @@ var require_atomic_sleep = __commonJS({
9866
9876
  var require_sonic_boom = __commonJS({
9867
9877
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
9868
9878
  "use strict";
9869
- var fs72 = require("fs");
9879
+ var fs73 = require("fs");
9870
9880
  var EventEmitter3 = require("events");
9871
9881
  var inherits = require("util").inherits;
9872
- var path81 = require("path");
9882
+ var path82 = require("path");
9873
9883
  var sleep2 = require_atomic_sleep();
9874
9884
  var assert = require("assert");
9875
9885
  var BUSY_WRITE_TIMEOUT = 100;
@@ -9923,20 +9933,20 @@ var require_sonic_boom = __commonJS({
9923
9933
  const mode = sonic.mode;
9924
9934
  if (sonic.sync) {
9925
9935
  try {
9926
- if (sonic.mkdir) fs72.mkdirSync(path81.dirname(file), { recursive: true });
9927
- const fd = fs72.openSync(file, flags, mode);
9936
+ if (sonic.mkdir) fs73.mkdirSync(path82.dirname(file), { recursive: true });
9937
+ const fd = fs73.openSync(file, flags, mode);
9928
9938
  fileOpened(null, fd);
9929
9939
  } catch (err) {
9930
9940
  fileOpened(err);
9931
9941
  throw err;
9932
9942
  }
9933
9943
  } else if (sonic.mkdir) {
9934
- fs72.mkdir(path81.dirname(file), { recursive: true }, (err) => {
9944
+ fs73.mkdir(path82.dirname(file), { recursive: true }, (err) => {
9935
9945
  if (err) return fileOpened(err);
9936
- fs72.open(file, flags, mode, fileOpened);
9946
+ fs73.open(file, flags, mode, fileOpened);
9937
9947
  });
9938
9948
  } else {
9939
- fs72.open(file, flags, mode, fileOpened);
9949
+ fs73.open(file, flags, mode, fileOpened);
9940
9950
  }
9941
9951
  }
9942
9952
  function SonicBoom(opts) {
@@ -9977,8 +9987,8 @@ var require_sonic_boom = __commonJS({
9977
9987
  this.flush = flushBuffer;
9978
9988
  this.flushSync = flushBufferSync;
9979
9989
  this._actualWrite = actualWriteBuffer;
9980
- fsWriteSync = () => fs72.writeSync(this.fd, this._writingBuf);
9981
- fsWrite = () => fs72.write(this.fd, this._writingBuf, this.release);
9990
+ fsWriteSync = () => fs73.writeSync(this.fd, this._writingBuf);
9991
+ fsWrite = () => fs73.write(this.fd, this._writingBuf, this.release);
9982
9992
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
9983
9993
  this._writingBuf = "";
9984
9994
  this.write = write;
@@ -9987,15 +9997,15 @@ var require_sonic_boom = __commonJS({
9987
9997
  this._actualWrite = actualWrite;
9988
9998
  fsWriteSync = () => {
9989
9999
  if (Buffer.isBuffer(this._writingBuf)) {
9990
- return fs72.writeSync(this.fd, this._writingBuf);
10000
+ return fs73.writeSync(this.fd, this._writingBuf);
9991
10001
  }
9992
- return fs72.writeSync(this.fd, this._writingBuf, "utf8");
10002
+ return fs73.writeSync(this.fd, this._writingBuf, "utf8");
9993
10003
  };
9994
10004
  fsWrite = () => {
9995
10005
  if (Buffer.isBuffer(this._writingBuf)) {
9996
- return fs72.write(this.fd, this._writingBuf, this.release);
10006
+ return fs73.write(this.fd, this._writingBuf, this.release);
9997
10007
  }
9998
- return fs72.write(this.fd, this._writingBuf, "utf8", this.release);
10008
+ return fs73.write(this.fd, this._writingBuf, "utf8", this.release);
9999
10009
  };
10000
10010
  } else {
10001
10011
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -10052,7 +10062,7 @@ var require_sonic_boom = __commonJS({
10052
10062
  }
10053
10063
  }
10054
10064
  if (this._fsync) {
10055
- fs72.fsyncSync(this.fd);
10065
+ fs73.fsyncSync(this.fd);
10056
10066
  }
10057
10067
  const len = this._len;
10058
10068
  if (this._reopening) {
@@ -10166,7 +10176,7 @@ var require_sonic_boom = __commonJS({
10166
10176
  const onDrain = () => {
10167
10177
  if (!this._fsync) {
10168
10178
  try {
10169
- fs72.fsync(this.fd, (err) => {
10179
+ fs73.fsync(this.fd, (err) => {
10170
10180
  this._flushPending = false;
10171
10181
  cb(err);
10172
10182
  });
@@ -10268,7 +10278,7 @@ var require_sonic_boom = __commonJS({
10268
10278
  const fd = this.fd;
10269
10279
  this.once("ready", () => {
10270
10280
  if (fd !== this.fd) {
10271
- fs72.close(fd, (err) => {
10281
+ fs73.close(fd, (err) => {
10272
10282
  if (err) {
10273
10283
  return this.emit("error", err);
10274
10284
  }
@@ -10317,7 +10327,7 @@ var require_sonic_boom = __commonJS({
10317
10327
  buf = this._bufs[0];
10318
10328
  }
10319
10329
  try {
10320
- const n = Buffer.isBuffer(buf) ? fs72.writeSync(this.fd, buf) : fs72.writeSync(this.fd, buf, "utf8");
10330
+ const n = Buffer.isBuffer(buf) ? fs73.writeSync(this.fd, buf) : fs73.writeSync(this.fd, buf, "utf8");
10321
10331
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
10322
10332
  buf = releasedBufObj.writingBuf;
10323
10333
  this._len = releasedBufObj.len;
@@ -10333,7 +10343,7 @@ var require_sonic_boom = __commonJS({
10333
10343
  }
10334
10344
  }
10335
10345
  try {
10336
- fs72.fsyncSync(this.fd);
10346
+ fs73.fsyncSync(this.fd);
10337
10347
  } catch {
10338
10348
  }
10339
10349
  }
@@ -10354,7 +10364,7 @@ var require_sonic_boom = __commonJS({
10354
10364
  buf = mergeBuf(this._bufs[0], this._lens[0]);
10355
10365
  }
10356
10366
  try {
10357
- const n = fs72.writeSync(this.fd, buf);
10367
+ const n = fs73.writeSync(this.fd, buf);
10358
10368
  buf = buf.subarray(n);
10359
10369
  this._len = Math.max(this._len - n, 0);
10360
10370
  if (buf.length <= 0) {
@@ -10382,13 +10392,13 @@ var require_sonic_boom = __commonJS({
10382
10392
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
10383
10393
  if (this.sync) {
10384
10394
  try {
10385
- const written = Buffer.isBuffer(this._writingBuf) ? fs72.writeSync(this.fd, this._writingBuf) : fs72.writeSync(this.fd, this._writingBuf, "utf8");
10395
+ const written = Buffer.isBuffer(this._writingBuf) ? fs73.writeSync(this.fd, this._writingBuf) : fs73.writeSync(this.fd, this._writingBuf, "utf8");
10386
10396
  release(null, written);
10387
10397
  } catch (err) {
10388
10398
  release(err);
10389
10399
  }
10390
10400
  } else {
10391
- fs72.write(this.fd, this._writingBuf, release);
10401
+ fs73.write(this.fd, this._writingBuf, release);
10392
10402
  }
10393
10403
  }
10394
10404
  function actualWriteBuffer() {
@@ -10397,7 +10407,7 @@ var require_sonic_boom = __commonJS({
10397
10407
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
10398
10408
  if (this.sync) {
10399
10409
  try {
10400
- const written = fs72.writeSync(this.fd, this._writingBuf);
10410
+ const written = fs73.writeSync(this.fd, this._writingBuf);
10401
10411
  release(null, written);
10402
10412
  } catch (err) {
10403
10413
  release(err);
@@ -10406,7 +10416,7 @@ var require_sonic_boom = __commonJS({
10406
10416
  if (kCopyBuffer) {
10407
10417
  this._writingBuf = Buffer.from(this._writingBuf);
10408
10418
  }
10409
- fs72.write(this.fd, this._writingBuf, release);
10419
+ fs73.write(this.fd, this._writingBuf, release);
10410
10420
  }
10411
10421
  }
10412
10422
  function actualClose(sonic) {
@@ -10422,12 +10432,12 @@ var require_sonic_boom = __commonJS({
10422
10432
  sonic._lens = [];
10423
10433
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
10424
10434
  try {
10425
- fs72.fsync(sonic.fd, closeWrapped);
10435
+ fs73.fsync(sonic.fd, closeWrapped);
10426
10436
  } catch {
10427
10437
  }
10428
10438
  function closeWrapped() {
10429
10439
  if (sonic.fd !== 1 && sonic.fd !== 2) {
10430
- fs72.close(sonic.fd, done);
10440
+ fs73.close(sonic.fd, done);
10431
10441
  } else {
10432
10442
  done();
10433
10443
  }
@@ -12791,7 +12801,7 @@ var require_multistream = __commonJS({
12791
12801
  var require_pino = __commonJS({
12792
12802
  "../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
12793
12803
  "use strict";
12794
- var os25 = require("os");
12804
+ var os26 = require("os");
12795
12805
  var stdSerializers = require_pino_std_serializers();
12796
12806
  var caller = require_caller();
12797
12807
  var redaction = require_redaction();
@@ -12838,7 +12848,7 @@ var require_pino = __commonJS({
12838
12848
  } = symbols;
12839
12849
  var { epochTime, nullTime } = time;
12840
12850
  var { pid } = process;
12841
- var hostname = os25.hostname();
12851
+ var hostname = os26.hostname();
12842
12852
  var defaultErrorSerializer = stdSerializers.err;
12843
12853
  var defaultOptions2 = {
12844
12854
  level: "info",
@@ -13562,11 +13572,11 @@ var init_lib = __esm({
13562
13572
  }
13563
13573
  }
13564
13574
  },
13565
- addToPath: function addToPath(path81, added, removed, oldPosInc, options) {
13566
- var last = path81.lastComponent;
13575
+ addToPath: function addToPath(path82, added, removed, oldPosInc, options) {
13576
+ var last = path82.lastComponent;
13567
13577
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
13568
13578
  return {
13569
- oldPos: path81.oldPos + oldPosInc,
13579
+ oldPos: path82.oldPos + oldPosInc,
13570
13580
  lastComponent: {
13571
13581
  count: last.count + 1,
13572
13582
  added,
@@ -13576,7 +13586,7 @@ var init_lib = __esm({
13576
13586
  };
13577
13587
  } else {
13578
13588
  return {
13579
- oldPos: path81.oldPos + oldPosInc,
13589
+ oldPos: path82.oldPos + oldPosInc,
13580
13590
  lastComponent: {
13581
13591
  count: 1,
13582
13592
  added,
@@ -14108,10 +14118,10 @@ function attachmentToHistoryMessage(o, ts) {
14108
14118
  const memories = raw.map((m2) => {
14109
14119
  if (!m2 || typeof m2 !== "object") return null;
14110
14120
  const rec4 = m2;
14111
- const path81 = typeof rec4.path === "string" ? rec4.path : null;
14121
+ const path82 = typeof rec4.path === "string" ? rec4.path : null;
14112
14122
  const content = typeof rec4.content === "string" ? rec4.content : null;
14113
- if (!path81 || content == null) return null;
14114
- const entry = { path: path81, content };
14123
+ if (!path82 || content == null) return null;
14124
+ const entry = { path: path82, content };
14115
14125
  if (typeof rec4.mtimeMs === "number") entry.mtimeMs = rec4.mtimeMs;
14116
14126
  return entry;
14117
14127
  }).filter((m2) => m2 !== null);
@@ -14945,10 +14955,10 @@ function parseAttachment(obj) {
14945
14955
  const memories = raw.map((m2) => {
14946
14956
  if (!m2 || typeof m2 !== "object") return null;
14947
14957
  const rec4 = m2;
14948
- const path81 = typeof rec4.path === "string" ? rec4.path : null;
14958
+ const path82 = typeof rec4.path === "string" ? rec4.path : null;
14949
14959
  const content = typeof rec4.content === "string" ? rec4.content : null;
14950
- if (!path81 || content == null) return null;
14951
- const out = { path: path81, content };
14960
+ if (!path82 || content == null) return null;
14961
+ const out = { path: path82, content };
14952
14962
  if (typeof rec4.mtimeMs === "number") out.mtimeMs = rec4.mtimeMs;
14953
14963
  return out;
14954
14964
  }).filter((m2) => m2 !== null);
@@ -35922,8 +35932,8 @@ var require_utils = __commonJS({
35922
35932
  var result = transform[inputType][outputType](input);
35923
35933
  return result;
35924
35934
  };
35925
- exports2.resolve = function(path81) {
35926
- var parts = path81.split("/");
35935
+ exports2.resolve = function(path82) {
35936
+ var parts = path82.split("/");
35927
35937
  var result = [];
35928
35938
  for (var index = 0; index < parts.length; index++) {
35929
35939
  var part = parts[index];
@@ -41776,18 +41786,18 @@ var require_object = __commonJS({
41776
41786
  var object = new ZipObject(name, zipObjectContent, o);
41777
41787
  this.files[name] = object;
41778
41788
  };
41779
- var parentFolder = function(path81) {
41780
- if (path81.slice(-1) === "/") {
41781
- path81 = path81.substring(0, path81.length - 1);
41789
+ var parentFolder = function(path82) {
41790
+ if (path82.slice(-1) === "/") {
41791
+ path82 = path82.substring(0, path82.length - 1);
41782
41792
  }
41783
- var lastSlash = path81.lastIndexOf("/");
41784
- return lastSlash > 0 ? path81.substring(0, lastSlash) : "";
41793
+ var lastSlash = path82.lastIndexOf("/");
41794
+ return lastSlash > 0 ? path82.substring(0, lastSlash) : "";
41785
41795
  };
41786
- var forceTrailingSlash = function(path81) {
41787
- if (path81.slice(-1) !== "/") {
41788
- path81 += "/";
41796
+ var forceTrailingSlash = function(path82) {
41797
+ if (path82.slice(-1) !== "/") {
41798
+ path82 += "/";
41789
41799
  }
41790
- return path81;
41800
+ return path82;
41791
41801
  };
41792
41802
  var folderAdd = function(name, createFolders) {
41793
41803
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -42789,7 +42799,7 @@ var require_lib3 = __commonJS({
42789
42799
  // src/run-case/recorder.ts
42790
42800
  function startRunCaseRecorder(opts) {
42791
42801
  const now = opts.now ?? Date.now;
42792
- const dir = import_node_path68.default.dirname(opts.recordPath);
42802
+ const dir = import_node_path69.default.dirname(opts.recordPath);
42793
42803
  let stream = null;
42794
42804
  let closing = false;
42795
42805
  let closedSettled = false;
@@ -42803,8 +42813,8 @@ function startRunCaseRecorder(opts) {
42803
42813
  });
42804
42814
  const ensureStream = () => {
42805
42815
  if (stream) return stream;
42806
- import_node_fs52.default.mkdirSync(dir, { recursive: true });
42807
- stream = import_node_fs52.default.createWriteStream(opts.recordPath, { flags: "a" });
42816
+ import_node_fs53.default.mkdirSync(dir, { recursive: true });
42817
+ stream = import_node_fs53.default.createWriteStream(opts.recordPath, { flags: "a" });
42808
42818
  stream.on("close", () => closedResolve());
42809
42819
  return stream;
42810
42820
  };
@@ -42829,12 +42839,12 @@ function startRunCaseRecorder(opts) {
42829
42839
  };
42830
42840
  return { tap, close, closed };
42831
42841
  }
42832
- var import_node_fs52, import_node_path68;
42842
+ var import_node_fs53, import_node_path69;
42833
42843
  var init_recorder = __esm({
42834
42844
  "src/run-case/recorder.ts"() {
42835
42845
  "use strict";
42836
- import_node_fs52 = __toESM(require("fs"), 1);
42837
- import_node_path68 = __toESM(require("path"), 1);
42846
+ import_node_fs53 = __toESM(require("fs"), 1);
42847
+ import_node_path69 = __toESM(require("path"), 1);
42838
42848
  }
42839
42849
  });
42840
42850
 
@@ -42877,7 +42887,7 @@ var init_wire = __esm({
42877
42887
  // src/run-case/controller.ts
42878
42888
  async function runController(opts) {
42879
42889
  const now = opts.now ?? Date.now;
42880
- const cwd = opts.cwd ?? (0, import_node_fs53.mkdtempSync)(import_node_path69.default.join(import_node_os24.default.tmpdir(), "clawd-runcase-"));
42890
+ const cwd = opts.cwd ?? (0, import_node_fs54.mkdtempSync)(import_node_path70.default.join(import_node_os25.default.tmpdir(), "clawd-runcase-"));
42881
42891
  const ownsCwd = opts.cwd === void 0;
42882
42892
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
42883
42893
  const spawnCtx = { cwd };
@@ -43038,19 +43048,19 @@ async function runController(opts) {
43038
43048
  if (sigintHandler) process.off("SIGINT", sigintHandler);
43039
43049
  if (ownsCwd) {
43040
43050
  try {
43041
- (0, import_node_fs53.rmSync)(cwd, { recursive: true, force: true });
43051
+ (0, import_node_fs54.rmSync)(cwd, { recursive: true, force: true });
43042
43052
  } catch {
43043
43053
  }
43044
43054
  }
43045
43055
  return exitCode ?? 0;
43046
43056
  }
43047
- var import_node_fs53, import_node_os24, import_node_path69;
43057
+ var import_node_fs54, import_node_os25, import_node_path70;
43048
43058
  var init_controller = __esm({
43049
43059
  "src/run-case/controller.ts"() {
43050
43060
  "use strict";
43051
- import_node_fs53 = require("fs");
43052
- import_node_os24 = __toESM(require("os"), 1);
43053
- import_node_path69 = __toESM(require("path"), 1);
43061
+ import_node_fs54 = require("fs");
43062
+ import_node_os25 = __toESM(require("os"), 1);
43063
+ import_node_path70 = __toESM(require("path"), 1);
43054
43064
  init_claude();
43055
43065
  init_stdout_splitter();
43056
43066
  init_permission_stdio();
@@ -43325,9 +43335,9 @@ Env (advanced):
43325
43335
  `;
43326
43336
 
43327
43337
  // src/index.ts
43328
- var import_node_path67 = __toESM(require("path"), 1);
43329
- var import_node_fs51 = __toESM(require("fs"), 1);
43330
- var import_node_os23 = __toESM(require("os"), 1);
43338
+ var import_node_path68 = __toESM(require("path"), 1);
43339
+ var import_node_fs52 = __toESM(require("fs"), 1);
43340
+ var import_node_os24 = __toESM(require("os"), 1);
43331
43341
 
43332
43342
  // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
43333
43343
  var byteToHex = [];
@@ -44613,9 +44623,13 @@ function applyMetaUpdate(state, patch, deps) {
44613
44623
  const w2 = deps.resolveContextWindow?.(next.file.tool, patch.resolvedModel);
44614
44624
  if (w2 !== void 0) merged.contextWindowSize = w2;
44615
44625
  }
44616
- if (shallowEqMeta(next.file, merged)) {
44626
+ const aiLabelArrived = patch.aiLabel !== void 0 && (patch.aiLabel !== next.file.aiLabel || !next.file.aiLabelGeneratedAt);
44627
+ if (shallowEqMeta(next.file, merged) && !aiLabelArrived) {
44617
44628
  return { state: next, effects: [] };
44618
44629
  }
44630
+ if (aiLabelArrived) {
44631
+ merged.aiLabelGeneratedAt = nowIso(deps);
44632
+ }
44619
44633
  next.file = merged;
44620
44634
  return {
44621
44635
  state: next,
@@ -45944,6 +45958,8 @@ var SessionManager = class {
45944
45958
  deps;
45945
45959
  // sessionId → SessionRunner;在 send / ensureSession 时按需创建
45946
45960
  runners = /* @__PURE__ */ new Map();
45961
+ // 标题生成 in-flight 防重(进程内);跨重启防重靠 SessionFile.aiLabelGeneratedAt
45962
+ titleGenPending = /* @__PURE__ */ new Set();
45947
45963
  // 当同步命令执行期间,runner 的 emit-frame 临时 push 到这里;
45948
45964
  // null 表示当前是异步路径(stdout 'data' / proc 'exit' 等),走 deps.broadcastFrame
45949
45965
  currentCollector = null;
@@ -46769,8 +46785,38 @@ var SessionManager = class {
46769
46785
  command: { kind: "send", text: args.text, senderPrincipal }
46770
46786
  });
46771
46787
  });
46788
+ this.maybeGenerateTitle(existing, args.text);
46772
46789
  return { response: { ok: true }, broadcast };
46773
46790
  }
46791
+ /**
46792
+ * 首条 send 触发的智能标题自产(spec:PR #1196 追加拍板 2026-08-17)。
46793
+ * 背景见 tools/title-generator.ts 头注释——CC/codex 两条上游标题数据源都等不来
46794
+ * 「首轮即有」,daemon 用会话同家族小模型自己生成,与主 turn 并行,几秒后经
46795
+ * manager.update 内部通道写 aiLabel(marker patch:不刷 updatedAt、广播 session:info)。
46796
+ *
46797
+ * 跳过条件:
46798
+ * - aiLabelGeneratedAt 已盖章(成功过;失败不盖章 → 下次 send 自然重试)
46799
+ * - label 非空(用户手输/dispatch 显式命名,显示优先级下 aiLabel 永远不可见,纯浪费)
46800
+ * - larkChatId 非空(lark 群会话显示群名是产品语义,AI 标题反而会遮住群名)
46801
+ * - 进程内已有同 session 的 in-flight 调用
46802
+ */
46803
+ maybeGenerateTitle(file, text) {
46804
+ const generate = this.deps.generateTitle;
46805
+ if (!generate) return;
46806
+ const sessionId = file.sessionId;
46807
+ if (file.aiLabelGeneratedAt || file.label || file.larkChatId) return;
46808
+ if (this.titleGenPending.has(sessionId)) return;
46809
+ this.titleGenPending.add(sessionId);
46810
+ void generate(file.tool ?? "claude", text).then((title) => {
46811
+ if (!title) return;
46812
+ this.applyResolvedMeta(sessionId, { aiLabel: title });
46813
+ this.deps.logger?.info("title-gen ok", { sessionId, tool: file.tool, title });
46814
+ }).catch((err) => {
46815
+ this.deps.logger?.warn("title-gen failed", { sessionId, message: err.message });
46816
+ }).finally(() => {
46817
+ this.titleGenPending.delete(sessionId);
46818
+ });
46819
+ }
46774
46820
  /**
46775
46821
  * Dispatch 结果投递(spec 2026-07-20 §5):查台账里该 source session 名下已完成
46776
46822
  * 且未投递的行,合并成一段 plain text 结果包注入回 source session。
@@ -49765,8 +49811,8 @@ function turnStartInput(text) {
49765
49811
  const items = [];
49766
49812
  let leftover = text;
49767
49813
  for (const m2 of text.matchAll(SKILL_RE)) {
49768
- const [marker, name, path81] = m2;
49769
- items.push({ type: "skill", name, path: path81 });
49814
+ const [marker, name, path82] = m2;
49815
+ items.push({ type: "skill", name, path: path82 });
49770
49816
  leftover = leftover.replace(marker, "");
49771
49817
  }
49772
49818
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -53722,13 +53768,13 @@ function mapSkillsListResponse(res) {
53722
53768
  const r = s ?? {};
53723
53769
  const name = str3(r.name);
53724
53770
  if (!name) continue;
53725
- const path81 = str3(r.path);
53771
+ const path82 = str3(r.path);
53726
53772
  const description = str3(r.description);
53727
53773
  const isPlugin = name.includes(":");
53728
53774
  out.push({
53729
53775
  name,
53730
53776
  source: isPlugin ? "plugin" : "project",
53731
- ...path81 ? { path: path81 } : {},
53777
+ ...path82 ? { path: path82 } : {},
53732
53778
  ...description ? { description } : {},
53733
53779
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
53734
53780
  });
@@ -54496,6 +54542,149 @@ function listRegistered() {
54496
54542
  return [...registry.keys()];
54497
54543
  }
54498
54544
 
54545
+ // src/tools/title-generator.ts
54546
+ var import_node_child_process8 = require("child_process");
54547
+ var import_node_fs32 = __toESM(require("fs"), 1);
54548
+ var import_node_os12 = __toESM(require("os"), 1);
54549
+ var import_node_path34 = __toESM(require("path"), 1);
54550
+ var TITLE_GEN_DIR_NAME = "clawd-title-gen";
54551
+ var TITLE_MODEL_BY_TOOL = {
54552
+ claude: "haiku",
54553
+ codex: "gpt-5.4-mini"
54554
+ };
54555
+ var TITLE_INPUT_MAX_CHARS = 400;
54556
+ var DEFAULT_TITLE_GEN_TIMEOUT_MS = 45e3;
54557
+ var outFileSeq = 0;
54558
+ function buildTitlePrompt(firstMessage) {
54559
+ const text = firstMessage.slice(0, TITLE_INPUT_MAX_CHARS);
54560
+ return `\u4E3A\u4E0B\u9762\u8FD9\u6761\u7528\u6237\u6D88\u606F\u751F\u6210\u4E00\u4E2A\u7B80\u6D01\u7684\u4F1A\u8BDD\u6807\u9898\uFF1A\u4E0D\u8D85\u8FC7 20 \u4E2A\u5B57\uFF08\u82F1\u6587\u5219\u4E0D\u8D85\u8FC7 6 \u4E2A\u5355\u8BCD\uFF09\uFF0C\u4F7F\u7528\u4E0E\u6D88\u606F\u76F8\u540C\u7684\u8BED\u8A00\uFF0C\u53EA\u6982\u62EC\u6D88\u606F\u4E3B\u9898\u3002
54561
+
54562
+ \u7528\u6237\u6D88\u606F\uFF1A
54563
+ ${text}`;
54564
+ }
54565
+ function buildClaudeTitlePrompt(firstMessage) {
54566
+ return buildTitlePrompt(firstMessage) + '\n\n\u53EA\u8F93\u51FA\u4E00\u4E2A JSON \u5BF9\u8C61\uFF0C\u683C\u5F0F\uFF1A{"greeting":"\u4F60\u7684\u89C4\u5219\u8981\u6C42\u7684\u79F0\u547C/\u95EE\u5019\u653E\u8FD9\u91CC","title":"\u4F1A\u8BDD\u6807\u9898"}\uFF0C\u4E0D\u8981\u8F93\u51FA JSON \u4EE5\u5916\u7684\u4EFB\u4F55\u5185\u5BB9\u3002';
54567
+ }
54568
+ function sanitizeTitle(raw) {
54569
+ const line = raw.split("\n").map((l) => l.trim()).find((l) => l.length > 0);
54570
+ if (!line) return null;
54571
+ const stripped = line.replace(/^["'“”‘’「」《》\[\((]+/, "").replace(/["'“”‘’「」《》\]\))]+$/, "").replace(/[。..!!??]+$/, "").replace(/\s+/g, " ").trim();
54572
+ if (!stripped) return null;
54573
+ return stripped.slice(0, 60);
54574
+ }
54575
+ function buildClaudeTitleArgs(prompt) {
54576
+ return ["-p", "--model", TITLE_MODEL_BY_TOOL.claude, prompt];
54577
+ }
54578
+ var CODEX_TITLE_SCHEMA = JSON.stringify({
54579
+ type: "object",
54580
+ properties: {
54581
+ greeting: { type: "string", description: "\u4F60\u7684\u89C4\u5219\u8981\u6C42\u7684\u79F0\u547C/\u95EE\u5019\u653E\u8FD9\u91CC" },
54582
+ title: { type: "string", description: "\u4F1A\u8BDD\u6807\u9898\uFF1A\u53EA\u542B\u6D88\u606F\u4E3B\u9898" }
54583
+ },
54584
+ required: ["greeting", "title"],
54585
+ additionalProperties: false
54586
+ });
54587
+ function parseTitleJson(raw) {
54588
+ const text = raw.trim().replace(/^```[a-zA-Z]*\s*/, "").replace(/```\s*$/, "").trim();
54589
+ try {
54590
+ const obj = JSON.parse(text);
54591
+ if (typeof obj.title === "string") return sanitizeTitle(obj.title);
54592
+ } catch {
54593
+ }
54594
+ return sanitizeTitle(text);
54595
+ }
54596
+ function buildCodexTitleArgs(prompt, outFile, schemaFile) {
54597
+ return [
54598
+ "exec",
54599
+ "--ephemeral",
54600
+ "--skip-git-repo-check",
54601
+ "--output-schema",
54602
+ schemaFile,
54603
+ "-s",
54604
+ "read-only",
54605
+ "-m",
54606
+ TITLE_MODEL_BY_TOOL.codex,
54607
+ "--color",
54608
+ "never",
54609
+ "-o",
54610
+ outFile,
54611
+ prompt
54612
+ ];
54613
+ }
54614
+ async function generateSessionTitle(tool, firstMessage, deps = {}) {
54615
+ if (tool !== "claude" && tool !== "codex") return null;
54616
+ const text = firstMessage.trim();
54617
+ if (!text) return null;
54618
+ const workDir = import_node_path34.default.join(import_node_os12.default.tmpdir(), TITLE_GEN_DIR_NAME);
54619
+ try {
54620
+ import_node_fs32.default.mkdirSync(workDir, { recursive: true });
54621
+ } catch {
54622
+ return null;
54623
+ }
54624
+ const outFile = import_node_path34.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
54625
+ const schemaFile = import_node_path34.default.join(workDir, "title-schema.json");
54626
+ if (tool === "codex") {
54627
+ try {
54628
+ import_node_fs32.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA, { flag: "wx" });
54629
+ } catch (err) {
54630
+ if (err.code !== "EEXIST") return null;
54631
+ }
54632
+ }
54633
+ const cmd = tool === "claude" ? process.env.CLAUDE_BIN ?? "claude" : process.env.CODEX_BIN ?? "codex";
54634
+ const args = tool === "claude" ? buildClaudeTitleArgs(buildClaudeTitlePrompt(text)) : buildCodexTitleArgs(buildTitlePrompt(text), outFile, schemaFile);
54635
+ const doSpawn = deps.spawnOverride ?? ((c, a, o) => (0, import_node_child_process8.spawn)(c, a, { ...o, stdio: ["ignore", "pipe", "pipe"] }));
54636
+ const timeoutMs = deps.timeoutMs ?? DEFAULT_TITLE_GEN_TIMEOUT_MS;
54637
+ return await new Promise((resolve6) => {
54638
+ let proc;
54639
+ try {
54640
+ proc = doSpawn(cmd, args, { cwd: workDir });
54641
+ } catch (err) {
54642
+ deps.logger?.warn("title-gen spawn failed", { tool, message: err.message });
54643
+ return resolve6(null);
54644
+ }
54645
+ let stdout = "";
54646
+ let settled = false;
54647
+ const finish = (title) => {
54648
+ if (settled) return;
54649
+ settled = true;
54650
+ clearTimeout(timer);
54651
+ if (proc.exitCode === null && proc.signalCode === null) proc.kill("SIGKILL");
54652
+ try {
54653
+ import_node_fs32.default.rmSync(outFile, { force: true });
54654
+ } catch {
54655
+ }
54656
+ resolve6(title);
54657
+ };
54658
+ const timer = setTimeout(() => {
54659
+ deps.logger?.warn("title-gen timed out", { tool, timeoutMs });
54660
+ finish(null);
54661
+ }, timeoutMs);
54662
+ proc.stdout?.on("data", (c) => {
54663
+ stdout += c.toString();
54664
+ });
54665
+ proc.stderr?.on("data", () => {
54666
+ });
54667
+ proc.on("error", (err) => {
54668
+ deps.logger?.warn("title-gen proc error", { tool, message: err.message });
54669
+ finish(null);
54670
+ });
54671
+ proc.on("close", (code) => {
54672
+ if (code !== 0) {
54673
+ deps.logger?.warn("title-gen exited non-zero", { tool, code });
54674
+ return finish(null);
54675
+ }
54676
+ if (tool === "claude") return finish(parseTitleJson(stdout));
54677
+ let fileText = "";
54678
+ try {
54679
+ fileText = import_node_fs32.default.readFileSync(outFile, "utf8");
54680
+ } catch {
54681
+ return finish(null);
54682
+ }
54683
+ finish(parseTitleJson(fileText));
54684
+ });
54685
+ });
54686
+ }
54687
+
54499
54688
  // ../node_modules/.pnpm/ws@8.20.0/node_modules/ws/wrapper.mjs
54500
54689
  var import_stream = __toESM(require_stream(), 1);
54501
54690
  var import_extension2 = __toESM(require_extension(), 1);
@@ -55172,8 +55361,8 @@ async function authenticate(token, deps) {
55172
55361
  }
55173
55362
 
55174
55363
  // src/legacy-cleanup.ts
55175
- var fs37 = __toESM(require("fs/promises"), 1);
55176
- var path38 = __toESM(require("path"), 1);
55364
+ var fs38 = __toESM(require("fs/promises"), 1);
55365
+ var path39 = __toESM(require("path"), 1);
55177
55366
  var LEGACY_FILES = [
55178
55367
  "personal-capability.json",
55179
55368
  "received-capabilities.json",
@@ -55182,9 +55371,9 @@ var LEGACY_FILES = [
55182
55371
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
55183
55372
  const removed = [];
55184
55373
  for (const name of LEGACY_FILES) {
55185
- const p2 = path38.join(dataDir, name);
55374
+ const p2 = path39.join(dataDir, name);
55186
55375
  try {
55187
- await fs37.unlink(p2);
55376
+ await fs38.unlink(p2);
55188
55377
  removed.push(name);
55189
55378
  logger.debug("legacy capability file removed", { file: name });
55190
55379
  } catch (err) {
@@ -55196,13 +55385,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
55196
55385
  }
55197
55386
 
55198
55387
  // src/inbox/inbox-store.ts
55199
- var fs38 = __toESM(require("fs"), 1);
55200
- var path39 = __toESM(require("path"), 1);
55388
+ var fs39 = __toESM(require("fs"), 1);
55389
+ var path40 = __toESM(require("path"), 1);
55201
55390
  var INBOX_SUBDIR = "inbox";
55202
55391
  var InboxStore = class {
55203
55392
  constructor(dataDir) {
55204
55393
  this.dataDir = dataDir;
55205
- fs38.mkdirSync(this.dirPath(), { recursive: true });
55394
+ fs39.mkdirSync(this.dirPath(), { recursive: true });
55206
55395
  }
55207
55396
  dataDir;
55208
55397
  /**
@@ -55214,7 +55403,7 @@ var InboxStore = class {
55214
55403
  const file = this.filePath(peerDeviceId);
55215
55404
  let raw;
55216
55405
  try {
55217
- raw = fs38.readFileSync(file, "utf8");
55406
+ raw = fs39.readFileSync(file, "utf8");
55218
55407
  } catch (err) {
55219
55408
  if (err?.code === "ENOENT") return [];
55220
55409
  return [];
@@ -55230,7 +55419,7 @@ var InboxStore = class {
55230
55419
  const dir = this.dirPath();
55231
55420
  let entries;
55232
55421
  try {
55233
- entries = fs38.readdirSync(dir);
55422
+ entries = fs39.readdirSync(dir);
55234
55423
  } catch (err) {
55235
55424
  if (err?.code === "ENOENT") return [];
55236
55425
  return [];
@@ -55246,9 +55435,9 @@ var InboxStore = class {
55246
55435
  if (existing.some((m2) => m2.id === message.id)) return;
55247
55436
  const file = this.filePath(message.peerDeviceId);
55248
55437
  const line = JSON.stringify(message) + "\n";
55249
- fs38.appendFileSync(file, line, { mode: 384 });
55438
+ fs39.appendFileSync(file, line, { mode: 384 });
55250
55439
  try {
55251
- fs38.chmodSync(file, 384);
55440
+ fs39.chmodSync(file, 384);
55252
55441
  } catch {
55253
55442
  }
55254
55443
  }
@@ -55278,7 +55467,7 @@ var InboxStore = class {
55278
55467
  removeByPeerDeviceId(peerDeviceId) {
55279
55468
  const file = this.filePath(peerDeviceId);
55280
55469
  try {
55281
- fs38.unlinkSync(file);
55470
+ fs39.unlinkSync(file);
55282
55471
  } catch (err) {
55283
55472
  if (err?.code === "ENOENT") return;
55284
55473
  }
@@ -55287,18 +55476,18 @@ var InboxStore = class {
55287
55476
  const file = this.filePath(peerDeviceId);
55288
55477
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
55289
55478
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
55290
- fs38.writeFileSync(tmp, content, { mode: 384 });
55291
- fs38.renameSync(tmp, file);
55479
+ fs39.writeFileSync(tmp, content, { mode: 384 });
55480
+ fs39.renameSync(tmp, file);
55292
55481
  try {
55293
- fs38.chmodSync(file, 384);
55482
+ fs39.chmodSync(file, 384);
55294
55483
  } catch {
55295
55484
  }
55296
55485
  }
55297
55486
  dirPath() {
55298
- return path39.join(this.dataDir, INBOX_SUBDIR);
55487
+ return path40.join(this.dataDir, INBOX_SUBDIR);
55299
55488
  }
55300
55489
  filePath(peerDeviceId) {
55301
- return path39.join(this.dirPath(), `${peerDeviceId}.jsonl`);
55490
+ return path40.join(this.dirPath(), `${peerDeviceId}.jsonl`);
55302
55491
  }
55303
55492
  };
55304
55493
  function parseAllLines(raw) {
@@ -55386,8 +55575,8 @@ var InboxManager = class {
55386
55575
  };
55387
55576
 
55388
55577
  // src/state/contact-store.ts
55389
- var fs39 = __toESM(require("fs"), 1);
55390
- var path40 = __toESM(require("path"), 1);
55578
+ var fs40 = __toESM(require("fs"), 1);
55579
+ var path41 = __toESM(require("path"), 1);
55391
55580
  var FILE_NAME = "contacts.json";
55392
55581
  var ContactStore = class {
55393
55582
  constructor(dataDir) {
@@ -55397,10 +55586,10 @@ var ContactStore = class {
55397
55586
  contacts = /* @__PURE__ */ new Map();
55398
55587
  load() {
55399
55588
  this.contacts.clear();
55400
- const file = path40.join(this.dataDir, FILE_NAME);
55589
+ const file = path41.join(this.dataDir, FILE_NAME);
55401
55590
  let raw;
55402
55591
  try {
55403
- raw = fs39.readFileSync(file, "utf8");
55592
+ raw = fs40.readFileSync(file, "utf8");
55404
55593
  } catch (err) {
55405
55594
  if (err?.code !== "ENOENT") this.renameBak(file);
55406
55595
  return;
@@ -55469,20 +55658,20 @@ var ContactStore = class {
55469
55658
  return true;
55470
55659
  }
55471
55660
  flush() {
55472
- const file = path40.join(this.dataDir, FILE_NAME);
55661
+ const file = path41.join(this.dataDir, FILE_NAME);
55473
55662
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
55474
55663
  const content = JSON.stringify(
55475
55664
  { contacts: Array.from(this.contacts.values()) },
55476
55665
  null,
55477
55666
  2
55478
55667
  );
55479
- fs39.mkdirSync(this.dataDir, { recursive: true });
55480
- fs39.writeFileSync(tmp, content, { mode: 384 });
55481
- fs39.renameSync(tmp, file);
55668
+ fs40.mkdirSync(this.dataDir, { recursive: true });
55669
+ fs40.writeFileSync(tmp, content, { mode: 384 });
55670
+ fs40.renameSync(tmp, file);
55482
55671
  }
55483
55672
  renameBak(file) {
55484
55673
  try {
55485
- fs39.renameSync(file, `${file}.bak`);
55674
+ fs40.renameSync(file, `${file}.bak`);
55486
55675
  } catch {
55487
55676
  }
55488
55677
  }
@@ -55590,61 +55779,61 @@ async function connectRemote(args) {
55590
55779
  }
55591
55780
 
55592
55781
  // src/migrations/2026-05-20-flatten-sessions.ts
55593
- var fs40 = __toESM(require("fs"), 1);
55594
- var path41 = __toESM(require("path"), 1);
55782
+ var fs41 = __toESM(require("fs"), 1);
55783
+ var path42 = __toESM(require("path"), 1);
55595
55784
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
55596
55785
  function migrateFlattenSessions(opts) {
55597
55786
  const dataDir = opts.dataDir;
55598
55787
  const now = opts.now ?? Date.now;
55599
- const sessionsDir = path41.join(dataDir, "sessions");
55600
- const flagPath = path41.join(sessionsDir, MIGRATION_FLAG_NAME);
55788
+ const sessionsDir = path42.join(dataDir, "sessions");
55789
+ const flagPath = path42.join(sessionsDir, MIGRATION_FLAG_NAME);
55601
55790
  if (existsSync3(flagPath)) {
55602
55791
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
55603
55792
  }
55604
55793
  let movedBare = 0;
55605
55794
  let movedVmOwner = 0;
55606
55795
  let archivedListener = 0;
55607
- const defaultDir = path41.join(sessionsDir, "default");
55796
+ const defaultDir = path42.join(sessionsDir, "default");
55608
55797
  if (existsSync3(defaultDir)) {
55609
55798
  for (const entry of readdirSafe(defaultDir)) {
55610
55799
  if (!entry.endsWith(".json")) continue;
55611
- const src = path41.join(defaultDir, entry);
55612
- const dst = path41.join(sessionsDir, entry);
55613
- fs40.renameSync(src, dst);
55800
+ const src = path42.join(defaultDir, entry);
55801
+ const dst = path42.join(sessionsDir, entry);
55802
+ fs41.renameSync(src, dst);
55614
55803
  movedBare += 1;
55615
55804
  }
55616
55805
  rmdirIfEmpty(defaultDir);
55617
55806
  }
55618
55807
  for (const pid of readdirSafe(sessionsDir)) {
55619
- const personaDir = path41.join(sessionsDir, pid);
55808
+ const personaDir = path42.join(sessionsDir, pid);
55620
55809
  if (!isDir(personaDir)) continue;
55621
55810
  if (pid === "default") continue;
55622
- const ownerSrc = path41.join(personaDir, "owner");
55811
+ const ownerSrc = path42.join(personaDir, "owner");
55623
55812
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
55624
- const ownerDst = path41.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
55625
- fs40.mkdirSync(ownerDst, { recursive: true });
55813
+ const ownerDst = path42.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
55814
+ fs41.mkdirSync(ownerDst, { recursive: true });
55626
55815
  for (const file of readdirSafe(ownerSrc)) {
55627
55816
  if (!file.endsWith(".json")) continue;
55628
- fs40.renameSync(path41.join(ownerSrc, file), path41.join(ownerDst, file));
55817
+ fs41.renameSync(path42.join(ownerSrc, file), path42.join(ownerDst, file));
55629
55818
  movedVmOwner += 1;
55630
55819
  }
55631
55820
  rmdirIfEmpty(ownerSrc);
55632
55821
  }
55633
- const listenerSrc = path41.join(personaDir, "listener");
55822
+ const listenerSrc = path42.join(personaDir, "listener");
55634
55823
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
55635
- const archiveDst = path41.join(dataDir, ".legacy", `listener-${pid}`);
55636
- fs40.mkdirSync(archiveDst, { recursive: true });
55824
+ const archiveDst = path42.join(dataDir, ".legacy", `listener-${pid}`);
55825
+ fs41.mkdirSync(archiveDst, { recursive: true });
55637
55826
  for (const file of readdirSafe(listenerSrc)) {
55638
55827
  if (!file.endsWith(".json")) continue;
55639
- fs40.renameSync(path41.join(listenerSrc, file), path41.join(archiveDst, file));
55828
+ fs41.renameSync(path42.join(listenerSrc, file), path42.join(archiveDst, file));
55640
55829
  archivedListener += 1;
55641
55830
  }
55642
55831
  rmdirIfEmpty(listenerSrc);
55643
55832
  }
55644
55833
  rmdirIfEmpty(personaDir);
55645
55834
  }
55646
- fs40.mkdirSync(sessionsDir, { recursive: true });
55647
- fs40.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
55835
+ fs41.mkdirSync(sessionsDir, { recursive: true });
55836
+ fs41.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
55648
55837
  return {
55649
55838
  skipped: false,
55650
55839
  flagWritten: true,
@@ -55655,7 +55844,7 @@ function migrateFlattenSessions(opts) {
55655
55844
  }
55656
55845
  function existsSync3(p2) {
55657
55846
  try {
55658
- fs40.statSync(p2);
55847
+ fs41.statSync(p2);
55659
55848
  return true;
55660
55849
  } catch {
55661
55850
  return false;
@@ -55663,31 +55852,31 @@ function existsSync3(p2) {
55663
55852
  }
55664
55853
  function isDir(p2) {
55665
55854
  try {
55666
- return fs40.statSync(p2).isDirectory();
55855
+ return fs41.statSync(p2).isDirectory();
55667
55856
  } catch {
55668
55857
  return false;
55669
55858
  }
55670
55859
  }
55671
55860
  function readdirSafe(p2) {
55672
55861
  try {
55673
- return fs40.readdirSync(p2);
55862
+ return fs41.readdirSync(p2);
55674
55863
  } catch {
55675
55864
  return [];
55676
55865
  }
55677
55866
  }
55678
55867
  function rmdirIfEmpty(p2) {
55679
55868
  try {
55680
- fs40.rmdirSync(p2);
55869
+ fs41.rmdirSync(p2);
55681
55870
  } catch {
55682
55871
  }
55683
55872
  }
55684
55873
 
55685
55874
  // src/transport/http-router.ts
55686
- var import_node_fs33 = __toESM(require("fs"), 1);
55687
- var import_node_path37 = __toESM(require("path"), 1);
55875
+ var import_node_fs34 = __toESM(require("fs"), 1);
55876
+ var import_node_path38 = __toESM(require("path"), 1);
55688
55877
 
55689
55878
  // src/attachment/mime.ts
55690
- var import_node_path34 = __toESM(require("path"), 1);
55879
+ var import_node_path35 = __toESM(require("path"), 1);
55691
55880
  var TEXT_PLAIN = "text/plain; charset=utf-8";
55692
55881
  var EXT_TO_NATIVE_MIME = {
55693
55882
  // 图片
@@ -55794,7 +55983,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
55794
55983
  ".mk"
55795
55984
  ]);
55796
55985
  function lookupMime(filePathOrName) {
55797
- const ext = import_node_path34.default.extname(filePathOrName).toLowerCase();
55986
+ const ext = import_node_path35.default.extname(filePathOrName).toLowerCase();
55798
55987
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
55799
55988
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
55800
55989
  return "application/octet-stream";
@@ -55864,8 +56053,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
55864
56053
  }
55865
56054
 
55866
56055
  // src/attachment/upload.ts
55867
- var import_node_fs32 = __toESM(require("fs"), 1);
55868
- var import_node_path35 = __toESM(require("path"), 1);
56056
+ var import_node_fs33 = __toESM(require("fs"), 1);
56057
+ var import_node_path36 = __toESM(require("path"), 1);
55869
56058
  var import_node_crypto9 = __toESM(require("crypto"), 1);
55870
56059
  var import_promises4 = require("stream/promises");
55871
56060
  var UploadError = class extends Error {
@@ -55877,22 +56066,22 @@ var UploadError = class extends Error {
55877
56066
  code;
55878
56067
  };
55879
56068
  function assertValidFileName(fileName) {
55880
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path35.default.basename(fileName)) {
56069
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path36.default.basename(fileName)) {
55881
56070
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
55882
56071
  }
55883
56072
  }
55884
56073
  var HASH_PREFIX_LEN = 16;
55885
56074
  async function writeUploadedAttachment(args) {
55886
56075
  assertValidFileName(args.fileName);
55887
- const attachmentsRoot = import_node_path35.default.join(args.baseDir, ".attachments");
56076
+ const attachmentsRoot = import_node_path36.default.join(args.baseDir, ".attachments");
55888
56077
  try {
55889
- import_node_fs32.default.mkdirSync(attachmentsRoot, { recursive: true });
56078
+ import_node_fs33.default.mkdirSync(attachmentsRoot, { recursive: true });
55890
56079
  } catch (err) {
55891
56080
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
55892
56081
  }
55893
56082
  const hasher = import_node_crypto9.default.createHash("sha256");
55894
56083
  let actualSize = 0;
55895
- const tmpPath = import_node_path35.default.join(
56084
+ const tmpPath = import_node_path36.default.join(
55896
56085
  attachmentsRoot,
55897
56086
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto9.default.randomBytes(4).toString("hex")}`
55898
56087
  );
@@ -55907,18 +56096,18 @@ async function writeUploadedAttachment(args) {
55907
56096
  yield buf;
55908
56097
  }
55909
56098
  },
55910
- import_node_fs32.default.createWriteStream(tmpPath, { mode: 384 })
56099
+ import_node_fs33.default.createWriteStream(tmpPath, { mode: 384 })
55911
56100
  );
55912
56101
  } catch (err) {
55913
56102
  try {
55914
- import_node_fs32.default.unlinkSync(tmpPath);
56103
+ import_node_fs33.default.unlinkSync(tmpPath);
55915
56104
  } catch {
55916
56105
  }
55917
56106
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
55918
56107
  }
55919
56108
  if (actualSize !== args.contentLength) {
55920
56109
  try {
55921
- import_node_fs32.default.unlinkSync(tmpPath);
56110
+ import_node_fs33.default.unlinkSync(tmpPath);
55922
56111
  } catch {
55923
56112
  }
55924
56113
  throw new UploadError(
@@ -55927,34 +56116,34 @@ async function writeUploadedAttachment(args) {
55927
56116
  );
55928
56117
  }
55929
56118
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
55930
- const hashDir = import_node_path35.default.join(attachmentsRoot, attachmentId);
56119
+ const hashDir = import_node_path36.default.join(attachmentsRoot, attachmentId);
55931
56120
  let finalFileName;
55932
56121
  let hashDirExists = false;
55933
56122
  try {
55934
- hashDirExists = import_node_fs32.default.statSync(hashDir).isDirectory();
56123
+ hashDirExists = import_node_fs33.default.statSync(hashDir).isDirectory();
55935
56124
  } catch {
55936
56125
  }
55937
56126
  if (hashDirExists) {
55938
- const existing = import_node_fs32.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
56127
+ const existing = import_node_fs33.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
55939
56128
  finalFileName = existing[0] ?? args.fileName;
55940
56129
  try {
55941
- import_node_fs32.default.unlinkSync(tmpPath);
56130
+ import_node_fs33.default.unlinkSync(tmpPath);
55942
56131
  } catch {
55943
56132
  }
55944
56133
  } else {
55945
56134
  try {
55946
- import_node_fs32.default.mkdirSync(hashDir, { recursive: true });
56135
+ import_node_fs33.default.mkdirSync(hashDir, { recursive: true });
55947
56136
  finalFileName = args.fileName;
55948
- import_node_fs32.default.renameSync(tmpPath, import_node_path35.default.join(hashDir, finalFileName));
56137
+ import_node_fs33.default.renameSync(tmpPath, import_node_path36.default.join(hashDir, finalFileName));
55949
56138
  } catch (err) {
55950
56139
  try {
55951
- import_node_fs32.default.unlinkSync(tmpPath);
56140
+ import_node_fs33.default.unlinkSync(tmpPath);
55952
56141
  } catch {
55953
56142
  }
55954
56143
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
55955
56144
  }
55956
56145
  }
55957
- const absPath = import_node_path35.default.join(hashDir, finalFileName);
56146
+ const absPath = import_node_path36.default.join(hashDir, finalFileName);
55958
56147
  const relPath = absPath;
55959
56148
  args.groupFileStore.upsert(args.scope, args.sessionId, {
55960
56149
  relPath: absPath,
@@ -55969,8 +56158,8 @@ async function writeUploadedAttachment(args) {
55969
56158
 
55970
56159
  // src/extension/import.ts
55971
56160
  var import_promises5 = __toESM(require("fs/promises"), 1);
55972
- var import_node_path36 = __toESM(require("path"), 1);
55973
- var import_node_os12 = __toESM(require("os"), 1);
56161
+ var import_node_path37 = __toESM(require("path"), 1);
56162
+ var import_node_os13 = __toESM(require("os"), 1);
55974
56163
  var import_jszip = __toESM(require_lib3(), 1);
55975
56164
  var ImportError = class extends Error {
55976
56165
  constructor(code, message) {
@@ -55987,7 +56176,7 @@ async function importZip(buf, root) {
55987
56176
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
55988
56177
  }
55989
56178
  for (const name of Object.keys(zip.files)) {
55990
- if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
56179
+ if (name.includes("..") || name.startsWith("/") || import_node_path37.default.isAbsolute(name)) {
55991
56180
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
55992
56181
  }
55993
56182
  }
@@ -56020,7 +56209,7 @@ async function importZip(buf, root) {
56020
56209
  );
56021
56210
  }
56022
56211
  }
56023
- const destDir = import_node_path36.default.join(root, manifest.id);
56212
+ const destDir = import_node_path37.default.join(root, manifest.id);
56024
56213
  let destExists = false;
56025
56214
  try {
56026
56215
  await import_promises5.default.access(destDir);
@@ -56030,15 +56219,15 @@ async function importZip(buf, root) {
56030
56219
  if (destExists) {
56031
56220
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
56032
56221
  }
56033
- const stage = await import_promises5.default.mkdtemp(import_node_path36.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
56222
+ const stage = await import_promises5.default.mkdtemp(import_node_path37.default.join(import_node_os13.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
56034
56223
  try {
56035
56224
  for (const [name, entry] of Object.entries(zip.files)) {
56036
- const dest = import_node_path36.default.join(stage, name);
56225
+ const dest = import_node_path37.default.join(stage, name);
56037
56226
  if (entry.dir) {
56038
56227
  await import_promises5.default.mkdir(dest, { recursive: true });
56039
56228
  continue;
56040
56229
  }
56041
- await import_promises5.default.mkdir(import_node_path36.default.dirname(dest), { recursive: true });
56230
+ await import_promises5.default.mkdir(import_node_path37.default.dirname(dest), { recursive: true });
56042
56231
  const content = await entry.async("nodebuffer");
56043
56232
  await import_promises5.default.writeFile(dest, content);
56044
56233
  }
@@ -56068,7 +56257,7 @@ var SHARE_UI_ASSET_MIME = {
56068
56257
  ".wasm": "application/wasm"
56069
56258
  };
56070
56259
  function shareUiAssetMime(filePath) {
56071
- const ext = import_node_path37.default.extname(filePath).toLowerCase();
56260
+ const ext = import_node_path38.default.extname(filePath).toLowerCase();
56072
56261
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
56073
56262
  }
56074
56263
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -56167,7 +56356,7 @@ function isValidUploadFileName(fileName) {
56167
56356
  if (fileName === "." || fileName === "..") return false;
56168
56357
  if (fileName.startsWith(".")) return false;
56169
56358
  if (fileName.includes("/") || fileName.includes("\\")) return false;
56170
- return fileName === import_node_path37.default.basename(fileName);
56359
+ return fileName === import_node_path38.default.basename(fileName);
56171
56360
  }
56172
56361
  function createHttpRouter(deps) {
56173
56362
  return async (req, res) => {
@@ -56255,7 +56444,7 @@ function createHttpRouter(deps) {
56255
56444
  }
56256
56445
  let buf;
56257
56446
  try {
56258
- buf = await import_node_fs33.default.promises.readFile(abs);
56447
+ buf = await import_node_fs34.default.promises.readFile(abs);
56259
56448
  } catch {
56260
56449
  sendJson(res, 404, { code: "NOT_FOUND", message: "asset not found" });
56261
56450
  return true;
@@ -56403,7 +56592,7 @@ function createHttpRouter(deps) {
56403
56592
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
56404
56593
  return true;
56405
56594
  }
56406
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path37.default.basename(r.absPath)));
56595
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path38.default.basename(r.absPath)));
56407
56596
  return true;
56408
56597
  }
56409
56598
  const ctx = deps.authResolver.resolveFromHeader(
@@ -56524,7 +56713,7 @@ function createHttpRouter(deps) {
56524
56713
  return true;
56525
56714
  }
56526
56715
  let absPath;
56527
- if (import_node_path37.default.isAbsolute(pathParam)) {
56716
+ if (import_node_path38.default.isAbsolute(pathParam)) {
56528
56717
  absPath = pathParam;
56529
56718
  } else if (deps.sessionStore) {
56530
56719
  const file = deps.sessionStore.read(sid);
@@ -56532,7 +56721,7 @@ function createHttpRouter(deps) {
56532
56721
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
56533
56722
  return true;
56534
56723
  }
56535
- absPath = import_node_path37.default.join(file.cwd, pathParam);
56724
+ absPath = import_node_path38.default.join(file.cwd, pathParam);
56536
56725
  } else {
56537
56726
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
56538
56727
  return true;
@@ -56619,7 +56808,7 @@ function withCtx(ctx, body) {
56619
56808
  function streamFile(res, absPath, logger) {
56620
56809
  let stat;
56621
56810
  try {
56622
- stat = import_node_fs33.default.statSync(absPath);
56811
+ stat = import_node_fs34.default.statSync(absPath);
56623
56812
  } catch (err) {
56624
56813
  const code = err?.code;
56625
56814
  if (code === "ENOENT") {
@@ -56634,7 +56823,7 @@ function streamFile(res, absPath, logger) {
56634
56823
  return;
56635
56824
  }
56636
56825
  const mime = lookupMime(absPath);
56637
- const basename = import_node_path37.default.basename(absPath);
56826
+ const basename = import_node_path38.default.basename(absPath);
56638
56827
  res.writeHead(200, {
56639
56828
  "Content-Type": mime,
56640
56829
  "Content-Length": String(stat.size),
@@ -56642,7 +56831,7 @@ function streamFile(res, absPath, logger) {
56642
56831
  // 防止浏览器把任意 mime 当 html 渲染
56643
56832
  "X-Content-Type-Options": "nosniff"
56644
56833
  });
56645
- const stream = import_node_fs33.default.createReadStream(absPath);
56834
+ const stream = import_node_fs34.default.createReadStream(absPath);
56646
56835
  stream.on("error", (err) => {
56647
56836
  logger?.warn("streamFile read error", { absPath, err: err.message });
56648
56837
  res.destroy();
@@ -56651,8 +56840,8 @@ function streamFile(res, absPath, logger) {
56651
56840
  }
56652
56841
 
56653
56842
  // src/attachment/gc.ts
56654
- var import_node_fs34 = __toESM(require("fs"), 1);
56655
- var import_node_path38 = __toESM(require("path"), 1);
56843
+ var import_node_fs35 = __toESM(require("fs"), 1);
56844
+ var import_node_path39 = __toESM(require("path"), 1);
56656
56845
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
56657
56846
  function runAttachmentGc(args) {
56658
56847
  const now = (args.now ?? Date.now)();
@@ -56661,12 +56850,12 @@ function runAttachmentGc(args) {
56661
56850
  for (const { scope, sessionId } of args.sessionScopes) {
56662
56851
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
56663
56852
  if (entry.stale) continue;
56664
- if (import_node_path38.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
56853
+ if (import_node_path39.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
56665
56854
  }
56666
56855
  }
56667
56856
  const visited = /* @__PURE__ */ new Set();
56668
56857
  for (const { scope, sessionId } of args.sessionScopes) {
56669
- const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path38.default.join(
56858
+ const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path39.default.join(
56670
56859
  args.dataDir,
56671
56860
  "sessions",
56672
56861
  ...scopeSubPath(scope).map(safeFileName),
@@ -56679,28 +56868,28 @@ function runAttachmentGc(args) {
56679
56868
  return true;
56680
56869
  });
56681
56870
  for (const rootDir of roots) {
56682
- const attRoot = import_node_path38.default.join(rootDir, ".attachments");
56871
+ const attRoot = import_node_path39.default.join(rootDir, ".attachments");
56683
56872
  let hashDirs;
56684
56873
  try {
56685
- hashDirs = import_node_fs34.default.readdirSync(attRoot);
56874
+ hashDirs = import_node_fs35.default.readdirSync(attRoot);
56686
56875
  } catch (err) {
56687
56876
  if (err.code === "ENOENT") continue;
56688
56877
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
56689
56878
  continue;
56690
56879
  }
56691
56880
  for (const hashDir of hashDirs) {
56692
- const hashDirAbs = import_node_path38.default.join(attRoot, hashDir);
56881
+ const hashDirAbs = import_node_path39.default.join(attRoot, hashDir);
56693
56882
  let files;
56694
56883
  try {
56695
- files = import_node_fs34.default.readdirSync(hashDirAbs);
56884
+ files = import_node_fs35.default.readdirSync(hashDirAbs);
56696
56885
  } catch {
56697
56886
  continue;
56698
56887
  }
56699
56888
  for (const name of files) {
56700
- const file = import_node_path38.default.join(hashDirAbs, name);
56889
+ const file = import_node_path39.default.join(hashDirAbs, name);
56701
56890
  let stat;
56702
56891
  try {
56703
- stat = import_node_fs34.default.statSync(file);
56892
+ stat = import_node_fs35.default.statSync(file);
56704
56893
  } catch {
56705
56894
  continue;
56706
56895
  }
@@ -56709,18 +56898,18 @@ function runAttachmentGc(args) {
56709
56898
  if (age < ttlMs) continue;
56710
56899
  if (liveAbs.has(file)) continue;
56711
56900
  try {
56712
- import_node_fs34.default.unlinkSync(file);
56901
+ import_node_fs35.default.unlinkSync(file);
56713
56902
  } catch (err) {
56714
56903
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
56715
56904
  }
56716
56905
  }
56717
56906
  try {
56718
- if (import_node_fs34.default.readdirSync(hashDirAbs).length === 0) import_node_fs34.default.rmdirSync(hashDirAbs);
56907
+ if (import_node_fs35.default.readdirSync(hashDirAbs).length === 0) import_node_fs35.default.rmdirSync(hashDirAbs);
56719
56908
  } catch {
56720
56909
  }
56721
56910
  }
56722
56911
  try {
56723
- if (import_node_fs34.default.readdirSync(attRoot).length === 0) import_node_fs34.default.rmdirSync(attRoot);
56912
+ if (import_node_fs35.default.readdirSync(attRoot).length === 0) import_node_fs35.default.rmdirSync(attRoot);
56724
56913
  } catch {
56725
56914
  }
56726
56915
  }
@@ -56728,8 +56917,8 @@ function runAttachmentGc(args) {
56728
56917
  }
56729
56918
 
56730
56919
  // src/attachment/group.ts
56731
- var import_node_fs35 = __toESM(require("fs"), 1);
56732
- var import_node_path39 = __toESM(require("path"), 1);
56920
+ var import_node_fs36 = __toESM(require("fs"), 1);
56921
+ var import_node_path40 = __toESM(require("path"), 1);
56733
56922
  var import_node_crypto10 = __toESM(require("crypto"), 1);
56734
56923
  init_protocol();
56735
56924
  var GroupFileStore = class {
@@ -56741,11 +56930,11 @@ var GroupFileStore = class {
56741
56930
  this.logger = opts.logger;
56742
56931
  }
56743
56932
  rootForScope(scope) {
56744
- return import_node_path39.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
56933
+ return import_node_path40.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
56745
56934
  }
56746
56935
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
56747
56936
  filePath(scope, sessionId) {
56748
- return import_node_path39.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
56937
+ return import_node_path40.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
56749
56938
  }
56750
56939
  cacheKey(scope, sessionId) {
56751
56940
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -56754,7 +56943,7 @@ var GroupFileStore = class {
56754
56943
  readFile(scope, sessionId) {
56755
56944
  const file = this.filePath(scope, sessionId);
56756
56945
  try {
56757
- const raw = import_node_fs35.default.readFileSync(file, "utf8");
56946
+ const raw = import_node_fs36.default.readFileSync(file, "utf8");
56758
56947
  const parsed = JSON.parse(raw);
56759
56948
  if (!Array.isArray(parsed)) {
56760
56949
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -56780,10 +56969,10 @@ var GroupFileStore = class {
56780
56969
  }
56781
56970
  writeFile(scope, sessionId, entries) {
56782
56971
  const file = this.filePath(scope, sessionId);
56783
- import_node_fs35.default.mkdirSync(import_node_path39.default.dirname(file), { recursive: true });
56972
+ import_node_fs36.default.mkdirSync(import_node_path40.default.dirname(file), { recursive: true });
56784
56973
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
56785
- import_node_fs35.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
56786
- import_node_fs35.default.renameSync(tmp, file);
56974
+ import_node_fs36.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
56975
+ import_node_fs36.default.renameSync(tmp, file);
56787
56976
  }
56788
56977
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
56789
56978
  list(scope, sessionId) {
@@ -56869,10 +57058,10 @@ var GroupFileStore = class {
56869
57058
  };
56870
57059
 
56871
57060
  // src/discovery/state-file.ts
56872
- var import_node_fs36 = __toESM(require("fs"), 1);
56873
- var import_node_path40 = __toESM(require("path"), 1);
57061
+ var import_node_fs37 = __toESM(require("fs"), 1);
57062
+ var import_node_path41 = __toESM(require("path"), 1);
56874
57063
  function defaultStateFilePath(dataDir) {
56875
- return import_node_path40.default.join(dataDir, "state.json");
57064
+ return import_node_path41.default.join(dataDir, "state.json");
56876
57065
  }
56877
57066
  function isPidAlive(pid) {
56878
57067
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -56894,7 +57083,7 @@ var StateFileManager = class {
56894
57083
  }
56895
57084
  read() {
56896
57085
  try {
56897
- const raw = import_node_fs36.default.readFileSync(this.file, "utf8");
57086
+ const raw = import_node_fs37.default.readFileSync(this.file, "utf8");
56898
57087
  const parsed = JSON.parse(raw);
56899
57088
  return parsed;
56900
57089
  } catch {
@@ -56908,20 +57097,20 @@ var StateFileManager = class {
56908
57097
  return { status: "stale", existing };
56909
57098
  }
56910
57099
  write(state) {
56911
- import_node_fs36.default.mkdirSync(import_node_path40.default.dirname(this.file), { recursive: true });
57100
+ import_node_fs37.default.mkdirSync(import_node_path41.default.dirname(this.file), { recursive: true });
56912
57101
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
56913
- import_node_fs36.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
56914
- import_node_fs36.default.renameSync(tmp, this.file);
57102
+ import_node_fs37.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
57103
+ import_node_fs37.default.renameSync(tmp, this.file);
56915
57104
  if (process.platform !== "win32") {
56916
57105
  try {
56917
- import_node_fs36.default.chmodSync(this.file, 384);
57106
+ import_node_fs37.default.chmodSync(this.file, 384);
56918
57107
  } catch {
56919
57108
  }
56920
57109
  }
56921
57110
  }
56922
57111
  delete() {
56923
57112
  try {
56924
- import_node_fs36.default.unlinkSync(this.file);
57113
+ import_node_fs37.default.unlinkSync(this.file);
56925
57114
  } catch {
56926
57115
  }
56927
57116
  }
@@ -56935,14 +57124,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
56935
57124
  }
56936
57125
 
56937
57126
  // src/tunnel/tunnel-manager.ts
56938
- var import_node_fs40 = __toESM(require("fs"), 1);
56939
- var import_node_path44 = __toESM(require("path"), 1);
57127
+ var import_node_fs41 = __toESM(require("fs"), 1);
57128
+ var import_node_path45 = __toESM(require("path"), 1);
56940
57129
  var import_node_crypto11 = __toESM(require("crypto"), 1);
56941
- var import_node_child_process10 = require("child_process");
57130
+ var import_node_child_process11 = require("child_process");
56942
57131
 
56943
57132
  // src/tunnel/tunnel-store.ts
56944
- var import_node_fs37 = __toESM(require("fs"), 1);
56945
- var import_node_path41 = __toESM(require("path"), 1);
57133
+ var import_node_fs38 = __toESM(require("fs"), 1);
57134
+ var import_node_path42 = __toESM(require("path"), 1);
56946
57135
  var TunnelStore = class {
56947
57136
  constructor(filePath) {
56948
57137
  this.filePath = filePath;
@@ -56950,7 +57139,7 @@ var TunnelStore = class {
56950
57139
  filePath;
56951
57140
  async get() {
56952
57141
  try {
56953
- const raw = await import_node_fs37.default.promises.readFile(this.filePath, "utf8");
57142
+ const raw = await import_node_fs38.default.promises.readFile(this.filePath, "utf8");
56954
57143
  const obj = JSON.parse(raw);
56955
57144
  if (!isPersistedTunnel(obj)) return null;
56956
57145
  return obj;
@@ -56961,22 +57150,22 @@ var TunnelStore = class {
56961
57150
  }
56962
57151
  }
56963
57152
  async set(v2) {
56964
- const dir = import_node_path41.default.dirname(this.filePath);
56965
- await import_node_fs37.default.promises.mkdir(dir, { recursive: true });
57153
+ const dir = import_node_path42.default.dirname(this.filePath);
57154
+ await import_node_fs38.default.promises.mkdir(dir, { recursive: true });
56966
57155
  const data = JSON.stringify(v2, null, 2);
56967
57156
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
56968
- await import_node_fs37.default.promises.writeFile(tmp, data, { mode: 384 });
57157
+ await import_node_fs38.default.promises.writeFile(tmp, data, { mode: 384 });
56969
57158
  if (process.platform !== "win32") {
56970
57159
  try {
56971
- await import_node_fs37.default.promises.chmod(tmp, 384);
57160
+ await import_node_fs38.default.promises.chmod(tmp, 384);
56972
57161
  } catch {
56973
57162
  }
56974
57163
  }
56975
- await import_node_fs37.default.promises.rename(tmp, this.filePath);
57164
+ await import_node_fs38.default.promises.rename(tmp, this.filePath);
56976
57165
  }
56977
57166
  async clear() {
56978
57167
  try {
56979
- await import_node_fs37.default.promises.unlink(this.filePath);
57168
+ await import_node_fs38.default.promises.unlink(this.filePath);
56980
57169
  } catch (err) {
56981
57170
  const code = err?.code;
56982
57171
  if (code !== "ENOENT") throw err;
@@ -57071,10 +57260,10 @@ function escape(v2) {
57071
57260
  }
57072
57261
 
57073
57262
  // src/tunnel/frpc-binary.ts
57074
- var import_node_fs38 = __toESM(require("fs"), 1);
57075
- var import_node_os13 = __toESM(require("os"), 1);
57076
- var import_node_path42 = __toESM(require("path"), 1);
57077
- var import_node_child_process8 = require("child_process");
57263
+ var import_node_fs39 = __toESM(require("fs"), 1);
57264
+ var import_node_os14 = __toESM(require("os"), 1);
57265
+ var import_node_path43 = __toESM(require("path"), 1);
57266
+ var import_node_child_process9 = require("child_process");
57078
57267
  var import_node_stream3 = require("stream");
57079
57268
  var import_promises6 = require("stream/promises");
57080
57269
  var FRPC_VERSION = "0.68.0";
@@ -57105,20 +57294,20 @@ function frpcDownloadUrl(version2, p2) {
57105
57294
  }
57106
57295
  async function ensureFrpcBinary(opts) {
57107
57296
  if (opts.override) {
57108
- if (!import_node_fs38.default.existsSync(opts.override)) {
57297
+ if (!import_node_fs39.default.existsSync(opts.override)) {
57109
57298
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
57110
57299
  }
57111
57300
  return opts.override;
57112
57301
  }
57113
57302
  const version2 = opts.version ?? FRPC_VERSION;
57114
57303
  const platform = opts.platform ?? detectPlatform();
57115
- const binDir = import_node_path42.default.join(opts.dataDir, "bin");
57116
- import_node_fs38.default.mkdirSync(binDir, { recursive: true });
57304
+ const binDir = import_node_path43.default.join(opts.dataDir, "bin");
57305
+ import_node_fs39.default.mkdirSync(binDir, { recursive: true });
57117
57306
  cleanupStaleArtifacts(binDir);
57118
- const stableBin = import_node_path42.default.join(binDir, "frpc");
57119
- if (import_node_fs38.default.existsSync(stableBin)) return stableBin;
57307
+ const stableBin = import_node_path43.default.join(binDir, "frpc");
57308
+ if (import_node_fs39.default.existsSync(stableBin)) return stableBin;
57120
57309
  const partialBin = `${stableBin}.partial`;
57121
- const tarballPath = import_node_path42.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
57310
+ const tarballPath = import_node_path43.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
57122
57311
  try {
57123
57312
  const url = frpcDownloadUrl(version2, platform);
57124
57313
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -57127,8 +57316,8 @@ async function ensureFrpcBinary(opts) {
57127
57316
  } else {
57128
57317
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
57129
57318
  }
57130
- import_node_fs38.default.chmodSync(partialBin, 493);
57131
- import_node_fs38.default.renameSync(partialBin, stableBin);
57319
+ import_node_fs39.default.chmodSync(partialBin, 493);
57320
+ import_node_fs39.default.renameSync(partialBin, stableBin);
57132
57321
  } finally {
57133
57322
  safeUnlink(tarballPath);
57134
57323
  safeUnlink(partialBin);
@@ -57138,15 +57327,15 @@ async function ensureFrpcBinary(opts) {
57138
57327
  function cleanupStaleArtifacts(binDir) {
57139
57328
  let entries;
57140
57329
  try {
57141
- entries = import_node_fs38.default.readdirSync(binDir);
57330
+ entries = import_node_fs39.default.readdirSync(binDir);
57142
57331
  } catch {
57143
57332
  return;
57144
57333
  }
57145
57334
  for (const name of entries) {
57146
57335
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
57147
- const full = import_node_path42.default.join(binDir, name);
57336
+ const full = import_node_path43.default.join(binDir, name);
57148
57337
  try {
57149
- import_node_fs38.default.rmSync(full, { recursive: true, force: true });
57338
+ import_node_fs39.default.rmSync(full, { recursive: true, force: true });
57150
57339
  } catch {
57151
57340
  }
57152
57341
  }
@@ -57154,7 +57343,7 @@ function cleanupStaleArtifacts(binDir) {
57154
57343
  }
57155
57344
  function safeUnlink(p2) {
57156
57345
  try {
57157
- import_node_fs38.default.unlinkSync(p2);
57346
+ import_node_fs39.default.unlinkSync(p2);
57158
57347
  } catch {
57159
57348
  }
57160
57349
  }
@@ -57165,46 +57354,46 @@ async function downloadToFile(url, dest, fetchImpl) {
57165
57354
  if (!res.ok || !res.body) {
57166
57355
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
57167
57356
  }
57168
- const out = import_node_fs38.default.createWriteStream(dest);
57357
+ const out = import_node_fs39.default.createWriteStream(dest);
57169
57358
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
57170
57359
  await (0, import_promises6.pipeline)(nodeStream, out);
57171
57360
  }
57172
57361
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
57173
- const work = import_node_path42.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
57174
- import_node_fs38.default.mkdirSync(work, { recursive: true });
57362
+ const work = import_node_path43.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
57363
+ import_node_fs39.default.mkdirSync(work, { recursive: true });
57175
57364
  try {
57176
57365
  await new Promise((resolve6, reject) => {
57177
- const proc = (0, import_node_child_process8.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
57366
+ const proc = (0, import_node_child_process9.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
57178
57367
  proc.on("error", reject);
57179
57368
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
57180
57369
  });
57181
57370
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
57182
- const src = import_node_path42.default.join(work, dirName, "frpc");
57183
- if (!import_node_fs38.default.existsSync(src)) {
57371
+ const src = import_node_path43.default.join(work, dirName, "frpc");
57372
+ if (!import_node_fs39.default.existsSync(src)) {
57184
57373
  throw new Error(`frpc not found inside tarball at ${src}`);
57185
57374
  }
57186
- import_node_fs38.default.copyFileSync(src, destBin);
57375
+ import_node_fs39.default.copyFileSync(src, destBin);
57187
57376
  } finally {
57188
- import_node_fs38.default.rmSync(work, { recursive: true, force: true });
57377
+ import_node_fs39.default.rmSync(work, { recursive: true, force: true });
57189
57378
  }
57190
57379
  }
57191
57380
 
57192
57381
  // src/tunnel/frpc-process.ts
57193
- var import_node_fs39 = __toESM(require("fs"), 1);
57194
- var import_node_path43 = __toESM(require("path"), 1);
57195
- var import_node_child_process9 = require("child_process");
57382
+ var import_node_fs40 = __toESM(require("fs"), 1);
57383
+ var import_node_path44 = __toESM(require("path"), 1);
57384
+ var import_node_child_process10 = require("child_process");
57196
57385
  function frpcPidFilePath(dataDir) {
57197
- return import_node_path43.default.join(dataDir, "frpc.pid");
57386
+ return import_node_path44.default.join(dataDir, "frpc.pid");
57198
57387
  }
57199
57388
  function writeFrpcPid(dataDir, pid) {
57200
57389
  try {
57201
- import_node_fs39.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
57390
+ import_node_fs40.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
57202
57391
  } catch {
57203
57392
  }
57204
57393
  }
57205
57394
  function clearFrpcPid(dataDir) {
57206
57395
  try {
57207
- import_node_fs39.default.unlinkSync(frpcPidFilePath(dataDir));
57396
+ import_node_fs40.default.unlinkSync(frpcPidFilePath(dataDir));
57208
57397
  } catch {
57209
57398
  }
57210
57399
  }
@@ -57220,7 +57409,7 @@ function defaultIsPidAlive(pid) {
57220
57409
  }
57221
57410
  function defaultReadPidFile(file) {
57222
57411
  try {
57223
- return import_node_fs39.default.readFileSync(file, "utf8");
57412
+ return import_node_fs40.default.readFileSync(file, "utf8");
57224
57413
  } catch {
57225
57414
  return null;
57226
57415
  }
@@ -57236,7 +57425,7 @@ function defaultSleep2(ms) {
57236
57425
  }
57237
57426
  async function killStaleFrpc(deps) {
57238
57427
  const pidFile = frpcPidFilePath(deps.dataDir);
57239
- const tomlPath = import_node_path43.default.join(deps.dataDir, "frpc.toml");
57428
+ const tomlPath = import_node_path44.default.join(deps.dataDir, "frpc.toml");
57240
57429
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
57241
57430
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
57242
57431
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -57260,7 +57449,7 @@ async function killStaleFrpc(deps) {
57260
57449
  }
57261
57450
  if (victims.size === 0) {
57262
57451
  try {
57263
- import_node_fs39.default.unlinkSync(pidFile);
57452
+ import_node_fs40.default.unlinkSync(pidFile);
57264
57453
  } catch {
57265
57454
  }
57266
57455
  return;
@@ -57271,14 +57460,14 @@ async function killStaleFrpc(deps) {
57271
57460
  }
57272
57461
  await sleep2(deps.reapWaitMs ?? 300);
57273
57462
  try {
57274
- import_node_fs39.default.unlinkSync(pidFile);
57463
+ import_node_fs40.default.unlinkSync(pidFile);
57275
57464
  } catch {
57276
57465
  }
57277
57466
  }
57278
57467
  async function defaultScanFrpcPidsByCmdline(tomlPath, logger) {
57279
57468
  if (process.platform === "win32") return [];
57280
57469
  return new Promise((resolve6) => {
57281
- const ps = (0, import_node_child_process9.spawn)("ps", ["-axo", "pid=,command="], { stdio: ["ignore", "pipe", "ignore"] });
57470
+ const ps = (0, import_node_child_process10.spawn)("ps", ["-axo", "pid=,command="], { stdio: ["ignore", "pipe", "ignore"] });
57282
57471
  let buf = "";
57283
57472
  ps.stdout.on("data", (c) => {
57284
57473
  buf += c.toString();
@@ -57308,7 +57497,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
57308
57497
  var TunnelManager = class {
57309
57498
  constructor(deps) {
57310
57499
  this.deps = deps;
57311
- this.store = deps.store ?? new TunnelStore(import_node_path44.default.join(deps.dataDir, "tunnel.json"));
57500
+ this.store = deps.store ?? new TunnelStore(import_node_path45.default.join(deps.dataDir, "tunnel.json"));
57312
57501
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
57313
57502
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
57314
57503
  }
@@ -57435,7 +57624,7 @@ var TunnelManager = class {
57435
57624
  dataDir: this.deps.dataDir,
57436
57625
  override: this.deps.frpcBinaryOverride ?? void 0
57437
57626
  });
57438
- const tomlPath = import_node_path44.default.join(this.deps.dataDir, "frpc.toml");
57627
+ const tomlPath = import_node_path45.default.join(this.deps.dataDir, "frpc.toml");
57439
57628
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto11.default.randomBytes(3).toString("hex")}`;
57440
57629
  const toml = buildFrpcToml({
57441
57630
  serverAddr: t.frpsHost,
@@ -57446,14 +57635,14 @@ var TunnelManager = class {
57446
57635
  localPort,
57447
57636
  logLevel: "info"
57448
57637
  });
57449
- await import_node_fs40.default.promises.writeFile(tomlPath, toml, { mode: 384 });
57450
- const proc = (this.deps.spawnImpl ?? import_node_child_process10.spawn)(frpcBin, ["-c", tomlPath], {
57638
+ await import_node_fs41.default.promises.writeFile(tomlPath, toml, { mode: 384 });
57639
+ const proc = (this.deps.spawnImpl ?? import_node_child_process11.spawn)(frpcBin, ["-c", tomlPath], {
57451
57640
  stdio: ["ignore", "pipe", "pipe"]
57452
57641
  });
57453
- const logDir = import_node_path44.default.join(this.deps.dataDir, "log");
57454
- import_node_fs40.default.mkdirSync(logDir, { recursive: true });
57455
- const logFilePath = import_node_path44.default.join(logDir, "frpc.log");
57456
- const logStream = import_node_fs40.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
57642
+ const logDir = import_node_path45.default.join(this.deps.dataDir, "log");
57643
+ import_node_fs41.default.mkdirSync(logDir, { recursive: true });
57644
+ const logFilePath = import_node_path45.default.join(logDir, "frpc.log");
57645
+ const logStream = import_node_fs41.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
57457
57646
  logStream.on("error", () => {
57458
57647
  });
57459
57648
  const tee = (chunk) => {
@@ -57535,28 +57724,28 @@ async function waitForFrpcReady(proc, timeoutMs) {
57535
57724
  }
57536
57725
 
57537
57726
  // src/tunnel/device-key.ts
57538
- var import_node_os14 = __toESM(require("os"), 1);
57539
- var import_node_path45 = __toESM(require("path"), 1);
57727
+ var import_node_os15 = __toESM(require("os"), 1);
57728
+ var import_node_path46 = __toESM(require("path"), 1);
57540
57729
  var import_node_crypto12 = __toESM(require("crypto"), 1);
57541
57730
  var DERIVE_SALT = "clawd-tunnel-device-v1";
57542
57731
  function deriveStableDeviceKey(opts = {}) {
57543
- const hostname = opts.hostname ?? import_node_os14.default.hostname();
57544
- const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
57545
- const home = opts.home ?? import_node_os14.default.homedir();
57546
- const defaultDataDir = import_node_path45.default.resolve(import_node_path45.default.join(home, ".clawd"));
57547
- const normalizedDataDir = opts.dataDir ? import_node_path45.default.resolve(opts.dataDir) : null;
57732
+ const hostname = opts.hostname ?? import_node_os15.default.hostname();
57733
+ const uid = opts.uid ?? (typeof import_node_os15.default.userInfo === "function" ? import_node_os15.default.userInfo().uid : 0);
57734
+ const home = opts.home ?? import_node_os15.default.homedir();
57735
+ const defaultDataDir = import_node_path46.default.resolve(import_node_path46.default.join(home, ".clawd"));
57736
+ const normalizedDataDir = opts.dataDir ? import_node_path46.default.resolve(opts.dataDir) : null;
57548
57737
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
57549
57738
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
57550
57739
  return import_node_crypto12.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
57551
57740
  }
57552
57741
 
57553
57742
  // src/auth-store.ts
57554
- var import_node_fs41 = __toESM(require("fs"), 1);
57555
- var import_node_path46 = __toESM(require("path"), 1);
57743
+ var import_node_fs42 = __toESM(require("fs"), 1);
57744
+ var import_node_path47 = __toESM(require("path"), 1);
57556
57745
  var import_node_crypto13 = __toESM(require("crypto"), 1);
57557
57746
  var AUTH_FILE_NAME = "auth.json";
57558
57747
  function authFilePath(dataDir) {
57559
- return import_node_path46.default.join(dataDir, AUTH_FILE_NAME);
57748
+ return import_node_path47.default.join(dataDir, AUTH_FILE_NAME);
57560
57749
  }
57561
57750
  function loadOrCreateAuthFile(opts) {
57562
57751
  const file = authFilePath(opts.dataDir);
@@ -57588,7 +57777,7 @@ function defaultGenerateOwnerPrincipalId() {
57588
57777
  }
57589
57778
  function readAuthFile(file) {
57590
57779
  try {
57591
- const raw = import_node_fs41.default.readFileSync(file, "utf8");
57780
+ const raw = import_node_fs42.default.readFileSync(file, "utf8");
57592
57781
  const parsed = JSON.parse(raw);
57593
57782
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
57594
57783
  return null;
@@ -57608,26 +57797,26 @@ function readAuthFile(file) {
57608
57797
  }
57609
57798
  }
57610
57799
  function writeAuthFile(file, content) {
57611
- import_node_fs41.default.mkdirSync(import_node_path46.default.dirname(file), { recursive: true });
57612
- import_node_fs41.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
57800
+ import_node_fs42.default.mkdirSync(import_node_path47.default.dirname(file), { recursive: true });
57801
+ import_node_fs42.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
57613
57802
  try {
57614
- import_node_fs41.default.chmodSync(file, 384);
57803
+ import_node_fs42.default.chmodSync(file, 384);
57615
57804
  } catch {
57616
57805
  }
57617
57806
  }
57618
57807
 
57619
57808
  // src/owner-profile.ts
57620
- var import_node_fs42 = __toESM(require("fs"), 1);
57621
- var import_node_os15 = __toESM(require("os"), 1);
57622
- var import_node_path47 = __toESM(require("path"), 1);
57809
+ var import_node_fs43 = __toESM(require("fs"), 1);
57810
+ var import_node_os16 = __toESM(require("os"), 1);
57811
+ var import_node_path48 = __toESM(require("path"), 1);
57623
57812
  var PROFILE_FILENAME = "profile.json";
57624
57813
  function profilePath(dataDir) {
57625
- return import_node_path47.default.join(dataDir, PROFILE_FILENAME);
57814
+ return import_node_path48.default.join(dataDir, PROFILE_FILENAME);
57626
57815
  }
57627
57816
  function loadOwnerProfile(dataDir) {
57628
57817
  let raw;
57629
57818
  try {
57630
- raw = import_node_fs42.default.readFileSync(profilePath(dataDir), "utf8");
57819
+ raw = import_node_fs43.default.readFileSync(profilePath(dataDir), "utf8");
57631
57820
  } catch {
57632
57821
  return {};
57633
57822
  }
@@ -57643,11 +57832,11 @@ function loadOwnerProfile(dataDir) {
57643
57832
  }
57644
57833
  function patchOwnerProfile(dataDir, patch) {
57645
57834
  const merged = { ...loadOwnerProfile(dataDir), ...patch };
57646
- import_node_fs42.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
57835
+ import_node_fs43.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
57647
57836
  return merged;
57648
57837
  }
57649
57838
  function loadOwnerDisplayName(dataDir) {
57650
- const fallback = import_node_os15.default.userInfo().username;
57839
+ const fallback = import_node_os16.default.userInfo().username;
57651
57840
  const displayName = loadOwnerProfile(dataDir).displayName;
57652
57841
  if (typeof displayName !== "string" || displayName.length === 0) {
57653
57842
  if (displayName !== void 0) {
@@ -57659,18 +57848,18 @@ function loadOwnerDisplayName(dataDir) {
57659
57848
  }
57660
57849
 
57661
57850
  // src/feishu-auth/owner-identity-store.ts
57662
- var import_node_fs43 = __toESM(require("fs"), 1);
57663
- var import_node_path48 = __toESM(require("path"), 1);
57851
+ var import_node_fs44 = __toESM(require("fs"), 1);
57852
+ var import_node_path49 = __toESM(require("path"), 1);
57664
57853
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
57665
57854
  var OwnerIdentityStore = class {
57666
57855
  file;
57667
57856
  constructor(dataDir) {
57668
- this.file = import_node_path48.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
57857
+ this.file = import_node_path49.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
57669
57858
  }
57670
57859
  read() {
57671
57860
  let raw;
57672
57861
  try {
57673
- raw = import_node_fs43.default.readFileSync(this.file, "utf8");
57862
+ raw = import_node_fs44.default.readFileSync(this.file, "utf8");
57674
57863
  } catch {
57675
57864
  return null;
57676
57865
  }
@@ -57698,16 +57887,16 @@ var OwnerIdentityStore = class {
57698
57887
  };
57699
57888
  }
57700
57889
  write(record) {
57701
- import_node_fs43.default.mkdirSync(import_node_path48.default.dirname(this.file), { recursive: true });
57702
- import_node_fs43.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
57890
+ import_node_fs44.default.mkdirSync(import_node_path49.default.dirname(this.file), { recursive: true });
57891
+ import_node_fs44.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
57703
57892
  try {
57704
- import_node_fs43.default.chmodSync(this.file, 384);
57893
+ import_node_fs44.default.chmodSync(this.file, 384);
57705
57894
  } catch {
57706
57895
  }
57707
57896
  }
57708
57897
  clear() {
57709
57898
  try {
57710
- import_node_fs43.default.unlinkSync(this.file);
57899
+ import_node_fs44.default.unlinkSync(this.file);
57711
57900
  } catch (err) {
57712
57901
  const code = err?.code;
57713
57902
  if (code !== "ENOENT") throw err;
@@ -57844,9 +58033,9 @@ var CentralClientError = class extends Error {
57844
58033
  code;
57845
58034
  cause;
57846
58035
  };
57847
- async function centralRequest(opts, path81, init) {
58036
+ async function centralRequest(opts, path82, init) {
57848
58037
  const f = opts.fetchImpl ?? globalThis.fetch;
57849
- const url = `${opts.api.replace(/\/+$/, "")}${path81}`;
58038
+ const url = `${opts.api.replace(/\/+$/, "")}${path82}`;
57850
58039
  const ctrl = new AbortController();
57851
58040
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
57852
58041
  let res;
@@ -58040,8 +58229,8 @@ function verifyConnectToken(args) {
58040
58229
  }
58041
58230
 
58042
58231
  // src/feishu-auth/server-key.ts
58043
- var fs54 = __toESM(require("fs"), 1);
58044
- var path57 = __toESM(require("path"), 1);
58232
+ var fs55 = __toESM(require("fs"), 1);
58233
+ var path58 = __toESM(require("path"), 1);
58045
58234
  var FILE_NAME2 = "server-signing-key.json";
58046
58235
  var ServerKeyStore = class {
58047
58236
  constructor(dataDir) {
@@ -58049,12 +58238,12 @@ var ServerKeyStore = class {
58049
58238
  }
58050
58239
  dataDir;
58051
58240
  filePath() {
58052
- return path57.join(this.dataDir, FILE_NAME2);
58241
+ return path58.join(this.dataDir, FILE_NAME2);
58053
58242
  }
58054
58243
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
58055
58244
  read() {
58056
58245
  try {
58057
- const raw = fs54.readFileSync(this.filePath(), "utf8");
58246
+ const raw = fs55.readFileSync(this.filePath(), "utf8");
58058
58247
  const parsed = JSON.parse(raw);
58059
58248
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
58060
58249
  return parsed.publicKeyPem;
@@ -58069,12 +58258,12 @@ var ServerKeyStore = class {
58069
58258
  publicKeyPem,
58070
58259
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
58071
58260
  };
58072
- fs54.mkdirSync(this.dataDir, { recursive: true });
58073
- fs54.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
58261
+ fs55.mkdirSync(this.dataDir, { recursive: true });
58262
+ fs55.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
58074
58263
  }
58075
58264
  clear() {
58076
58265
  try {
58077
- fs54.unlinkSync(this.filePath());
58266
+ fs55.unlinkSync(this.filePath());
58078
58267
  } catch {
58079
58268
  }
58080
58269
  }
@@ -58087,12 +58276,12 @@ init_protocol();
58087
58276
  init_protocol();
58088
58277
 
58089
58278
  // src/session/fork.ts
58090
- var import_node_fs44 = __toESM(require("fs"), 1);
58091
- var import_node_os16 = __toESM(require("os"), 1);
58092
- var import_node_path49 = __toESM(require("path"), 1);
58279
+ var import_node_fs45 = __toESM(require("fs"), 1);
58280
+ var import_node_os17 = __toESM(require("os"), 1);
58281
+ var import_node_path50 = __toESM(require("path"), 1);
58093
58282
  init_claude_history();
58094
58283
  function readJsonlEntries(file) {
58095
- const raw = import_node_fs44.default.readFileSync(file, "utf8");
58284
+ const raw = import_node_fs45.default.readFileSync(file, "utf8");
58096
58285
  const out = [];
58097
58286
  for (const line of raw.split("\n")) {
58098
58287
  const t = line.trim();
@@ -58105,19 +58294,19 @@ function readJsonlEntries(file) {
58105
58294
  return out;
58106
58295
  }
58107
58296
  function forkSession(input) {
58108
- const baseDir = input.baseDir ?? import_node_path49.default.join(import_node_os16.default.homedir(), ".claude");
58109
- let projectDir = import_node_path49.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
58110
- let sourceFile = import_node_path49.default.join(projectDir, `${input.toolSessionId}.jsonl`);
58111
- if (!import_node_fs44.default.existsSync(sourceFile)) {
58297
+ const baseDir = input.baseDir ?? import_node_path50.default.join(import_node_os17.default.homedir(), ".claude");
58298
+ let projectDir = import_node_path50.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
58299
+ let sourceFile = import_node_path50.default.join(projectDir, `${input.toolSessionId}.jsonl`);
58300
+ if (!import_node_fs45.default.existsSync(sourceFile)) {
58112
58301
  const found = findTranscriptByToolSessionId(
58113
- import_node_path49.default.join(baseDir, "projects"),
58302
+ import_node_path50.default.join(baseDir, "projects"),
58114
58303
  input.toolSessionId
58115
58304
  );
58116
58305
  if (!found) {
58117
58306
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
58118
58307
  }
58119
58308
  sourceFile = found;
58120
- projectDir = import_node_path49.default.dirname(found);
58309
+ projectDir = import_node_path50.default.dirname(found);
58121
58310
  }
58122
58311
  const entries = readJsonlEntries(sourceFile);
58123
58312
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -58146,27 +58335,27 @@ function forkSession(input) {
58146
58335
  }
58147
58336
  forkedLines.push(JSON.stringify(forked));
58148
58337
  }
58149
- const outDir = input.targetCwd ? import_node_path49.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
58150
- const forkedFilePath = import_node_path49.default.join(outDir, `${forkedToolSessionId}.jsonl`);
58151
- import_node_fs44.default.mkdirSync(outDir, { recursive: true });
58152
- import_node_fs44.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
58338
+ const outDir = input.targetCwd ? import_node_path50.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
58339
+ const forkedFilePath = import_node_path50.default.join(outDir, `${forkedToolSessionId}.jsonl`);
58340
+ import_node_fs45.default.mkdirSync(outDir, { recursive: true });
58341
+ import_node_fs45.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
58153
58342
  return { forkedToolSessionId, forkedFilePath };
58154
58343
  }
58155
58344
 
58156
58345
  // src/session/external-scan.ts
58157
- var import_node_fs45 = __toESM(require("fs"), 1);
58346
+ var import_node_fs46 = __toESM(require("fs"), 1);
58158
58347
  var import_promises7 = __toESM(require("fs/promises"), 1);
58159
- var import_node_os17 = __toESM(require("os"), 1);
58160
- var import_node_path50 = __toESM(require("path"), 1);
58348
+ var import_node_os18 = __toESM(require("os"), 1);
58349
+ var import_node_path51 = __toESM(require("path"), 1);
58161
58350
  var import_node_module = require("module");
58162
- var import_node_child_process11 = require("child_process");
58351
+ var import_node_child_process12 = require("child_process");
58163
58352
  var import_meta4 = {};
58164
58353
  function defaultRoots() {
58165
- const home = import_node_os17.default.homedir();
58354
+ const home = import_node_os18.default.homedir();
58166
58355
  return {
58167
- claudeProjectsDir: import_node_path50.default.join(home, ".claude", "projects"),
58168
- codexDir: import_node_path50.default.join(home, ".codex"),
58169
- clawdDir: import_node_path50.default.join(home, ".clawd")
58356
+ claudeProjectsDir: import_node_path51.default.join(home, ".claude", "projects"),
58357
+ codexDir: import_node_path51.default.join(home, ".codex"),
58358
+ clawdDir: import_node_path51.default.join(home, ".clawd")
58170
58359
  };
58171
58360
  }
58172
58361
  function width(s) {
@@ -58194,12 +58383,12 @@ function toMs(v2) {
58194
58383
  function listFiles(dir, depth = 0, maxDepth = 8, out = []) {
58195
58384
  let entries;
58196
58385
  try {
58197
- entries = import_node_fs45.default.readdirSync(dir, { withFileTypes: true });
58386
+ entries = import_node_fs46.default.readdirSync(dir, { withFileTypes: true });
58198
58387
  } catch {
58199
58388
  return out;
58200
58389
  }
58201
58390
  for (const e of entries) {
58202
- const full = import_node_path50.default.join(dir, e.name);
58391
+ const full = import_node_path51.default.join(dir, e.name);
58203
58392
  if (e.isDirectory()) {
58204
58393
  if (depth < maxDepth) listFiles(full, depth + 1, maxDepth, out);
58205
58394
  } else if (e.isFile()) {
@@ -58234,7 +58423,7 @@ function userText(msg) {
58234
58423
  }
58235
58424
  function isDir2(p2) {
58236
58425
  try {
58237
- return import_node_fs45.default.statSync(p2).isDirectory();
58426
+ return import_node_fs46.default.statSync(p2).isDirectory();
58238
58427
  } catch {
58239
58428
  return false;
58240
58429
  }
@@ -58243,7 +58432,7 @@ async function scanClaude(roots) {
58243
58432
  const out = [];
58244
58433
  let dirs;
58245
58434
  try {
58246
- dirs = import_node_fs45.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
58435
+ dirs = import_node_fs46.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
58247
58436
  } catch {
58248
58437
  return out;
58249
58438
  }
@@ -58251,16 +58440,16 @@ async function scanClaude(roots) {
58251
58440
  if (!d.isDirectory()) continue;
58252
58441
  let files;
58253
58442
  try {
58254
- files = import_node_fs45.default.readdirSync(import_node_path50.default.join(roots.claudeProjectsDir, d.name));
58443
+ files = import_node_fs46.default.readdirSync(import_node_path51.default.join(roots.claudeProjectsDir, d.name));
58255
58444
  } catch {
58256
58445
  continue;
58257
58446
  }
58258
58447
  for (const name of files) {
58259
58448
  if (!name.endsWith(".jsonl")) continue;
58260
- const file = import_node_path50.default.join(roots.claudeProjectsDir, d.name, name);
58449
+ const file = import_node_path51.default.join(roots.claudeProjectsDir, d.name, name);
58261
58450
  let st;
58262
58451
  try {
58263
- st = import_node_fs45.default.statSync(file);
58452
+ st = import_node_fs46.default.statSync(file);
58264
58453
  } catch {
58265
58454
  continue;
58266
58455
  }
@@ -58304,13 +58493,14 @@ async function scanClaude(roots) {
58304
58493
  };
58305
58494
  if (!hasMainLine) cand.skip = "subagent \u652F\u7EBF";
58306
58495
  else if (!cwd) cand.skip = "\u65E0 cwd";
58496
+ else if (cwd.includes("clawd-title-gen")) cand.skip = "\u6807\u9898\u751F\u6210\u4E34\u65F6\u4F1A\u8BDD";
58307
58497
  out.push(cand);
58308
58498
  }
58309
58499
  }
58310
58500
  return out;
58311
58501
  }
58312
58502
  async function countCodexTurns(rolloutPath) {
58313
- if (!rolloutPath || !import_node_fs45.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
58503
+ if (!rolloutPath || !import_node_fs46.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
58314
58504
  let turns = 0;
58315
58505
  let first = "";
58316
58506
  for await (const rec4 of jsonLines(rolloutPath)) {
@@ -58341,14 +58531,14 @@ function readCodexThreads(db) {
58341
58531
  } catch {
58342
58532
  }
58343
58533
  try {
58344
- const info = (0, import_node_child_process11.spawnSync)("sqlite3", [db, "PRAGMA table_info(threads);"], { encoding: "utf8" });
58534
+ const info = (0, import_node_child_process12.spawnSync)("sqlite3", [db, "PRAGMA table_info(threads);"], { encoding: "utf8" });
58345
58535
  if (info.status !== 0) return null;
58346
58536
  const have = new Set(
58347
58537
  info.stdout.split("\n").map((l) => l.split("|")[1]).filter(Boolean)
58348
58538
  );
58349
58539
  if (!["id", "cwd", "updated_at"].every((c) => have.has(c))) return null;
58350
58540
  const sel = COLS.map((c) => have.has(c) ? c : `NULL AS ${c}`).join(", ");
58351
- const res = (0, import_node_child_process11.spawnSync)("sqlite3", ["-json", db, `SELECT ${sel} FROM threads;`], {
58541
+ const res = (0, import_node_child_process12.spawnSync)("sqlite3", ["-json", db, `SELECT ${sel} FROM threads;`], {
58352
58542
  encoding: "utf8",
58353
58543
  maxBuffer: 64 * 1024 * 1024
58354
58544
  });
@@ -58382,11 +58572,11 @@ async function codexFromRows(rows) {
58382
58572
  }
58383
58573
  async function scanCodexRollouts(roots) {
58384
58574
  const out = [];
58385
- for (const file of listFiles(import_node_path50.default.join(roots.codexDir, "sessions"))) {
58575
+ for (const file of listFiles(import_node_path51.default.join(roots.codexDir, "sessions"))) {
58386
58576
  if (!file.endsWith(".jsonl")) continue;
58387
58577
  let st;
58388
58578
  try {
58389
- st = import_node_fs45.default.statSync(file);
58579
+ st = import_node_fs46.default.statSync(file);
58390
58580
  } catch {
58391
58581
  continue;
58392
58582
  }
@@ -58418,7 +58608,7 @@ async function scanCodexRollouts(roots) {
58418
58608
  async function scanCodex(roots) {
58419
58609
  let dbs = [];
58420
58610
  try {
58421
- dbs = import_node_fs45.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path50.default.join(roots.codexDir, n));
58611
+ dbs = import_node_fs46.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path51.default.join(roots.codexDir, n));
58422
58612
  } catch {
58423
58613
  }
58424
58614
  if (dbs.length) {
@@ -58429,14 +58619,14 @@ async function scanCodex(roots) {
58429
58619
  }
58430
58620
  async function scanExternalSessions(rootsIn) {
58431
58621
  const roots = { ...defaultRoots(), ...rootsIn };
58432
- const personaRoot = import_node_path50.default.join(roots.clawdDir, "personas");
58622
+ const personaRoot = import_node_path51.default.join(roots.clawdDir, "personas");
58433
58623
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
58434
58624
  const out = [];
58435
58625
  for (const c of all) {
58436
58626
  if (c.skip) continue;
58437
58627
  if (c.turns < 1) continue;
58438
58628
  if (!c.cwd || !isDir2(c.cwd)) continue;
58439
- if (c.cwd === roots.clawdDir || c.cwd === personaRoot || c.cwd.startsWith(personaRoot + import_node_path50.default.sep) || c.cwd.startsWith(roots.clawdDir + import_node_path50.default.sep)) {
58629
+ if (c.cwd === roots.clawdDir || c.cwd === personaRoot || c.cwd.startsWith(personaRoot + import_node_path51.default.sep) || c.cwd.startsWith(roots.clawdDir + import_node_path51.default.sep)) {
58440
58630
  continue;
58441
58631
  }
58442
58632
  out.push({
@@ -58453,19 +58643,19 @@ async function scanExternalSessions(rootsIn) {
58453
58643
  }
58454
58644
 
58455
58645
  // src/session/import-ledger.ts
58456
- var import_node_fs46 = __toESM(require("fs"), 1);
58457
- var import_node_path51 = __toESM(require("path"), 1);
58646
+ var import_node_fs47 = __toESM(require("fs"), 1);
58647
+ var import_node_path52 = __toESM(require("path"), 1);
58458
58648
  var LEDGER_FILENAME = "session-import-ledger.json";
58459
58649
  function appendImportLedger(dataDir, entry) {
58460
- const file = import_node_path51.default.join(dataDir, LEDGER_FILENAME);
58650
+ const file = import_node_path52.default.join(dataDir, LEDGER_FILENAME);
58461
58651
  let entries = [];
58462
58652
  try {
58463
- const parsed = JSON.parse(import_node_fs46.default.readFileSync(file, "utf8"));
58653
+ const parsed = JSON.parse(import_node_fs47.default.readFileSync(file, "utf8"));
58464
58654
  if (Array.isArray(parsed)) entries = parsed;
58465
58655
  } catch {
58466
58656
  }
58467
58657
  entries.push(entry);
58468
- import_node_fs46.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
58658
+ import_node_fs47.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
58469
58659
  }
58470
58660
 
58471
58661
  // src/handlers/session.ts
@@ -58958,7 +59148,7 @@ function buildPermissionHandlers(deps) {
58958
59148
  }
58959
59149
 
58960
59150
  // src/handlers/history.ts
58961
- var path62 = __toESM(require("path"), 1);
59151
+ var path63 = __toESM(require("path"), 1);
58962
59152
  init_protocol();
58963
59153
 
58964
59154
  // src/session/recent-dirs.ts
@@ -58976,7 +59166,7 @@ function listRecentDirs(store, limit = 50) {
58976
59166
  }
58977
59167
 
58978
59168
  // src/permission/persona-paths.ts
58979
- var path61 = __toESM(require("path"), 1);
59169
+ var path62 = __toESM(require("path"), 1);
58980
59170
  function getAllowedPersonaIds(grants, action) {
58981
59171
  const ids = /* @__PURE__ */ new Set();
58982
59172
  for (const g2 of grants) {
@@ -58989,42 +59179,42 @@ function getAllowedPersonaIds(grants, action) {
58989
59179
  return ids;
58990
59180
  }
58991
59181
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
58992
- const target = path61.resolve(absPath);
59182
+ const target = path62.resolve(absPath);
58993
59183
  if (userWorkDir) {
58994
- const u = path61.resolve(userWorkDir);
58995
- const usep = u.endsWith(path61.sep) ? "" : path61.sep;
59184
+ const u = path62.resolve(userWorkDir);
59185
+ const usep = u.endsWith(path62.sep) ? "" : path62.sep;
58996
59186
  if (target === u || target.startsWith(u + usep)) return true;
58997
59187
  }
58998
- const root = path61.resolve(personaRoot);
58999
- const sep3 = root.endsWith(path61.sep) ? "" : path61.sep;
59188
+ const root = path62.resolve(personaRoot);
59189
+ const sep3 = root.endsWith(path62.sep) ? "" : path62.sep;
59000
59190
  if (!target.startsWith(root + sep3)) return false;
59001
- const rel = path61.relative(root, target);
59191
+ const rel = path62.relative(root, target);
59002
59192
  if (!rel || rel.startsWith("..")) return false;
59003
- const personaId2 = rel.split(path61.sep)[0];
59193
+ const personaId2 = rel.split(path62.sep)[0];
59004
59194
  if (!personaId2) return false;
59005
59195
  const allowed = getAllowedPersonaIds(grants, action);
59006
59196
  if (allowed === "*") return true;
59007
59197
  return allowed.has(personaId2);
59008
59198
  }
59009
59199
  function personaIdFromPath(absPath, personaRoot) {
59010
- const root = path61.resolve(personaRoot);
59011
- const target = path61.resolve(absPath);
59012
- const sep3 = root.endsWith(path61.sep) ? "" : path61.sep;
59200
+ const root = path62.resolve(personaRoot);
59201
+ const target = path62.resolve(absPath);
59202
+ const sep3 = root.endsWith(path62.sep) ? "" : path62.sep;
59013
59203
  if (!target.startsWith(root + sep3)) return null;
59014
- const rel = path61.relative(root, target);
59204
+ const rel = path62.relative(root, target);
59015
59205
  if (!rel || rel.startsWith("..")) return null;
59016
- const id = rel.split(path61.sep)[0];
59206
+ const id = rel.split(path62.sep)[0];
59017
59207
  return id || null;
59018
59208
  }
59019
59209
  function isPathWithin(dir, absPath) {
59020
- const d = path61.resolve(dir);
59021
- const t = path61.resolve(absPath);
59022
- const sep3 = d.endsWith(path61.sep) ? "" : path61.sep;
59210
+ const d = path62.resolve(dir);
59211
+ const t = path62.resolve(absPath);
59212
+ const sep3 = d.endsWith(path62.sep) ? "" : path62.sep;
59023
59213
  return t === d || t.startsWith(d + sep3);
59024
59214
  }
59025
59215
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
59026
59216
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
59027
- return personaIdFromPath(path61.resolve(absPath), personaRoot) === personaId2;
59217
+ return personaIdFromPath(path62.resolve(absPath), personaRoot) === personaId2;
59028
59218
  }
59029
59219
 
59030
59220
  // src/handlers/history.ts
@@ -59077,7 +59267,7 @@ function buildHistoryHandlers(deps) {
59077
59267
  if (!pid) return false;
59078
59268
  return isGuestPathAllowed(
59079
59269
  ctx.grants,
59080
- path62.join(personaRoot, pid),
59270
+ path63.join(personaRoot, pid),
59081
59271
  personaRoot,
59082
59272
  "read",
59083
59273
  userWorkDir
@@ -59089,7 +59279,7 @@ function buildHistoryHandlers(deps) {
59089
59279
  };
59090
59280
  const list = async (frame, _client, ctx) => {
59091
59281
  const args = HistoryListArgs.parse(frame);
59092
- assertGuestPath(ctx, path62.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
59282
+ assertGuestPath(ctx, path63.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
59093
59283
  const sessions = await history.listSessions(args);
59094
59284
  return { response: { type: "history:list", sessions } };
59095
59285
  };
@@ -59133,14 +59323,14 @@ function buildHistoryHandlers(deps) {
59133
59323
  };
59134
59324
  const subagents = async (frame, _client, ctx) => {
59135
59325
  const args = HistorySubagentsArgs.parse(frame);
59136
- assertGuestPath(ctx, path62.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
59326
+ assertGuestPath(ctx, path63.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
59137
59327
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
59138
59328
  const subs = await history.listSubagents(args);
59139
59329
  return { response: { type: "history:subagents", subagents: subs } };
59140
59330
  };
59141
59331
  const subagentRead = async (frame, _client, ctx) => {
59142
59332
  const args = HistorySubagentReadArgs.parse(frame);
59143
- assertGuestPath(ctx, path62.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
59333
+ assertGuestPath(ctx, path63.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
59144
59334
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
59145
59335
  const res = await history.readSubagent(args);
59146
59336
  return { response: { type: "history:subagent-read", ...res } };
@@ -59150,7 +59340,7 @@ function buildHistoryHandlers(deps) {
59150
59340
  if (ctx?.principal.kind === "guest" && personaRoot) {
59151
59341
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
59152
59342
  const filtered = dirs.filter(
59153
- (d) => isGuestPathAllowed(ctx.grants, path62.resolve(d.cwd), personaRoot, "read", userWorkDir)
59343
+ (d) => isGuestPathAllowed(ctx.grants, path63.resolve(d.cwd), personaRoot, "read", userWorkDir)
59154
59344
  );
59155
59345
  return { response: { type: "history:recentDirs", dirs: filtered } };
59156
59346
  }
@@ -59167,8 +59357,8 @@ function buildHistoryHandlers(deps) {
59167
59357
  }
59168
59358
 
59169
59359
  // src/handlers/workspace.ts
59170
- var path63 = __toESM(require("path"), 1);
59171
- var os17 = __toESM(require("os"), 1);
59360
+ var path64 = __toESM(require("path"), 1);
59361
+ var os18 = __toESM(require("os"), 1);
59172
59362
  init_protocol();
59173
59363
  init_protocol();
59174
59364
  function buildEnabledPluginNames(personaManager, personaId2) {
@@ -59208,23 +59398,23 @@ function buildWorkspaceHandlers(deps) {
59208
59398
  const list = async (frame, _client, ctx) => {
59209
59399
  const args = WorkspaceListArgs.parse(frame);
59210
59400
  const isGuest = ctx?.principal.kind === "guest";
59211
- const fallbackCwd = isGuest && personaRoot ? personaRoot : os17.homedir();
59212
- const resolvedCwd = path63.resolve(args.cwd ?? fallbackCwd);
59213
- const target = args.path ? path63.resolve(resolvedCwd, args.path) : resolvedCwd;
59401
+ const fallbackCwd = isGuest && personaRoot ? personaRoot : os18.homedir();
59402
+ const resolvedCwd = path64.resolve(args.cwd ?? fallbackCwd);
59403
+ const target = args.path ? path64.resolve(resolvedCwd, args.path) : resolvedCwd;
59214
59404
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
59215
59405
  const res = workspace.list({ ...args, cwd: resolvedCwd });
59216
59406
  return { response: { type: "workspace:list", ...res } };
59217
59407
  };
59218
59408
  const read = async (frame, _client, ctx) => {
59219
59409
  const args = WorkspaceReadArgs.parse(frame);
59220
- const target = path63.isAbsolute(args.path) ? path63.resolve(args.path) : path63.resolve(args.cwd, args.path);
59410
+ const target = path64.isAbsolute(args.path) ? path64.resolve(args.path) : path64.resolve(args.cwd, args.path);
59221
59411
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
59222
59412
  const res = workspace.read(args);
59223
59413
  return { response: { type: "workspace:read", ...res } };
59224
59414
  };
59225
59415
  const skillsList = async (frame, _client, ctx) => {
59226
59416
  const args = SkillsListArgs.parse(frame);
59227
- const cwdAbs = path63.resolve(args.cwd);
59417
+ const cwdAbs = path64.resolve(args.cwd);
59228
59418
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
59229
59419
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
59230
59420
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -59236,7 +59426,7 @@ function buildWorkspaceHandlers(deps) {
59236
59426
  };
59237
59427
  const agentsList = async (frame, _client, ctx) => {
59238
59428
  const args = AgentsListArgs.parse(frame);
59239
- const cwdAbs = path63.resolve(args.cwd);
59429
+ const cwdAbs = path64.resolve(args.cwd);
59240
59430
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
59241
59431
  if (args.tool === "codex") {
59242
59432
  return { response: { type: "agents:list", agents: [] } };
@@ -59258,20 +59448,20 @@ function buildWorkspaceHandlers(deps) {
59258
59448
  }
59259
59449
 
59260
59450
  // src/handlers/git.ts
59261
- var path65 = __toESM(require("path"), 1);
59451
+ var path66 = __toESM(require("path"), 1);
59262
59452
  init_protocol();
59263
59453
  init_protocol();
59264
59454
 
59265
59455
  // src/workspace/git.ts
59266
- var import_node_child_process12 = require("child_process");
59267
- var import_node_fs47 = __toESM(require("fs"), 1);
59268
- var import_node_path52 = __toESM(require("path"), 1);
59456
+ var import_node_child_process13 = require("child_process");
59457
+ var import_node_fs48 = __toESM(require("fs"), 1);
59458
+ var import_node_path53 = __toESM(require("path"), 1);
59269
59459
  var import_node_util = require("util");
59270
- var pexec = (0, import_node_util.promisify)(import_node_child_process12.execFile);
59460
+ var pexec = (0, import_node_util.promisify)(import_node_child_process13.execFile);
59271
59461
  function normalizePath(p2) {
59272
- const resolved = import_node_path52.default.resolve(p2);
59462
+ const resolved = import_node_path53.default.resolve(p2);
59273
59463
  try {
59274
- return import_node_fs47.default.realpathSync(resolved);
59464
+ return import_node_fs48.default.realpathSync(resolved);
59275
59465
  } catch {
59276
59466
  return resolved;
59277
59467
  }
@@ -59345,7 +59535,7 @@ async function listGitBranches(cwd) {
59345
59535
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
59346
59536
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
59347
59537
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
59348
- if (!isGuestPathAllowed(ctx.grants, path65.resolve(cwd), personaRoot, "read", userWorkDir)) {
59538
+ if (!isGuestPathAllowed(ctx.grants, path66.resolve(cwd), personaRoot, "read", userWorkDir)) {
59349
59539
  throw new ClawdError(
59350
59540
  ERROR_CODES.UNAUTHORIZED,
59351
59541
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -59836,7 +60026,9 @@ function buildFeishuAuthHandlers(deps) {
59836
60026
  type: "auth:getIdentity:ok",
59837
60027
  identity: record ? record.identity : null,
59838
60028
  // 决策 #15:设备属性,与登录态无关——UI"分享我的 Hub 标识"用
59839
- deviceId: deps.deviceId
60029
+ deviceId: deps.deviceId,
60030
+ // 过期时间戳(仅时间戳,token 本体永不出 ws)——UI 派生 过期/临期 提示
60031
+ ttcTokenExpiresAt: record ? record.ttcTokenExpiresAt : null
59840
60032
  }
59841
60033
  };
59842
60034
  };
@@ -59862,11 +60054,20 @@ function ensureOwner3(ctx) {
59862
60054
  throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "UNAUTHORIZED: device:* requires owner ctx");
59863
60055
  }
59864
60056
  }
60057
+ function rethrowLoginExpired(e) {
60058
+ if (e instanceof CentralClientError && e.code === "UNAUTHORIZED") {
60059
+ throw new ClawdError(
60060
+ ERROR_CODES.VALIDATION_ERROR,
60061
+ "LOGIN_EXPIRED: \u767B\u5F55\u51ED\u8BC1\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u5728\u8054\u7CFB\u4EBA\u9762\u677F\u91CD\u65B0\u767B\u5F55"
60062
+ );
60063
+ }
60064
+ throw e;
60065
+ }
59865
60066
  function buildDeviceHandlers(deps) {
59866
60067
  const now = deps.now ?? Date.now;
59867
60068
  const list = async (_frame, _client, ctx) => {
59868
60069
  ensureOwner3(ctx);
59869
- const devices = await deps.listDevices();
60070
+ const devices = await deps.listDevices().catch(rethrowLoginExpired);
59870
60071
  return {
59871
60072
  response: { type: "device:list:ok", devices }
59872
60073
  };
@@ -59882,7 +60083,7 @@ function buildDeviceHandlers(deps) {
59882
60083
  "TUNNEL_REQUIRED: \u672C\u673A\u672A\u5F00 tunnel\uFF0C\u5F00\u542F\u540E\u91CD\u8BD5"
59883
60084
  );
59884
60085
  }
59885
- const exchanged = await deps.exchange(args.deviceId);
60086
+ const exchanged = await deps.exchange(args.deviceId).catch(rethrowLoginExpired);
59886
60087
  const url = args.url ?? exchanged.deviceUrl;
59887
60088
  if (!url) {
59888
60089
  throw new ClawdError(
@@ -59967,7 +60168,7 @@ function buildDeviceHandlers(deps) {
59967
60168
  }
59968
60169
 
59969
60170
  // src/handlers/meta.ts
59970
- var import_node_os18 = __toESM(require("os"), 1);
60171
+ var import_node_os19 = __toESM(require("os"), 1);
59971
60172
  init_protocol();
59972
60173
 
59973
60174
  // src/handlers/method-grants.ts
@@ -60227,21 +60428,21 @@ function computeMethodAccess(args) {
60227
60428
  }
60228
60429
 
60229
60430
  // src/version.ts
60230
- var version = "0.2.351".length > 0 ? "0.2.351" : "dev";
60431
+ var version = "0.2.353".length > 0 ? "0.2.353" : "dev";
60231
60432
 
60232
60433
  // src/cli-probe/probe.ts
60233
- var fs59 = __toESM(require("fs"), 1);
60234
- var path66 = __toESM(require("path"), 1);
60434
+ var fs60 = __toESM(require("fs"), 1);
60435
+ var path67 = __toESM(require("path"), 1);
60235
60436
  var PKG_NAME = "@clawos-dev/clawd";
60236
60437
  var BIN_NAME = "clawd";
60237
60438
  var MAX_PARENT_HOPS = 5;
60238
60439
  function probeGlobalCli(pathEnv) {
60239
60440
  if (!pathEnv) return null;
60240
- for (const dir of pathEnv.split(path66.delimiter)) {
60441
+ for (const dir of pathEnv.split(path67.delimiter)) {
60241
60442
  if (!dir) continue;
60242
60443
  let real;
60243
60444
  try {
60244
- real = fs59.realpathSync(path66.join(dir, BIN_NAME));
60445
+ real = fs60.realpathSync(path67.join(dir, BIN_NAME));
60245
60446
  } catch {
60246
60447
  continue;
60247
60448
  }
@@ -60251,15 +60452,15 @@ function probeGlobalCli(pathEnv) {
60251
60452
  return null;
60252
60453
  }
60253
60454
  function readOwnPackageVersion(entryPath) {
60254
- let dir = path66.dirname(entryPath);
60455
+ let dir = path67.dirname(entryPath);
60255
60456
  for (let i = 0; i < MAX_PARENT_HOPS; i++) {
60256
60457
  try {
60257
- const raw = fs59.readFileSync(path66.join(dir, "package.json"), "utf8");
60458
+ const raw = fs60.readFileSync(path67.join(dir, "package.json"), "utf8");
60258
60459
  const pkg = JSON.parse(raw);
60259
60460
  if (pkg.name !== PKG_NAME) return null;
60260
60461
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
60261
60462
  } catch {
60262
- const parent = path66.dirname(dir);
60463
+ const parent = path67.dirname(dir);
60263
60464
  if (parent === dir) return null;
60264
60465
  dir = parent;
60265
60466
  }
@@ -60295,7 +60496,7 @@ function buildReadyFrame(deps, client) {
60295
60496
  return {
60296
60497
  version,
60297
60498
  protocolVersion: PROTOCOL_VERSION,
60298
- hostname: import_node_os18.default.hostname(),
60499
+ hostname: import_node_os19.default.hostname(),
60299
60500
  os: process.platform,
60300
60501
  tools,
60301
60502
  runningSessions: info.runningSessions,
@@ -60422,7 +60623,7 @@ function buildPersonaHandlers(deps) {
60422
60623
  }
60423
60624
 
60424
60625
  // src/handlers/attachment.ts
60425
- var import_node_path53 = __toESM(require("path"), 1);
60626
+ var import_node_path54 = __toESM(require("path"), 1);
60426
60627
  init_protocol();
60427
60628
  init_protocol();
60428
60629
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -60502,12 +60703,12 @@ function buildAttachmentHandlers(deps) {
60502
60703
  `session ${args.sessionId} scope unresolved`
60503
60704
  );
60504
60705
  }
60505
- const cwdAbs = import_node_path53.default.resolve(sessionFile.cwd);
60506
- const candidateAbs = import_node_path53.default.isAbsolute(args.relPath) ? import_node_path53.default.resolve(args.relPath) : import_node_path53.default.resolve(cwdAbs, args.relPath);
60706
+ const cwdAbs = import_node_path54.default.resolve(sessionFile.cwd);
60707
+ const candidateAbs = import_node_path54.default.isAbsolute(args.relPath) ? import_node_path54.default.resolve(args.relPath) : import_node_path54.default.resolve(cwdAbs, args.relPath);
60507
60708
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
60508
60709
  const entries = deps.groupFileStore.list(scope, args.sessionId);
60509
60710
  const entry = entries.find((e) => {
60510
- const storedAbs = import_node_path53.default.isAbsolute(e.relPath) ? import_node_path53.default.resolve(e.relPath) : import_node_path53.default.resolve(cwdAbs, e.relPath);
60711
+ const storedAbs = import_node_path54.default.isAbsolute(e.relPath) ? import_node_path54.default.resolve(e.relPath) : import_node_path54.default.resolve(cwdAbs, e.relPath);
60511
60712
  return storedAbs === candidateAbs && !e.stale;
60512
60713
  });
60513
60714
  if (!entry) {
@@ -60532,7 +60733,7 @@ function buildAttachmentHandlers(deps) {
60532
60733
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
60533
60734
  const f = deps.sessionStore.read(sessionId);
60534
60735
  if (!f) return;
60535
- assertGuestAttachmentPath(ctx, import_node_path53.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
60736
+ assertGuestAttachmentPath(ctx, import_node_path54.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
60536
60737
  }
60537
60738
  const groupAdd = async (frame, _client, ctx) => {
60538
60739
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -60547,8 +60748,8 @@ function buildAttachmentHandlers(deps) {
60547
60748
  if (!scope) {
60548
60749
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
60549
60750
  }
60550
- const cwdAbs = import_node_path53.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
60551
- const candidateAbs = import_node_path53.default.isAbsolute(args.relPath) ? import_node_path53.default.resolve(args.relPath) : import_node_path53.default.resolve(cwdAbs, args.relPath);
60751
+ const cwdAbs = import_node_path54.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
60752
+ const candidateAbs = import_node_path54.default.isAbsolute(args.relPath) ? import_node_path54.default.resolve(args.relPath) : import_node_path54.default.resolve(cwdAbs, args.relPath);
60552
60753
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
60553
60754
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
60554
60755
  const size = 0;
@@ -60607,19 +60808,19 @@ function buildAttachmentHandlers(deps) {
60607
60808
 
60608
60809
  // src/handlers/extension.ts
60609
60810
  var import_promises11 = __toESM(require("fs/promises"), 1);
60610
- var import_node_path58 = __toESM(require("path"), 1);
60811
+ var import_node_path59 = __toESM(require("path"), 1);
60611
60812
  init_protocol();
60612
60813
 
60613
60814
  // src/extension/bundle-zip.ts
60614
60815
  var import_promises8 = __toESM(require("fs/promises"), 1);
60615
- var import_node_path54 = __toESM(require("path"), 1);
60816
+ var import_node_path55 = __toESM(require("path"), 1);
60616
60817
  var import_node_crypto15 = __toESM(require("crypto"), 1);
60617
60818
  var import_jszip2 = __toESM(require_lib3(), 1);
60618
60819
  async function bundleExtensionDir(dir) {
60619
60820
  const entries = await listFilesSorted(dir);
60620
60821
  const zip = new import_jszip2.default();
60621
60822
  for (const rel of entries) {
60622
- const abs = import_node_path54.default.join(dir, rel);
60823
+ const abs = import_node_path55.default.join(dir, rel);
60623
60824
  const content = await import_promises8.default.readFile(abs);
60624
60825
  zip.file(rel, content, { date: FIXED_DATE });
60625
60826
  }
@@ -60640,7 +60841,7 @@ async function listFilesSorted(rootDir) {
60640
60841
  return out;
60641
60842
  }
60642
60843
  async function walk(absRoot, relPrefix, out) {
60643
- const dirAbs = import_node_path54.default.join(absRoot, relPrefix);
60844
+ const dirAbs = import_node_path55.default.join(absRoot, relPrefix);
60644
60845
  const entries = await import_promises8.default.readdir(dirAbs, { withFileTypes: true });
60645
60846
  for (const e of entries) {
60646
60847
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -60694,25 +60895,25 @@ function computePublishCheck(args) {
60694
60895
 
60695
60896
  // src/extension/install-flow.ts
60696
60897
  var import_promises9 = __toESM(require("fs/promises"), 1);
60697
- var import_node_path56 = __toESM(require("path"), 1);
60698
- var import_node_os20 = __toESM(require("os"), 1);
60898
+ var import_node_path57 = __toESM(require("path"), 1);
60899
+ var import_node_os21 = __toESM(require("os"), 1);
60699
60900
  var import_node_crypto16 = __toESM(require("crypto"), 1);
60700
60901
  var import_jszip3 = __toESM(require_lib3(), 1);
60701
60902
 
60702
60903
  // src/extension/paths.ts
60703
- var import_node_os19 = __toESM(require("os"), 1);
60704
- var import_node_path55 = __toESM(require("path"), 1);
60904
+ var import_node_os20 = __toESM(require("os"), 1);
60905
+ var import_node_path56 = __toESM(require("path"), 1);
60705
60906
  function clawdHomeRoot(override) {
60706
- return override ?? process.env.CLAWD_HOME ?? import_node_path55.default.join(import_node_os19.default.homedir(), ".clawd");
60907
+ return override ?? process.env.CLAWD_HOME ?? import_node_path56.default.join(import_node_os20.default.homedir(), ".clawd");
60707
60908
  }
60708
60909
  function extensionsRoot(override) {
60709
- return import_node_path55.default.join(clawdHomeRoot(override), "extensions");
60910
+ return import_node_path56.default.join(clawdHomeRoot(override), "extensions");
60710
60911
  }
60711
60912
  function publishedChannelsFile(override) {
60712
- return import_node_path55.default.join(clawdHomeRoot(override), "extensions-published.json");
60913
+ return import_node_path56.default.join(clawdHomeRoot(override), "extensions-published.json");
60713
60914
  }
60714
60915
  function bundleCacheRoot(override) {
60715
- return import_node_path55.default.join(clawdHomeRoot(override), "extension-bundles");
60916
+ return import_node_path56.default.join(clawdHomeRoot(override), "extension-bundles");
60716
60917
  }
60717
60918
 
60718
60919
  // src/extension/install-flow.ts
@@ -60739,7 +60940,7 @@ async function installFromChannel(args, deps) {
60739
60940
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
60740
60941
  }
60741
60942
  for (const name of Object.keys(zip.files)) {
60742
- if (name.includes("..") || name.startsWith("/") || import_node_path56.default.isAbsolute(name)) {
60943
+ if (name.includes("..") || name.startsWith("/") || import_node_path57.default.isAbsolute(name)) {
60743
60944
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
60744
60945
  }
60745
60946
  }
@@ -60771,7 +60972,7 @@ async function installFromChannel(args, deps) {
60771
60972
  );
60772
60973
  }
60773
60974
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
60774
- const destDir = import_node_path56.default.join(deps.extensionsRoot, localExtId);
60975
+ const destDir = import_node_path57.default.join(deps.extensionsRoot, localExtId);
60775
60976
  let destExists = false;
60776
60977
  try {
60777
60978
  await import_promises9.default.access(destDir);
@@ -60785,16 +60986,16 @@ async function installFromChannel(args, deps) {
60785
60986
  );
60786
60987
  }
60787
60988
  const stage = await import_promises9.default.mkdtemp(
60788
- import_node_path56.default.join(import_node_os20.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
60989
+ import_node_path57.default.join(import_node_os21.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
60789
60990
  );
60790
60991
  try {
60791
60992
  for (const [name, entry] of Object.entries(zip.files)) {
60792
- const dest = import_node_path56.default.join(stage, name);
60993
+ const dest = import_node_path57.default.join(stage, name);
60793
60994
  if (entry.dir) {
60794
60995
  await import_promises9.default.mkdir(dest, { recursive: true });
60795
60996
  continue;
60796
60997
  }
60797
- await import_promises9.default.mkdir(import_node_path56.default.dirname(dest), { recursive: true });
60998
+ await import_promises9.default.mkdir(import_node_path57.default.dirname(dest), { recursive: true });
60798
60999
  if (name === "manifest.json") {
60799
61000
  const rewritten = { ...parsed.data, id: localExtId };
60800
61001
  await import_promises9.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -60815,8 +61016,8 @@ async function installFromChannel(args, deps) {
60815
61016
 
60816
61017
  // src/extension/update-flow.ts
60817
61018
  var import_promises10 = __toESM(require("fs/promises"), 1);
60818
- var import_node_path57 = __toESM(require("path"), 1);
60819
- var import_node_os21 = __toESM(require("os"), 1);
61019
+ var import_node_path58 = __toESM(require("path"), 1);
61020
+ var import_node_os22 = __toESM(require("os"), 1);
60820
61021
  var import_node_crypto17 = __toESM(require("crypto"), 1);
60821
61022
  var import_jszip4 = __toESM(require_lib3(), 1);
60822
61023
  var UpdateError = class extends Error {
@@ -60832,11 +61033,11 @@ async function updateFromChannel(args, deps) {
60832
61033
  channelRef.extId,
60833
61034
  channelRef.ownerPrincipalId
60834
61035
  );
60835
- const liveDir = import_node_path57.default.join(deps.extensionsRoot, localExtId);
61036
+ const liveDir = import_node_path58.default.join(deps.extensionsRoot, localExtId);
60836
61037
  const prevDir = `${liveDir}.prev`;
60837
61038
  let existingVersion;
60838
61039
  try {
60839
- const raw = await import_promises10.default.readFile(import_node_path57.default.join(liveDir, "manifest.json"), "utf8");
61040
+ const raw = await import_promises10.default.readFile(import_node_path58.default.join(liveDir, "manifest.json"), "utf8");
60840
61041
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
60841
61042
  if (!parsed2.success) {
60842
61043
  throw new UpdateError(
@@ -60869,7 +61070,7 @@ async function updateFromChannel(args, deps) {
60869
61070
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
60870
61071
  }
60871
61072
  for (const name of Object.keys(zip.files)) {
60872
- if (name.includes("..") || name.startsWith("/") || import_node_path57.default.isAbsolute(name)) {
61073
+ if (name.includes("..") || name.startsWith("/") || import_node_path58.default.isAbsolute(name)) {
60873
61074
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
60874
61075
  }
60875
61076
  }
@@ -60904,16 +61105,16 @@ async function updateFromChannel(args, deps) {
60904
61105
  await import_promises10.default.rm(prevDir, { recursive: true, force: true });
60905
61106
  await import_promises10.default.rename(liveDir, prevDir);
60906
61107
  const stage = await import_promises10.default.mkdtemp(
60907
- import_node_path57.default.join(import_node_os21.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
61108
+ import_node_path58.default.join(import_node_os22.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
60908
61109
  );
60909
61110
  try {
60910
61111
  for (const [name, entry] of Object.entries(zip.files)) {
60911
- const dest = import_node_path57.default.join(stage, name);
61112
+ const dest = import_node_path58.default.join(stage, name);
60912
61113
  if (entry.dir) {
60913
61114
  await import_promises10.default.mkdir(dest, { recursive: true });
60914
61115
  continue;
60915
61116
  }
60916
- await import_promises10.default.mkdir(import_node_path57.default.dirname(dest), { recursive: true });
61117
+ await import_promises10.default.mkdir(import_node_path58.default.dirname(dest), { recursive: true });
60917
61118
  if (name === "manifest.json") {
60918
61119
  const rewritten = { ...parsed.data, id: localExtId };
60919
61120
  await import_promises10.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -60980,7 +61181,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
60980
61181
  );
60981
61182
  }
60982
61183
  }
60983
- const manifestPath = import_node_path58.default.join(root, extId, "manifest.json");
61184
+ const manifestPath = import_node_path59.default.join(root, extId, "manifest.json");
60984
61185
  const manifest = await readManifest(root, extId);
60985
61186
  const next = { ...manifest, version: newVersion };
60986
61187
  const tmp = `${manifestPath}.tmp`;
@@ -60988,7 +61189,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
60988
61189
  await import_promises11.default.rename(tmp, manifestPath);
60989
61190
  }
60990
61191
  async function readManifest(root, extId) {
60991
- const file = import_node_path58.default.join(root, extId, "manifest.json");
61192
+ const file = import_node_path59.default.join(root, extId, "manifest.json");
60992
61193
  let raw;
60993
61194
  try {
60994
61195
  raw = await import_promises11.default.readFile(file, "utf8");
@@ -61072,7 +61273,7 @@ function buildExtensionHandlers(deps) {
61072
61273
  };
61073
61274
  async function buildSnapshotMeta(extId) {
61074
61275
  const manifest = await readManifest(deps.root, extId);
61075
- const { sha256, buffer } = await bundleExtensionDir(import_node_path58.default.join(deps.root, extId));
61276
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path59.default.join(deps.root, extId));
61076
61277
  return { manifest, contentHash: sha256, buffer };
61077
61278
  }
61078
61279
  const publish = async (frame, _client, ctx) => {
@@ -61247,9 +61448,9 @@ function buildExtensionHandlers(deps) {
61247
61448
  }
61248
61449
 
61249
61450
  // src/app-builder/project-store.ts
61250
- var import_node_fs48 = require("fs");
61251
- var import_node_child_process13 = require("child_process");
61252
- var import_node_path59 = require("path");
61451
+ var import_node_fs49 = require("fs");
61452
+ var import_node_child_process14 = require("child_process");
61453
+ var import_node_path60 = require("path");
61253
61454
  init_protocol();
61254
61455
  var PROJECTS_DIR = "projects";
61255
61456
  var META_FILE = ".clawd-project.json";
@@ -61263,19 +61464,19 @@ var ProjectStore = class {
61263
61464
  root;
61264
61465
  /** projects/<name>/.clawd-project.json 路径 */
61265
61466
  metaPath(name) {
61266
- return (0, import_node_path59.join)(this.projectsRoot(), name, META_FILE);
61467
+ return (0, import_node_path60.join)(this.projectsRoot(), name, META_FILE);
61267
61468
  }
61268
61469
  /** projects/<name>/ 目录路径(cwd 用) */
61269
61470
  projectDir(name) {
61270
- return (0, import_node_path59.join)(this.projectsRoot(), name);
61471
+ return (0, import_node_path60.join)(this.projectsRoot(), name);
61271
61472
  }
61272
61473
  projectsRoot() {
61273
- return (0, import_node_path59.join)(this.root, PROJECTS_DIR);
61474
+ return (0, import_node_path60.join)(this.root, PROJECTS_DIR);
61274
61475
  }
61275
61476
  async list() {
61276
61477
  let entries;
61277
61478
  try {
61278
- entries = await import_node_fs48.promises.readdir(this.projectsRoot());
61479
+ entries = await import_node_fs49.promises.readdir(this.projectsRoot());
61279
61480
  } catch (err) {
61280
61481
  if (err.code === "ENOENT") return [];
61281
61482
  throw err;
@@ -61283,7 +61484,7 @@ var ProjectStore = class {
61283
61484
  const out = [];
61284
61485
  for (const name of entries) {
61285
61486
  try {
61286
- const raw = await import_node_fs48.promises.readFile(this.metaPath(name), "utf8");
61487
+ const raw = await import_node_fs49.promises.readFile(this.metaPath(name), "utf8");
61287
61488
  const json = JSON.parse(raw);
61288
61489
  let migrated = false;
61289
61490
  if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
@@ -61294,7 +61495,7 @@ var ProjectStore = class {
61294
61495
  if (parsed.success) {
61295
61496
  out.push(parsed.data);
61296
61497
  if (migrated) {
61297
- void import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
61498
+ void import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
61298
61499
  });
61299
61500
  }
61300
61501
  }
@@ -61338,8 +61539,8 @@ var ProjectStore = class {
61338
61539
  throw new Error(`invalid name "${name}": ${validated.error.message}`);
61339
61540
  }
61340
61541
  const dir = this.projectDir(name);
61341
- await import_node_fs48.promises.mkdir(dir, { recursive: true });
61342
- await import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
61542
+ await import_node_fs49.promises.mkdir(dir, { recursive: true });
61543
+ await import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
61343
61544
  return meta;
61344
61545
  }
61345
61546
  /**
@@ -61353,7 +61554,7 @@ var ProjectStore = class {
61353
61554
  async scaffold(name, templateSrcDir, scaffoldScriptPath) {
61354
61555
  const destDir = this.projectDir(name);
61355
61556
  return await new Promise((resolve6, reject) => {
61356
- const child = (0, import_node_child_process13.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
61557
+ const child = (0, import_node_child_process14.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
61357
61558
  env: { ...process.env, PATH: process.env.PATH ?? "" },
61358
61559
  stdio: ["ignore", "pipe", "pipe"]
61359
61560
  });
@@ -61382,7 +61583,7 @@ var ProjectStore = class {
61382
61583
  }
61383
61584
  async delete(name) {
61384
61585
  const dir = this.projectDir(name);
61385
- await import_node_fs48.promises.rm(dir, { recursive: true, force: true });
61586
+ await import_node_fs49.promises.rm(dir, { recursive: true, force: true });
61386
61587
  }
61387
61588
  async updatePort(name, newPort) {
61388
61589
  if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
@@ -61398,7 +61599,7 @@ var ProjectStore = class {
61398
61599
  throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
61399
61600
  }
61400
61601
  const updated = { ...target, port: newPort };
61401
- await import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
61602
+ await import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
61402
61603
  return updated;
61403
61604
  }
61404
61605
  /**
@@ -61415,7 +61616,7 @@ var ProjectStore = class {
61415
61616
  if (!validated.success) {
61416
61617
  throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
61417
61618
  }
61418
- await import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
61619
+ await import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
61419
61620
  return validated.data;
61420
61621
  }
61421
61622
  /**
@@ -61436,7 +61637,7 @@ var ProjectStore = class {
61436
61637
  if (!validated.success) {
61437
61638
  throw new Error(`invalid publishJob: ${validated.error.message}`);
61438
61639
  }
61439
- await import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
61640
+ await import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
61440
61641
  return validated.data;
61441
61642
  }
61442
61643
  /** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
@@ -61451,13 +61652,13 @@ var ProjectStore = class {
61451
61652
  if (!validated.success) {
61452
61653
  throw new Error(`failed to clear publishJob: ${validated.error.message}`);
61453
61654
  }
61454
- await import_node_fs48.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
61655
+ await import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
61455
61656
  return validated.data;
61456
61657
  }
61457
61658
  };
61458
61659
 
61459
61660
  // src/app-builder/kill-port.ts
61460
- var import_node_child_process14 = require("child_process");
61661
+ var import_node_child_process15 = require("child_process");
61461
61662
  async function killPortOccupants(port, ownedPids, logger) {
61462
61663
  let pids;
61463
61664
  try {
@@ -61499,7 +61700,7 @@ async function killPortOccupants(port, ownedPids, logger) {
61499
61700
  }
61500
61701
  function listPidsOnPort(port) {
61501
61702
  return new Promise((resolve6, reject) => {
61502
- (0, import_node_child_process14.execFile)(
61703
+ (0, import_node_child_process15.execFile)(
61503
61704
  "lsof",
61504
61705
  ["-ti", `:${port}`],
61505
61706
  { timeout: 3e3 },
@@ -61571,9 +61772,9 @@ var PublishJobRegistry = class {
61571
61772
  };
61572
61773
 
61573
61774
  // src/app-builder/publish-job-runner.ts
61574
- var import_node_child_process15 = require("child_process");
61575
- var import_node_fs49 = require("fs");
61576
- var import_node_path60 = require("path");
61775
+ var import_node_child_process16 = require("child_process");
61776
+ var import_node_fs50 = require("fs");
61777
+ var import_node_path61 = require("path");
61577
61778
 
61578
61779
  // src/app-builder/publish-stage-parser.ts
61579
61780
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -61600,19 +61801,19 @@ function tailStderrLines(buf, n) {
61600
61801
  // src/app-builder/publish-job-runner.ts
61601
61802
  async function startPublishJob(deps, args) {
61602
61803
  const { registry: registry2, projectDir } = deps;
61603
- const spawn12 = deps.spawnImpl ?? import_node_child_process15.spawn;
61804
+ const spawn13 = deps.spawnImpl ?? import_node_child_process16.spawn;
61604
61805
  if (registry2.has(args.name)) {
61605
61806
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
61606
61807
  }
61607
61808
  const projDir = projectDir(args.name);
61608
- const logPath = (0, import_node_path60.join)(projDir, ".publish.log");
61809
+ const logPath = (0, import_node_path61.join)(projDir, ".publish.log");
61609
61810
  let logStream = null;
61610
61811
  try {
61611
- logStream = (0, import_node_fs49.createWriteStream)(logPath, { flags: "w" });
61812
+ logStream = (0, import_node_fs50.createWriteStream)(logPath, { flags: "w" });
61612
61813
  } catch {
61613
61814
  logStream = null;
61614
61815
  }
61615
- const child = spawn12("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
61816
+ const child = spawn13("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
61616
61817
  cwd: projDir,
61617
61818
  env: process.env,
61618
61819
  stdio: ["ignore", "pipe", "pipe"]
@@ -61865,8 +62066,8 @@ async function recoverInterruptedJobs(deps) {
61865
62066
 
61866
62067
  // src/handlers/app-builder.ts
61867
62068
  init_protocol();
61868
- var import_node_path61 = require("path");
61869
- var import_node_fs50 = require("fs");
62069
+ var import_node_path62 = require("path");
62070
+ var import_node_fs51 = require("fs");
61870
62071
  var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
61871
62072
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
61872
62073
  async function recoverInterruptedPublishJobs(store, logger) {
@@ -61947,7 +62148,7 @@ function buildAppBuilderHandlers(deps) {
61947
62148
  async function listAllUsersProjects() {
61948
62149
  if (!deps.usersRoot || !deps.getStore) return [];
61949
62150
  const getStore = deps.getStore;
61950
- const userIds = await import_node_fs50.promises.readdir(deps.usersRoot).catch(() => []);
62151
+ const userIds = await import_node_fs51.promises.readdir(deps.usersRoot).catch(() => []);
61951
62152
  const perUser = await Promise.all(
61952
62153
  userIds.map((uid) => getStore(uid).list().catch(() => []))
61953
62154
  );
@@ -62016,8 +62217,8 @@ function buildAppBuilderHandlers(deps) {
62016
62217
  const project = await userStore.create(f.name, reservedPorts);
62017
62218
  try {
62018
62219
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
62019
- const templateSrcDir = (0, import_node_path61.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
62020
- const scaffoldScript = (0, import_node_path61.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
62220
+ const templateSrcDir = (0, import_node_path62.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
62221
+ const scaffoldScript = (0, import_node_path62.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
62021
62222
  const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
62022
62223
  deps.logger?.info("app-builder.scaffold.done", {
62023
62224
  name: project.name,
@@ -62221,7 +62422,7 @@ function buildAppBuilderHandlers(deps) {
62221
62422
  await userStore.clearPublishJob(args.name);
62222
62423
  }
62223
62424
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
62224
- const scriptPath = (0, import_node_path61.join)(deps.deployKitRoot, "scripts", "publish.sh");
62425
+ const scriptPath = (0, import_node_path62.join)(deps.deployKitRoot, "scripts", "publish.sh");
62225
62426
  deps.logger?.info("app-builder.publish.start", {
62226
62427
  name: args.name,
62227
62428
  sessionId: boundSession.sessionId,
@@ -62641,7 +62842,7 @@ function buildVisitorHandlers(deps) {
62641
62842
 
62642
62843
  // src/extension/registry.ts
62643
62844
  var import_promises12 = __toESM(require("fs/promises"), 1);
62644
- var import_node_path62 = __toESM(require("path"), 1);
62845
+ var import_node_path63 = __toESM(require("path"), 1);
62645
62846
  async function loadAll(root) {
62646
62847
  let entries;
62647
62848
  try {
@@ -62654,13 +62855,13 @@ async function loadAll(root) {
62654
62855
  for (const ent of entries) {
62655
62856
  if (!ent.isDirectory()) continue;
62656
62857
  if (ent.name.startsWith(".")) continue;
62657
- records.push(await loadOne(import_node_path62.default.join(root, ent.name), ent.name));
62858
+ records.push(await loadOne(import_node_path63.default.join(root, ent.name), ent.name));
62658
62859
  }
62659
62860
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
62660
62861
  return records;
62661
62862
  }
62662
62863
  async function loadOne(dir, dirName) {
62663
- const manifestPath = import_node_path62.default.join(dir, "manifest.json");
62864
+ const manifestPath = import_node_path63.default.join(dir, "manifest.json");
62664
62865
  let raw;
62665
62866
  try {
62666
62867
  raw = await import_promises12.default.readFile(manifestPath, "utf8");
@@ -62705,7 +62906,7 @@ async function loadOne(dir, dirName) {
62705
62906
 
62706
62907
  // src/extension/uninstall.ts
62707
62908
  var import_promises13 = __toESM(require("fs/promises"), 1);
62708
- var import_node_path63 = __toESM(require("path"), 1);
62909
+ var import_node_path64 = __toESM(require("path"), 1);
62709
62910
  var UninstallError = class extends Error {
62710
62911
  constructor(code, message) {
62711
62912
  super(message);
@@ -62714,7 +62915,7 @@ var UninstallError = class extends Error {
62714
62915
  code;
62715
62916
  };
62716
62917
  async function uninstall(deps) {
62717
- const dir = import_node_path63.default.join(deps.root, deps.extId);
62918
+ const dir = import_node_path64.default.join(deps.root, deps.extId);
62718
62919
  try {
62719
62920
  await import_promises13.default.access(dir);
62720
62921
  } catch {
@@ -62731,15 +62932,15 @@ var import_node_crypto19 = require("crypto");
62731
62932
  init_protocol();
62732
62933
 
62733
62934
  // src/peer-ops/run-command.ts
62734
- var import_node_child_process16 = require("child_process");
62735
- var import_node_os22 = __toESM(require("os"), 1);
62935
+ var import_node_child_process17 = require("child_process");
62936
+ var import_node_os23 = __toESM(require("os"), 1);
62736
62937
  var DEFAULT_TIMEOUT_MS4 = 3e4;
62737
62938
  var MAX_TIMEOUT_MS = 3e5;
62738
62939
  var MAX_OUTPUT_BYTES = 1048576;
62739
62940
  function runCommand(command, opts = {}) {
62740
62941
  const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS4, MAX_TIMEOUT_MS);
62741
62942
  return new Promise((resolve6) => {
62742
- const child = (0, import_node_child_process16.spawn)("bash", ["-c", command], { cwd: import_node_os22.default.homedir() });
62943
+ const child = (0, import_node_child_process17.spawn)("bash", ["-c", command], { cwd: import_node_os23.default.homedir() });
62743
62944
  const out = [];
62744
62945
  const err = [];
62745
62946
  let outBytes = 0;
@@ -62958,14 +63159,14 @@ function buildMethodHandlers(deps) {
62958
63159
  init_protocol();
62959
63160
 
62960
63161
  // src/tools/version-probe.ts
62961
- var import_node_child_process17 = require("child_process");
63162
+ var import_node_child_process18 = require("child_process");
62962
63163
  init_claude();
62963
63164
  function parseVersionOutput(out) {
62964
63165
  return /(\d+\.\d+\.\d+)/.exec(out)?.[1];
62965
63166
  }
62966
63167
  function execVersion(bin) {
62967
63168
  return new Promise((resolve6, reject) => {
62968
- (0, import_node_child_process17.execFile)(bin, ["--version"], { timeout: 5e3 }, (err, stdout) => {
63169
+ (0, import_node_child_process18.execFile)(bin, ["--version"], { timeout: 5e3 }, (err, stdout) => {
62969
63170
  if (err) reject(err);
62970
63171
  else resolve6(String(stdout));
62971
63172
  });
@@ -63076,7 +63277,7 @@ function buildOnboardingHandlers(deps) {
63076
63277
  }
63077
63278
 
63078
63279
  // src/app-builder/dev-server-supervisor.ts
63079
- var import_node_child_process18 = require("child_process");
63280
+ var import_node_child_process19 = require("child_process");
63080
63281
  var import_node_events2 = require("events");
63081
63282
  var DEFAULT_READY_PATTERN = /Local:\s+https?:\/\/|Nest application successfully started|server listening on/i;
63082
63283
  var DevServerSupervisor = class extends import_node_events2.EventEmitter {
@@ -63113,7 +63314,7 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
63113
63314
  tunnelHost: args.tunnelHost,
63114
63315
  devCommand: cmd
63115
63316
  });
63116
- const child = (0, import_node_child_process18.spawn)("sh", ["-c", cmd], {
63317
+ const child = (0, import_node_child_process19.spawn)("sh", ["-c", cmd], {
63117
63318
  cwd: args.cwd,
63118
63319
  env,
63119
63320
  stdio: "pipe",
@@ -63365,8 +63566,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
63365
63566
  }
63366
63567
 
63367
63568
  // src/extension/runtime.ts
63368
- var import_node_child_process19 = require("child_process");
63369
- var import_node_path64 = __toESM(require("path"), 1);
63569
+ var import_node_child_process20 = require("child_process");
63570
+ var import_node_path65 = __toESM(require("path"), 1);
63370
63571
  var import_promises14 = require("timers/promises");
63371
63572
 
63372
63573
  // src/extension/port-allocator.ts
@@ -63467,13 +63668,13 @@ var Runtime = class {
63467
63668
  /\$CLAWOS_EXT_PORT/g,
63468
63669
  String(port)
63469
63670
  );
63470
- const dir = import_node_path64.default.join(this.root, extId);
63671
+ const dir = import_node_path65.default.join(this.root, extId);
63471
63672
  const env = {
63472
63673
  ...process.env,
63473
63674
  CLAWOS_EXT_PORT: String(port),
63474
63675
  CLAWOS_EXT_ID: extId
63475
63676
  };
63476
- const child = (0, import_node_child_process19.spawn)("sh", ["-c", cmd], {
63677
+ const child = (0, import_node_child_process20.spawn)("sh", ["-c", cmd], {
63477
63678
  cwd: dir,
63478
63679
  env,
63479
63680
  stdio: ["ignore", "pipe", "pipe"],
@@ -63579,7 +63780,7 @@ ${handle.stderrTail}`
63579
63780
 
63580
63781
  // src/extension/published-channels.ts
63581
63782
  var import_promises15 = __toESM(require("fs/promises"), 1);
63582
- var import_node_path65 = __toESM(require("path"), 1);
63783
+ var import_node_path66 = __toESM(require("path"), 1);
63583
63784
  init_zod();
63584
63785
  var PublishedChannelsError = class extends Error {
63585
63786
  constructor(code, message) {
@@ -63678,7 +63879,7 @@ var PublishedChannelStore = class {
63678
63879
  )
63679
63880
  };
63680
63881
  const tmp = `${this.filePath}.tmp`;
63681
- await import_promises15.default.mkdir(import_node_path65.default.dirname(this.filePath), { recursive: true });
63882
+ await import_promises15.default.mkdir(import_node_path66.default.dirname(this.filePath), { recursive: true });
63682
63883
  await import_promises15.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
63683
63884
  await import_promises15.default.rename(tmp, this.filePath);
63684
63885
  }
@@ -63686,7 +63887,7 @@ var PublishedChannelStore = class {
63686
63887
 
63687
63888
  // src/extension/bundle-cache.ts
63688
63889
  var import_promises16 = __toESM(require("fs/promises"), 1);
63689
- var import_node_path66 = __toESM(require("path"), 1);
63890
+ var import_node_path67 = __toESM(require("path"), 1);
63690
63891
  var BundleCache = class {
63691
63892
  constructor(rootDir) {
63692
63893
  this.rootDir = rootDir;
@@ -63695,14 +63896,14 @@ var BundleCache = class {
63695
63896
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
63696
63897
  async write(snapshotHash, buffer) {
63697
63898
  await import_promises16.default.mkdir(this.rootDir, { recursive: true });
63698
- const file = import_node_path66.default.join(this.rootDir, `${snapshotHash}.zip`);
63899
+ const file = import_node_path67.default.join(this.rootDir, `${snapshotHash}.zip`);
63699
63900
  const tmp = `${file}.tmp`;
63700
63901
  await import_promises16.default.writeFile(tmp, buffer, { mode: 384 });
63701
63902
  await import_promises16.default.rename(tmp, file);
63702
63903
  }
63703
63904
  /** Returns the bundle bytes, or null when the file doesn't exist. */
63704
63905
  async read(snapshotHash) {
63705
- const file = import_node_path66.default.join(this.rootDir, `${snapshotHash}.zip`);
63906
+ const file = import_node_path67.default.join(this.rootDir, `${snapshotHash}.zip`);
63706
63907
  try {
63707
63908
  return await import_promises16.default.readFile(file);
63708
63909
  } catch (e) {
@@ -63712,7 +63913,7 @@ var BundleCache = class {
63712
63913
  }
63713
63914
  /** Idempotent — missing file is not an error. */
63714
63915
  async delete(snapshotHash) {
63715
- const file = import_node_path66.default.join(this.rootDir, `${snapshotHash}.zip`);
63916
+ const file = import_node_path67.default.join(this.rootDir, `${snapshotHash}.zip`);
63716
63917
  await import_promises16.default.rm(file, { force: true });
63717
63918
  }
63718
63919
  };
@@ -63733,26 +63934,26 @@ async function startDaemon(config) {
63733
63934
  },
63734
63935
  source: "daemon",
63735
63936
  sampling: logShippingCfg.sampling,
63736
- homeDir: import_node_os23.default.homedir()
63937
+ homeDir: import_node_os24.default.homedir()
63737
63938
  });
63738
- const logDir = import_node_path67.default.join(config.dataDir, "log");
63739
- import_node_fs51.default.mkdirSync(logDir, { recursive: true });
63939
+ const logDir = import_node_path68.default.join(config.dataDir, "log");
63940
+ import_node_fs52.default.mkdirSync(logDir, { recursive: true });
63740
63941
  const logger = createLogger({
63741
63942
  level: config.logLevel,
63742
- file: import_node_path67.default.join(logDir, "clawd.log"),
63943
+ file: import_node_path68.default.join(logDir, "clawd.log"),
63743
63944
  logClient
63744
63945
  });
63745
63946
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
63746
63947
  const screenIdleProbeLogger = createFileOnlyLogger({
63747
- file: import_node_path67.default.join(logDir, "screen-idle-probe.log"),
63948
+ file: import_node_path68.default.join(logDir, "screen-idle-probe.log"),
63748
63949
  level: "debug"
63749
63950
  });
63750
63951
  logger.info("screen-idle probe logger enabled", {
63751
- file: import_node_path67.default.join(logDir, "screen-idle-probe.log")
63952
+ file: import_node_path68.default.join(logDir, "screen-idle-probe.log")
63752
63953
  });
63753
63954
  const CAP_TARGETS = [
63754
- import_node_path67.default.join(logDir, "clawd.log"),
63755
- import_node_path67.default.join(logDir, "screen-idle-probe.log")
63955
+ import_node_path68.default.join(logDir, "clawd.log"),
63956
+ import_node_path68.default.join(logDir, "screen-idle-probe.log")
63756
63957
  ];
63757
63958
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
63758
63959
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -63848,8 +64049,8 @@ async function startDaemon(config) {
63848
64049
  const agents = new AgentsScanner();
63849
64050
  const history = new ClaudeHistoryReader();
63850
64051
  let transport = null;
63851
- const personaStore = new PersonaStore(import_node_path67.default.join(config.dataDir, "personas"));
63852
- const usersRoot = import_node_path67.default.join(config.dataDir, "users");
64052
+ const personaStore = new PersonaStore(import_node_path68.default.join(config.dataDir, "personas"));
64053
+ const usersRoot = import_node_path68.default.join(config.dataDir, "users");
63853
64054
  const defaultsRoot = findDefaultsRoot(logger);
63854
64055
  if (defaultsRoot) {
63855
64056
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -63872,7 +64073,7 @@ async function startDaemon(config) {
63872
64073
  retirePersonaBuilder({ store: personaStore, logger });
63873
64074
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
63874
64075
  const dispatchStore = createDispatchStore({
63875
- filePath: import_node_path67.default.join(config.dataDir, "dispatch.json"),
64076
+ filePath: import_node_path68.default.join(config.dataDir, "dispatch.json"),
63876
64077
  now: () => Date.now(),
63877
64078
  onFlushError: (err) => logger.error("dispatch store flush failed", {
63878
64079
  reason: err instanceof Error ? err.message : String(err)
@@ -63887,18 +64088,18 @@ async function startDaemon(config) {
63887
64088
  now: () => Date.now(),
63888
64089
  onCompleted: (sid) => deliverPendingRef?.(sid)
63889
64090
  });
63890
- const here = typeof __dirname === "string" ? __dirname : import_node_path67.default.dirname((0, import_node_url4.fileURLToPath)(import_meta7.url));
64091
+ const here = typeof __dirname === "string" ? __dirname : import_node_path68.default.dirname((0, import_node_url4.fileURLToPath)(import_meta7.url));
63891
64092
  const mcpConfigs = [];
63892
64093
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
63893
64094
  const dispatchServerCandidates = [
63894
- import_node_path67.default.join(here, "dispatch", "mcp-server.cjs"),
64095
+ import_node_path68.default.join(here, "dispatch", "mcp-server.cjs"),
63895
64096
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
63896
- import_node_path67.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
64097
+ import_node_path68.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
63897
64098
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
63898
64099
  ];
63899
- const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64100
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
63900
64101
  if (dispatchServerScriptPath) {
63901
- const dispatchLogPath = import_node_path67.default.join(logDir, "dispatch-mcp-server.log");
64102
+ const dispatchLogPath = import_node_path68.default.join(logDir, "dispatch-mcp-server.log");
63902
64103
  const dispatchCfgPath = writeDispatchMcpConfig({
63903
64104
  dataDir: config.dataDir,
63904
64105
  serverScriptPath: dispatchServerScriptPath,
@@ -63918,12 +64119,12 @@ async function startDaemon(config) {
63918
64119
  });
63919
64120
  }
63920
64121
  const ticketServerCandidates = [
63921
- import_node_path67.default.join(here, "ticket", "mcp-server.cjs"),
63922
- import_node_path67.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
64122
+ import_node_path68.default.join(here, "ticket", "mcp-server.cjs"),
64123
+ import_node_path68.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
63923
64124
  ];
63924
- const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64125
+ const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
63925
64126
  if (ticketServerScriptPath) {
63926
- const ticketLogPath = import_node_path67.default.join(logDir, "ticket-mcp-server.log");
64127
+ const ticketLogPath = import_node_path68.default.join(logDir, "ticket-mcp-server.log");
63927
64128
  const ticketCfgPath = writeTicketMcpConfig({
63928
64129
  dataDir: config.dataDir,
63929
64130
  serverScriptPath: ticketServerScriptPath,
@@ -63945,12 +64146,12 @@ async function startDaemon(config) {
63945
64146
  });
63946
64147
  }
63947
64148
  const shiftServerCandidates = [
63948
- import_node_path67.default.join(here, "shift", "mcp-server.cjs"),
63949
- import_node_path67.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
64149
+ import_node_path68.default.join(here, "shift", "mcp-server.cjs"),
64150
+ import_node_path68.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
63950
64151
  ];
63951
- const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64152
+ const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
63952
64153
  if (shiftServerScriptPath) {
63953
- const shiftLogPath = import_node_path67.default.join(logDir, "shift-mcp-server.log");
64154
+ const shiftLogPath = import_node_path68.default.join(logDir, "shift-mcp-server.log");
63954
64155
  const shiftCfgPath = await writeShiftMcpConfig({
63955
64156
  dataDir: config.dataDir,
63956
64157
  serverScriptPath: shiftServerScriptPath,
@@ -63971,12 +64172,12 @@ async function startDaemon(config) {
63971
64172
  );
63972
64173
  }
63973
64174
  const inboxServerCandidates = [
63974
- import_node_path67.default.join(here, "inbox", "mcp-server.cjs"),
63975
- import_node_path67.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
64175
+ import_node_path68.default.join(here, "inbox", "mcp-server.cjs"),
64176
+ import_node_path68.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
63976
64177
  ];
63977
- const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64178
+ const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
63978
64179
  if (inboxServerScriptPath) {
63979
- const inboxLogPath = import_node_path67.default.join(logDir, "inbox-mcp-server.log");
64180
+ const inboxLogPath = import_node_path68.default.join(logDir, "inbox-mcp-server.log");
63980
64181
  const inboxCfgPath = await writeInboxMcpConfig({
63981
64182
  dataDir: config.dataDir,
63982
64183
  serverScriptPath: inboxServerScriptPath,
@@ -63997,10 +64198,10 @@ async function startDaemon(config) {
63997
64198
  );
63998
64199
  }
63999
64200
  const peerOpsServerCandidates = [
64000
- import_node_path67.default.join(here, "peer-ops", "mcp-server.cjs"),
64001
- import_node_path67.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
64201
+ import_node_path68.default.join(here, "peer-ops", "mcp-server.cjs"),
64202
+ import_node_path68.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
64002
64203
  ];
64003
- const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64204
+ const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
64004
64205
  if (peerOpsServerScriptPath) {
64005
64206
  const peerOpsCfgPath = writePeerOpsMcpConfig({
64006
64207
  dataDir: config.dataDir,
@@ -64020,12 +64221,12 @@ async function startDaemon(config) {
64020
64221
  );
64021
64222
  }
64022
64223
  const rpcToolServerCandidates = [
64023
- import_node_path67.default.join(here, "rpc-tool", "mcp-server.cjs"),
64024
- import_node_path67.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
64224
+ import_node_path68.default.join(here, "rpc-tool", "mcp-server.cjs"),
64225
+ import_node_path68.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
64025
64226
  ];
64026
- const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64227
+ const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
64027
64228
  if (rpcToolServerScriptPath) {
64028
- const rpcToolLogPath = import_node_path67.default.join(logDir, "rpc-tool-mcp-server.log");
64229
+ const rpcToolLogPath = import_node_path68.default.join(logDir, "rpc-tool-mcp-server.log");
64029
64230
  const rpcToolCfgPath = writeRpcToolMcpConfig({
64030
64231
  dataDir: config.dataDir,
64031
64232
  serverScriptPath: rpcToolServerScriptPath,
@@ -64046,7 +64247,7 @@ async function startDaemon(config) {
64046
64247
  );
64047
64248
  }
64048
64249
  const shiftStore = createShiftStore({
64049
- filePath: import_node_path67.default.join(config.dataDir, "shift.json"),
64250
+ filePath: import_node_path68.default.join(config.dataDir, "shift.json"),
64050
64251
  ownerIdProvider: () => ownerPrincipalId,
64051
64252
  now: () => Date.now()
64052
64253
  });
@@ -64068,7 +64269,7 @@ async function startDaemon(config) {
64068
64269
  getAdapter,
64069
64270
  historyReader: history,
64070
64271
  dataDir: config.dataDir,
64071
- personaRoot: import_node_path67.default.join(config.dataDir, "personas"),
64272
+ personaRoot: import_node_path68.default.join(config.dataDir, "personas"),
64072
64273
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
64073
64274
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
64074
64275
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -64100,6 +64301,9 @@ async function startDaemon(config) {
64100
64301
  // daemon 级 MCP server 登记表(dispatch / ticket / shift / inbox / ...,上方各 writer
64101
64302
  // 块写盘成功即登记);reducer 透传到 SpawnContext.mcpConfigs,cc spawn 逐项 --mcp-config。
64102
64303
  mcpConfigs,
64304
+ // 会话标题自产(首条 send 并行 fire,claude→haiku / codex→gpt-5.4-mini)。
64305
+ // 不注入 = 功能关(manager 测试默认关闭防烧真调用),这里是唯一的生产装配点。
64306
+ generateTitle: (tool, firstMessage) => generateSessionTitle(tool, firstMessage, { logger }),
64103
64307
  broadcastFrame: (frame, target) => {
64104
64308
  if (target === "all") {
64105
64309
  transport?.broadcastAll(frame);
@@ -64119,10 +64323,10 @@ async function startDaemon(config) {
64119
64323
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
64120
64324
  attachmentGroup: {
64121
64325
  onFileEdit: (input) => {
64122
- const absPath = import_node_path67.default.isAbsolute(input.relPath) ? input.relPath : import_node_path67.default.join(input.cwd, input.relPath);
64326
+ const absPath = import_node_path68.default.isAbsolute(input.relPath) ? input.relPath : import_node_path68.default.join(input.cwd, input.relPath);
64123
64327
  let size = 0;
64124
64328
  try {
64125
- size = import_node_fs51.default.statSync(absPath).size;
64329
+ size = import_node_fs52.default.statSync(absPath).size;
64126
64330
  } catch (err) {
64127
64331
  logger.warn("attachment.onFileEdit stat failed", {
64128
64332
  sessionId: input.sessionId,
@@ -64390,11 +64594,11 @@ async function startDaemon(config) {
64390
64594
  // 'persona/<pid>/owner',default 走 'default'。
64391
64595
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
64392
64596
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
64393
- personaRoot: import_node_path67.default.join(config.dataDir, "personas"),
64597
+ personaRoot: import_node_path68.default.join(config.dataDir, "personas"),
64394
64598
  usersRoot
64395
64599
  },
64396
64600
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
64397
- personaRoot: import_node_path67.default.join(config.dataDir, "personas"),
64601
+ personaRoot: import_node_path68.default.join(config.dataDir, "personas"),
64398
64602
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
64399
64603
  usersRoot,
64400
64604
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -64520,11 +64724,11 @@ async function startDaemon(config) {
64520
64724
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
64521
64725
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
64522
64726
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
64523
- appBuilderPersonaRoot: import_node_path67.default.join(config.dataDir, "personas", "persona-app-builder"),
64727
+ appBuilderPersonaRoot: import_node_path68.default.join(config.dataDir, "personas", "persona-app-builder"),
64524
64728
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
64525
- deployKitRoot: import_node_path67.default.join(config.dataDir, "deploy-kit"),
64729
+ deployKitRoot: import_node_path68.default.join(config.dataDir, "deploy-kit"),
64526
64730
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
64527
- resolvePersonaRoot: (personaId2) => import_node_path67.default.join(config.dataDir, "personas", personaId2),
64731
+ resolvePersonaRoot: (personaId2) => import_node_path68.default.join(config.dataDir, "personas", personaId2),
64528
64732
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
64529
64733
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
64530
64734
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -64567,7 +64771,7 @@ async function startDaemon(config) {
64567
64771
  sourceSessionId: args.sourceSessionId
64568
64772
  });
64569
64773
  const sourceFile = manager.findOwnedSession(args.sourceSessionId);
64570
- const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os23.default.homedir());
64774
+ const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os24.default.homedir());
64571
64775
  logger.info("dispatch.spawnB.source-resolved", {
64572
64776
  dispatchId: args.dispatchId,
64573
64777
  sourceJsonlPath,
@@ -64629,7 +64833,7 @@ async function startDaemon(config) {
64629
64833
  });
64630
64834
  shiftScheduler.start();
64631
64835
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
64632
- const larkBotStore = createLarkBotBindingStore(import_node_path67.default.join(config.dataDir, "personas"));
64836
+ const larkBotStore = createLarkBotBindingStore(import_node_path68.default.join(config.dataDir, "personas"));
64633
64837
  const larkBotCloud = createLarkBotCloudClient({
64634
64838
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
64635
64839
  apiKey: resolveClawdTicketsApiKey(),
@@ -64643,7 +64847,7 @@ async function startDaemon(config) {
64643
64847
  store: larkBotStore,
64644
64848
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
64645
64849
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
64646
- mediaRootFor: (chatId) => import_node_path67.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
64850
+ mediaRootFor: (chatId) => import_node_path68.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
64647
64851
  isShuttingDown: () => larkDraining,
64648
64852
  logger: {
64649
64853
  warn: (msg) => logger.warn(msg),
@@ -64947,8 +65151,8 @@ async function startDaemon(config) {
64947
65151
  const lines = [
64948
65152
  `Tunnel: ${r.url}`,
64949
65153
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
64950
- `Frpc config: ${import_node_path67.default.join(config.dataDir, "frpc.toml")}`,
64951
- `Frpc log: ${import_node_path67.default.join(logDir, "frpc.log")}`
65154
+ `Frpc config: ${import_node_path68.default.join(config.dataDir, "frpc.toml")}`,
65155
+ `Frpc log: ${import_node_path68.default.join(logDir, "frpc.log")}`
64952
65156
  ];
64953
65157
  const width2 = Math.max(...lines.map((l) => l.length));
64954
65158
  const bar = "\u2550".repeat(width2 + 4);
@@ -64961,8 +65165,8 @@ ${bar}
64961
65165
 
64962
65166
  `);
64963
65167
  try {
64964
- const connectPath = import_node_path67.default.join(config.dataDir, "connect.txt");
64965
- import_node_fs51.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
65168
+ const connectPath = import_node_path68.default.join(config.dataDir, "connect.txt");
65169
+ import_node_fs52.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
64966
65170
  } catch {
64967
65171
  }
64968
65172
  } catch (err) {
@@ -65037,9 +65241,9 @@ ${bar}
65037
65241
  };
65038
65242
  }
65039
65243
  function migrateDropPersonsDir(dataDir) {
65040
- const dir = import_node_path67.default.join(dataDir, "persons");
65244
+ const dir = import_node_path68.default.join(dataDir, "persons");
65041
65245
  try {
65042
- import_node_fs51.default.rmSync(dir, { recursive: true, force: true });
65246
+ import_node_fs52.default.rmSync(dir, { recursive: true, force: true });
65043
65247
  } catch {
65044
65248
  }
65045
65249
  }