@clawos-dev/clawd 0.2.352 → 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() {
@@ -7018,6 +7018,10 @@ var init_schemas = __esm({
7018
7018
  effort: external_exports.string().optional(),
7019
7019
  // 归一化运行时观测字段(daemon 独立计算,session:update 不接受;meta_update 事件投递)
7020
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(),
7021
7025
  permissionRules: external_exports.array(AllowRuleSchema).optional(),
7022
7026
  // Sidebar 置顶时间戳;null/undefined 表示未置顶
7023
7027
  pinnedAt: external_exports.number().int().nonnegative().nullable().optional(),
@@ -8960,8 +8964,8 @@ var require_req = __commonJS({
8960
8964
  if (req.originalUrl) {
8961
8965
  _req.url = req.originalUrl;
8962
8966
  } else {
8963
- const path81 = req.path;
8964
- _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;
8965
8969
  }
8966
8970
  if (req.query) {
8967
8971
  _req.query = req.query;
@@ -9126,14 +9130,14 @@ var require_redact = __commonJS({
9126
9130
  }
9127
9131
  return obj;
9128
9132
  }
9129
- function parsePath(path81) {
9133
+ function parsePath(path82) {
9130
9134
  const parts = [];
9131
9135
  let current = "";
9132
9136
  let inBrackets = false;
9133
9137
  let inQuotes = false;
9134
9138
  let quoteChar = "";
9135
- for (let i = 0; i < path81.length; i++) {
9136
- const char = path81[i];
9139
+ for (let i = 0; i < path82.length; i++) {
9140
+ const char = path82[i];
9137
9141
  if (!inBrackets && char === ".") {
9138
9142
  if (current) {
9139
9143
  parts.push(current);
@@ -9264,10 +9268,10 @@ var require_redact = __commonJS({
9264
9268
  return current;
9265
9269
  }
9266
9270
  function redactPaths(obj, paths, censor, remove = false) {
9267
- for (const path81 of paths) {
9268
- const parts = parsePath(path81);
9271
+ for (const path82 of paths) {
9272
+ const parts = parsePath(path82);
9269
9273
  if (parts.includes("*")) {
9270
- redactWildcardPath(obj, parts, censor, path81, remove);
9274
+ redactWildcardPath(obj, parts, censor, path82, remove);
9271
9275
  } else {
9272
9276
  if (remove) {
9273
9277
  removeKey(obj, parts);
@@ -9352,8 +9356,8 @@ var require_redact = __commonJS({
9352
9356
  }
9353
9357
  } else {
9354
9358
  if (afterWildcard.includes("*")) {
9355
- const wrappedCensor = typeof censor === "function" ? (value, path81) => {
9356
- const fullPath = [...pathArray.slice(0, pathLength), ...path81];
9359
+ const wrappedCensor = typeof censor === "function" ? (value, path82) => {
9360
+ const fullPath = [...pathArray.slice(0, pathLength), ...path82];
9357
9361
  return censor(value, fullPath);
9358
9362
  } : censor;
9359
9363
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -9388,8 +9392,8 @@ var require_redact = __commonJS({
9388
9392
  return null;
9389
9393
  }
9390
9394
  const pathStructure = /* @__PURE__ */ new Map();
9391
- for (const path81 of pathsToClone) {
9392
- const parts = parsePath(path81);
9395
+ for (const path82 of pathsToClone) {
9396
+ const parts = parsePath(path82);
9393
9397
  let current = pathStructure;
9394
9398
  for (let i = 0; i < parts.length; i++) {
9395
9399
  const part = parts[i];
@@ -9441,24 +9445,24 @@ var require_redact = __commonJS({
9441
9445
  }
9442
9446
  return cloneSelectively(obj, pathStructure);
9443
9447
  }
9444
- function validatePath(path81) {
9445
- if (typeof path81 !== "string") {
9448
+ function validatePath(path82) {
9449
+ if (typeof path82 !== "string") {
9446
9450
  throw new Error("Paths must be (non-empty) strings");
9447
9451
  }
9448
- if (path81 === "") {
9452
+ if (path82 === "") {
9449
9453
  throw new Error("Invalid redaction path ()");
9450
9454
  }
9451
- if (path81.includes("..")) {
9452
- throw new Error(`Invalid redaction path (${path81})`);
9455
+ if (path82.includes("..")) {
9456
+ throw new Error(`Invalid redaction path (${path82})`);
9453
9457
  }
9454
- if (path81.includes(",")) {
9455
- throw new Error(`Invalid redaction path (${path81})`);
9458
+ if (path82.includes(",")) {
9459
+ throw new Error(`Invalid redaction path (${path82})`);
9456
9460
  }
9457
9461
  let bracketCount = 0;
9458
9462
  let inQuotes = false;
9459
9463
  let quoteChar = "";
9460
- for (let i = 0; i < path81.length; i++) {
9461
- const char = path81[i];
9464
+ for (let i = 0; i < path82.length; i++) {
9465
+ const char = path82[i];
9462
9466
  if ((char === '"' || char === "'") && bracketCount > 0) {
9463
9467
  if (!inQuotes) {
9464
9468
  inQuotes = true;
@@ -9472,20 +9476,20 @@ var require_redact = __commonJS({
9472
9476
  } else if (char === "]" && !inQuotes) {
9473
9477
  bracketCount--;
9474
9478
  if (bracketCount < 0) {
9475
- throw new Error(`Invalid redaction path (${path81})`);
9479
+ throw new Error(`Invalid redaction path (${path82})`);
9476
9480
  }
9477
9481
  }
9478
9482
  }
9479
9483
  if (bracketCount !== 0) {
9480
- throw new Error(`Invalid redaction path (${path81})`);
9484
+ throw new Error(`Invalid redaction path (${path82})`);
9481
9485
  }
9482
9486
  }
9483
9487
  function validatePaths(paths) {
9484
9488
  if (!Array.isArray(paths)) {
9485
9489
  throw new TypeError("paths must be an array");
9486
9490
  }
9487
- for (const path81 of paths) {
9488
- validatePath(path81);
9491
+ for (const path82 of paths) {
9492
+ validatePath(path82);
9489
9493
  }
9490
9494
  }
9491
9495
  function slowRedact(options = {}) {
@@ -9653,8 +9657,8 @@ var require_redaction = __commonJS({
9653
9657
  if (shape[k2] === null) {
9654
9658
  o[k2] = (value) => topCensor(value, [k2]);
9655
9659
  } else {
9656
- const wrappedCensor = typeof censor === "function" ? (value, path81) => {
9657
- return censor(value, [k2, ...path81]);
9660
+ const wrappedCensor = typeof censor === "function" ? (value, path82) => {
9661
+ return censor(value, [k2, ...path82]);
9658
9662
  } : censor;
9659
9663
  o[k2] = Redact({
9660
9664
  paths: shape[k2],
@@ -9872,10 +9876,10 @@ var require_atomic_sleep = __commonJS({
9872
9876
  var require_sonic_boom = __commonJS({
9873
9877
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
9874
9878
  "use strict";
9875
- var fs72 = require("fs");
9879
+ var fs73 = require("fs");
9876
9880
  var EventEmitter3 = require("events");
9877
9881
  var inherits = require("util").inherits;
9878
- var path81 = require("path");
9882
+ var path82 = require("path");
9879
9883
  var sleep2 = require_atomic_sleep();
9880
9884
  var assert = require("assert");
9881
9885
  var BUSY_WRITE_TIMEOUT = 100;
@@ -9929,20 +9933,20 @@ var require_sonic_boom = __commonJS({
9929
9933
  const mode = sonic.mode;
9930
9934
  if (sonic.sync) {
9931
9935
  try {
9932
- if (sonic.mkdir) fs72.mkdirSync(path81.dirname(file), { recursive: true });
9933
- 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);
9934
9938
  fileOpened(null, fd);
9935
9939
  } catch (err) {
9936
9940
  fileOpened(err);
9937
9941
  throw err;
9938
9942
  }
9939
9943
  } else if (sonic.mkdir) {
9940
- fs72.mkdir(path81.dirname(file), { recursive: true }, (err) => {
9944
+ fs73.mkdir(path82.dirname(file), { recursive: true }, (err) => {
9941
9945
  if (err) return fileOpened(err);
9942
- fs72.open(file, flags, mode, fileOpened);
9946
+ fs73.open(file, flags, mode, fileOpened);
9943
9947
  });
9944
9948
  } else {
9945
- fs72.open(file, flags, mode, fileOpened);
9949
+ fs73.open(file, flags, mode, fileOpened);
9946
9950
  }
9947
9951
  }
9948
9952
  function SonicBoom(opts) {
@@ -9983,8 +9987,8 @@ var require_sonic_boom = __commonJS({
9983
9987
  this.flush = flushBuffer;
9984
9988
  this.flushSync = flushBufferSync;
9985
9989
  this._actualWrite = actualWriteBuffer;
9986
- fsWriteSync = () => fs72.writeSync(this.fd, this._writingBuf);
9987
- 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);
9988
9992
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
9989
9993
  this._writingBuf = "";
9990
9994
  this.write = write;
@@ -9993,15 +9997,15 @@ var require_sonic_boom = __commonJS({
9993
9997
  this._actualWrite = actualWrite;
9994
9998
  fsWriteSync = () => {
9995
9999
  if (Buffer.isBuffer(this._writingBuf)) {
9996
- return fs72.writeSync(this.fd, this._writingBuf);
10000
+ return fs73.writeSync(this.fd, this._writingBuf);
9997
10001
  }
9998
- return fs72.writeSync(this.fd, this._writingBuf, "utf8");
10002
+ return fs73.writeSync(this.fd, this._writingBuf, "utf8");
9999
10003
  };
10000
10004
  fsWrite = () => {
10001
10005
  if (Buffer.isBuffer(this._writingBuf)) {
10002
- return fs72.write(this.fd, this._writingBuf, this.release);
10006
+ return fs73.write(this.fd, this._writingBuf, this.release);
10003
10007
  }
10004
- return fs72.write(this.fd, this._writingBuf, "utf8", this.release);
10008
+ return fs73.write(this.fd, this._writingBuf, "utf8", this.release);
10005
10009
  };
10006
10010
  } else {
10007
10011
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -10058,7 +10062,7 @@ var require_sonic_boom = __commonJS({
10058
10062
  }
10059
10063
  }
10060
10064
  if (this._fsync) {
10061
- fs72.fsyncSync(this.fd);
10065
+ fs73.fsyncSync(this.fd);
10062
10066
  }
10063
10067
  const len = this._len;
10064
10068
  if (this._reopening) {
@@ -10172,7 +10176,7 @@ var require_sonic_boom = __commonJS({
10172
10176
  const onDrain = () => {
10173
10177
  if (!this._fsync) {
10174
10178
  try {
10175
- fs72.fsync(this.fd, (err) => {
10179
+ fs73.fsync(this.fd, (err) => {
10176
10180
  this._flushPending = false;
10177
10181
  cb(err);
10178
10182
  });
@@ -10274,7 +10278,7 @@ var require_sonic_boom = __commonJS({
10274
10278
  const fd = this.fd;
10275
10279
  this.once("ready", () => {
10276
10280
  if (fd !== this.fd) {
10277
- fs72.close(fd, (err) => {
10281
+ fs73.close(fd, (err) => {
10278
10282
  if (err) {
10279
10283
  return this.emit("error", err);
10280
10284
  }
@@ -10323,7 +10327,7 @@ var require_sonic_boom = __commonJS({
10323
10327
  buf = this._bufs[0];
10324
10328
  }
10325
10329
  try {
10326
- 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");
10327
10331
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
10328
10332
  buf = releasedBufObj.writingBuf;
10329
10333
  this._len = releasedBufObj.len;
@@ -10339,7 +10343,7 @@ var require_sonic_boom = __commonJS({
10339
10343
  }
10340
10344
  }
10341
10345
  try {
10342
- fs72.fsyncSync(this.fd);
10346
+ fs73.fsyncSync(this.fd);
10343
10347
  } catch {
10344
10348
  }
10345
10349
  }
@@ -10360,7 +10364,7 @@ var require_sonic_boom = __commonJS({
10360
10364
  buf = mergeBuf(this._bufs[0], this._lens[0]);
10361
10365
  }
10362
10366
  try {
10363
- const n = fs72.writeSync(this.fd, buf);
10367
+ const n = fs73.writeSync(this.fd, buf);
10364
10368
  buf = buf.subarray(n);
10365
10369
  this._len = Math.max(this._len - n, 0);
10366
10370
  if (buf.length <= 0) {
@@ -10388,13 +10392,13 @@ var require_sonic_boom = __commonJS({
10388
10392
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
10389
10393
  if (this.sync) {
10390
10394
  try {
10391
- 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");
10392
10396
  release(null, written);
10393
10397
  } catch (err) {
10394
10398
  release(err);
10395
10399
  }
10396
10400
  } else {
10397
- fs72.write(this.fd, this._writingBuf, release);
10401
+ fs73.write(this.fd, this._writingBuf, release);
10398
10402
  }
10399
10403
  }
10400
10404
  function actualWriteBuffer() {
@@ -10403,7 +10407,7 @@ var require_sonic_boom = __commonJS({
10403
10407
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
10404
10408
  if (this.sync) {
10405
10409
  try {
10406
- const written = fs72.writeSync(this.fd, this._writingBuf);
10410
+ const written = fs73.writeSync(this.fd, this._writingBuf);
10407
10411
  release(null, written);
10408
10412
  } catch (err) {
10409
10413
  release(err);
@@ -10412,7 +10416,7 @@ var require_sonic_boom = __commonJS({
10412
10416
  if (kCopyBuffer) {
10413
10417
  this._writingBuf = Buffer.from(this._writingBuf);
10414
10418
  }
10415
- fs72.write(this.fd, this._writingBuf, release);
10419
+ fs73.write(this.fd, this._writingBuf, release);
10416
10420
  }
10417
10421
  }
10418
10422
  function actualClose(sonic) {
@@ -10428,12 +10432,12 @@ var require_sonic_boom = __commonJS({
10428
10432
  sonic._lens = [];
10429
10433
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
10430
10434
  try {
10431
- fs72.fsync(sonic.fd, closeWrapped);
10435
+ fs73.fsync(sonic.fd, closeWrapped);
10432
10436
  } catch {
10433
10437
  }
10434
10438
  function closeWrapped() {
10435
10439
  if (sonic.fd !== 1 && sonic.fd !== 2) {
10436
- fs72.close(sonic.fd, done);
10440
+ fs73.close(sonic.fd, done);
10437
10441
  } else {
10438
10442
  done();
10439
10443
  }
@@ -12797,7 +12801,7 @@ var require_multistream = __commonJS({
12797
12801
  var require_pino = __commonJS({
12798
12802
  "../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
12799
12803
  "use strict";
12800
- var os25 = require("os");
12804
+ var os26 = require("os");
12801
12805
  var stdSerializers = require_pino_std_serializers();
12802
12806
  var caller = require_caller();
12803
12807
  var redaction = require_redaction();
@@ -12844,7 +12848,7 @@ var require_pino = __commonJS({
12844
12848
  } = symbols;
12845
12849
  var { epochTime, nullTime } = time;
12846
12850
  var { pid } = process;
12847
- var hostname = os25.hostname();
12851
+ var hostname = os26.hostname();
12848
12852
  var defaultErrorSerializer = stdSerializers.err;
12849
12853
  var defaultOptions2 = {
12850
12854
  level: "info",
@@ -13568,11 +13572,11 @@ var init_lib = __esm({
13568
13572
  }
13569
13573
  }
13570
13574
  },
13571
- addToPath: function addToPath(path81, added, removed, oldPosInc, options) {
13572
- var last = path81.lastComponent;
13575
+ addToPath: function addToPath(path82, added, removed, oldPosInc, options) {
13576
+ var last = path82.lastComponent;
13573
13577
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
13574
13578
  return {
13575
- oldPos: path81.oldPos + oldPosInc,
13579
+ oldPos: path82.oldPos + oldPosInc,
13576
13580
  lastComponent: {
13577
13581
  count: last.count + 1,
13578
13582
  added,
@@ -13582,7 +13586,7 @@ var init_lib = __esm({
13582
13586
  };
13583
13587
  } else {
13584
13588
  return {
13585
- oldPos: path81.oldPos + oldPosInc,
13589
+ oldPos: path82.oldPos + oldPosInc,
13586
13590
  lastComponent: {
13587
13591
  count: 1,
13588
13592
  added,
@@ -14114,10 +14118,10 @@ function attachmentToHistoryMessage(o, ts) {
14114
14118
  const memories = raw.map((m2) => {
14115
14119
  if (!m2 || typeof m2 !== "object") return null;
14116
14120
  const rec4 = m2;
14117
- const path81 = typeof rec4.path === "string" ? rec4.path : null;
14121
+ const path82 = typeof rec4.path === "string" ? rec4.path : null;
14118
14122
  const content = typeof rec4.content === "string" ? rec4.content : null;
14119
- if (!path81 || content == null) return null;
14120
- const entry = { path: path81, content };
14123
+ if (!path82 || content == null) return null;
14124
+ const entry = { path: path82, content };
14121
14125
  if (typeof rec4.mtimeMs === "number") entry.mtimeMs = rec4.mtimeMs;
14122
14126
  return entry;
14123
14127
  }).filter((m2) => m2 !== null);
@@ -14951,10 +14955,10 @@ function parseAttachment(obj) {
14951
14955
  const memories = raw.map((m2) => {
14952
14956
  if (!m2 || typeof m2 !== "object") return null;
14953
14957
  const rec4 = m2;
14954
- const path81 = typeof rec4.path === "string" ? rec4.path : null;
14958
+ const path82 = typeof rec4.path === "string" ? rec4.path : null;
14955
14959
  const content = typeof rec4.content === "string" ? rec4.content : null;
14956
- if (!path81 || content == null) return null;
14957
- const out = { path: path81, content };
14960
+ if (!path82 || content == null) return null;
14961
+ const out = { path: path82, content };
14958
14962
  if (typeof rec4.mtimeMs === "number") out.mtimeMs = rec4.mtimeMs;
14959
14963
  return out;
14960
14964
  }).filter((m2) => m2 !== null);
@@ -35928,8 +35932,8 @@ var require_utils = __commonJS({
35928
35932
  var result = transform[inputType][outputType](input);
35929
35933
  return result;
35930
35934
  };
35931
- exports2.resolve = function(path81) {
35932
- var parts = path81.split("/");
35935
+ exports2.resolve = function(path82) {
35936
+ var parts = path82.split("/");
35933
35937
  var result = [];
35934
35938
  for (var index = 0; index < parts.length; index++) {
35935
35939
  var part = parts[index];
@@ -41782,18 +41786,18 @@ var require_object = __commonJS({
41782
41786
  var object = new ZipObject(name, zipObjectContent, o);
41783
41787
  this.files[name] = object;
41784
41788
  };
41785
- var parentFolder = function(path81) {
41786
- if (path81.slice(-1) === "/") {
41787
- 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);
41788
41792
  }
41789
- var lastSlash = path81.lastIndexOf("/");
41790
- return lastSlash > 0 ? path81.substring(0, lastSlash) : "";
41793
+ var lastSlash = path82.lastIndexOf("/");
41794
+ return lastSlash > 0 ? path82.substring(0, lastSlash) : "";
41791
41795
  };
41792
- var forceTrailingSlash = function(path81) {
41793
- if (path81.slice(-1) !== "/") {
41794
- path81 += "/";
41796
+ var forceTrailingSlash = function(path82) {
41797
+ if (path82.slice(-1) !== "/") {
41798
+ path82 += "/";
41795
41799
  }
41796
- return path81;
41800
+ return path82;
41797
41801
  };
41798
41802
  var folderAdd = function(name, createFolders) {
41799
41803
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -42795,7 +42799,7 @@ var require_lib3 = __commonJS({
42795
42799
  // src/run-case/recorder.ts
42796
42800
  function startRunCaseRecorder(opts) {
42797
42801
  const now = opts.now ?? Date.now;
42798
- const dir = import_node_path68.default.dirname(opts.recordPath);
42802
+ const dir = import_node_path69.default.dirname(opts.recordPath);
42799
42803
  let stream = null;
42800
42804
  let closing = false;
42801
42805
  let closedSettled = false;
@@ -42809,8 +42813,8 @@ function startRunCaseRecorder(opts) {
42809
42813
  });
42810
42814
  const ensureStream = () => {
42811
42815
  if (stream) return stream;
42812
- import_node_fs52.default.mkdirSync(dir, { recursive: true });
42813
- 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" });
42814
42818
  stream.on("close", () => closedResolve());
42815
42819
  return stream;
42816
42820
  };
@@ -42835,12 +42839,12 @@ function startRunCaseRecorder(opts) {
42835
42839
  };
42836
42840
  return { tap, close, closed };
42837
42841
  }
42838
- var import_node_fs52, import_node_path68;
42842
+ var import_node_fs53, import_node_path69;
42839
42843
  var init_recorder = __esm({
42840
42844
  "src/run-case/recorder.ts"() {
42841
42845
  "use strict";
42842
- import_node_fs52 = __toESM(require("fs"), 1);
42843
- import_node_path68 = __toESM(require("path"), 1);
42846
+ import_node_fs53 = __toESM(require("fs"), 1);
42847
+ import_node_path69 = __toESM(require("path"), 1);
42844
42848
  }
42845
42849
  });
42846
42850
 
@@ -42883,7 +42887,7 @@ var init_wire = __esm({
42883
42887
  // src/run-case/controller.ts
42884
42888
  async function runController(opts) {
42885
42889
  const now = opts.now ?? Date.now;
42886
- 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-"));
42887
42891
  const ownsCwd = opts.cwd === void 0;
42888
42892
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
42889
42893
  const spawnCtx = { cwd };
@@ -43044,19 +43048,19 @@ async function runController(opts) {
43044
43048
  if (sigintHandler) process.off("SIGINT", sigintHandler);
43045
43049
  if (ownsCwd) {
43046
43050
  try {
43047
- (0, import_node_fs53.rmSync)(cwd, { recursive: true, force: true });
43051
+ (0, import_node_fs54.rmSync)(cwd, { recursive: true, force: true });
43048
43052
  } catch {
43049
43053
  }
43050
43054
  }
43051
43055
  return exitCode ?? 0;
43052
43056
  }
43053
- var import_node_fs53, import_node_os24, import_node_path69;
43057
+ var import_node_fs54, import_node_os25, import_node_path70;
43054
43058
  var init_controller = __esm({
43055
43059
  "src/run-case/controller.ts"() {
43056
43060
  "use strict";
43057
- import_node_fs53 = require("fs");
43058
- import_node_os24 = __toESM(require("os"), 1);
43059
- 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);
43060
43064
  init_claude();
43061
43065
  init_stdout_splitter();
43062
43066
  init_permission_stdio();
@@ -43331,9 +43335,9 @@ Env (advanced):
43331
43335
  `;
43332
43336
 
43333
43337
  // src/index.ts
43334
- var import_node_path67 = __toESM(require("path"), 1);
43335
- var import_node_fs51 = __toESM(require("fs"), 1);
43336
- 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);
43337
43341
 
43338
43342
  // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
43339
43343
  var byteToHex = [];
@@ -44619,9 +44623,13 @@ function applyMetaUpdate(state, patch, deps) {
44619
44623
  const w2 = deps.resolveContextWindow?.(next.file.tool, patch.resolvedModel);
44620
44624
  if (w2 !== void 0) merged.contextWindowSize = w2;
44621
44625
  }
44622
- 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) {
44623
44628
  return { state: next, effects: [] };
44624
44629
  }
44630
+ if (aiLabelArrived) {
44631
+ merged.aiLabelGeneratedAt = nowIso(deps);
44632
+ }
44625
44633
  next.file = merged;
44626
44634
  return {
44627
44635
  state: next,
@@ -45950,6 +45958,8 @@ var SessionManager = class {
45950
45958
  deps;
45951
45959
  // sessionId → SessionRunner;在 send / ensureSession 时按需创建
45952
45960
  runners = /* @__PURE__ */ new Map();
45961
+ // 标题生成 in-flight 防重(进程内);跨重启防重靠 SessionFile.aiLabelGeneratedAt
45962
+ titleGenPending = /* @__PURE__ */ new Set();
45953
45963
  // 当同步命令执行期间,runner 的 emit-frame 临时 push 到这里;
45954
45964
  // null 表示当前是异步路径(stdout 'data' / proc 'exit' 等),走 deps.broadcastFrame
45955
45965
  currentCollector = null;
@@ -46775,8 +46785,38 @@ var SessionManager = class {
46775
46785
  command: { kind: "send", text: args.text, senderPrincipal }
46776
46786
  });
46777
46787
  });
46788
+ this.maybeGenerateTitle(existing, args.text);
46778
46789
  return { response: { ok: true }, broadcast };
46779
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
+ }
46780
46820
  /**
46781
46821
  * Dispatch 结果投递(spec 2026-07-20 §5):查台账里该 source session 名下已完成
46782
46822
  * 且未投递的行,合并成一段 plain text 结果包注入回 source session。
@@ -49771,8 +49811,8 @@ function turnStartInput(text) {
49771
49811
  const items = [];
49772
49812
  let leftover = text;
49773
49813
  for (const m2 of text.matchAll(SKILL_RE)) {
49774
- const [marker, name, path81] = m2;
49775
- items.push({ type: "skill", name, path: path81 });
49814
+ const [marker, name, path82] = m2;
49815
+ items.push({ type: "skill", name, path: path82 });
49776
49816
  leftover = leftover.replace(marker, "");
49777
49817
  }
49778
49818
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -53728,13 +53768,13 @@ function mapSkillsListResponse(res) {
53728
53768
  const r = s ?? {};
53729
53769
  const name = str3(r.name);
53730
53770
  if (!name) continue;
53731
- const path81 = str3(r.path);
53771
+ const path82 = str3(r.path);
53732
53772
  const description = str3(r.description);
53733
53773
  const isPlugin = name.includes(":");
53734
53774
  out.push({
53735
53775
  name,
53736
53776
  source: isPlugin ? "plugin" : "project",
53737
- ...path81 ? { path: path81 } : {},
53777
+ ...path82 ? { path: path82 } : {},
53738
53778
  ...description ? { description } : {},
53739
53779
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
53740
53780
  });
@@ -54502,6 +54542,149 @@ function listRegistered() {
54502
54542
  return [...registry.keys()];
54503
54543
  }
54504
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
+
54505
54688
  // ../node_modules/.pnpm/ws@8.20.0/node_modules/ws/wrapper.mjs
54506
54689
  var import_stream = __toESM(require_stream(), 1);
54507
54690
  var import_extension2 = __toESM(require_extension(), 1);
@@ -55178,8 +55361,8 @@ async function authenticate(token, deps) {
55178
55361
  }
55179
55362
 
55180
55363
  // src/legacy-cleanup.ts
55181
- var fs37 = __toESM(require("fs/promises"), 1);
55182
- var path38 = __toESM(require("path"), 1);
55364
+ var fs38 = __toESM(require("fs/promises"), 1);
55365
+ var path39 = __toESM(require("path"), 1);
55183
55366
  var LEGACY_FILES = [
55184
55367
  "personal-capability.json",
55185
55368
  "received-capabilities.json",
@@ -55188,9 +55371,9 @@ var LEGACY_FILES = [
55188
55371
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
55189
55372
  const removed = [];
55190
55373
  for (const name of LEGACY_FILES) {
55191
- const p2 = path38.join(dataDir, name);
55374
+ const p2 = path39.join(dataDir, name);
55192
55375
  try {
55193
- await fs37.unlink(p2);
55376
+ await fs38.unlink(p2);
55194
55377
  removed.push(name);
55195
55378
  logger.debug("legacy capability file removed", { file: name });
55196
55379
  } catch (err) {
@@ -55202,13 +55385,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
55202
55385
  }
55203
55386
 
55204
55387
  // src/inbox/inbox-store.ts
55205
- var fs38 = __toESM(require("fs"), 1);
55206
- var path39 = __toESM(require("path"), 1);
55388
+ var fs39 = __toESM(require("fs"), 1);
55389
+ var path40 = __toESM(require("path"), 1);
55207
55390
  var INBOX_SUBDIR = "inbox";
55208
55391
  var InboxStore = class {
55209
55392
  constructor(dataDir) {
55210
55393
  this.dataDir = dataDir;
55211
- fs38.mkdirSync(this.dirPath(), { recursive: true });
55394
+ fs39.mkdirSync(this.dirPath(), { recursive: true });
55212
55395
  }
55213
55396
  dataDir;
55214
55397
  /**
@@ -55220,7 +55403,7 @@ var InboxStore = class {
55220
55403
  const file = this.filePath(peerDeviceId);
55221
55404
  let raw;
55222
55405
  try {
55223
- raw = fs38.readFileSync(file, "utf8");
55406
+ raw = fs39.readFileSync(file, "utf8");
55224
55407
  } catch (err) {
55225
55408
  if (err?.code === "ENOENT") return [];
55226
55409
  return [];
@@ -55236,7 +55419,7 @@ var InboxStore = class {
55236
55419
  const dir = this.dirPath();
55237
55420
  let entries;
55238
55421
  try {
55239
- entries = fs38.readdirSync(dir);
55422
+ entries = fs39.readdirSync(dir);
55240
55423
  } catch (err) {
55241
55424
  if (err?.code === "ENOENT") return [];
55242
55425
  return [];
@@ -55252,9 +55435,9 @@ var InboxStore = class {
55252
55435
  if (existing.some((m2) => m2.id === message.id)) return;
55253
55436
  const file = this.filePath(message.peerDeviceId);
55254
55437
  const line = JSON.stringify(message) + "\n";
55255
- fs38.appendFileSync(file, line, { mode: 384 });
55438
+ fs39.appendFileSync(file, line, { mode: 384 });
55256
55439
  try {
55257
- fs38.chmodSync(file, 384);
55440
+ fs39.chmodSync(file, 384);
55258
55441
  } catch {
55259
55442
  }
55260
55443
  }
@@ -55284,7 +55467,7 @@ var InboxStore = class {
55284
55467
  removeByPeerDeviceId(peerDeviceId) {
55285
55468
  const file = this.filePath(peerDeviceId);
55286
55469
  try {
55287
- fs38.unlinkSync(file);
55470
+ fs39.unlinkSync(file);
55288
55471
  } catch (err) {
55289
55472
  if (err?.code === "ENOENT") return;
55290
55473
  }
@@ -55293,18 +55476,18 @@ var InboxStore = class {
55293
55476
  const file = this.filePath(peerDeviceId);
55294
55477
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
55295
55478
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
55296
- fs38.writeFileSync(tmp, content, { mode: 384 });
55297
- fs38.renameSync(tmp, file);
55479
+ fs39.writeFileSync(tmp, content, { mode: 384 });
55480
+ fs39.renameSync(tmp, file);
55298
55481
  try {
55299
- fs38.chmodSync(file, 384);
55482
+ fs39.chmodSync(file, 384);
55300
55483
  } catch {
55301
55484
  }
55302
55485
  }
55303
55486
  dirPath() {
55304
- return path39.join(this.dataDir, INBOX_SUBDIR);
55487
+ return path40.join(this.dataDir, INBOX_SUBDIR);
55305
55488
  }
55306
55489
  filePath(peerDeviceId) {
55307
- return path39.join(this.dirPath(), `${peerDeviceId}.jsonl`);
55490
+ return path40.join(this.dirPath(), `${peerDeviceId}.jsonl`);
55308
55491
  }
55309
55492
  };
55310
55493
  function parseAllLines(raw) {
@@ -55392,8 +55575,8 @@ var InboxManager = class {
55392
55575
  };
55393
55576
 
55394
55577
  // src/state/contact-store.ts
55395
- var fs39 = __toESM(require("fs"), 1);
55396
- var path40 = __toESM(require("path"), 1);
55578
+ var fs40 = __toESM(require("fs"), 1);
55579
+ var path41 = __toESM(require("path"), 1);
55397
55580
  var FILE_NAME = "contacts.json";
55398
55581
  var ContactStore = class {
55399
55582
  constructor(dataDir) {
@@ -55403,10 +55586,10 @@ var ContactStore = class {
55403
55586
  contacts = /* @__PURE__ */ new Map();
55404
55587
  load() {
55405
55588
  this.contacts.clear();
55406
- const file = path40.join(this.dataDir, FILE_NAME);
55589
+ const file = path41.join(this.dataDir, FILE_NAME);
55407
55590
  let raw;
55408
55591
  try {
55409
- raw = fs39.readFileSync(file, "utf8");
55592
+ raw = fs40.readFileSync(file, "utf8");
55410
55593
  } catch (err) {
55411
55594
  if (err?.code !== "ENOENT") this.renameBak(file);
55412
55595
  return;
@@ -55475,20 +55658,20 @@ var ContactStore = class {
55475
55658
  return true;
55476
55659
  }
55477
55660
  flush() {
55478
- const file = path40.join(this.dataDir, FILE_NAME);
55661
+ const file = path41.join(this.dataDir, FILE_NAME);
55479
55662
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
55480
55663
  const content = JSON.stringify(
55481
55664
  { contacts: Array.from(this.contacts.values()) },
55482
55665
  null,
55483
55666
  2
55484
55667
  );
55485
- fs39.mkdirSync(this.dataDir, { recursive: true });
55486
- fs39.writeFileSync(tmp, content, { mode: 384 });
55487
- fs39.renameSync(tmp, file);
55668
+ fs40.mkdirSync(this.dataDir, { recursive: true });
55669
+ fs40.writeFileSync(tmp, content, { mode: 384 });
55670
+ fs40.renameSync(tmp, file);
55488
55671
  }
55489
55672
  renameBak(file) {
55490
55673
  try {
55491
- fs39.renameSync(file, `${file}.bak`);
55674
+ fs40.renameSync(file, `${file}.bak`);
55492
55675
  } catch {
55493
55676
  }
55494
55677
  }
@@ -55596,61 +55779,61 @@ async function connectRemote(args) {
55596
55779
  }
55597
55780
 
55598
55781
  // src/migrations/2026-05-20-flatten-sessions.ts
55599
- var fs40 = __toESM(require("fs"), 1);
55600
- var path41 = __toESM(require("path"), 1);
55782
+ var fs41 = __toESM(require("fs"), 1);
55783
+ var path42 = __toESM(require("path"), 1);
55601
55784
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
55602
55785
  function migrateFlattenSessions(opts) {
55603
55786
  const dataDir = opts.dataDir;
55604
55787
  const now = opts.now ?? Date.now;
55605
- const sessionsDir = path41.join(dataDir, "sessions");
55606
- const flagPath = path41.join(sessionsDir, MIGRATION_FLAG_NAME);
55788
+ const sessionsDir = path42.join(dataDir, "sessions");
55789
+ const flagPath = path42.join(sessionsDir, MIGRATION_FLAG_NAME);
55607
55790
  if (existsSync3(flagPath)) {
55608
55791
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
55609
55792
  }
55610
55793
  let movedBare = 0;
55611
55794
  let movedVmOwner = 0;
55612
55795
  let archivedListener = 0;
55613
- const defaultDir = path41.join(sessionsDir, "default");
55796
+ const defaultDir = path42.join(sessionsDir, "default");
55614
55797
  if (existsSync3(defaultDir)) {
55615
55798
  for (const entry of readdirSafe(defaultDir)) {
55616
55799
  if (!entry.endsWith(".json")) continue;
55617
- const src = path41.join(defaultDir, entry);
55618
- const dst = path41.join(sessionsDir, entry);
55619
- fs40.renameSync(src, dst);
55800
+ const src = path42.join(defaultDir, entry);
55801
+ const dst = path42.join(sessionsDir, entry);
55802
+ fs41.renameSync(src, dst);
55620
55803
  movedBare += 1;
55621
55804
  }
55622
55805
  rmdirIfEmpty(defaultDir);
55623
55806
  }
55624
55807
  for (const pid of readdirSafe(sessionsDir)) {
55625
- const personaDir = path41.join(sessionsDir, pid);
55808
+ const personaDir = path42.join(sessionsDir, pid);
55626
55809
  if (!isDir(personaDir)) continue;
55627
55810
  if (pid === "default") continue;
55628
- const ownerSrc = path41.join(personaDir, "owner");
55811
+ const ownerSrc = path42.join(personaDir, "owner");
55629
55812
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
55630
- const ownerDst = path41.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
55631
- fs40.mkdirSync(ownerDst, { recursive: true });
55813
+ const ownerDst = path42.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
55814
+ fs41.mkdirSync(ownerDst, { recursive: true });
55632
55815
  for (const file of readdirSafe(ownerSrc)) {
55633
55816
  if (!file.endsWith(".json")) continue;
55634
- fs40.renameSync(path41.join(ownerSrc, file), path41.join(ownerDst, file));
55817
+ fs41.renameSync(path42.join(ownerSrc, file), path42.join(ownerDst, file));
55635
55818
  movedVmOwner += 1;
55636
55819
  }
55637
55820
  rmdirIfEmpty(ownerSrc);
55638
55821
  }
55639
- const listenerSrc = path41.join(personaDir, "listener");
55822
+ const listenerSrc = path42.join(personaDir, "listener");
55640
55823
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
55641
- const archiveDst = path41.join(dataDir, ".legacy", `listener-${pid}`);
55642
- fs40.mkdirSync(archiveDst, { recursive: true });
55824
+ const archiveDst = path42.join(dataDir, ".legacy", `listener-${pid}`);
55825
+ fs41.mkdirSync(archiveDst, { recursive: true });
55643
55826
  for (const file of readdirSafe(listenerSrc)) {
55644
55827
  if (!file.endsWith(".json")) continue;
55645
- fs40.renameSync(path41.join(listenerSrc, file), path41.join(archiveDst, file));
55828
+ fs41.renameSync(path42.join(listenerSrc, file), path42.join(archiveDst, file));
55646
55829
  archivedListener += 1;
55647
55830
  }
55648
55831
  rmdirIfEmpty(listenerSrc);
55649
55832
  }
55650
55833
  rmdirIfEmpty(personaDir);
55651
55834
  }
55652
- fs40.mkdirSync(sessionsDir, { recursive: true });
55653
- 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));
55654
55837
  return {
55655
55838
  skipped: false,
55656
55839
  flagWritten: true,
@@ -55661,7 +55844,7 @@ function migrateFlattenSessions(opts) {
55661
55844
  }
55662
55845
  function existsSync3(p2) {
55663
55846
  try {
55664
- fs40.statSync(p2);
55847
+ fs41.statSync(p2);
55665
55848
  return true;
55666
55849
  } catch {
55667
55850
  return false;
@@ -55669,31 +55852,31 @@ function existsSync3(p2) {
55669
55852
  }
55670
55853
  function isDir(p2) {
55671
55854
  try {
55672
- return fs40.statSync(p2).isDirectory();
55855
+ return fs41.statSync(p2).isDirectory();
55673
55856
  } catch {
55674
55857
  return false;
55675
55858
  }
55676
55859
  }
55677
55860
  function readdirSafe(p2) {
55678
55861
  try {
55679
- return fs40.readdirSync(p2);
55862
+ return fs41.readdirSync(p2);
55680
55863
  } catch {
55681
55864
  return [];
55682
55865
  }
55683
55866
  }
55684
55867
  function rmdirIfEmpty(p2) {
55685
55868
  try {
55686
- fs40.rmdirSync(p2);
55869
+ fs41.rmdirSync(p2);
55687
55870
  } catch {
55688
55871
  }
55689
55872
  }
55690
55873
 
55691
55874
  // src/transport/http-router.ts
55692
- var import_node_fs33 = __toESM(require("fs"), 1);
55693
- 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);
55694
55877
 
55695
55878
  // src/attachment/mime.ts
55696
- var import_node_path34 = __toESM(require("path"), 1);
55879
+ var import_node_path35 = __toESM(require("path"), 1);
55697
55880
  var TEXT_PLAIN = "text/plain; charset=utf-8";
55698
55881
  var EXT_TO_NATIVE_MIME = {
55699
55882
  // 图片
@@ -55800,7 +55983,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
55800
55983
  ".mk"
55801
55984
  ]);
55802
55985
  function lookupMime(filePathOrName) {
55803
- const ext = import_node_path34.default.extname(filePathOrName).toLowerCase();
55986
+ const ext = import_node_path35.default.extname(filePathOrName).toLowerCase();
55804
55987
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
55805
55988
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
55806
55989
  return "application/octet-stream";
@@ -55870,8 +56053,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
55870
56053
  }
55871
56054
 
55872
56055
  // src/attachment/upload.ts
55873
- var import_node_fs32 = __toESM(require("fs"), 1);
55874
- 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);
55875
56058
  var import_node_crypto9 = __toESM(require("crypto"), 1);
55876
56059
  var import_promises4 = require("stream/promises");
55877
56060
  var UploadError = class extends Error {
@@ -55883,22 +56066,22 @@ var UploadError = class extends Error {
55883
56066
  code;
55884
56067
  };
55885
56068
  function assertValidFileName(fileName) {
55886
- 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)) {
55887
56070
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
55888
56071
  }
55889
56072
  }
55890
56073
  var HASH_PREFIX_LEN = 16;
55891
56074
  async function writeUploadedAttachment(args) {
55892
56075
  assertValidFileName(args.fileName);
55893
- const attachmentsRoot = import_node_path35.default.join(args.baseDir, ".attachments");
56076
+ const attachmentsRoot = import_node_path36.default.join(args.baseDir, ".attachments");
55894
56077
  try {
55895
- import_node_fs32.default.mkdirSync(attachmentsRoot, { recursive: true });
56078
+ import_node_fs33.default.mkdirSync(attachmentsRoot, { recursive: true });
55896
56079
  } catch (err) {
55897
56080
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
55898
56081
  }
55899
56082
  const hasher = import_node_crypto9.default.createHash("sha256");
55900
56083
  let actualSize = 0;
55901
- const tmpPath = import_node_path35.default.join(
56084
+ const tmpPath = import_node_path36.default.join(
55902
56085
  attachmentsRoot,
55903
56086
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto9.default.randomBytes(4).toString("hex")}`
55904
56087
  );
@@ -55913,18 +56096,18 @@ async function writeUploadedAttachment(args) {
55913
56096
  yield buf;
55914
56097
  }
55915
56098
  },
55916
- import_node_fs32.default.createWriteStream(tmpPath, { mode: 384 })
56099
+ import_node_fs33.default.createWriteStream(tmpPath, { mode: 384 })
55917
56100
  );
55918
56101
  } catch (err) {
55919
56102
  try {
55920
- import_node_fs32.default.unlinkSync(tmpPath);
56103
+ import_node_fs33.default.unlinkSync(tmpPath);
55921
56104
  } catch {
55922
56105
  }
55923
56106
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
55924
56107
  }
55925
56108
  if (actualSize !== args.contentLength) {
55926
56109
  try {
55927
- import_node_fs32.default.unlinkSync(tmpPath);
56110
+ import_node_fs33.default.unlinkSync(tmpPath);
55928
56111
  } catch {
55929
56112
  }
55930
56113
  throw new UploadError(
@@ -55933,34 +56116,34 @@ async function writeUploadedAttachment(args) {
55933
56116
  );
55934
56117
  }
55935
56118
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
55936
- const hashDir = import_node_path35.default.join(attachmentsRoot, attachmentId);
56119
+ const hashDir = import_node_path36.default.join(attachmentsRoot, attachmentId);
55937
56120
  let finalFileName;
55938
56121
  let hashDirExists = false;
55939
56122
  try {
55940
- hashDirExists = import_node_fs32.default.statSync(hashDir).isDirectory();
56123
+ hashDirExists = import_node_fs33.default.statSync(hashDir).isDirectory();
55941
56124
  } catch {
55942
56125
  }
55943
56126
  if (hashDirExists) {
55944
- 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("."));
55945
56128
  finalFileName = existing[0] ?? args.fileName;
55946
56129
  try {
55947
- import_node_fs32.default.unlinkSync(tmpPath);
56130
+ import_node_fs33.default.unlinkSync(tmpPath);
55948
56131
  } catch {
55949
56132
  }
55950
56133
  } else {
55951
56134
  try {
55952
- import_node_fs32.default.mkdirSync(hashDir, { recursive: true });
56135
+ import_node_fs33.default.mkdirSync(hashDir, { recursive: true });
55953
56136
  finalFileName = args.fileName;
55954
- 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));
55955
56138
  } catch (err) {
55956
56139
  try {
55957
- import_node_fs32.default.unlinkSync(tmpPath);
56140
+ import_node_fs33.default.unlinkSync(tmpPath);
55958
56141
  } catch {
55959
56142
  }
55960
56143
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
55961
56144
  }
55962
56145
  }
55963
- const absPath = import_node_path35.default.join(hashDir, finalFileName);
56146
+ const absPath = import_node_path36.default.join(hashDir, finalFileName);
55964
56147
  const relPath = absPath;
55965
56148
  args.groupFileStore.upsert(args.scope, args.sessionId, {
55966
56149
  relPath: absPath,
@@ -55975,8 +56158,8 @@ async function writeUploadedAttachment(args) {
55975
56158
 
55976
56159
  // src/extension/import.ts
55977
56160
  var import_promises5 = __toESM(require("fs/promises"), 1);
55978
- var import_node_path36 = __toESM(require("path"), 1);
55979
- 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);
55980
56163
  var import_jszip = __toESM(require_lib3(), 1);
55981
56164
  var ImportError = class extends Error {
55982
56165
  constructor(code, message) {
@@ -55993,7 +56176,7 @@ async function importZip(buf, root) {
55993
56176
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
55994
56177
  }
55995
56178
  for (const name of Object.keys(zip.files)) {
55996
- if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
56179
+ if (name.includes("..") || name.startsWith("/") || import_node_path37.default.isAbsolute(name)) {
55997
56180
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
55998
56181
  }
55999
56182
  }
@@ -56026,7 +56209,7 @@ async function importZip(buf, root) {
56026
56209
  );
56027
56210
  }
56028
56211
  }
56029
- const destDir = import_node_path36.default.join(root, manifest.id);
56212
+ const destDir = import_node_path37.default.join(root, manifest.id);
56030
56213
  let destExists = false;
56031
56214
  try {
56032
56215
  await import_promises5.default.access(destDir);
@@ -56036,15 +56219,15 @@ async function importZip(buf, root) {
56036
56219
  if (destExists) {
56037
56220
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
56038
56221
  }
56039
- 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}-`));
56040
56223
  try {
56041
56224
  for (const [name, entry] of Object.entries(zip.files)) {
56042
- const dest = import_node_path36.default.join(stage, name);
56225
+ const dest = import_node_path37.default.join(stage, name);
56043
56226
  if (entry.dir) {
56044
56227
  await import_promises5.default.mkdir(dest, { recursive: true });
56045
56228
  continue;
56046
56229
  }
56047
- 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 });
56048
56231
  const content = await entry.async("nodebuffer");
56049
56232
  await import_promises5.default.writeFile(dest, content);
56050
56233
  }
@@ -56074,7 +56257,7 @@ var SHARE_UI_ASSET_MIME = {
56074
56257
  ".wasm": "application/wasm"
56075
56258
  };
56076
56259
  function shareUiAssetMime(filePath) {
56077
- const ext = import_node_path37.default.extname(filePath).toLowerCase();
56260
+ const ext = import_node_path38.default.extname(filePath).toLowerCase();
56078
56261
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
56079
56262
  }
56080
56263
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -56173,7 +56356,7 @@ function isValidUploadFileName(fileName) {
56173
56356
  if (fileName === "." || fileName === "..") return false;
56174
56357
  if (fileName.startsWith(".")) return false;
56175
56358
  if (fileName.includes("/") || fileName.includes("\\")) return false;
56176
- return fileName === import_node_path37.default.basename(fileName);
56359
+ return fileName === import_node_path38.default.basename(fileName);
56177
56360
  }
56178
56361
  function createHttpRouter(deps) {
56179
56362
  return async (req, res) => {
@@ -56261,7 +56444,7 @@ function createHttpRouter(deps) {
56261
56444
  }
56262
56445
  let buf;
56263
56446
  try {
56264
- buf = await import_node_fs33.default.promises.readFile(abs);
56447
+ buf = await import_node_fs34.default.promises.readFile(abs);
56265
56448
  } catch {
56266
56449
  sendJson(res, 404, { code: "NOT_FOUND", message: "asset not found" });
56267
56450
  return true;
@@ -56409,7 +56592,7 @@ function createHttpRouter(deps) {
56409
56592
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
56410
56593
  return true;
56411
56594
  }
56412
- 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)));
56413
56596
  return true;
56414
56597
  }
56415
56598
  const ctx = deps.authResolver.resolveFromHeader(
@@ -56530,7 +56713,7 @@ function createHttpRouter(deps) {
56530
56713
  return true;
56531
56714
  }
56532
56715
  let absPath;
56533
- if (import_node_path37.default.isAbsolute(pathParam)) {
56716
+ if (import_node_path38.default.isAbsolute(pathParam)) {
56534
56717
  absPath = pathParam;
56535
56718
  } else if (deps.sessionStore) {
56536
56719
  const file = deps.sessionStore.read(sid);
@@ -56538,7 +56721,7 @@ function createHttpRouter(deps) {
56538
56721
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
56539
56722
  return true;
56540
56723
  }
56541
- absPath = import_node_path37.default.join(file.cwd, pathParam);
56724
+ absPath = import_node_path38.default.join(file.cwd, pathParam);
56542
56725
  } else {
56543
56726
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
56544
56727
  return true;
@@ -56625,7 +56808,7 @@ function withCtx(ctx, body) {
56625
56808
  function streamFile(res, absPath, logger) {
56626
56809
  let stat;
56627
56810
  try {
56628
- stat = import_node_fs33.default.statSync(absPath);
56811
+ stat = import_node_fs34.default.statSync(absPath);
56629
56812
  } catch (err) {
56630
56813
  const code = err?.code;
56631
56814
  if (code === "ENOENT") {
@@ -56640,7 +56823,7 @@ function streamFile(res, absPath, logger) {
56640
56823
  return;
56641
56824
  }
56642
56825
  const mime = lookupMime(absPath);
56643
- const basename = import_node_path37.default.basename(absPath);
56826
+ const basename = import_node_path38.default.basename(absPath);
56644
56827
  res.writeHead(200, {
56645
56828
  "Content-Type": mime,
56646
56829
  "Content-Length": String(stat.size),
@@ -56648,7 +56831,7 @@ function streamFile(res, absPath, logger) {
56648
56831
  // 防止浏览器把任意 mime 当 html 渲染
56649
56832
  "X-Content-Type-Options": "nosniff"
56650
56833
  });
56651
- const stream = import_node_fs33.default.createReadStream(absPath);
56834
+ const stream = import_node_fs34.default.createReadStream(absPath);
56652
56835
  stream.on("error", (err) => {
56653
56836
  logger?.warn("streamFile read error", { absPath, err: err.message });
56654
56837
  res.destroy();
@@ -56657,8 +56840,8 @@ function streamFile(res, absPath, logger) {
56657
56840
  }
56658
56841
 
56659
56842
  // src/attachment/gc.ts
56660
- var import_node_fs34 = __toESM(require("fs"), 1);
56661
- 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);
56662
56845
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
56663
56846
  function runAttachmentGc(args) {
56664
56847
  const now = (args.now ?? Date.now)();
@@ -56667,12 +56850,12 @@ function runAttachmentGc(args) {
56667
56850
  for (const { scope, sessionId } of args.sessionScopes) {
56668
56851
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
56669
56852
  if (entry.stale) continue;
56670
- 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);
56671
56854
  }
56672
56855
  }
56673
56856
  const visited = /* @__PURE__ */ new Set();
56674
56857
  for (const { scope, sessionId } of args.sessionScopes) {
56675
- const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path38.default.join(
56858
+ const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path39.default.join(
56676
56859
  args.dataDir,
56677
56860
  "sessions",
56678
56861
  ...scopeSubPath(scope).map(safeFileName),
@@ -56685,28 +56868,28 @@ function runAttachmentGc(args) {
56685
56868
  return true;
56686
56869
  });
56687
56870
  for (const rootDir of roots) {
56688
- const attRoot = import_node_path38.default.join(rootDir, ".attachments");
56871
+ const attRoot = import_node_path39.default.join(rootDir, ".attachments");
56689
56872
  let hashDirs;
56690
56873
  try {
56691
- hashDirs = import_node_fs34.default.readdirSync(attRoot);
56874
+ hashDirs = import_node_fs35.default.readdirSync(attRoot);
56692
56875
  } catch (err) {
56693
56876
  if (err.code === "ENOENT") continue;
56694
56877
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
56695
56878
  continue;
56696
56879
  }
56697
56880
  for (const hashDir of hashDirs) {
56698
- const hashDirAbs = import_node_path38.default.join(attRoot, hashDir);
56881
+ const hashDirAbs = import_node_path39.default.join(attRoot, hashDir);
56699
56882
  let files;
56700
56883
  try {
56701
- files = import_node_fs34.default.readdirSync(hashDirAbs);
56884
+ files = import_node_fs35.default.readdirSync(hashDirAbs);
56702
56885
  } catch {
56703
56886
  continue;
56704
56887
  }
56705
56888
  for (const name of files) {
56706
- const file = import_node_path38.default.join(hashDirAbs, name);
56889
+ const file = import_node_path39.default.join(hashDirAbs, name);
56707
56890
  let stat;
56708
56891
  try {
56709
- stat = import_node_fs34.default.statSync(file);
56892
+ stat = import_node_fs35.default.statSync(file);
56710
56893
  } catch {
56711
56894
  continue;
56712
56895
  }
@@ -56715,18 +56898,18 @@ function runAttachmentGc(args) {
56715
56898
  if (age < ttlMs) continue;
56716
56899
  if (liveAbs.has(file)) continue;
56717
56900
  try {
56718
- import_node_fs34.default.unlinkSync(file);
56901
+ import_node_fs35.default.unlinkSync(file);
56719
56902
  } catch (err) {
56720
56903
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
56721
56904
  }
56722
56905
  }
56723
56906
  try {
56724
- 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);
56725
56908
  } catch {
56726
56909
  }
56727
56910
  }
56728
56911
  try {
56729
- 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);
56730
56913
  } catch {
56731
56914
  }
56732
56915
  }
@@ -56734,8 +56917,8 @@ function runAttachmentGc(args) {
56734
56917
  }
56735
56918
 
56736
56919
  // src/attachment/group.ts
56737
- var import_node_fs35 = __toESM(require("fs"), 1);
56738
- 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);
56739
56922
  var import_node_crypto10 = __toESM(require("crypto"), 1);
56740
56923
  init_protocol();
56741
56924
  var GroupFileStore = class {
@@ -56747,11 +56930,11 @@ var GroupFileStore = class {
56747
56930
  this.logger = opts.logger;
56748
56931
  }
56749
56932
  rootForScope(scope) {
56750
- 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));
56751
56934
  }
56752
56935
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
56753
56936
  filePath(scope, sessionId) {
56754
- 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`);
56755
56938
  }
56756
56939
  cacheKey(scope, sessionId) {
56757
56940
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -56760,7 +56943,7 @@ var GroupFileStore = class {
56760
56943
  readFile(scope, sessionId) {
56761
56944
  const file = this.filePath(scope, sessionId);
56762
56945
  try {
56763
- const raw = import_node_fs35.default.readFileSync(file, "utf8");
56946
+ const raw = import_node_fs36.default.readFileSync(file, "utf8");
56764
56947
  const parsed = JSON.parse(raw);
56765
56948
  if (!Array.isArray(parsed)) {
56766
56949
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -56786,10 +56969,10 @@ var GroupFileStore = class {
56786
56969
  }
56787
56970
  writeFile(scope, sessionId, entries) {
56788
56971
  const file = this.filePath(scope, sessionId);
56789
- 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 });
56790
56973
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
56791
- import_node_fs35.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
56792
- 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);
56793
56976
  }
56794
56977
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
56795
56978
  list(scope, sessionId) {
@@ -56875,10 +57058,10 @@ var GroupFileStore = class {
56875
57058
  };
56876
57059
 
56877
57060
  // src/discovery/state-file.ts
56878
- var import_node_fs36 = __toESM(require("fs"), 1);
56879
- 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);
56880
57063
  function defaultStateFilePath(dataDir) {
56881
- return import_node_path40.default.join(dataDir, "state.json");
57064
+ return import_node_path41.default.join(dataDir, "state.json");
56882
57065
  }
56883
57066
  function isPidAlive(pid) {
56884
57067
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -56900,7 +57083,7 @@ var StateFileManager = class {
56900
57083
  }
56901
57084
  read() {
56902
57085
  try {
56903
- const raw = import_node_fs36.default.readFileSync(this.file, "utf8");
57086
+ const raw = import_node_fs37.default.readFileSync(this.file, "utf8");
56904
57087
  const parsed = JSON.parse(raw);
56905
57088
  return parsed;
56906
57089
  } catch {
@@ -56914,20 +57097,20 @@ var StateFileManager = class {
56914
57097
  return { status: "stale", existing };
56915
57098
  }
56916
57099
  write(state) {
56917
- 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 });
56918
57101
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
56919
- import_node_fs36.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
56920
- 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);
56921
57104
  if (process.platform !== "win32") {
56922
57105
  try {
56923
- import_node_fs36.default.chmodSync(this.file, 384);
57106
+ import_node_fs37.default.chmodSync(this.file, 384);
56924
57107
  } catch {
56925
57108
  }
56926
57109
  }
56927
57110
  }
56928
57111
  delete() {
56929
57112
  try {
56930
- import_node_fs36.default.unlinkSync(this.file);
57113
+ import_node_fs37.default.unlinkSync(this.file);
56931
57114
  } catch {
56932
57115
  }
56933
57116
  }
@@ -56941,14 +57124,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
56941
57124
  }
56942
57125
 
56943
57126
  // src/tunnel/tunnel-manager.ts
56944
- var import_node_fs40 = __toESM(require("fs"), 1);
56945
- 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);
56946
57129
  var import_node_crypto11 = __toESM(require("crypto"), 1);
56947
- var import_node_child_process10 = require("child_process");
57130
+ var import_node_child_process11 = require("child_process");
56948
57131
 
56949
57132
  // src/tunnel/tunnel-store.ts
56950
- var import_node_fs37 = __toESM(require("fs"), 1);
56951
- 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);
56952
57135
  var TunnelStore = class {
56953
57136
  constructor(filePath) {
56954
57137
  this.filePath = filePath;
@@ -56956,7 +57139,7 @@ var TunnelStore = class {
56956
57139
  filePath;
56957
57140
  async get() {
56958
57141
  try {
56959
- 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");
56960
57143
  const obj = JSON.parse(raw);
56961
57144
  if (!isPersistedTunnel(obj)) return null;
56962
57145
  return obj;
@@ -56967,22 +57150,22 @@ var TunnelStore = class {
56967
57150
  }
56968
57151
  }
56969
57152
  async set(v2) {
56970
- const dir = import_node_path41.default.dirname(this.filePath);
56971
- 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 });
56972
57155
  const data = JSON.stringify(v2, null, 2);
56973
57156
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
56974
- await import_node_fs37.default.promises.writeFile(tmp, data, { mode: 384 });
57157
+ await import_node_fs38.default.promises.writeFile(tmp, data, { mode: 384 });
56975
57158
  if (process.platform !== "win32") {
56976
57159
  try {
56977
- await import_node_fs37.default.promises.chmod(tmp, 384);
57160
+ await import_node_fs38.default.promises.chmod(tmp, 384);
56978
57161
  } catch {
56979
57162
  }
56980
57163
  }
56981
- await import_node_fs37.default.promises.rename(tmp, this.filePath);
57164
+ await import_node_fs38.default.promises.rename(tmp, this.filePath);
56982
57165
  }
56983
57166
  async clear() {
56984
57167
  try {
56985
- await import_node_fs37.default.promises.unlink(this.filePath);
57168
+ await import_node_fs38.default.promises.unlink(this.filePath);
56986
57169
  } catch (err) {
56987
57170
  const code = err?.code;
56988
57171
  if (code !== "ENOENT") throw err;
@@ -57077,10 +57260,10 @@ function escape(v2) {
57077
57260
  }
57078
57261
 
57079
57262
  // src/tunnel/frpc-binary.ts
57080
- var import_node_fs38 = __toESM(require("fs"), 1);
57081
- var import_node_os13 = __toESM(require("os"), 1);
57082
- var import_node_path42 = __toESM(require("path"), 1);
57083
- 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");
57084
57267
  var import_node_stream3 = require("stream");
57085
57268
  var import_promises6 = require("stream/promises");
57086
57269
  var FRPC_VERSION = "0.68.0";
@@ -57111,20 +57294,20 @@ function frpcDownloadUrl(version2, p2) {
57111
57294
  }
57112
57295
  async function ensureFrpcBinary(opts) {
57113
57296
  if (opts.override) {
57114
- if (!import_node_fs38.default.existsSync(opts.override)) {
57297
+ if (!import_node_fs39.default.existsSync(opts.override)) {
57115
57298
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
57116
57299
  }
57117
57300
  return opts.override;
57118
57301
  }
57119
57302
  const version2 = opts.version ?? FRPC_VERSION;
57120
57303
  const platform = opts.platform ?? detectPlatform();
57121
- const binDir = import_node_path42.default.join(opts.dataDir, "bin");
57122
- 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 });
57123
57306
  cleanupStaleArtifacts(binDir);
57124
- const stableBin = import_node_path42.default.join(binDir, "frpc");
57125
- 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;
57126
57309
  const partialBin = `${stableBin}.partial`;
57127
- 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`);
57128
57311
  try {
57129
57312
  const url = frpcDownloadUrl(version2, platform);
57130
57313
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -57133,8 +57316,8 @@ async function ensureFrpcBinary(opts) {
57133
57316
  } else {
57134
57317
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
57135
57318
  }
57136
- import_node_fs38.default.chmodSync(partialBin, 493);
57137
- import_node_fs38.default.renameSync(partialBin, stableBin);
57319
+ import_node_fs39.default.chmodSync(partialBin, 493);
57320
+ import_node_fs39.default.renameSync(partialBin, stableBin);
57138
57321
  } finally {
57139
57322
  safeUnlink(tarballPath);
57140
57323
  safeUnlink(partialBin);
@@ -57144,15 +57327,15 @@ async function ensureFrpcBinary(opts) {
57144
57327
  function cleanupStaleArtifacts(binDir) {
57145
57328
  let entries;
57146
57329
  try {
57147
- entries = import_node_fs38.default.readdirSync(binDir);
57330
+ entries = import_node_fs39.default.readdirSync(binDir);
57148
57331
  } catch {
57149
57332
  return;
57150
57333
  }
57151
57334
  for (const name of entries) {
57152
57335
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
57153
- const full = import_node_path42.default.join(binDir, name);
57336
+ const full = import_node_path43.default.join(binDir, name);
57154
57337
  try {
57155
- import_node_fs38.default.rmSync(full, { recursive: true, force: true });
57338
+ import_node_fs39.default.rmSync(full, { recursive: true, force: true });
57156
57339
  } catch {
57157
57340
  }
57158
57341
  }
@@ -57160,7 +57343,7 @@ function cleanupStaleArtifacts(binDir) {
57160
57343
  }
57161
57344
  function safeUnlink(p2) {
57162
57345
  try {
57163
- import_node_fs38.default.unlinkSync(p2);
57346
+ import_node_fs39.default.unlinkSync(p2);
57164
57347
  } catch {
57165
57348
  }
57166
57349
  }
@@ -57171,46 +57354,46 @@ async function downloadToFile(url, dest, fetchImpl) {
57171
57354
  if (!res.ok || !res.body) {
57172
57355
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
57173
57356
  }
57174
- const out = import_node_fs38.default.createWriteStream(dest);
57357
+ const out = import_node_fs39.default.createWriteStream(dest);
57175
57358
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
57176
57359
  await (0, import_promises6.pipeline)(nodeStream, out);
57177
57360
  }
57178
57361
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
57179
- const work = import_node_path42.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
57180
- 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 });
57181
57364
  try {
57182
57365
  await new Promise((resolve6, reject) => {
57183
- 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" });
57184
57367
  proc.on("error", reject);
57185
57368
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
57186
57369
  });
57187
57370
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
57188
- const src = import_node_path42.default.join(work, dirName, "frpc");
57189
- 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)) {
57190
57373
  throw new Error(`frpc not found inside tarball at ${src}`);
57191
57374
  }
57192
- import_node_fs38.default.copyFileSync(src, destBin);
57375
+ import_node_fs39.default.copyFileSync(src, destBin);
57193
57376
  } finally {
57194
- import_node_fs38.default.rmSync(work, { recursive: true, force: true });
57377
+ import_node_fs39.default.rmSync(work, { recursive: true, force: true });
57195
57378
  }
57196
57379
  }
57197
57380
 
57198
57381
  // src/tunnel/frpc-process.ts
57199
- var import_node_fs39 = __toESM(require("fs"), 1);
57200
- var import_node_path43 = __toESM(require("path"), 1);
57201
- 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");
57202
57385
  function frpcPidFilePath(dataDir) {
57203
- return import_node_path43.default.join(dataDir, "frpc.pid");
57386
+ return import_node_path44.default.join(dataDir, "frpc.pid");
57204
57387
  }
57205
57388
  function writeFrpcPid(dataDir, pid) {
57206
57389
  try {
57207
- import_node_fs39.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
57390
+ import_node_fs40.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
57208
57391
  } catch {
57209
57392
  }
57210
57393
  }
57211
57394
  function clearFrpcPid(dataDir) {
57212
57395
  try {
57213
- import_node_fs39.default.unlinkSync(frpcPidFilePath(dataDir));
57396
+ import_node_fs40.default.unlinkSync(frpcPidFilePath(dataDir));
57214
57397
  } catch {
57215
57398
  }
57216
57399
  }
@@ -57226,7 +57409,7 @@ function defaultIsPidAlive(pid) {
57226
57409
  }
57227
57410
  function defaultReadPidFile(file) {
57228
57411
  try {
57229
- return import_node_fs39.default.readFileSync(file, "utf8");
57412
+ return import_node_fs40.default.readFileSync(file, "utf8");
57230
57413
  } catch {
57231
57414
  return null;
57232
57415
  }
@@ -57242,7 +57425,7 @@ function defaultSleep2(ms) {
57242
57425
  }
57243
57426
  async function killStaleFrpc(deps) {
57244
57427
  const pidFile = frpcPidFilePath(deps.dataDir);
57245
- const tomlPath = import_node_path43.default.join(deps.dataDir, "frpc.toml");
57428
+ const tomlPath = import_node_path44.default.join(deps.dataDir, "frpc.toml");
57246
57429
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
57247
57430
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
57248
57431
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -57266,7 +57449,7 @@ async function killStaleFrpc(deps) {
57266
57449
  }
57267
57450
  if (victims.size === 0) {
57268
57451
  try {
57269
- import_node_fs39.default.unlinkSync(pidFile);
57452
+ import_node_fs40.default.unlinkSync(pidFile);
57270
57453
  } catch {
57271
57454
  }
57272
57455
  return;
@@ -57277,14 +57460,14 @@ async function killStaleFrpc(deps) {
57277
57460
  }
57278
57461
  await sleep2(deps.reapWaitMs ?? 300);
57279
57462
  try {
57280
- import_node_fs39.default.unlinkSync(pidFile);
57463
+ import_node_fs40.default.unlinkSync(pidFile);
57281
57464
  } catch {
57282
57465
  }
57283
57466
  }
57284
57467
  async function defaultScanFrpcPidsByCmdline(tomlPath, logger) {
57285
57468
  if (process.platform === "win32") return [];
57286
57469
  return new Promise((resolve6) => {
57287
- 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"] });
57288
57471
  let buf = "";
57289
57472
  ps.stdout.on("data", (c) => {
57290
57473
  buf += c.toString();
@@ -57314,7 +57497,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
57314
57497
  var TunnelManager = class {
57315
57498
  constructor(deps) {
57316
57499
  this.deps = deps;
57317
- 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"));
57318
57501
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
57319
57502
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
57320
57503
  }
@@ -57441,7 +57624,7 @@ var TunnelManager = class {
57441
57624
  dataDir: this.deps.dataDir,
57442
57625
  override: this.deps.frpcBinaryOverride ?? void 0
57443
57626
  });
57444
- 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");
57445
57628
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto11.default.randomBytes(3).toString("hex")}`;
57446
57629
  const toml = buildFrpcToml({
57447
57630
  serverAddr: t.frpsHost,
@@ -57452,14 +57635,14 @@ var TunnelManager = class {
57452
57635
  localPort,
57453
57636
  logLevel: "info"
57454
57637
  });
57455
- await import_node_fs40.default.promises.writeFile(tomlPath, toml, { mode: 384 });
57456
- 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], {
57457
57640
  stdio: ["ignore", "pipe", "pipe"]
57458
57641
  });
57459
- const logDir = import_node_path44.default.join(this.deps.dataDir, "log");
57460
- import_node_fs40.default.mkdirSync(logDir, { recursive: true });
57461
- const logFilePath = import_node_path44.default.join(logDir, "frpc.log");
57462
- 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 });
57463
57646
  logStream.on("error", () => {
57464
57647
  });
57465
57648
  const tee = (chunk) => {
@@ -57541,28 +57724,28 @@ async function waitForFrpcReady(proc, timeoutMs) {
57541
57724
  }
57542
57725
 
57543
57726
  // src/tunnel/device-key.ts
57544
- var import_node_os14 = __toESM(require("os"), 1);
57545
- 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);
57546
57729
  var import_node_crypto12 = __toESM(require("crypto"), 1);
57547
57730
  var DERIVE_SALT = "clawd-tunnel-device-v1";
57548
57731
  function deriveStableDeviceKey(opts = {}) {
57549
- const hostname = opts.hostname ?? import_node_os14.default.hostname();
57550
- const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
57551
- const home = opts.home ?? import_node_os14.default.homedir();
57552
- const defaultDataDir = import_node_path45.default.resolve(import_node_path45.default.join(home, ".clawd"));
57553
- 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;
57554
57737
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
57555
57738
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
57556
57739
  return import_node_crypto12.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
57557
57740
  }
57558
57741
 
57559
57742
  // src/auth-store.ts
57560
- var import_node_fs41 = __toESM(require("fs"), 1);
57561
- 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);
57562
57745
  var import_node_crypto13 = __toESM(require("crypto"), 1);
57563
57746
  var AUTH_FILE_NAME = "auth.json";
57564
57747
  function authFilePath(dataDir) {
57565
- return import_node_path46.default.join(dataDir, AUTH_FILE_NAME);
57748
+ return import_node_path47.default.join(dataDir, AUTH_FILE_NAME);
57566
57749
  }
57567
57750
  function loadOrCreateAuthFile(opts) {
57568
57751
  const file = authFilePath(opts.dataDir);
@@ -57594,7 +57777,7 @@ function defaultGenerateOwnerPrincipalId() {
57594
57777
  }
57595
57778
  function readAuthFile(file) {
57596
57779
  try {
57597
- const raw = import_node_fs41.default.readFileSync(file, "utf8");
57780
+ const raw = import_node_fs42.default.readFileSync(file, "utf8");
57598
57781
  const parsed = JSON.parse(raw);
57599
57782
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
57600
57783
  return null;
@@ -57614,26 +57797,26 @@ function readAuthFile(file) {
57614
57797
  }
57615
57798
  }
57616
57799
  function writeAuthFile(file, content) {
57617
- import_node_fs41.default.mkdirSync(import_node_path46.default.dirname(file), { recursive: true });
57618
- 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 });
57619
57802
  try {
57620
- import_node_fs41.default.chmodSync(file, 384);
57803
+ import_node_fs42.default.chmodSync(file, 384);
57621
57804
  } catch {
57622
57805
  }
57623
57806
  }
57624
57807
 
57625
57808
  // src/owner-profile.ts
57626
- var import_node_fs42 = __toESM(require("fs"), 1);
57627
- var import_node_os15 = __toESM(require("os"), 1);
57628
- 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);
57629
57812
  var PROFILE_FILENAME = "profile.json";
57630
57813
  function profilePath(dataDir) {
57631
- return import_node_path47.default.join(dataDir, PROFILE_FILENAME);
57814
+ return import_node_path48.default.join(dataDir, PROFILE_FILENAME);
57632
57815
  }
57633
57816
  function loadOwnerProfile(dataDir) {
57634
57817
  let raw;
57635
57818
  try {
57636
- raw = import_node_fs42.default.readFileSync(profilePath(dataDir), "utf8");
57819
+ raw = import_node_fs43.default.readFileSync(profilePath(dataDir), "utf8");
57637
57820
  } catch {
57638
57821
  return {};
57639
57822
  }
@@ -57649,11 +57832,11 @@ function loadOwnerProfile(dataDir) {
57649
57832
  }
57650
57833
  function patchOwnerProfile(dataDir, patch) {
57651
57834
  const merged = { ...loadOwnerProfile(dataDir), ...patch };
57652
- 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 });
57653
57836
  return merged;
57654
57837
  }
57655
57838
  function loadOwnerDisplayName(dataDir) {
57656
- const fallback = import_node_os15.default.userInfo().username;
57839
+ const fallback = import_node_os16.default.userInfo().username;
57657
57840
  const displayName = loadOwnerProfile(dataDir).displayName;
57658
57841
  if (typeof displayName !== "string" || displayName.length === 0) {
57659
57842
  if (displayName !== void 0) {
@@ -57665,18 +57848,18 @@ function loadOwnerDisplayName(dataDir) {
57665
57848
  }
57666
57849
 
57667
57850
  // src/feishu-auth/owner-identity-store.ts
57668
- var import_node_fs43 = __toESM(require("fs"), 1);
57669
- 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);
57670
57853
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
57671
57854
  var OwnerIdentityStore = class {
57672
57855
  file;
57673
57856
  constructor(dataDir) {
57674
- 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);
57675
57858
  }
57676
57859
  read() {
57677
57860
  let raw;
57678
57861
  try {
57679
- raw = import_node_fs43.default.readFileSync(this.file, "utf8");
57862
+ raw = import_node_fs44.default.readFileSync(this.file, "utf8");
57680
57863
  } catch {
57681
57864
  return null;
57682
57865
  }
@@ -57704,16 +57887,16 @@ var OwnerIdentityStore = class {
57704
57887
  };
57705
57888
  }
57706
57889
  write(record) {
57707
- import_node_fs43.default.mkdirSync(import_node_path48.default.dirname(this.file), { recursive: true });
57708
- 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 });
57709
57892
  try {
57710
- import_node_fs43.default.chmodSync(this.file, 384);
57893
+ import_node_fs44.default.chmodSync(this.file, 384);
57711
57894
  } catch {
57712
57895
  }
57713
57896
  }
57714
57897
  clear() {
57715
57898
  try {
57716
- import_node_fs43.default.unlinkSync(this.file);
57899
+ import_node_fs44.default.unlinkSync(this.file);
57717
57900
  } catch (err) {
57718
57901
  const code = err?.code;
57719
57902
  if (code !== "ENOENT") throw err;
@@ -57850,9 +58033,9 @@ var CentralClientError = class extends Error {
57850
58033
  code;
57851
58034
  cause;
57852
58035
  };
57853
- async function centralRequest(opts, path81, init) {
58036
+ async function centralRequest(opts, path82, init) {
57854
58037
  const f = opts.fetchImpl ?? globalThis.fetch;
57855
- const url = `${opts.api.replace(/\/+$/, "")}${path81}`;
58038
+ const url = `${opts.api.replace(/\/+$/, "")}${path82}`;
57856
58039
  const ctrl = new AbortController();
57857
58040
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
57858
58041
  let res;
@@ -58046,8 +58229,8 @@ function verifyConnectToken(args) {
58046
58229
  }
58047
58230
 
58048
58231
  // src/feishu-auth/server-key.ts
58049
- var fs54 = __toESM(require("fs"), 1);
58050
- var path57 = __toESM(require("path"), 1);
58232
+ var fs55 = __toESM(require("fs"), 1);
58233
+ var path58 = __toESM(require("path"), 1);
58051
58234
  var FILE_NAME2 = "server-signing-key.json";
58052
58235
  var ServerKeyStore = class {
58053
58236
  constructor(dataDir) {
@@ -58055,12 +58238,12 @@ var ServerKeyStore = class {
58055
58238
  }
58056
58239
  dataDir;
58057
58240
  filePath() {
58058
- return path57.join(this.dataDir, FILE_NAME2);
58241
+ return path58.join(this.dataDir, FILE_NAME2);
58059
58242
  }
58060
58243
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
58061
58244
  read() {
58062
58245
  try {
58063
- const raw = fs54.readFileSync(this.filePath(), "utf8");
58246
+ const raw = fs55.readFileSync(this.filePath(), "utf8");
58064
58247
  const parsed = JSON.parse(raw);
58065
58248
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
58066
58249
  return parsed.publicKeyPem;
@@ -58075,12 +58258,12 @@ var ServerKeyStore = class {
58075
58258
  publicKeyPem,
58076
58259
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
58077
58260
  };
58078
- fs54.mkdirSync(this.dataDir, { recursive: true });
58079
- 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 });
58080
58263
  }
58081
58264
  clear() {
58082
58265
  try {
58083
- fs54.unlinkSync(this.filePath());
58266
+ fs55.unlinkSync(this.filePath());
58084
58267
  } catch {
58085
58268
  }
58086
58269
  }
@@ -58093,12 +58276,12 @@ init_protocol();
58093
58276
  init_protocol();
58094
58277
 
58095
58278
  // src/session/fork.ts
58096
- var import_node_fs44 = __toESM(require("fs"), 1);
58097
- var import_node_os16 = __toESM(require("os"), 1);
58098
- 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);
58099
58282
  init_claude_history();
58100
58283
  function readJsonlEntries(file) {
58101
- const raw = import_node_fs44.default.readFileSync(file, "utf8");
58284
+ const raw = import_node_fs45.default.readFileSync(file, "utf8");
58102
58285
  const out = [];
58103
58286
  for (const line of raw.split("\n")) {
58104
58287
  const t = line.trim();
@@ -58111,19 +58294,19 @@ function readJsonlEntries(file) {
58111
58294
  return out;
58112
58295
  }
58113
58296
  function forkSession(input) {
58114
- const baseDir = input.baseDir ?? import_node_path49.default.join(import_node_os16.default.homedir(), ".claude");
58115
- let projectDir = import_node_path49.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
58116
- let sourceFile = import_node_path49.default.join(projectDir, `${input.toolSessionId}.jsonl`);
58117
- 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)) {
58118
58301
  const found = findTranscriptByToolSessionId(
58119
- import_node_path49.default.join(baseDir, "projects"),
58302
+ import_node_path50.default.join(baseDir, "projects"),
58120
58303
  input.toolSessionId
58121
58304
  );
58122
58305
  if (!found) {
58123
58306
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
58124
58307
  }
58125
58308
  sourceFile = found;
58126
- projectDir = import_node_path49.default.dirname(found);
58309
+ projectDir = import_node_path50.default.dirname(found);
58127
58310
  }
58128
58311
  const entries = readJsonlEntries(sourceFile);
58129
58312
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -58152,27 +58335,27 @@ function forkSession(input) {
58152
58335
  }
58153
58336
  forkedLines.push(JSON.stringify(forked));
58154
58337
  }
58155
- const outDir = input.targetCwd ? import_node_path49.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
58156
- const forkedFilePath = import_node_path49.default.join(outDir, `${forkedToolSessionId}.jsonl`);
58157
- import_node_fs44.default.mkdirSync(outDir, { recursive: true });
58158
- 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 });
58159
58342
  return { forkedToolSessionId, forkedFilePath };
58160
58343
  }
58161
58344
 
58162
58345
  // src/session/external-scan.ts
58163
- var import_node_fs45 = __toESM(require("fs"), 1);
58346
+ var import_node_fs46 = __toESM(require("fs"), 1);
58164
58347
  var import_promises7 = __toESM(require("fs/promises"), 1);
58165
- var import_node_os17 = __toESM(require("os"), 1);
58166
- 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);
58167
58350
  var import_node_module = require("module");
58168
- var import_node_child_process11 = require("child_process");
58351
+ var import_node_child_process12 = require("child_process");
58169
58352
  var import_meta4 = {};
58170
58353
  function defaultRoots() {
58171
- const home = import_node_os17.default.homedir();
58354
+ const home = import_node_os18.default.homedir();
58172
58355
  return {
58173
- claudeProjectsDir: import_node_path50.default.join(home, ".claude", "projects"),
58174
- codexDir: import_node_path50.default.join(home, ".codex"),
58175
- 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")
58176
58359
  };
58177
58360
  }
58178
58361
  function width(s) {
@@ -58200,12 +58383,12 @@ function toMs(v2) {
58200
58383
  function listFiles(dir, depth = 0, maxDepth = 8, out = []) {
58201
58384
  let entries;
58202
58385
  try {
58203
- entries = import_node_fs45.default.readdirSync(dir, { withFileTypes: true });
58386
+ entries = import_node_fs46.default.readdirSync(dir, { withFileTypes: true });
58204
58387
  } catch {
58205
58388
  return out;
58206
58389
  }
58207
58390
  for (const e of entries) {
58208
- const full = import_node_path50.default.join(dir, e.name);
58391
+ const full = import_node_path51.default.join(dir, e.name);
58209
58392
  if (e.isDirectory()) {
58210
58393
  if (depth < maxDepth) listFiles(full, depth + 1, maxDepth, out);
58211
58394
  } else if (e.isFile()) {
@@ -58240,7 +58423,7 @@ function userText(msg) {
58240
58423
  }
58241
58424
  function isDir2(p2) {
58242
58425
  try {
58243
- return import_node_fs45.default.statSync(p2).isDirectory();
58426
+ return import_node_fs46.default.statSync(p2).isDirectory();
58244
58427
  } catch {
58245
58428
  return false;
58246
58429
  }
@@ -58249,7 +58432,7 @@ async function scanClaude(roots) {
58249
58432
  const out = [];
58250
58433
  let dirs;
58251
58434
  try {
58252
- dirs = import_node_fs45.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
58435
+ dirs = import_node_fs46.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
58253
58436
  } catch {
58254
58437
  return out;
58255
58438
  }
@@ -58257,16 +58440,16 @@ async function scanClaude(roots) {
58257
58440
  if (!d.isDirectory()) continue;
58258
58441
  let files;
58259
58442
  try {
58260
- 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));
58261
58444
  } catch {
58262
58445
  continue;
58263
58446
  }
58264
58447
  for (const name of files) {
58265
58448
  if (!name.endsWith(".jsonl")) continue;
58266
- 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);
58267
58450
  let st;
58268
58451
  try {
58269
- st = import_node_fs45.default.statSync(file);
58452
+ st = import_node_fs46.default.statSync(file);
58270
58453
  } catch {
58271
58454
  continue;
58272
58455
  }
@@ -58310,13 +58493,14 @@ async function scanClaude(roots) {
58310
58493
  };
58311
58494
  if (!hasMainLine) cand.skip = "subagent \u652F\u7EBF";
58312
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";
58313
58497
  out.push(cand);
58314
58498
  }
58315
58499
  }
58316
58500
  return out;
58317
58501
  }
58318
58502
  async function countCodexTurns(rolloutPath) {
58319
- 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: "" };
58320
58504
  let turns = 0;
58321
58505
  let first = "";
58322
58506
  for await (const rec4 of jsonLines(rolloutPath)) {
@@ -58347,14 +58531,14 @@ function readCodexThreads(db) {
58347
58531
  } catch {
58348
58532
  }
58349
58533
  try {
58350
- 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" });
58351
58535
  if (info.status !== 0) return null;
58352
58536
  const have = new Set(
58353
58537
  info.stdout.split("\n").map((l) => l.split("|")[1]).filter(Boolean)
58354
58538
  );
58355
58539
  if (!["id", "cwd", "updated_at"].every((c) => have.has(c))) return null;
58356
58540
  const sel = COLS.map((c) => have.has(c) ? c : `NULL AS ${c}`).join(", ");
58357
- 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;`], {
58358
58542
  encoding: "utf8",
58359
58543
  maxBuffer: 64 * 1024 * 1024
58360
58544
  });
@@ -58388,11 +58572,11 @@ async function codexFromRows(rows) {
58388
58572
  }
58389
58573
  async function scanCodexRollouts(roots) {
58390
58574
  const out = [];
58391
- 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"))) {
58392
58576
  if (!file.endsWith(".jsonl")) continue;
58393
58577
  let st;
58394
58578
  try {
58395
- st = import_node_fs45.default.statSync(file);
58579
+ st = import_node_fs46.default.statSync(file);
58396
58580
  } catch {
58397
58581
  continue;
58398
58582
  }
@@ -58424,7 +58608,7 @@ async function scanCodexRollouts(roots) {
58424
58608
  async function scanCodex(roots) {
58425
58609
  let dbs = [];
58426
58610
  try {
58427
- 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));
58428
58612
  } catch {
58429
58613
  }
58430
58614
  if (dbs.length) {
@@ -58435,14 +58619,14 @@ async function scanCodex(roots) {
58435
58619
  }
58436
58620
  async function scanExternalSessions(rootsIn) {
58437
58621
  const roots = { ...defaultRoots(), ...rootsIn };
58438
- const personaRoot = import_node_path50.default.join(roots.clawdDir, "personas");
58622
+ const personaRoot = import_node_path51.default.join(roots.clawdDir, "personas");
58439
58623
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
58440
58624
  const out = [];
58441
58625
  for (const c of all) {
58442
58626
  if (c.skip) continue;
58443
58627
  if (c.turns < 1) continue;
58444
58628
  if (!c.cwd || !isDir2(c.cwd)) continue;
58445
- 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)) {
58446
58630
  continue;
58447
58631
  }
58448
58632
  out.push({
@@ -58459,19 +58643,19 @@ async function scanExternalSessions(rootsIn) {
58459
58643
  }
58460
58644
 
58461
58645
  // src/session/import-ledger.ts
58462
- var import_node_fs46 = __toESM(require("fs"), 1);
58463
- 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);
58464
58648
  var LEDGER_FILENAME = "session-import-ledger.json";
58465
58649
  function appendImportLedger(dataDir, entry) {
58466
- const file = import_node_path51.default.join(dataDir, LEDGER_FILENAME);
58650
+ const file = import_node_path52.default.join(dataDir, LEDGER_FILENAME);
58467
58651
  let entries = [];
58468
58652
  try {
58469
- const parsed = JSON.parse(import_node_fs46.default.readFileSync(file, "utf8"));
58653
+ const parsed = JSON.parse(import_node_fs47.default.readFileSync(file, "utf8"));
58470
58654
  if (Array.isArray(parsed)) entries = parsed;
58471
58655
  } catch {
58472
58656
  }
58473
58657
  entries.push(entry);
58474
- 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 });
58475
58659
  }
58476
58660
 
58477
58661
  // src/handlers/session.ts
@@ -58964,7 +59148,7 @@ function buildPermissionHandlers(deps) {
58964
59148
  }
58965
59149
 
58966
59150
  // src/handlers/history.ts
58967
- var path62 = __toESM(require("path"), 1);
59151
+ var path63 = __toESM(require("path"), 1);
58968
59152
  init_protocol();
58969
59153
 
58970
59154
  // src/session/recent-dirs.ts
@@ -58982,7 +59166,7 @@ function listRecentDirs(store, limit = 50) {
58982
59166
  }
58983
59167
 
58984
59168
  // src/permission/persona-paths.ts
58985
- var path61 = __toESM(require("path"), 1);
59169
+ var path62 = __toESM(require("path"), 1);
58986
59170
  function getAllowedPersonaIds(grants, action) {
58987
59171
  const ids = /* @__PURE__ */ new Set();
58988
59172
  for (const g2 of grants) {
@@ -58995,42 +59179,42 @@ function getAllowedPersonaIds(grants, action) {
58995
59179
  return ids;
58996
59180
  }
58997
59181
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
58998
- const target = path61.resolve(absPath);
59182
+ const target = path62.resolve(absPath);
58999
59183
  if (userWorkDir) {
59000
- const u = path61.resolve(userWorkDir);
59001
- const usep = u.endsWith(path61.sep) ? "" : path61.sep;
59184
+ const u = path62.resolve(userWorkDir);
59185
+ const usep = u.endsWith(path62.sep) ? "" : path62.sep;
59002
59186
  if (target === u || target.startsWith(u + usep)) return true;
59003
59187
  }
59004
- const root = path61.resolve(personaRoot);
59005
- const sep3 = root.endsWith(path61.sep) ? "" : path61.sep;
59188
+ const root = path62.resolve(personaRoot);
59189
+ const sep3 = root.endsWith(path62.sep) ? "" : path62.sep;
59006
59190
  if (!target.startsWith(root + sep3)) return false;
59007
- const rel = path61.relative(root, target);
59191
+ const rel = path62.relative(root, target);
59008
59192
  if (!rel || rel.startsWith("..")) return false;
59009
- const personaId2 = rel.split(path61.sep)[0];
59193
+ const personaId2 = rel.split(path62.sep)[0];
59010
59194
  if (!personaId2) return false;
59011
59195
  const allowed = getAllowedPersonaIds(grants, action);
59012
59196
  if (allowed === "*") return true;
59013
59197
  return allowed.has(personaId2);
59014
59198
  }
59015
59199
  function personaIdFromPath(absPath, personaRoot) {
59016
- const root = path61.resolve(personaRoot);
59017
- const target = path61.resolve(absPath);
59018
- 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;
59019
59203
  if (!target.startsWith(root + sep3)) return null;
59020
- const rel = path61.relative(root, target);
59204
+ const rel = path62.relative(root, target);
59021
59205
  if (!rel || rel.startsWith("..")) return null;
59022
- const id = rel.split(path61.sep)[0];
59206
+ const id = rel.split(path62.sep)[0];
59023
59207
  return id || null;
59024
59208
  }
59025
59209
  function isPathWithin(dir, absPath) {
59026
- const d = path61.resolve(dir);
59027
- const t = path61.resolve(absPath);
59028
- 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;
59029
59213
  return t === d || t.startsWith(d + sep3);
59030
59214
  }
59031
59215
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
59032
59216
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
59033
- return personaIdFromPath(path61.resolve(absPath), personaRoot) === personaId2;
59217
+ return personaIdFromPath(path62.resolve(absPath), personaRoot) === personaId2;
59034
59218
  }
59035
59219
 
59036
59220
  // src/handlers/history.ts
@@ -59083,7 +59267,7 @@ function buildHistoryHandlers(deps) {
59083
59267
  if (!pid) return false;
59084
59268
  return isGuestPathAllowed(
59085
59269
  ctx.grants,
59086
- path62.join(personaRoot, pid),
59270
+ path63.join(personaRoot, pid),
59087
59271
  personaRoot,
59088
59272
  "read",
59089
59273
  userWorkDir
@@ -59095,7 +59279,7 @@ function buildHistoryHandlers(deps) {
59095
59279
  };
59096
59280
  const list = async (frame, _client, ctx) => {
59097
59281
  const args = HistoryListArgs.parse(frame);
59098
- assertGuestPath(ctx, path62.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
59282
+ assertGuestPath(ctx, path63.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
59099
59283
  const sessions = await history.listSessions(args);
59100
59284
  return { response: { type: "history:list", sessions } };
59101
59285
  };
@@ -59139,14 +59323,14 @@ function buildHistoryHandlers(deps) {
59139
59323
  };
59140
59324
  const subagents = async (frame, _client, ctx) => {
59141
59325
  const args = HistorySubagentsArgs.parse(frame);
59142
- assertGuestPath(ctx, path62.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
59326
+ assertGuestPath(ctx, path63.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
59143
59327
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
59144
59328
  const subs = await history.listSubagents(args);
59145
59329
  return { response: { type: "history:subagents", subagents: subs } };
59146
59330
  };
59147
59331
  const subagentRead = async (frame, _client, ctx) => {
59148
59332
  const args = HistorySubagentReadArgs.parse(frame);
59149
- assertGuestPath(ctx, path62.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
59333
+ assertGuestPath(ctx, path63.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
59150
59334
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
59151
59335
  const res = await history.readSubagent(args);
59152
59336
  return { response: { type: "history:subagent-read", ...res } };
@@ -59156,7 +59340,7 @@ function buildHistoryHandlers(deps) {
59156
59340
  if (ctx?.principal.kind === "guest" && personaRoot) {
59157
59341
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
59158
59342
  const filtered = dirs.filter(
59159
- (d) => isGuestPathAllowed(ctx.grants, path62.resolve(d.cwd), personaRoot, "read", userWorkDir)
59343
+ (d) => isGuestPathAllowed(ctx.grants, path63.resolve(d.cwd), personaRoot, "read", userWorkDir)
59160
59344
  );
59161
59345
  return { response: { type: "history:recentDirs", dirs: filtered } };
59162
59346
  }
@@ -59173,8 +59357,8 @@ function buildHistoryHandlers(deps) {
59173
59357
  }
59174
59358
 
59175
59359
  // src/handlers/workspace.ts
59176
- var path63 = __toESM(require("path"), 1);
59177
- var os17 = __toESM(require("os"), 1);
59360
+ var path64 = __toESM(require("path"), 1);
59361
+ var os18 = __toESM(require("os"), 1);
59178
59362
  init_protocol();
59179
59363
  init_protocol();
59180
59364
  function buildEnabledPluginNames(personaManager, personaId2) {
@@ -59214,23 +59398,23 @@ function buildWorkspaceHandlers(deps) {
59214
59398
  const list = async (frame, _client, ctx) => {
59215
59399
  const args = WorkspaceListArgs.parse(frame);
59216
59400
  const isGuest = ctx?.principal.kind === "guest";
59217
- const fallbackCwd = isGuest && personaRoot ? personaRoot : os17.homedir();
59218
- const resolvedCwd = path63.resolve(args.cwd ?? fallbackCwd);
59219
- 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;
59220
59404
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
59221
59405
  const res = workspace.list({ ...args, cwd: resolvedCwd });
59222
59406
  return { response: { type: "workspace:list", ...res } };
59223
59407
  };
59224
59408
  const read = async (frame, _client, ctx) => {
59225
59409
  const args = WorkspaceReadArgs.parse(frame);
59226
- 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);
59227
59411
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
59228
59412
  const res = workspace.read(args);
59229
59413
  return { response: { type: "workspace:read", ...res } };
59230
59414
  };
59231
59415
  const skillsList = async (frame, _client, ctx) => {
59232
59416
  const args = SkillsListArgs.parse(frame);
59233
- const cwdAbs = path63.resolve(args.cwd);
59417
+ const cwdAbs = path64.resolve(args.cwd);
59234
59418
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
59235
59419
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
59236
59420
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -59242,7 +59426,7 @@ function buildWorkspaceHandlers(deps) {
59242
59426
  };
59243
59427
  const agentsList = async (frame, _client, ctx) => {
59244
59428
  const args = AgentsListArgs.parse(frame);
59245
- const cwdAbs = path63.resolve(args.cwd);
59429
+ const cwdAbs = path64.resolve(args.cwd);
59246
59430
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
59247
59431
  if (args.tool === "codex") {
59248
59432
  return { response: { type: "agents:list", agents: [] } };
@@ -59264,20 +59448,20 @@ function buildWorkspaceHandlers(deps) {
59264
59448
  }
59265
59449
 
59266
59450
  // src/handlers/git.ts
59267
- var path65 = __toESM(require("path"), 1);
59451
+ var path66 = __toESM(require("path"), 1);
59268
59452
  init_protocol();
59269
59453
  init_protocol();
59270
59454
 
59271
59455
  // src/workspace/git.ts
59272
- var import_node_child_process12 = require("child_process");
59273
- var import_node_fs47 = __toESM(require("fs"), 1);
59274
- 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);
59275
59459
  var import_node_util = require("util");
59276
- 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);
59277
59461
  function normalizePath(p2) {
59278
- const resolved = import_node_path52.default.resolve(p2);
59462
+ const resolved = import_node_path53.default.resolve(p2);
59279
59463
  try {
59280
- return import_node_fs47.default.realpathSync(resolved);
59464
+ return import_node_fs48.default.realpathSync(resolved);
59281
59465
  } catch {
59282
59466
  return resolved;
59283
59467
  }
@@ -59351,7 +59535,7 @@ async function listGitBranches(cwd) {
59351
59535
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
59352
59536
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
59353
59537
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
59354
- if (!isGuestPathAllowed(ctx.grants, path65.resolve(cwd), personaRoot, "read", userWorkDir)) {
59538
+ if (!isGuestPathAllowed(ctx.grants, path66.resolve(cwd), personaRoot, "read", userWorkDir)) {
59355
59539
  throw new ClawdError(
59356
59540
  ERROR_CODES.UNAUTHORIZED,
59357
59541
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -59984,7 +60168,7 @@ function buildDeviceHandlers(deps) {
59984
60168
  }
59985
60169
 
59986
60170
  // src/handlers/meta.ts
59987
- var import_node_os18 = __toESM(require("os"), 1);
60171
+ var import_node_os19 = __toESM(require("os"), 1);
59988
60172
  init_protocol();
59989
60173
 
59990
60174
  // src/handlers/method-grants.ts
@@ -60244,21 +60428,21 @@ function computeMethodAccess(args) {
60244
60428
  }
60245
60429
 
60246
60430
  // src/version.ts
60247
- var version = "0.2.352".length > 0 ? "0.2.352" : "dev";
60431
+ var version = "0.2.353".length > 0 ? "0.2.353" : "dev";
60248
60432
 
60249
60433
  // src/cli-probe/probe.ts
60250
- var fs59 = __toESM(require("fs"), 1);
60251
- var path66 = __toESM(require("path"), 1);
60434
+ var fs60 = __toESM(require("fs"), 1);
60435
+ var path67 = __toESM(require("path"), 1);
60252
60436
  var PKG_NAME = "@clawos-dev/clawd";
60253
60437
  var BIN_NAME = "clawd";
60254
60438
  var MAX_PARENT_HOPS = 5;
60255
60439
  function probeGlobalCli(pathEnv) {
60256
60440
  if (!pathEnv) return null;
60257
- for (const dir of pathEnv.split(path66.delimiter)) {
60441
+ for (const dir of pathEnv.split(path67.delimiter)) {
60258
60442
  if (!dir) continue;
60259
60443
  let real;
60260
60444
  try {
60261
- real = fs59.realpathSync(path66.join(dir, BIN_NAME));
60445
+ real = fs60.realpathSync(path67.join(dir, BIN_NAME));
60262
60446
  } catch {
60263
60447
  continue;
60264
60448
  }
@@ -60268,15 +60452,15 @@ function probeGlobalCli(pathEnv) {
60268
60452
  return null;
60269
60453
  }
60270
60454
  function readOwnPackageVersion(entryPath) {
60271
- let dir = path66.dirname(entryPath);
60455
+ let dir = path67.dirname(entryPath);
60272
60456
  for (let i = 0; i < MAX_PARENT_HOPS; i++) {
60273
60457
  try {
60274
- const raw = fs59.readFileSync(path66.join(dir, "package.json"), "utf8");
60458
+ const raw = fs60.readFileSync(path67.join(dir, "package.json"), "utf8");
60275
60459
  const pkg = JSON.parse(raw);
60276
60460
  if (pkg.name !== PKG_NAME) return null;
60277
60461
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
60278
60462
  } catch {
60279
- const parent = path66.dirname(dir);
60463
+ const parent = path67.dirname(dir);
60280
60464
  if (parent === dir) return null;
60281
60465
  dir = parent;
60282
60466
  }
@@ -60312,7 +60496,7 @@ function buildReadyFrame(deps, client) {
60312
60496
  return {
60313
60497
  version,
60314
60498
  protocolVersion: PROTOCOL_VERSION,
60315
- hostname: import_node_os18.default.hostname(),
60499
+ hostname: import_node_os19.default.hostname(),
60316
60500
  os: process.platform,
60317
60501
  tools,
60318
60502
  runningSessions: info.runningSessions,
@@ -60439,7 +60623,7 @@ function buildPersonaHandlers(deps) {
60439
60623
  }
60440
60624
 
60441
60625
  // src/handlers/attachment.ts
60442
- var import_node_path53 = __toESM(require("path"), 1);
60626
+ var import_node_path54 = __toESM(require("path"), 1);
60443
60627
  init_protocol();
60444
60628
  init_protocol();
60445
60629
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -60519,12 +60703,12 @@ function buildAttachmentHandlers(deps) {
60519
60703
  `session ${args.sessionId} scope unresolved`
60520
60704
  );
60521
60705
  }
60522
- const cwdAbs = import_node_path53.default.resolve(sessionFile.cwd);
60523
- 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);
60524
60708
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
60525
60709
  const entries = deps.groupFileStore.list(scope, args.sessionId);
60526
60710
  const entry = entries.find((e) => {
60527
- 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);
60528
60712
  return storedAbs === candidateAbs && !e.stale;
60529
60713
  });
60530
60714
  if (!entry) {
@@ -60549,7 +60733,7 @@ function buildAttachmentHandlers(deps) {
60549
60733
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
60550
60734
  const f = deps.sessionStore.read(sessionId);
60551
60735
  if (!f) return;
60552
- 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);
60553
60737
  }
60554
60738
  const groupAdd = async (frame, _client, ctx) => {
60555
60739
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -60564,8 +60748,8 @@ function buildAttachmentHandlers(deps) {
60564
60748
  if (!scope) {
60565
60749
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
60566
60750
  }
60567
- const cwdAbs = import_node_path53.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
60568
- 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);
60569
60753
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
60570
60754
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
60571
60755
  const size = 0;
@@ -60624,19 +60808,19 @@ function buildAttachmentHandlers(deps) {
60624
60808
 
60625
60809
  // src/handlers/extension.ts
60626
60810
  var import_promises11 = __toESM(require("fs/promises"), 1);
60627
- var import_node_path58 = __toESM(require("path"), 1);
60811
+ var import_node_path59 = __toESM(require("path"), 1);
60628
60812
  init_protocol();
60629
60813
 
60630
60814
  // src/extension/bundle-zip.ts
60631
60815
  var import_promises8 = __toESM(require("fs/promises"), 1);
60632
- var import_node_path54 = __toESM(require("path"), 1);
60816
+ var import_node_path55 = __toESM(require("path"), 1);
60633
60817
  var import_node_crypto15 = __toESM(require("crypto"), 1);
60634
60818
  var import_jszip2 = __toESM(require_lib3(), 1);
60635
60819
  async function bundleExtensionDir(dir) {
60636
60820
  const entries = await listFilesSorted(dir);
60637
60821
  const zip = new import_jszip2.default();
60638
60822
  for (const rel of entries) {
60639
- const abs = import_node_path54.default.join(dir, rel);
60823
+ const abs = import_node_path55.default.join(dir, rel);
60640
60824
  const content = await import_promises8.default.readFile(abs);
60641
60825
  zip.file(rel, content, { date: FIXED_DATE });
60642
60826
  }
@@ -60657,7 +60841,7 @@ async function listFilesSorted(rootDir) {
60657
60841
  return out;
60658
60842
  }
60659
60843
  async function walk(absRoot, relPrefix, out) {
60660
- const dirAbs = import_node_path54.default.join(absRoot, relPrefix);
60844
+ const dirAbs = import_node_path55.default.join(absRoot, relPrefix);
60661
60845
  const entries = await import_promises8.default.readdir(dirAbs, { withFileTypes: true });
60662
60846
  for (const e of entries) {
60663
60847
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -60711,25 +60895,25 @@ function computePublishCheck(args) {
60711
60895
 
60712
60896
  // src/extension/install-flow.ts
60713
60897
  var import_promises9 = __toESM(require("fs/promises"), 1);
60714
- var import_node_path56 = __toESM(require("path"), 1);
60715
- 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);
60716
60900
  var import_node_crypto16 = __toESM(require("crypto"), 1);
60717
60901
  var import_jszip3 = __toESM(require_lib3(), 1);
60718
60902
 
60719
60903
  // src/extension/paths.ts
60720
- var import_node_os19 = __toESM(require("os"), 1);
60721
- 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);
60722
60906
  function clawdHomeRoot(override) {
60723
- 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");
60724
60908
  }
60725
60909
  function extensionsRoot(override) {
60726
- return import_node_path55.default.join(clawdHomeRoot(override), "extensions");
60910
+ return import_node_path56.default.join(clawdHomeRoot(override), "extensions");
60727
60911
  }
60728
60912
  function publishedChannelsFile(override) {
60729
- return import_node_path55.default.join(clawdHomeRoot(override), "extensions-published.json");
60913
+ return import_node_path56.default.join(clawdHomeRoot(override), "extensions-published.json");
60730
60914
  }
60731
60915
  function bundleCacheRoot(override) {
60732
- return import_node_path55.default.join(clawdHomeRoot(override), "extension-bundles");
60916
+ return import_node_path56.default.join(clawdHomeRoot(override), "extension-bundles");
60733
60917
  }
60734
60918
 
60735
60919
  // src/extension/install-flow.ts
@@ -60756,7 +60940,7 @@ async function installFromChannel(args, deps) {
60756
60940
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
60757
60941
  }
60758
60942
  for (const name of Object.keys(zip.files)) {
60759
- if (name.includes("..") || name.startsWith("/") || import_node_path56.default.isAbsolute(name)) {
60943
+ if (name.includes("..") || name.startsWith("/") || import_node_path57.default.isAbsolute(name)) {
60760
60944
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
60761
60945
  }
60762
60946
  }
@@ -60788,7 +60972,7 @@ async function installFromChannel(args, deps) {
60788
60972
  );
60789
60973
  }
60790
60974
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
60791
- const destDir = import_node_path56.default.join(deps.extensionsRoot, localExtId);
60975
+ const destDir = import_node_path57.default.join(deps.extensionsRoot, localExtId);
60792
60976
  let destExists = false;
60793
60977
  try {
60794
60978
  await import_promises9.default.access(destDir);
@@ -60802,16 +60986,16 @@ async function installFromChannel(args, deps) {
60802
60986
  );
60803
60987
  }
60804
60988
  const stage = await import_promises9.default.mkdtemp(
60805
- 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}-`)
60806
60990
  );
60807
60991
  try {
60808
60992
  for (const [name, entry] of Object.entries(zip.files)) {
60809
- const dest = import_node_path56.default.join(stage, name);
60993
+ const dest = import_node_path57.default.join(stage, name);
60810
60994
  if (entry.dir) {
60811
60995
  await import_promises9.default.mkdir(dest, { recursive: true });
60812
60996
  continue;
60813
60997
  }
60814
- 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 });
60815
60999
  if (name === "manifest.json") {
60816
61000
  const rewritten = { ...parsed.data, id: localExtId };
60817
61001
  await import_promises9.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -60832,8 +61016,8 @@ async function installFromChannel(args, deps) {
60832
61016
 
60833
61017
  // src/extension/update-flow.ts
60834
61018
  var import_promises10 = __toESM(require("fs/promises"), 1);
60835
- var import_node_path57 = __toESM(require("path"), 1);
60836
- 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);
60837
61021
  var import_node_crypto17 = __toESM(require("crypto"), 1);
60838
61022
  var import_jszip4 = __toESM(require_lib3(), 1);
60839
61023
  var UpdateError = class extends Error {
@@ -60849,11 +61033,11 @@ async function updateFromChannel(args, deps) {
60849
61033
  channelRef.extId,
60850
61034
  channelRef.ownerPrincipalId
60851
61035
  );
60852
- const liveDir = import_node_path57.default.join(deps.extensionsRoot, localExtId);
61036
+ const liveDir = import_node_path58.default.join(deps.extensionsRoot, localExtId);
60853
61037
  const prevDir = `${liveDir}.prev`;
60854
61038
  let existingVersion;
60855
61039
  try {
60856
- 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");
60857
61041
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
60858
61042
  if (!parsed2.success) {
60859
61043
  throw new UpdateError(
@@ -60886,7 +61070,7 @@ async function updateFromChannel(args, deps) {
60886
61070
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
60887
61071
  }
60888
61072
  for (const name of Object.keys(zip.files)) {
60889
- if (name.includes("..") || name.startsWith("/") || import_node_path57.default.isAbsolute(name)) {
61073
+ if (name.includes("..") || name.startsWith("/") || import_node_path58.default.isAbsolute(name)) {
60890
61074
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
60891
61075
  }
60892
61076
  }
@@ -60921,16 +61105,16 @@ async function updateFromChannel(args, deps) {
60921
61105
  await import_promises10.default.rm(prevDir, { recursive: true, force: true });
60922
61106
  await import_promises10.default.rename(liveDir, prevDir);
60923
61107
  const stage = await import_promises10.default.mkdtemp(
60924
- 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}-`)
60925
61109
  );
60926
61110
  try {
60927
61111
  for (const [name, entry] of Object.entries(zip.files)) {
60928
- const dest = import_node_path57.default.join(stage, name);
61112
+ const dest = import_node_path58.default.join(stage, name);
60929
61113
  if (entry.dir) {
60930
61114
  await import_promises10.default.mkdir(dest, { recursive: true });
60931
61115
  continue;
60932
61116
  }
60933
- 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 });
60934
61118
  if (name === "manifest.json") {
60935
61119
  const rewritten = { ...parsed.data, id: localExtId };
60936
61120
  await import_promises10.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -60997,7 +61181,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
60997
61181
  );
60998
61182
  }
60999
61183
  }
61000
- const manifestPath = import_node_path58.default.join(root, extId, "manifest.json");
61184
+ const manifestPath = import_node_path59.default.join(root, extId, "manifest.json");
61001
61185
  const manifest = await readManifest(root, extId);
61002
61186
  const next = { ...manifest, version: newVersion };
61003
61187
  const tmp = `${manifestPath}.tmp`;
@@ -61005,7 +61189,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
61005
61189
  await import_promises11.default.rename(tmp, manifestPath);
61006
61190
  }
61007
61191
  async function readManifest(root, extId) {
61008
- const file = import_node_path58.default.join(root, extId, "manifest.json");
61192
+ const file = import_node_path59.default.join(root, extId, "manifest.json");
61009
61193
  let raw;
61010
61194
  try {
61011
61195
  raw = await import_promises11.default.readFile(file, "utf8");
@@ -61089,7 +61273,7 @@ function buildExtensionHandlers(deps) {
61089
61273
  };
61090
61274
  async function buildSnapshotMeta(extId) {
61091
61275
  const manifest = await readManifest(deps.root, extId);
61092
- 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));
61093
61277
  return { manifest, contentHash: sha256, buffer };
61094
61278
  }
61095
61279
  const publish = async (frame, _client, ctx) => {
@@ -61264,9 +61448,9 @@ function buildExtensionHandlers(deps) {
61264
61448
  }
61265
61449
 
61266
61450
  // src/app-builder/project-store.ts
61267
- var import_node_fs48 = require("fs");
61268
- var import_node_child_process13 = require("child_process");
61269
- 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");
61270
61454
  init_protocol();
61271
61455
  var PROJECTS_DIR = "projects";
61272
61456
  var META_FILE = ".clawd-project.json";
@@ -61280,19 +61464,19 @@ var ProjectStore = class {
61280
61464
  root;
61281
61465
  /** projects/<name>/.clawd-project.json 路径 */
61282
61466
  metaPath(name) {
61283
- return (0, import_node_path59.join)(this.projectsRoot(), name, META_FILE);
61467
+ return (0, import_node_path60.join)(this.projectsRoot(), name, META_FILE);
61284
61468
  }
61285
61469
  /** projects/<name>/ 目录路径(cwd 用) */
61286
61470
  projectDir(name) {
61287
- return (0, import_node_path59.join)(this.projectsRoot(), name);
61471
+ return (0, import_node_path60.join)(this.projectsRoot(), name);
61288
61472
  }
61289
61473
  projectsRoot() {
61290
- return (0, import_node_path59.join)(this.root, PROJECTS_DIR);
61474
+ return (0, import_node_path60.join)(this.root, PROJECTS_DIR);
61291
61475
  }
61292
61476
  async list() {
61293
61477
  let entries;
61294
61478
  try {
61295
- entries = await import_node_fs48.promises.readdir(this.projectsRoot());
61479
+ entries = await import_node_fs49.promises.readdir(this.projectsRoot());
61296
61480
  } catch (err) {
61297
61481
  if (err.code === "ENOENT") return [];
61298
61482
  throw err;
@@ -61300,7 +61484,7 @@ var ProjectStore = class {
61300
61484
  const out = [];
61301
61485
  for (const name of entries) {
61302
61486
  try {
61303
- 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");
61304
61488
  const json = JSON.parse(raw);
61305
61489
  let migrated = false;
61306
61490
  if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
@@ -61311,7 +61495,7 @@ var ProjectStore = class {
61311
61495
  if (parsed.success) {
61312
61496
  out.push(parsed.data);
61313
61497
  if (migrated) {
61314
- 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(() => {
61315
61499
  });
61316
61500
  }
61317
61501
  }
@@ -61355,8 +61539,8 @@ var ProjectStore = class {
61355
61539
  throw new Error(`invalid name "${name}": ${validated.error.message}`);
61356
61540
  }
61357
61541
  const dir = this.projectDir(name);
61358
- await import_node_fs48.promises.mkdir(dir, { recursive: true });
61359
- 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");
61360
61544
  return meta;
61361
61545
  }
61362
61546
  /**
@@ -61370,7 +61554,7 @@ var ProjectStore = class {
61370
61554
  async scaffold(name, templateSrcDir, scaffoldScriptPath) {
61371
61555
  const destDir = this.projectDir(name);
61372
61556
  return await new Promise((resolve6, reject) => {
61373
- 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], {
61374
61558
  env: { ...process.env, PATH: process.env.PATH ?? "" },
61375
61559
  stdio: ["ignore", "pipe", "pipe"]
61376
61560
  });
@@ -61399,7 +61583,7 @@ var ProjectStore = class {
61399
61583
  }
61400
61584
  async delete(name) {
61401
61585
  const dir = this.projectDir(name);
61402
- await import_node_fs48.promises.rm(dir, { recursive: true, force: true });
61586
+ await import_node_fs49.promises.rm(dir, { recursive: true, force: true });
61403
61587
  }
61404
61588
  async updatePort(name, newPort) {
61405
61589
  if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
@@ -61415,7 +61599,7 @@ var ProjectStore = class {
61415
61599
  throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
61416
61600
  }
61417
61601
  const updated = { ...target, port: newPort };
61418
- 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");
61419
61603
  return updated;
61420
61604
  }
61421
61605
  /**
@@ -61432,7 +61616,7 @@ var ProjectStore = class {
61432
61616
  if (!validated.success) {
61433
61617
  throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
61434
61618
  }
61435
- 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");
61436
61620
  return validated.data;
61437
61621
  }
61438
61622
  /**
@@ -61453,7 +61637,7 @@ var ProjectStore = class {
61453
61637
  if (!validated.success) {
61454
61638
  throw new Error(`invalid publishJob: ${validated.error.message}`);
61455
61639
  }
61456
- 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");
61457
61641
  return validated.data;
61458
61642
  }
61459
61643
  /** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
@@ -61468,13 +61652,13 @@ var ProjectStore = class {
61468
61652
  if (!validated.success) {
61469
61653
  throw new Error(`failed to clear publishJob: ${validated.error.message}`);
61470
61654
  }
61471
- 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");
61472
61656
  return validated.data;
61473
61657
  }
61474
61658
  };
61475
61659
 
61476
61660
  // src/app-builder/kill-port.ts
61477
- var import_node_child_process14 = require("child_process");
61661
+ var import_node_child_process15 = require("child_process");
61478
61662
  async function killPortOccupants(port, ownedPids, logger) {
61479
61663
  let pids;
61480
61664
  try {
@@ -61516,7 +61700,7 @@ async function killPortOccupants(port, ownedPids, logger) {
61516
61700
  }
61517
61701
  function listPidsOnPort(port) {
61518
61702
  return new Promise((resolve6, reject) => {
61519
- (0, import_node_child_process14.execFile)(
61703
+ (0, import_node_child_process15.execFile)(
61520
61704
  "lsof",
61521
61705
  ["-ti", `:${port}`],
61522
61706
  { timeout: 3e3 },
@@ -61588,9 +61772,9 @@ var PublishJobRegistry = class {
61588
61772
  };
61589
61773
 
61590
61774
  // src/app-builder/publish-job-runner.ts
61591
- var import_node_child_process15 = require("child_process");
61592
- var import_node_fs49 = require("fs");
61593
- 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");
61594
61778
 
61595
61779
  // src/app-builder/publish-stage-parser.ts
61596
61780
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -61617,19 +61801,19 @@ function tailStderrLines(buf, n) {
61617
61801
  // src/app-builder/publish-job-runner.ts
61618
61802
  async function startPublishJob(deps, args) {
61619
61803
  const { registry: registry2, projectDir } = deps;
61620
- const spawn12 = deps.spawnImpl ?? import_node_child_process15.spawn;
61804
+ const spawn13 = deps.spawnImpl ?? import_node_child_process16.spawn;
61621
61805
  if (registry2.has(args.name)) {
61622
61806
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
61623
61807
  }
61624
61808
  const projDir = projectDir(args.name);
61625
- const logPath = (0, import_node_path60.join)(projDir, ".publish.log");
61809
+ const logPath = (0, import_node_path61.join)(projDir, ".publish.log");
61626
61810
  let logStream = null;
61627
61811
  try {
61628
- logStream = (0, import_node_fs49.createWriteStream)(logPath, { flags: "w" });
61812
+ logStream = (0, import_node_fs50.createWriteStream)(logPath, { flags: "w" });
61629
61813
  } catch {
61630
61814
  logStream = null;
61631
61815
  }
61632
- const child = spawn12("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
61816
+ const child = spawn13("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
61633
61817
  cwd: projDir,
61634
61818
  env: process.env,
61635
61819
  stdio: ["ignore", "pipe", "pipe"]
@@ -61882,8 +62066,8 @@ async function recoverInterruptedJobs(deps) {
61882
62066
 
61883
62067
  // src/handlers/app-builder.ts
61884
62068
  init_protocol();
61885
- var import_node_path61 = require("path");
61886
- var import_node_fs50 = require("fs");
62069
+ var import_node_path62 = require("path");
62070
+ var import_node_fs51 = require("fs");
61887
62071
  var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
61888
62072
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
61889
62073
  async function recoverInterruptedPublishJobs(store, logger) {
@@ -61964,7 +62148,7 @@ function buildAppBuilderHandlers(deps) {
61964
62148
  async function listAllUsersProjects() {
61965
62149
  if (!deps.usersRoot || !deps.getStore) return [];
61966
62150
  const getStore = deps.getStore;
61967
- const userIds = await import_node_fs50.promises.readdir(deps.usersRoot).catch(() => []);
62151
+ const userIds = await import_node_fs51.promises.readdir(deps.usersRoot).catch(() => []);
61968
62152
  const perUser = await Promise.all(
61969
62153
  userIds.map((uid) => getStore(uid).list().catch(() => []))
61970
62154
  );
@@ -62033,8 +62217,8 @@ function buildAppBuilderHandlers(deps) {
62033
62217
  const project = await userStore.create(f.name, reservedPorts);
62034
62218
  try {
62035
62219
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
62036
- const templateSrcDir = (0, import_node_path61.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
62037
- 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");
62038
62222
  const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
62039
62223
  deps.logger?.info("app-builder.scaffold.done", {
62040
62224
  name: project.name,
@@ -62238,7 +62422,7 @@ function buildAppBuilderHandlers(deps) {
62238
62422
  await userStore.clearPublishJob(args.name);
62239
62423
  }
62240
62424
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
62241
- 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");
62242
62426
  deps.logger?.info("app-builder.publish.start", {
62243
62427
  name: args.name,
62244
62428
  sessionId: boundSession.sessionId,
@@ -62658,7 +62842,7 @@ function buildVisitorHandlers(deps) {
62658
62842
 
62659
62843
  // src/extension/registry.ts
62660
62844
  var import_promises12 = __toESM(require("fs/promises"), 1);
62661
- var import_node_path62 = __toESM(require("path"), 1);
62845
+ var import_node_path63 = __toESM(require("path"), 1);
62662
62846
  async function loadAll(root) {
62663
62847
  let entries;
62664
62848
  try {
@@ -62671,13 +62855,13 @@ async function loadAll(root) {
62671
62855
  for (const ent of entries) {
62672
62856
  if (!ent.isDirectory()) continue;
62673
62857
  if (ent.name.startsWith(".")) continue;
62674
- 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));
62675
62859
  }
62676
62860
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
62677
62861
  return records;
62678
62862
  }
62679
62863
  async function loadOne(dir, dirName) {
62680
- const manifestPath = import_node_path62.default.join(dir, "manifest.json");
62864
+ const manifestPath = import_node_path63.default.join(dir, "manifest.json");
62681
62865
  let raw;
62682
62866
  try {
62683
62867
  raw = await import_promises12.default.readFile(manifestPath, "utf8");
@@ -62722,7 +62906,7 @@ async function loadOne(dir, dirName) {
62722
62906
 
62723
62907
  // src/extension/uninstall.ts
62724
62908
  var import_promises13 = __toESM(require("fs/promises"), 1);
62725
- var import_node_path63 = __toESM(require("path"), 1);
62909
+ var import_node_path64 = __toESM(require("path"), 1);
62726
62910
  var UninstallError = class extends Error {
62727
62911
  constructor(code, message) {
62728
62912
  super(message);
@@ -62731,7 +62915,7 @@ var UninstallError = class extends Error {
62731
62915
  code;
62732
62916
  };
62733
62917
  async function uninstall(deps) {
62734
- const dir = import_node_path63.default.join(deps.root, deps.extId);
62918
+ const dir = import_node_path64.default.join(deps.root, deps.extId);
62735
62919
  try {
62736
62920
  await import_promises13.default.access(dir);
62737
62921
  } catch {
@@ -62748,15 +62932,15 @@ var import_node_crypto19 = require("crypto");
62748
62932
  init_protocol();
62749
62933
 
62750
62934
  // src/peer-ops/run-command.ts
62751
- var import_node_child_process16 = require("child_process");
62752
- 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);
62753
62937
  var DEFAULT_TIMEOUT_MS4 = 3e4;
62754
62938
  var MAX_TIMEOUT_MS = 3e5;
62755
62939
  var MAX_OUTPUT_BYTES = 1048576;
62756
62940
  function runCommand(command, opts = {}) {
62757
62941
  const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS4, MAX_TIMEOUT_MS);
62758
62942
  return new Promise((resolve6) => {
62759
- 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() });
62760
62944
  const out = [];
62761
62945
  const err = [];
62762
62946
  let outBytes = 0;
@@ -62975,14 +63159,14 @@ function buildMethodHandlers(deps) {
62975
63159
  init_protocol();
62976
63160
 
62977
63161
  // src/tools/version-probe.ts
62978
- var import_node_child_process17 = require("child_process");
63162
+ var import_node_child_process18 = require("child_process");
62979
63163
  init_claude();
62980
63164
  function parseVersionOutput(out) {
62981
63165
  return /(\d+\.\d+\.\d+)/.exec(out)?.[1];
62982
63166
  }
62983
63167
  function execVersion(bin) {
62984
63168
  return new Promise((resolve6, reject) => {
62985
- (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) => {
62986
63170
  if (err) reject(err);
62987
63171
  else resolve6(String(stdout));
62988
63172
  });
@@ -63093,7 +63277,7 @@ function buildOnboardingHandlers(deps) {
63093
63277
  }
63094
63278
 
63095
63279
  // src/app-builder/dev-server-supervisor.ts
63096
- var import_node_child_process18 = require("child_process");
63280
+ var import_node_child_process19 = require("child_process");
63097
63281
  var import_node_events2 = require("events");
63098
63282
  var DEFAULT_READY_PATTERN = /Local:\s+https?:\/\/|Nest application successfully started|server listening on/i;
63099
63283
  var DevServerSupervisor = class extends import_node_events2.EventEmitter {
@@ -63130,7 +63314,7 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
63130
63314
  tunnelHost: args.tunnelHost,
63131
63315
  devCommand: cmd
63132
63316
  });
63133
- const child = (0, import_node_child_process18.spawn)("sh", ["-c", cmd], {
63317
+ const child = (0, import_node_child_process19.spawn)("sh", ["-c", cmd], {
63134
63318
  cwd: args.cwd,
63135
63319
  env,
63136
63320
  stdio: "pipe",
@@ -63382,8 +63566,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
63382
63566
  }
63383
63567
 
63384
63568
  // src/extension/runtime.ts
63385
- var import_node_child_process19 = require("child_process");
63386
- 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);
63387
63571
  var import_promises14 = require("timers/promises");
63388
63572
 
63389
63573
  // src/extension/port-allocator.ts
@@ -63484,13 +63668,13 @@ var Runtime = class {
63484
63668
  /\$CLAWOS_EXT_PORT/g,
63485
63669
  String(port)
63486
63670
  );
63487
- const dir = import_node_path64.default.join(this.root, extId);
63671
+ const dir = import_node_path65.default.join(this.root, extId);
63488
63672
  const env = {
63489
63673
  ...process.env,
63490
63674
  CLAWOS_EXT_PORT: String(port),
63491
63675
  CLAWOS_EXT_ID: extId
63492
63676
  };
63493
- const child = (0, import_node_child_process19.spawn)("sh", ["-c", cmd], {
63677
+ const child = (0, import_node_child_process20.spawn)("sh", ["-c", cmd], {
63494
63678
  cwd: dir,
63495
63679
  env,
63496
63680
  stdio: ["ignore", "pipe", "pipe"],
@@ -63596,7 +63780,7 @@ ${handle.stderrTail}`
63596
63780
 
63597
63781
  // src/extension/published-channels.ts
63598
63782
  var import_promises15 = __toESM(require("fs/promises"), 1);
63599
- var import_node_path65 = __toESM(require("path"), 1);
63783
+ var import_node_path66 = __toESM(require("path"), 1);
63600
63784
  init_zod();
63601
63785
  var PublishedChannelsError = class extends Error {
63602
63786
  constructor(code, message) {
@@ -63695,7 +63879,7 @@ var PublishedChannelStore = class {
63695
63879
  )
63696
63880
  };
63697
63881
  const tmp = `${this.filePath}.tmp`;
63698
- 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 });
63699
63883
  await import_promises15.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
63700
63884
  await import_promises15.default.rename(tmp, this.filePath);
63701
63885
  }
@@ -63703,7 +63887,7 @@ var PublishedChannelStore = class {
63703
63887
 
63704
63888
  // src/extension/bundle-cache.ts
63705
63889
  var import_promises16 = __toESM(require("fs/promises"), 1);
63706
- var import_node_path66 = __toESM(require("path"), 1);
63890
+ var import_node_path67 = __toESM(require("path"), 1);
63707
63891
  var BundleCache = class {
63708
63892
  constructor(rootDir) {
63709
63893
  this.rootDir = rootDir;
@@ -63712,14 +63896,14 @@ var BundleCache = class {
63712
63896
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
63713
63897
  async write(snapshotHash, buffer) {
63714
63898
  await import_promises16.default.mkdir(this.rootDir, { recursive: true });
63715
- const file = import_node_path66.default.join(this.rootDir, `${snapshotHash}.zip`);
63899
+ const file = import_node_path67.default.join(this.rootDir, `${snapshotHash}.zip`);
63716
63900
  const tmp = `${file}.tmp`;
63717
63901
  await import_promises16.default.writeFile(tmp, buffer, { mode: 384 });
63718
63902
  await import_promises16.default.rename(tmp, file);
63719
63903
  }
63720
63904
  /** Returns the bundle bytes, or null when the file doesn't exist. */
63721
63905
  async read(snapshotHash) {
63722
- const file = import_node_path66.default.join(this.rootDir, `${snapshotHash}.zip`);
63906
+ const file = import_node_path67.default.join(this.rootDir, `${snapshotHash}.zip`);
63723
63907
  try {
63724
63908
  return await import_promises16.default.readFile(file);
63725
63909
  } catch (e) {
@@ -63729,7 +63913,7 @@ var BundleCache = class {
63729
63913
  }
63730
63914
  /** Idempotent — missing file is not an error. */
63731
63915
  async delete(snapshotHash) {
63732
- const file = import_node_path66.default.join(this.rootDir, `${snapshotHash}.zip`);
63916
+ const file = import_node_path67.default.join(this.rootDir, `${snapshotHash}.zip`);
63733
63917
  await import_promises16.default.rm(file, { force: true });
63734
63918
  }
63735
63919
  };
@@ -63750,26 +63934,26 @@ async function startDaemon(config) {
63750
63934
  },
63751
63935
  source: "daemon",
63752
63936
  sampling: logShippingCfg.sampling,
63753
- homeDir: import_node_os23.default.homedir()
63937
+ homeDir: import_node_os24.default.homedir()
63754
63938
  });
63755
- const logDir = import_node_path67.default.join(config.dataDir, "log");
63756
- 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 });
63757
63941
  const logger = createLogger({
63758
63942
  level: config.logLevel,
63759
- file: import_node_path67.default.join(logDir, "clawd.log"),
63943
+ file: import_node_path68.default.join(logDir, "clawd.log"),
63760
63944
  logClient
63761
63945
  });
63762
63946
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
63763
63947
  const screenIdleProbeLogger = createFileOnlyLogger({
63764
- file: import_node_path67.default.join(logDir, "screen-idle-probe.log"),
63948
+ file: import_node_path68.default.join(logDir, "screen-idle-probe.log"),
63765
63949
  level: "debug"
63766
63950
  });
63767
63951
  logger.info("screen-idle probe logger enabled", {
63768
- file: import_node_path67.default.join(logDir, "screen-idle-probe.log")
63952
+ file: import_node_path68.default.join(logDir, "screen-idle-probe.log")
63769
63953
  });
63770
63954
  const CAP_TARGETS = [
63771
- import_node_path67.default.join(logDir, "clawd.log"),
63772
- 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")
63773
63957
  ];
63774
63958
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
63775
63959
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -63865,8 +64049,8 @@ async function startDaemon(config) {
63865
64049
  const agents = new AgentsScanner();
63866
64050
  const history = new ClaudeHistoryReader();
63867
64051
  let transport = null;
63868
- const personaStore = new PersonaStore(import_node_path67.default.join(config.dataDir, "personas"));
63869
- 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");
63870
64054
  const defaultsRoot = findDefaultsRoot(logger);
63871
64055
  if (defaultsRoot) {
63872
64056
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -63889,7 +64073,7 @@ async function startDaemon(config) {
63889
64073
  retirePersonaBuilder({ store: personaStore, logger });
63890
64074
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
63891
64075
  const dispatchStore = createDispatchStore({
63892
- filePath: import_node_path67.default.join(config.dataDir, "dispatch.json"),
64076
+ filePath: import_node_path68.default.join(config.dataDir, "dispatch.json"),
63893
64077
  now: () => Date.now(),
63894
64078
  onFlushError: (err) => logger.error("dispatch store flush failed", {
63895
64079
  reason: err instanceof Error ? err.message : String(err)
@@ -63904,18 +64088,18 @@ async function startDaemon(config) {
63904
64088
  now: () => Date.now(),
63905
64089
  onCompleted: (sid) => deliverPendingRef?.(sid)
63906
64090
  });
63907
- 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));
63908
64092
  const mcpConfigs = [];
63909
64093
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
63910
64094
  const dispatchServerCandidates = [
63911
- import_node_path67.default.join(here, "dispatch", "mcp-server.cjs"),
64095
+ import_node_path68.default.join(here, "dispatch", "mcp-server.cjs"),
63912
64096
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
63913
- import_node_path67.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
64097
+ import_node_path68.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
63914
64098
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
63915
64099
  ];
63916
- const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64100
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
63917
64101
  if (dispatchServerScriptPath) {
63918
- 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");
63919
64103
  const dispatchCfgPath = writeDispatchMcpConfig({
63920
64104
  dataDir: config.dataDir,
63921
64105
  serverScriptPath: dispatchServerScriptPath,
@@ -63935,12 +64119,12 @@ async function startDaemon(config) {
63935
64119
  });
63936
64120
  }
63937
64121
  const ticketServerCandidates = [
63938
- import_node_path67.default.join(here, "ticket", "mcp-server.cjs"),
63939
- 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")
63940
64124
  ];
63941
- const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64125
+ const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
63942
64126
  if (ticketServerScriptPath) {
63943
- 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");
63944
64128
  const ticketCfgPath = writeTicketMcpConfig({
63945
64129
  dataDir: config.dataDir,
63946
64130
  serverScriptPath: ticketServerScriptPath,
@@ -63962,12 +64146,12 @@ async function startDaemon(config) {
63962
64146
  });
63963
64147
  }
63964
64148
  const shiftServerCandidates = [
63965
- import_node_path67.default.join(here, "shift", "mcp-server.cjs"),
63966
- 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")
63967
64151
  ];
63968
- const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64152
+ const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
63969
64153
  if (shiftServerScriptPath) {
63970
- 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");
63971
64155
  const shiftCfgPath = await writeShiftMcpConfig({
63972
64156
  dataDir: config.dataDir,
63973
64157
  serverScriptPath: shiftServerScriptPath,
@@ -63988,12 +64172,12 @@ async function startDaemon(config) {
63988
64172
  );
63989
64173
  }
63990
64174
  const inboxServerCandidates = [
63991
- import_node_path67.default.join(here, "inbox", "mcp-server.cjs"),
63992
- 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")
63993
64177
  ];
63994
- const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64178
+ const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
63995
64179
  if (inboxServerScriptPath) {
63996
- 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");
63997
64181
  const inboxCfgPath = await writeInboxMcpConfig({
63998
64182
  dataDir: config.dataDir,
63999
64183
  serverScriptPath: inboxServerScriptPath,
@@ -64014,10 +64198,10 @@ async function startDaemon(config) {
64014
64198
  );
64015
64199
  }
64016
64200
  const peerOpsServerCandidates = [
64017
- import_node_path67.default.join(here, "peer-ops", "mcp-server.cjs"),
64018
- 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")
64019
64203
  ];
64020
- const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64204
+ const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
64021
64205
  if (peerOpsServerScriptPath) {
64022
64206
  const peerOpsCfgPath = writePeerOpsMcpConfig({
64023
64207
  dataDir: config.dataDir,
@@ -64037,12 +64221,12 @@ async function startDaemon(config) {
64037
64221
  );
64038
64222
  }
64039
64223
  const rpcToolServerCandidates = [
64040
- import_node_path67.default.join(here, "rpc-tool", "mcp-server.cjs"),
64041
- 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")
64042
64226
  ];
64043
- const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
64227
+ const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
64044
64228
  if (rpcToolServerScriptPath) {
64045
- 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");
64046
64230
  const rpcToolCfgPath = writeRpcToolMcpConfig({
64047
64231
  dataDir: config.dataDir,
64048
64232
  serverScriptPath: rpcToolServerScriptPath,
@@ -64063,7 +64247,7 @@ async function startDaemon(config) {
64063
64247
  );
64064
64248
  }
64065
64249
  const shiftStore = createShiftStore({
64066
- filePath: import_node_path67.default.join(config.dataDir, "shift.json"),
64250
+ filePath: import_node_path68.default.join(config.dataDir, "shift.json"),
64067
64251
  ownerIdProvider: () => ownerPrincipalId,
64068
64252
  now: () => Date.now()
64069
64253
  });
@@ -64085,7 +64269,7 @@ async function startDaemon(config) {
64085
64269
  getAdapter,
64086
64270
  historyReader: history,
64087
64271
  dataDir: config.dataDir,
64088
- personaRoot: import_node_path67.default.join(config.dataDir, "personas"),
64272
+ personaRoot: import_node_path68.default.join(config.dataDir, "personas"),
64089
64273
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
64090
64274
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
64091
64275
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -64117,6 +64301,9 @@ async function startDaemon(config) {
64117
64301
  // daemon 级 MCP server 登记表(dispatch / ticket / shift / inbox / ...,上方各 writer
64118
64302
  // 块写盘成功即登记);reducer 透传到 SpawnContext.mcpConfigs,cc spawn 逐项 --mcp-config。
64119
64303
  mcpConfigs,
64304
+ // 会话标题自产(首条 send 并行 fire,claude→haiku / codex→gpt-5.4-mini)。
64305
+ // 不注入 = 功能关(manager 测试默认关闭防烧真调用),这里是唯一的生产装配点。
64306
+ generateTitle: (tool, firstMessage) => generateSessionTitle(tool, firstMessage, { logger }),
64120
64307
  broadcastFrame: (frame, target) => {
64121
64308
  if (target === "all") {
64122
64309
  transport?.broadcastAll(frame);
@@ -64136,10 +64323,10 @@ async function startDaemon(config) {
64136
64323
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
64137
64324
  attachmentGroup: {
64138
64325
  onFileEdit: (input) => {
64139
- 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);
64140
64327
  let size = 0;
64141
64328
  try {
64142
- size = import_node_fs51.default.statSync(absPath).size;
64329
+ size = import_node_fs52.default.statSync(absPath).size;
64143
64330
  } catch (err) {
64144
64331
  logger.warn("attachment.onFileEdit stat failed", {
64145
64332
  sessionId: input.sessionId,
@@ -64407,11 +64594,11 @@ async function startDaemon(config) {
64407
64594
  // 'persona/<pid>/owner',default 走 'default'。
64408
64595
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
64409
64596
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
64410
- personaRoot: import_node_path67.default.join(config.dataDir, "personas"),
64597
+ personaRoot: import_node_path68.default.join(config.dataDir, "personas"),
64411
64598
  usersRoot
64412
64599
  },
64413
64600
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
64414
- personaRoot: import_node_path67.default.join(config.dataDir, "personas"),
64601
+ personaRoot: import_node_path68.default.join(config.dataDir, "personas"),
64415
64602
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
64416
64603
  usersRoot,
64417
64604
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -64537,11 +64724,11 @@ async function startDaemon(config) {
64537
64724
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
64538
64725
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
64539
64726
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
64540
- 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"),
64541
64728
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
64542
- deployKitRoot: import_node_path67.default.join(config.dataDir, "deploy-kit"),
64729
+ deployKitRoot: import_node_path68.default.join(config.dataDir, "deploy-kit"),
64543
64730
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
64544
- resolvePersonaRoot: (personaId2) => import_node_path67.default.join(config.dataDir, "personas", personaId2),
64731
+ resolvePersonaRoot: (personaId2) => import_node_path68.default.join(config.dataDir, "personas", personaId2),
64545
64732
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
64546
64733
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
64547
64734
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -64584,7 +64771,7 @@ async function startDaemon(config) {
64584
64771
  sourceSessionId: args.sourceSessionId
64585
64772
  });
64586
64773
  const sourceFile = manager.findOwnedSession(args.sourceSessionId);
64587
- const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os23.default.homedir());
64774
+ const sourceJsonlPath = resolveSourceJsonlPath(sourceFile, import_node_os24.default.homedir());
64588
64775
  logger.info("dispatch.spawnB.source-resolved", {
64589
64776
  dispatchId: args.dispatchId,
64590
64777
  sourceJsonlPath,
@@ -64646,7 +64833,7 @@ async function startDaemon(config) {
64646
64833
  });
64647
64834
  shiftScheduler.start();
64648
64835
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
64649
- const larkBotStore = createLarkBotBindingStore(import_node_path67.default.join(config.dataDir, "personas"));
64836
+ const larkBotStore = createLarkBotBindingStore(import_node_path68.default.join(config.dataDir, "personas"));
64650
64837
  const larkBotCloud = createLarkBotCloudClient({
64651
64838
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
64652
64839
  apiKey: resolveClawdTicketsApiKey(),
@@ -64660,7 +64847,7 @@ async function startDaemon(config) {
64660
64847
  store: larkBotStore,
64661
64848
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
64662
64849
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
64663
- 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"),
64664
64851
  isShuttingDown: () => larkDraining,
64665
64852
  logger: {
64666
64853
  warn: (msg) => logger.warn(msg),
@@ -64964,8 +65151,8 @@ async function startDaemon(config) {
64964
65151
  const lines = [
64965
65152
  `Tunnel: ${r.url}`,
64966
65153
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
64967
- `Frpc config: ${import_node_path67.default.join(config.dataDir, "frpc.toml")}`,
64968
- `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")}`
64969
65156
  ];
64970
65157
  const width2 = Math.max(...lines.map((l) => l.length));
64971
65158
  const bar = "\u2550".repeat(width2 + 4);
@@ -64978,8 +65165,8 @@ ${bar}
64978
65165
 
64979
65166
  `);
64980
65167
  try {
64981
- const connectPath = import_node_path67.default.join(config.dataDir, "connect.txt");
64982
- 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 });
64983
65170
  } catch {
64984
65171
  }
64985
65172
  } catch (err) {
@@ -65054,9 +65241,9 @@ ${bar}
65054
65241
  };
65055
65242
  }
65056
65243
  function migrateDropPersonsDir(dataDir) {
65057
- const dir = import_node_path67.default.join(dataDir, "persons");
65244
+ const dir = import_node_path68.default.join(dataDir, "persons");
65058
65245
  try {
65059
- import_node_fs51.default.rmSync(dir, { recursive: true, force: true });
65246
+ import_node_fs52.default.rmSync(dir, { recursive: true, force: true });
65060
65247
  } catch {
65061
65248
  }
65062
65249
  }