@clawos-dev/clawd 0.2.383 → 0.2.384

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: path89, errorMaps, issueData } = params;
454
- const fullPath = [...path89, ...issueData.path || []];
453
+ const { data, path: path90, errorMaps, issueData } = params;
454
+ const fullPath = [...path90, ...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, path89, key) {
765
+ constructor(parent, value, path90, key) {
766
766
  this._cachedPath = [];
767
767
  this.parent = parent;
768
768
  this.data = value;
769
- this._path = path89;
769
+ this._path = path90;
770
770
  this._key = key;
771
771
  }
772
772
  get path() {
@@ -6192,11 +6192,21 @@ var init_dispatch = __esm({
6192
6192
  // 跨设备 dispatch:非空 = A 角色,转发到该 contact deviceId 的 peer daemon;
6193
6193
  // 省略 = 本地 dispatch / B 角色本地执行。A 转发给 B 时 body 不带此字段。
6194
6194
  targetDeviceId: external_exports.string().min(1).optional(),
6195
- // 可选:override B session 使用的 claude 模型。缺省 = 用 persona 默认。
6196
- // 合法值集与 claude adapter capabilities.models[].id 一致(见 daemon
6197
- // tools/claude.ts CLAUDE_MODEL_IDS);handler 层做二次校验,非法值 fail-fast。
6198
- // protocol 层保持 string 便于未来跨 tool 扩展(届时 union 收合法字面量)。
6195
+ // 可选:override B session 使用的模型。缺省 = 用 persona 默认。
6196
+ // 合法值集**从属于 tool**(见下面的 tool 字段):claude 侧与 tools/claude.ts
6197
+ // CLAUDE_MODEL_IDS 一致,codex 侧是运行时查来的模型表;handler 层做二次校验,
6198
+ // 非法值 fail-fast。protocol 层保持 string(不在协议里钉死枚举)。
6199
+ // **只能用于新开 dispatch**:续派不改任何 spawn 参数(worker session 已经跑起来了),
6200
+ // 与 dispatchId 互斥(下方 refine 硬拒)。
6199
6201
  model: external_exports.string().min(1).optional(),
6202
+ // 可选:override B session 使用的 agent tool(engine)。缺省 = 用 persona 绑定的 tool。
6203
+ // 语义是**一次性**——不改 persona 的持久绑定,只决定这条 dispatch 起的 worker session。
6204
+ // 为什么需要:`model` 的合法值集从属于 tool,想让一个 claude persona 这次用
6205
+ // `gpt-5.6-sol` 干活,必须能连 engine 一起换(否则 model 校验按 persona.tool 选表直接拒)。
6206
+ // 合法值集 = daemon 的 adapter 注册表('claude' / 'codex'),handler 层运行时校验;
6207
+ // protocol 层保持 string(与 model / SessionFile.tool 同款处理,不在协议里钉死枚举)。
6208
+ // 与 model 同样**只能用于新开 dispatch**(下方 refine 硬拒 dispatchId 组合)。
6209
+ tool: external_exports.string().min(1).optional(),
6200
6210
  // 可选:给新 worker session 起 label(写入 SessionFile.label,sidebar 显示)。
6201
6211
  // 仅在**新开 dispatch**(dispatchId 缺席)时生效;续派(dispatchId 非空)
6202
6212
  // 时 daemon 层静默丢弃(避免半途改 label 造成 sidebar 抖动)。
@@ -6211,6 +6221,10 @@ var init_dispatch = __esm({
6211
6221
  message: "either targetPersona (new dispatch) or dispatchId (follow-up) is required"
6212
6222
  }).refine((v2) => !(v2.dispatchId !== void 0 && v2.targetDeviceId !== void 0), {
6213
6223
  message: "cross-device dispatch cannot be continued (dispatchId + targetDeviceId are mutually exclusive)"
6224
+ }).refine((v2) => !(v2.tool !== void 0 && v2.targetDeviceId !== void 0), {
6225
+ message: "engine override is not supported for cross-device dispatch (tool + targetDeviceId are mutually exclusive)"
6226
+ }).refine((v2) => !(v2.dispatchId !== void 0 && (v2.tool !== void 0 || v2.model !== void 0)), {
6227
+ message: "a follow-up dispatch cannot change engine or model (dispatchId excludes tool / model); start a new dispatch instead"
6214
6228
  });
6215
6229
  DispatchCompleteArgsSchema = external_exports.object({
6216
6230
  dispatchId: external_exports.string().min(1),
@@ -9292,8 +9306,8 @@ var require_req = __commonJS({
9292
9306
  if (req.originalUrl) {
9293
9307
  _req.url = req.originalUrl;
9294
9308
  } else {
9295
- const path89 = req.path;
9296
- _req.url = typeof path89 === "string" ? path89 : req.url ? req.url.path || req.url : void 0;
9309
+ const path90 = req.path;
9310
+ _req.url = typeof path90 === "string" ? path90 : req.url ? req.url.path || req.url : void 0;
9297
9311
  }
9298
9312
  if (req.query) {
9299
9313
  _req.query = req.query;
@@ -9458,14 +9472,14 @@ var require_redact = __commonJS({
9458
9472
  }
9459
9473
  return obj;
9460
9474
  }
9461
- function parsePath(path89) {
9475
+ function parsePath(path90) {
9462
9476
  const parts = [];
9463
9477
  let current = "";
9464
9478
  let inBrackets = false;
9465
9479
  let inQuotes = false;
9466
9480
  let quoteChar = "";
9467
- for (let i = 0; i < path89.length; i++) {
9468
- const char = path89[i];
9481
+ for (let i = 0; i < path90.length; i++) {
9482
+ const char = path90[i];
9469
9483
  if (!inBrackets && char === ".") {
9470
9484
  if (current) {
9471
9485
  parts.push(current);
@@ -9596,10 +9610,10 @@ var require_redact = __commonJS({
9596
9610
  return current;
9597
9611
  }
9598
9612
  function redactPaths(obj, paths, censor, remove = false) {
9599
- for (const path89 of paths) {
9600
- const parts = parsePath(path89);
9613
+ for (const path90 of paths) {
9614
+ const parts = parsePath(path90);
9601
9615
  if (parts.includes("*")) {
9602
- redactWildcardPath(obj, parts, censor, path89, remove);
9616
+ redactWildcardPath(obj, parts, censor, path90, remove);
9603
9617
  } else {
9604
9618
  if (remove) {
9605
9619
  removeKey(obj, parts);
@@ -9684,8 +9698,8 @@ var require_redact = __commonJS({
9684
9698
  }
9685
9699
  } else {
9686
9700
  if (afterWildcard.includes("*")) {
9687
- const wrappedCensor = typeof censor === "function" ? (value, path89) => {
9688
- const fullPath = [...pathArray.slice(0, pathLength), ...path89];
9701
+ const wrappedCensor = typeof censor === "function" ? (value, path90) => {
9702
+ const fullPath = [...pathArray.slice(0, pathLength), ...path90];
9689
9703
  return censor(value, fullPath);
9690
9704
  } : censor;
9691
9705
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -9720,8 +9734,8 @@ var require_redact = __commonJS({
9720
9734
  return null;
9721
9735
  }
9722
9736
  const pathStructure = /* @__PURE__ */ new Map();
9723
- for (const path89 of pathsToClone) {
9724
- const parts = parsePath(path89);
9737
+ for (const path90 of pathsToClone) {
9738
+ const parts = parsePath(path90);
9725
9739
  let current = pathStructure;
9726
9740
  for (let i = 0; i < parts.length; i++) {
9727
9741
  const part = parts[i];
@@ -9773,24 +9787,24 @@ var require_redact = __commonJS({
9773
9787
  }
9774
9788
  return cloneSelectively(obj, pathStructure);
9775
9789
  }
9776
- function validatePath(path89) {
9777
- if (typeof path89 !== "string") {
9790
+ function validatePath(path90) {
9791
+ if (typeof path90 !== "string") {
9778
9792
  throw new Error("Paths must be (non-empty) strings");
9779
9793
  }
9780
- if (path89 === "") {
9794
+ if (path90 === "") {
9781
9795
  throw new Error("Invalid redaction path ()");
9782
9796
  }
9783
- if (path89.includes("..")) {
9784
- throw new Error(`Invalid redaction path (${path89})`);
9797
+ if (path90.includes("..")) {
9798
+ throw new Error(`Invalid redaction path (${path90})`);
9785
9799
  }
9786
- if (path89.includes(",")) {
9787
- throw new Error(`Invalid redaction path (${path89})`);
9800
+ if (path90.includes(",")) {
9801
+ throw new Error(`Invalid redaction path (${path90})`);
9788
9802
  }
9789
9803
  let bracketCount = 0;
9790
9804
  let inQuotes = false;
9791
9805
  let quoteChar = "";
9792
- for (let i = 0; i < path89.length; i++) {
9793
- const char = path89[i];
9806
+ for (let i = 0; i < path90.length; i++) {
9807
+ const char = path90[i];
9794
9808
  if ((char === '"' || char === "'") && bracketCount > 0) {
9795
9809
  if (!inQuotes) {
9796
9810
  inQuotes = true;
@@ -9804,20 +9818,20 @@ var require_redact = __commonJS({
9804
9818
  } else if (char === "]" && !inQuotes) {
9805
9819
  bracketCount--;
9806
9820
  if (bracketCount < 0) {
9807
- throw new Error(`Invalid redaction path (${path89})`);
9821
+ throw new Error(`Invalid redaction path (${path90})`);
9808
9822
  }
9809
9823
  }
9810
9824
  }
9811
9825
  if (bracketCount !== 0) {
9812
- throw new Error(`Invalid redaction path (${path89})`);
9826
+ throw new Error(`Invalid redaction path (${path90})`);
9813
9827
  }
9814
9828
  }
9815
9829
  function validatePaths(paths) {
9816
9830
  if (!Array.isArray(paths)) {
9817
9831
  throw new TypeError("paths must be an array");
9818
9832
  }
9819
- for (const path89 of paths) {
9820
- validatePath(path89);
9833
+ for (const path90 of paths) {
9834
+ validatePath(path90);
9821
9835
  }
9822
9836
  }
9823
9837
  function slowRedact(options = {}) {
@@ -9985,8 +9999,8 @@ var require_redaction = __commonJS({
9985
9999
  if (shape[k2] === null) {
9986
10000
  o[k2] = (value) => topCensor(value, [k2]);
9987
10001
  } else {
9988
- const wrappedCensor = typeof censor === "function" ? (value, path89) => {
9989
- return censor(value, [k2, ...path89]);
10002
+ const wrappedCensor = typeof censor === "function" ? (value, path90) => {
10003
+ return censor(value, [k2, ...path90]);
9990
10004
  } : censor;
9991
10005
  o[k2] = Redact({
9992
10006
  paths: shape[k2],
@@ -10204,10 +10218,10 @@ var require_atomic_sleep = __commonJS({
10204
10218
  var require_sonic_boom = __commonJS({
10205
10219
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
10206
10220
  "use strict";
10207
- var fs79 = require("fs");
10221
+ var fs80 = require("fs");
10208
10222
  var EventEmitter3 = require("events");
10209
10223
  var inherits = require("util").inherits;
10210
- var path89 = require("path");
10224
+ var path90 = require("path");
10211
10225
  var sleep2 = require_atomic_sleep();
10212
10226
  var assert = require("assert");
10213
10227
  var BUSY_WRITE_TIMEOUT = 100;
@@ -10261,20 +10275,20 @@ var require_sonic_boom = __commonJS({
10261
10275
  const mode = sonic.mode;
10262
10276
  if (sonic.sync) {
10263
10277
  try {
10264
- if (sonic.mkdir) fs79.mkdirSync(path89.dirname(file), { recursive: true });
10265
- const fd = fs79.openSync(file, flags, mode);
10278
+ if (sonic.mkdir) fs80.mkdirSync(path90.dirname(file), { recursive: true });
10279
+ const fd = fs80.openSync(file, flags, mode);
10266
10280
  fileOpened(null, fd);
10267
10281
  } catch (err) {
10268
10282
  fileOpened(err);
10269
10283
  throw err;
10270
10284
  }
10271
10285
  } else if (sonic.mkdir) {
10272
- fs79.mkdir(path89.dirname(file), { recursive: true }, (err) => {
10286
+ fs80.mkdir(path90.dirname(file), { recursive: true }, (err) => {
10273
10287
  if (err) return fileOpened(err);
10274
- fs79.open(file, flags, mode, fileOpened);
10288
+ fs80.open(file, flags, mode, fileOpened);
10275
10289
  });
10276
10290
  } else {
10277
- fs79.open(file, flags, mode, fileOpened);
10291
+ fs80.open(file, flags, mode, fileOpened);
10278
10292
  }
10279
10293
  }
10280
10294
  function SonicBoom(opts) {
@@ -10315,8 +10329,8 @@ var require_sonic_boom = __commonJS({
10315
10329
  this.flush = flushBuffer;
10316
10330
  this.flushSync = flushBufferSync;
10317
10331
  this._actualWrite = actualWriteBuffer;
10318
- fsWriteSync = () => fs79.writeSync(this.fd, this._writingBuf);
10319
- fsWrite = () => fs79.write(this.fd, this._writingBuf, this.release);
10332
+ fsWriteSync = () => fs80.writeSync(this.fd, this._writingBuf);
10333
+ fsWrite = () => fs80.write(this.fd, this._writingBuf, this.release);
10320
10334
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
10321
10335
  this._writingBuf = "";
10322
10336
  this.write = write;
@@ -10325,15 +10339,15 @@ var require_sonic_boom = __commonJS({
10325
10339
  this._actualWrite = actualWrite;
10326
10340
  fsWriteSync = () => {
10327
10341
  if (Buffer.isBuffer(this._writingBuf)) {
10328
- return fs79.writeSync(this.fd, this._writingBuf);
10342
+ return fs80.writeSync(this.fd, this._writingBuf);
10329
10343
  }
10330
- return fs79.writeSync(this.fd, this._writingBuf, "utf8");
10344
+ return fs80.writeSync(this.fd, this._writingBuf, "utf8");
10331
10345
  };
10332
10346
  fsWrite = () => {
10333
10347
  if (Buffer.isBuffer(this._writingBuf)) {
10334
- return fs79.write(this.fd, this._writingBuf, this.release);
10348
+ return fs80.write(this.fd, this._writingBuf, this.release);
10335
10349
  }
10336
- return fs79.write(this.fd, this._writingBuf, "utf8", this.release);
10350
+ return fs80.write(this.fd, this._writingBuf, "utf8", this.release);
10337
10351
  };
10338
10352
  } else {
10339
10353
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -10390,7 +10404,7 @@ var require_sonic_boom = __commonJS({
10390
10404
  }
10391
10405
  }
10392
10406
  if (this._fsync) {
10393
- fs79.fsyncSync(this.fd);
10407
+ fs80.fsyncSync(this.fd);
10394
10408
  }
10395
10409
  const len = this._len;
10396
10410
  if (this._reopening) {
@@ -10504,7 +10518,7 @@ var require_sonic_boom = __commonJS({
10504
10518
  const onDrain = () => {
10505
10519
  if (!this._fsync) {
10506
10520
  try {
10507
- fs79.fsync(this.fd, (err) => {
10521
+ fs80.fsync(this.fd, (err) => {
10508
10522
  this._flushPending = false;
10509
10523
  cb(err);
10510
10524
  });
@@ -10606,7 +10620,7 @@ var require_sonic_boom = __commonJS({
10606
10620
  const fd = this.fd;
10607
10621
  this.once("ready", () => {
10608
10622
  if (fd !== this.fd) {
10609
- fs79.close(fd, (err) => {
10623
+ fs80.close(fd, (err) => {
10610
10624
  if (err) {
10611
10625
  return this.emit("error", err);
10612
10626
  }
@@ -10655,7 +10669,7 @@ var require_sonic_boom = __commonJS({
10655
10669
  buf = this._bufs[0];
10656
10670
  }
10657
10671
  try {
10658
- const n = Buffer.isBuffer(buf) ? fs79.writeSync(this.fd, buf) : fs79.writeSync(this.fd, buf, "utf8");
10672
+ const n = Buffer.isBuffer(buf) ? fs80.writeSync(this.fd, buf) : fs80.writeSync(this.fd, buf, "utf8");
10659
10673
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
10660
10674
  buf = releasedBufObj.writingBuf;
10661
10675
  this._len = releasedBufObj.len;
@@ -10671,7 +10685,7 @@ var require_sonic_boom = __commonJS({
10671
10685
  }
10672
10686
  }
10673
10687
  try {
10674
- fs79.fsyncSync(this.fd);
10688
+ fs80.fsyncSync(this.fd);
10675
10689
  } catch {
10676
10690
  }
10677
10691
  }
@@ -10692,7 +10706,7 @@ var require_sonic_boom = __commonJS({
10692
10706
  buf = mergeBuf(this._bufs[0], this._lens[0]);
10693
10707
  }
10694
10708
  try {
10695
- const n = fs79.writeSync(this.fd, buf);
10709
+ const n = fs80.writeSync(this.fd, buf);
10696
10710
  buf = buf.subarray(n);
10697
10711
  this._len = Math.max(this._len - n, 0);
10698
10712
  if (buf.length <= 0) {
@@ -10720,13 +10734,13 @@ var require_sonic_boom = __commonJS({
10720
10734
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
10721
10735
  if (this.sync) {
10722
10736
  try {
10723
- const written = Buffer.isBuffer(this._writingBuf) ? fs79.writeSync(this.fd, this._writingBuf) : fs79.writeSync(this.fd, this._writingBuf, "utf8");
10737
+ const written = Buffer.isBuffer(this._writingBuf) ? fs80.writeSync(this.fd, this._writingBuf) : fs80.writeSync(this.fd, this._writingBuf, "utf8");
10724
10738
  release(null, written);
10725
10739
  } catch (err) {
10726
10740
  release(err);
10727
10741
  }
10728
10742
  } else {
10729
- fs79.write(this.fd, this._writingBuf, release);
10743
+ fs80.write(this.fd, this._writingBuf, release);
10730
10744
  }
10731
10745
  }
10732
10746
  function actualWriteBuffer() {
@@ -10735,7 +10749,7 @@ var require_sonic_boom = __commonJS({
10735
10749
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
10736
10750
  if (this.sync) {
10737
10751
  try {
10738
- const written = fs79.writeSync(this.fd, this._writingBuf);
10752
+ const written = fs80.writeSync(this.fd, this._writingBuf);
10739
10753
  release(null, written);
10740
10754
  } catch (err) {
10741
10755
  release(err);
@@ -10744,7 +10758,7 @@ var require_sonic_boom = __commonJS({
10744
10758
  if (kCopyBuffer) {
10745
10759
  this._writingBuf = Buffer.from(this._writingBuf);
10746
10760
  }
10747
- fs79.write(this.fd, this._writingBuf, release);
10761
+ fs80.write(this.fd, this._writingBuf, release);
10748
10762
  }
10749
10763
  }
10750
10764
  function actualClose(sonic) {
@@ -10760,12 +10774,12 @@ var require_sonic_boom = __commonJS({
10760
10774
  sonic._lens = [];
10761
10775
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
10762
10776
  try {
10763
- fs79.fsync(sonic.fd, closeWrapped);
10777
+ fs80.fsync(sonic.fd, closeWrapped);
10764
10778
  } catch {
10765
10779
  }
10766
10780
  function closeWrapped() {
10767
10781
  if (sonic.fd !== 1 && sonic.fd !== 2) {
10768
- fs79.close(sonic.fd, done);
10782
+ fs80.close(sonic.fd, done);
10769
10783
  } else {
10770
10784
  done();
10771
10785
  }
@@ -13900,11 +13914,11 @@ var init_lib = __esm({
13900
13914
  }
13901
13915
  }
13902
13916
  },
13903
- addToPath: function addToPath(path89, added, removed, oldPosInc, options) {
13904
- var last = path89.lastComponent;
13917
+ addToPath: function addToPath(path90, added, removed, oldPosInc, options) {
13918
+ var last = path90.lastComponent;
13905
13919
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
13906
13920
  return {
13907
- oldPos: path89.oldPos + oldPosInc,
13921
+ oldPos: path90.oldPos + oldPosInc,
13908
13922
  lastComponent: {
13909
13923
  count: last.count + 1,
13910
13924
  added,
@@ -13914,7 +13928,7 @@ var init_lib = __esm({
13914
13928
  };
13915
13929
  } else {
13916
13930
  return {
13917
- oldPos: path89.oldPos + oldPosInc,
13931
+ oldPos: path90.oldPos + oldPosInc,
13918
13932
  lastComponent: {
13919
13933
  count: 1,
13920
13934
  added,
@@ -14468,10 +14482,10 @@ function attachmentToHistoryMessage(o, ts) {
14468
14482
  const memories = raw.map((m2) => {
14469
14483
  if (!m2 || typeof m2 !== "object") return null;
14470
14484
  const rec4 = m2;
14471
- const path89 = typeof rec4.path === "string" ? rec4.path : null;
14485
+ const path90 = typeof rec4.path === "string" ? rec4.path : null;
14472
14486
  const content = typeof rec4.content === "string" ? rec4.content : null;
14473
- if (!path89 || content == null) return null;
14474
- const entry = { path: path89, content };
14487
+ if (!path90 || content == null) return null;
14488
+ const entry = { path: path90, content };
14475
14489
  if (typeof rec4.mtimeMs === "number") entry.mtimeMs = rec4.mtimeMs;
14476
14490
  return entry;
14477
14491
  }).filter((m2) => m2 !== null);
@@ -15338,10 +15352,10 @@ function parseAttachment(obj) {
15338
15352
  const memories = raw.map((m2) => {
15339
15353
  if (!m2 || typeof m2 !== "object") return null;
15340
15354
  const rec4 = m2;
15341
- const path89 = typeof rec4.path === "string" ? rec4.path : null;
15355
+ const path90 = typeof rec4.path === "string" ? rec4.path : null;
15342
15356
  const content = typeof rec4.content === "string" ? rec4.content : null;
15343
- if (!path89 || content == null) return null;
15344
- const out = { path: path89, content };
15357
+ if (!path90 || content == null) return null;
15358
+ const out = { path: path90, content };
15345
15359
  if (typeof rec4.mtimeMs === "number") out.mtimeMs = rec4.mtimeMs;
15346
15360
  return out;
15347
15361
  }).filter((m2) => m2 !== null);
@@ -36315,8 +36329,8 @@ var require_utils = __commonJS({
36315
36329
  var result = transform[inputType][outputType](input);
36316
36330
  return result;
36317
36331
  };
36318
- exports2.resolve = function(path89) {
36319
- var parts = path89.split("/");
36332
+ exports2.resolve = function(path90) {
36333
+ var parts = path90.split("/");
36320
36334
  var result = [];
36321
36335
  for (var index = 0; index < parts.length; index++) {
36322
36336
  var part = parts[index];
@@ -42169,18 +42183,18 @@ var require_object = __commonJS({
42169
42183
  var object = new ZipObject(name, zipObjectContent, o);
42170
42184
  this.files[name] = object;
42171
42185
  };
42172
- var parentFolder = function(path89) {
42173
- if (path89.slice(-1) === "/") {
42174
- path89 = path89.substring(0, path89.length - 1);
42186
+ var parentFolder = function(path90) {
42187
+ if (path90.slice(-1) === "/") {
42188
+ path90 = path90.substring(0, path90.length - 1);
42175
42189
  }
42176
- var lastSlash = path89.lastIndexOf("/");
42177
- return lastSlash > 0 ? path89.substring(0, lastSlash) : "";
42190
+ var lastSlash = path90.lastIndexOf("/");
42191
+ return lastSlash > 0 ? path90.substring(0, lastSlash) : "";
42178
42192
  };
42179
- var forceTrailingSlash = function(path89) {
42180
- if (path89.slice(-1) !== "/") {
42181
- path89 += "/";
42193
+ var forceTrailingSlash = function(path90) {
42194
+ if (path90.slice(-1) !== "/") {
42195
+ path90 += "/";
42182
42196
  }
42183
- return path89;
42197
+ return path90;
42184
42198
  };
42185
42199
  var folderAdd = function(name, createFolders) {
42186
42200
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -43182,7 +43196,7 @@ var require_lib3 = __commonJS({
43182
43196
  // src/run-case/recorder.ts
43183
43197
  function startRunCaseRecorder(opts) {
43184
43198
  const now = opts.now ?? Date.now;
43185
- const dir = import_node_path71.default.dirname(opts.recordPath);
43199
+ const dir = import_node_path72.default.dirname(opts.recordPath);
43186
43200
  let stream = null;
43187
43201
  let closing = false;
43188
43202
  let closedSettled = false;
@@ -43196,8 +43210,8 @@ function startRunCaseRecorder(opts) {
43196
43210
  });
43197
43211
  const ensureStream = () => {
43198
43212
  if (stream) return stream;
43199
- import_node_fs53.default.mkdirSync(dir, { recursive: true });
43200
- stream = import_node_fs53.default.createWriteStream(opts.recordPath, { flags: "a" });
43213
+ import_node_fs54.default.mkdirSync(dir, { recursive: true });
43214
+ stream = import_node_fs54.default.createWriteStream(opts.recordPath, { flags: "a" });
43201
43215
  stream.on("close", () => closedResolve());
43202
43216
  return stream;
43203
43217
  };
@@ -43222,12 +43236,12 @@ function startRunCaseRecorder(opts) {
43222
43236
  };
43223
43237
  return { tap, close, closed };
43224
43238
  }
43225
- var import_node_fs53, import_node_path71;
43239
+ var import_node_fs54, import_node_path72;
43226
43240
  var init_recorder = __esm({
43227
43241
  "src/run-case/recorder.ts"() {
43228
43242
  "use strict";
43229
- import_node_fs53 = __toESM(require("fs"), 1);
43230
- import_node_path71 = __toESM(require("path"), 1);
43243
+ import_node_fs54 = __toESM(require("fs"), 1);
43244
+ import_node_path72 = __toESM(require("path"), 1);
43231
43245
  }
43232
43246
  });
43233
43247
 
@@ -43270,7 +43284,7 @@ var init_wire = __esm({
43270
43284
  // src/run-case/controller.ts
43271
43285
  async function runController(opts) {
43272
43286
  const now = opts.now ?? Date.now;
43273
- const cwd = opts.cwd ?? (0, import_node_fs54.mkdtempSync)(import_node_path72.default.join(import_node_os25.default.tmpdir(), "clawd-runcase-"));
43287
+ const cwd = opts.cwd ?? (0, import_node_fs55.mkdtempSync)(import_node_path73.default.join(import_node_os25.default.tmpdir(), "clawd-runcase-"));
43274
43288
  const ownsCwd = opts.cwd === void 0;
43275
43289
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
43276
43290
  const spawnCtx = { cwd };
@@ -43431,19 +43445,19 @@ async function runController(opts) {
43431
43445
  if (sigintHandler) process.off("SIGINT", sigintHandler);
43432
43446
  if (ownsCwd) {
43433
43447
  try {
43434
- (0, import_node_fs54.rmSync)(cwd, { recursive: true, force: true });
43448
+ (0, import_node_fs55.rmSync)(cwd, { recursive: true, force: true });
43435
43449
  } catch {
43436
43450
  }
43437
43451
  }
43438
43452
  return exitCode ?? 0;
43439
43453
  }
43440
- var import_node_fs54, import_node_os25, import_node_path72;
43454
+ var import_node_fs55, import_node_os25, import_node_path73;
43441
43455
  var init_controller = __esm({
43442
43456
  "src/run-case/controller.ts"() {
43443
43457
  "use strict";
43444
- import_node_fs54 = require("fs");
43458
+ import_node_fs55 = require("fs");
43445
43459
  import_node_os25 = __toESM(require("os"), 1);
43446
- import_node_path72 = __toESM(require("path"), 1);
43460
+ import_node_path73 = __toESM(require("path"), 1);
43447
43461
  init_claude();
43448
43462
  init_stdout_splitter();
43449
43463
  init_permission_stdio();
@@ -43718,8 +43732,8 @@ Env (advanced):
43718
43732
  `;
43719
43733
 
43720
43734
  // src/index.ts
43721
- var import_node_path70 = __toESM(require("path"), 1);
43722
- var import_node_fs52 = __toESM(require("fs"), 1);
43735
+ var import_node_path71 = __toESM(require("path"), 1);
43736
+ var import_node_fs53 = __toESM(require("fs"), 1);
43723
43737
  var import_node_os24 = __toESM(require("os"), 1);
43724
43738
 
43725
43739
  // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
@@ -44789,6 +44803,21 @@ var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A perso
44789
44803
 
44790
44804
  \u7528\u6237\u5BF9\u4E00\u4EF6**\u5DF2\u59D4\u6D3E**\u7684\u4E8B\u4E0B\u540E\u7EED\u6307\u4EE4\u65F6\uFF0C\u8C03 \`personaDispatch({ dispatchId: <\u8BE5\u4E8B\u7684 dispatchId>, prompt: <\u65B0\u6307\u4EE4> })\`\uFF08targetPersona \u53EF\u7701\u7565\uFF09\u2014\u2014\u65B0\u6307\u4EE4\u4F1A\u8FDB\u5165\u539F worker session \u63A5\u7740\u5E72\uFF0C\u4E0A\u4E0B\u6587\u4E0D\u4E22\u3002dispatchId \u7528\u4F60\u9996\u6B21\u59D4\u6D3E\u65F6\u62FF\u5230\u7684\u90A3\u4E2A\uFF1B\u4E0D\u786E\u5B9A\u662F\u54EA\u4EF6\u4E8B\u5C31\u5148\u8C03 \`personaDispatchList\` \u67E5\u3002
44791
44805
 
44806
+ ### \u4E34\u65F6\u6362 engine / \u6A21\u578B\uFF08\u4E00\u6B21\u6027\uFF0C\u4E0D\u6539 persona \u7ED1\u5B9A\uFF09
44807
+
44808
+ \u60F3\u8BA9\u8FD9\u6B21\u4EFB\u52A1\u8DD1\u5728\u522B\u7684 engine \u6216\u6A21\u578B\u4E0A\uFF08\u4F8B\u5982\u300C\u7528 Codex \u7684 gpt-5.6-sol \u505A\u8FD9\u4E2A\u5F00\u53D1\u300D\uFF09\uFF0C\u52A0\u4E24\u4E2A\u53C2\u6570\uFF1A
44809
+
44810
+ - \`tool = 'codex' | 'claude'\` \u2014\u2014 \u8FD9\u4E00\u6761 dispatch \u7528\u54EA\u4E2A engine
44811
+ - \`model = <\u8BE5 engine \u7684\u6A21\u578B id>\` \u2014\u2014 \u4F8B\u5982 codex \u7684 \`gpt-5.6-sol\`\u3001claude \u7684 \`opus\`
44812
+
44813
+ **model \u7684\u5408\u6CD5\u503C\u96C6\u4ECE\u5C5E\u4E8E engine**\uFF1A\u7ED9\u4E00\u4E2A claude persona \u4F20 codex \u7684\u6A21\u578B\u65F6**\u5FC5\u987B\u540C\u65F6\u4F20 \`tool='codex'\`**\uFF0C
44814
+ \u5426\u5219\u6309 persona \u7ED1\u5B9A\u7684 engine \u9009\u8868\u6821\u9A8C\u3001\u76F4\u63A5\u88AB\u62D2\u3002\u4E24\u8005\u90FD\u4E0D\u4F20 = \u5B8C\u5168\u8DDF\u968F\u76EE\u6807 persona \u7684\u914D\u7F6E\uFF08\u9ED8\u8BA4\u884C\u4E3A\uFF09\u3002
44815
+
44816
+ \u4E00\u6B21\u6027\u8BED\u4E49\uFF1A\u76EE\u6807 persona \u81EA\u5DF1\u7684\u7ED1\u5B9A\u4E0D\u53D8\uFF0C\u53EA\u6709\u8FD9\u6761 dispatch \u8D77\u7684 worker session \u53D7\u5F71\u54CD\u3002
44817
+ \u8FD9\u4E24\u4E2A\u53C2\u6570**\u53EA\u80FD\u5728\u65B0\u5F00 dispatch \u65F6\u7528**\uFF1A\u7EED\u6D3E\uFF08\u5E26 dispatchId\uFF09\u53EA\u662F\u5F80\u5DF2\u7ECF\u8DD1\u7740\u7684 worker session \u6295\u65B0\u4E00\u8F6E
44818
+ \u6307\u4EE4\u3001\u4E0D\u91CD\u65B0\u8D77\u8FDB\u7A0B\uFF0C\u6240\u4EE5\u5E26 \`tool\` / \`model\` \u4F1A\u88AB\u76F4\u63A5\u62D2 \u2014\u2014 \u8981\u6362\u5C31\u65B0\u5F00\u4E00\u6761 dispatch\u3002\u8DE8\u8BBE\u5907\u59D4\u6D3E\u4E5F\u4E0D
44819
+ \u652F\u6301\u6362 engine\uFF08\u8FDC\u7AEF persona \u7528\u54EA\u4E2A engine \u7531\u90A3\u53F0\u673A\u5668\u7684\u4E3B\u4EBA\u51B3\u5B9A\uFF09\u3002
44820
+
44792
44821
  ### \u8DE8\u8BBE\u5907\u59D4\u6D3E\uFF08remote persona\uFF09
44793
44822
 
44794
44823
  \u5F53 @ token \u5F62\u5982 \`@persona/<id>@<deviceId>\`\uFF08\u7B2C\u4E8C\u6BB5\u662F\u8054\u7CFB\u4EBA**\u8BBE\u5907\u7684 deviceId**\uFF0CUI \u9009\u8054\u7CFB\u4EBA\u65F6\u5DF2\u89E3\u6790\u597D\u586B\u5165\uFF09\u65F6\uFF0C\u662F\u628A\u4EFB\u52A1\u59D4\u6D3E\u7ED9\u90A3\u53F0\u8BBE\u5907\u4E0A\u7684 persona\u3002\u9664 targetPersona / prompt \u5916\u518D\u5E26\uFF1A
@@ -47810,12 +47839,14 @@ var SessionManager = class {
47810
47839
  const cwd = import_node_path9.default.join(this.deps.personaRoot, safeFileName(args.targetPersona));
47811
47840
  const now = (/* @__PURE__ */ new Date()).toISOString();
47812
47841
  const personaDefaults = this.deps.getPersonaDefaults?.(args.targetPersona);
47842
+ const effectiveTool = args.tool ?? personaDefaults?.tool ?? "claude";
47843
+ const engineOverridden = effectiveTool !== (personaDefaults?.tool ?? "claude");
47813
47844
  const file = {
47814
47845
  sessionId,
47815
47846
  cwd,
47816
47847
  // dispatch B session 跟随 persona 绑定的 tool(codex persona 用 codex spawn);
47817
- // UI 手建路径另允许通过 session:create 显式覆盖。
47818
- tool: personaDefaults?.tool ?? "claude",
47848
+ // UI 手建路径另允许通过 session:create 显式覆盖,dispatch 走 args.tool 一次性 override。
47849
+ tool: effectiveTool,
47819
47850
  ownerPersonaId: args.targetPersona,
47820
47851
  dispatchedFromSessionId: args.sourceSessionId,
47821
47852
  // 跨设备显示关键(spec §8):creatorPrincipalId = A 的 deviceId,让 A 的
@@ -47829,7 +47860,8 @@ var SessionManager = class {
47829
47860
  } : {},
47830
47861
  // T-20 的 dispatch model override 优先;缺省回落 persona 默认值(spec 2026-08-12)。
47831
47862
  // effort 没有 override 参数(续派也不允许改),直接取 persona 默认值。
47832
- ...personaDefaultFields(personaDefaults, args.model),
47863
+ // engine 被 override 掉时 persona 的 model / effort 一概不继承(见 engineOverridden)。
47864
+ ...personaDefaultFields(engineOverridden ? void 0 : personaDefaults, args.model),
47833
47865
  // butler 顶部入口:dispatch 传下来的 label 落盘,sidebar 显示(否则兜底 cwd-basename)
47834
47866
  ...args.label ? { label: args.label } : {},
47835
47867
  createdAt: now,
@@ -50136,11 +50168,11 @@ init_claude();
50136
50168
 
50137
50169
  // src/tools/codex.ts
50138
50170
  var import_node_child_process6 = require("child_process");
50139
- var import_node_fs18 = __toESM(require("fs"), 1);
50171
+ var import_node_fs19 = __toESM(require("fs"), 1);
50140
50172
 
50141
50173
  // src/tools/codex-session.ts
50142
50174
  var import_node_child_process4 = require("child_process");
50143
- var import_node_path16 = __toESM(require("path"), 1);
50175
+ var import_node_path17 = __toESM(require("path"), 1);
50144
50176
 
50145
50177
  // src/tools/codex-app-server-client.ts
50146
50178
  var import_node_readline = require("readline");
@@ -50573,6 +50605,19 @@ function codexMcpCliArgs(defs) {
50573
50605
  }
50574
50606
  return out;
50575
50607
  }
50608
+ function codexAgentsCliArgs(cfg) {
50609
+ const out = [];
50610
+ if (cfg.defaultSubagentModel) {
50611
+ out.push("-c", `agents.default_subagent_model=${tomlValue(cfg.defaultSubagentModel)}`);
50612
+ }
50613
+ if (cfg.defaultSubagentReasoningEffort) {
50614
+ out.push(
50615
+ "-c",
50616
+ `agents.default_subagent_reasoning_effort=${tomlValue(cfg.defaultSubagentReasoningEffort)}`
50617
+ );
50618
+ }
50619
+ return out;
50620
+ }
50576
50621
  function threadStartParams(ctx) {
50577
50622
  const params = {
50578
50623
  cwd: ctx.cwd,
@@ -50596,8 +50641,8 @@ function turnStartInput(text) {
50596
50641
  const items = [];
50597
50642
  let leftover = text;
50598
50643
  for (const m2 of text.matchAll(SKILL_RE)) {
50599
- const [marker, name, path89] = m2;
50600
- items.push({ type: "skill", name, path: path89 });
50644
+ const [marker, name, path90] = m2;
50645
+ items.push({ type: "skill", name, path: path90 });
50601
50646
  leftover = leftover.replace(marker, "");
50602
50647
  }
50603
50648
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -50665,6 +50710,35 @@ function loadCodexMcpServerDefs(args) {
50665
50710
  return out;
50666
50711
  }
50667
50712
 
50713
+ // src/tools/codex-agents-config.ts
50714
+ var import_node_fs18 = __toESM(require("fs"), 1);
50715
+ var import_node_path16 = __toESM(require("path"), 1);
50716
+ var AGENTS_SECTION = /^\[agents\][^\n]*\n([\s\S]*?)(?=^\[|$(?![\s\S]))/m;
50717
+ function readKey(section, key) {
50718
+ const m2 = new RegExp(`^[ \\t]*${key}[ \\t]*=[ \\t]*(["'])(.*?)\\1`, "m").exec(section);
50719
+ return m2?.[2].trim() || void 0;
50720
+ }
50721
+ function loadCodexAgentsConfig(args) {
50722
+ const file = import_node_path16.default.join(args.cwd, ".codex", "config.toml");
50723
+ let text;
50724
+ try {
50725
+ text = import_node_fs18.default.readFileSync(file, "utf8");
50726
+ } catch (e) {
50727
+ const code = e.code;
50728
+ if (code !== "ENOENT") {
50729
+ args.logger?.warn("codex agents config unreadable, skipped", { file, code: code ?? "read-error" });
50730
+ }
50731
+ return {};
50732
+ }
50733
+ const section = AGENTS_SECTION.exec(text)?.[1] ?? "";
50734
+ const model = readKey(section, "default_subagent_model");
50735
+ const effort = readKey(section, "default_subagent_reasoning_effort");
50736
+ return {
50737
+ ...model ? { defaultSubagentModel: model } : {},
50738
+ ...effort ? { defaultSubagentReasoningEffort: effort } : {}
50739
+ };
50740
+ }
50741
+
50668
50742
  // src/tools/codex-features.ts
50669
50743
  var import_node_child_process3 = require("child_process");
50670
50744
  var cachedNetworkProxy;
@@ -50726,6 +50800,7 @@ function createCodexSession(ctx, sink, deps = {}) {
50726
50800
  })
50727
50801
  )
50728
50802
  );
50803
+ args.push(...codexAgentsCliArgs(loadCodexAgentsConfig({ cwd: ctx.cwd, logger: deps.logger })));
50729
50804
  const resolvedCodexHome = deps.codexHomeFor?.(ctx.cwd);
50730
50805
  const env = {
50731
50806
  ...process.env,
@@ -50805,7 +50880,7 @@ function createCodexSession(ctx, sink, deps = {}) {
50805
50880
  capabilities: null
50806
50881
  });
50807
50882
  client.notify("initialized", {});
50808
- void client.request("skills/extraRoots/set", { extraRoots: [import_node_path16.default.join(ctx.cwd, ".claude", "skills")] }).catch((e) => deps.logger?.warn("codex skills/extraRoots/set failed", { message: e.message }));
50883
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path17.default.join(ctx.cwd, ".claude", "skills")] }).catch((e) => deps.logger?.warn("codex skills/extraRoots/set failed", { message: e.message }));
50809
50884
  if (threadId) {
50810
50885
  await client.request("thread/resume", { threadId, ...threadStartParams(ctx) });
50811
50886
  } else {
@@ -51023,10 +51098,10 @@ function sanitizeCodexModel(model) {
51023
51098
  return model;
51024
51099
  }
51025
51100
  async function probeCodex(env = process.env) {
51026
- if (env.CODEX_BIN && import_node_fs18.default.existsSync(env.CODEX_BIN)) return { available: true, path: env.CODEX_BIN };
51101
+ if (env.CODEX_BIN && import_node_fs19.default.existsSync(env.CODEX_BIN)) return { available: true, path: env.CODEX_BIN };
51027
51102
  try {
51028
51103
  const out = (0, import_node_child_process6.execFileSync)("which", ["codex"], { encoding: "utf8" }).trim();
51029
- if (out && import_node_fs18.default.existsSync(out)) return { available: true, path: out };
51104
+ if (out && import_node_fs19.default.existsSync(out)) return { available: true, path: out };
51030
51105
  } catch {
51031
51106
  }
51032
51107
  return { available: false };
@@ -51099,9 +51174,9 @@ var CodexAdapter = class {
51099
51174
 
51100
51175
  // src/tools/claude-tui.ts
51101
51176
  var import_node_crypto5 = require("crypto");
51102
- var import_node_fs19 = __toESM(require("fs"), 1);
51177
+ var import_node_fs20 = __toESM(require("fs"), 1);
51103
51178
  var import_node_os7 = __toESM(require("os"), 1);
51104
- var import_node_path17 = __toESM(require("path"), 1);
51179
+ var import_node_path18 = __toESM(require("path"), 1);
51105
51180
  var import_headless = __toESM(require_xterm_headless(), 1);
51106
51181
 
51107
51182
  // ../node_modules/.pnpm/@xterm+addon-serialize@0.14.0/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs
@@ -52336,9 +52411,9 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
52336
52411
  function jsonlExistsForCtx(ctx) {
52337
52412
  if (!ctx.toolSessionId) return false;
52338
52413
  const home = import_node_os7.default.homedir();
52339
- const file = import_node_path17.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
52414
+ const file = import_node_path18.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
52340
52415
  try {
52341
- return import_node_fs19.default.statSync(file).isFile();
52416
+ return import_node_fs20.default.statSync(file).isFile();
52342
52417
  } catch {
52343
52418
  return false;
52344
52419
  }
@@ -52417,7 +52492,7 @@ var PersonaDispatchManager = class {
52417
52492
 
52418
52493
  // src/dispatch/store.ts
52419
52494
  var import_promises = __toESM(require("fs/promises"), 1);
52420
- var import_node_path18 = __toESM(require("path"), 1);
52495
+ var import_node_path19 = __toESM(require("path"), 1);
52421
52496
 
52422
52497
  // src/shift/constants.ts
52423
52498
  var MAX_RUNS_PER_SHIFT = 30;
@@ -52455,7 +52530,7 @@ function createDispatchStore(deps) {
52455
52530
  flushTimer = null;
52456
52531
  }
52457
52532
  const content = { version: 1, records };
52458
- await import_promises.default.mkdir(import_node_path18.default.dirname(deps.filePath), { recursive: true });
52533
+ await import_promises.default.mkdir(import_node_path19.default.dirname(deps.filePath), { recursive: true });
52459
52534
  const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
52460
52535
  await import_promises.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
52461
52536
  await import_promises.default.rename(tmp, deps.filePath);
@@ -52518,7 +52593,7 @@ function createDispatchStore(deps) {
52518
52593
 
52519
52594
  // src/channel/json-store.ts
52520
52595
  var import_promises2 = __toESM(require("fs/promises"), 1);
52521
- var import_node_path19 = __toESM(require("path"), 1);
52596
+ var import_node_path20 = __toESM(require("path"), 1);
52522
52597
  function createJsonStore(deps) {
52523
52598
  let items = [];
52524
52599
  let flushTimer = null;
@@ -52528,7 +52603,7 @@ function createJsonStore(deps) {
52528
52603
  flushTimer = null;
52529
52604
  }
52530
52605
  const content = { version: 1, [deps.key]: items };
52531
- await import_promises2.default.mkdir(import_node_path19.default.dirname(deps.filePath), { recursive: true });
52606
+ await import_promises2.default.mkdir(import_node_path20.default.dirname(deps.filePath), { recursive: true });
52532
52607
  const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
52533
52608
  await import_promises2.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
52534
52609
  await import_promises2.default.rename(tmp, deps.filePath);
@@ -52709,10 +52784,10 @@ function createTopicStore(deps) {
52709
52784
  }
52710
52785
 
52711
52786
  // src/dispatch/mcp-config.ts
52712
- var import_node_fs20 = __toESM(require("fs"), 1);
52713
- var import_node_path20 = __toESM(require("path"), 1);
52787
+ var import_node_fs21 = __toESM(require("fs"), 1);
52788
+ var import_node_path21 = __toESM(require("path"), 1);
52714
52789
  function dispatchMcpConfigPath(dataDir) {
52715
- return import_node_path20.default.join(dataDir, "dispatch.mcp.json");
52790
+ return import_node_path21.default.join(dataDir, "dispatch.mcp.json");
52716
52791
  }
52717
52792
  function writeDispatchMcpConfig(args) {
52718
52793
  const cfgPath = dispatchMcpConfigPath(args.dataDir);
@@ -52731,16 +52806,16 @@ function writeDispatchMcpConfig(args) {
52731
52806
  }
52732
52807
  }
52733
52808
  };
52734
- import_node_fs20.default.mkdirSync(args.dataDir, { recursive: true });
52735
- import_node_fs20.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
52809
+ import_node_fs21.default.mkdirSync(args.dataDir, { recursive: true });
52810
+ import_node_fs21.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
52736
52811
  return cfgPath;
52737
52812
  }
52738
52813
 
52739
52814
  // src/ticket/mcp-config.ts
52740
- var import_node_fs21 = __toESM(require("fs"), 1);
52741
- var import_node_path21 = __toESM(require("path"), 1);
52815
+ var import_node_fs22 = __toESM(require("fs"), 1);
52816
+ var import_node_path22 = __toESM(require("path"), 1);
52742
52817
  function ticketMcpConfigPath(dataDir) {
52743
- return import_node_path21.default.join(dataDir, "ticket.mcp.json");
52818
+ return import_node_path22.default.join(dataDir, "ticket.mcp.json");
52744
52819
  }
52745
52820
  function writeTicketMcpConfig(args) {
52746
52821
  const cfgPath = ticketMcpConfigPath(args.dataDir);
@@ -52762,16 +52837,16 @@ function writeTicketMcpConfig(args) {
52762
52837
  }
52763
52838
  }
52764
52839
  };
52765
- import_node_fs21.default.mkdirSync(args.dataDir, { recursive: true });
52766
- import_node_fs21.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
52840
+ import_node_fs22.default.mkdirSync(args.dataDir, { recursive: true });
52841
+ import_node_fs22.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
52767
52842
  return cfgPath;
52768
52843
  }
52769
52844
 
52770
52845
  // src/shift/mcp-config.ts
52771
- var import_node_fs22 = __toESM(require("fs"), 1);
52772
- var import_node_path22 = __toESM(require("path"), 1);
52846
+ var import_node_fs23 = __toESM(require("fs"), 1);
52847
+ var import_node_path23 = __toESM(require("path"), 1);
52773
52848
  function shiftMcpConfigPath(dataDir) {
52774
- return import_node_path22.default.join(dataDir, "shift.mcp.json");
52849
+ return import_node_path23.default.join(dataDir, "shift.mcp.json");
52775
52850
  }
52776
52851
  async function writeShiftMcpConfig(args) {
52777
52852
  const cfgPath = shiftMcpConfigPath(args.dataDir);
@@ -52790,16 +52865,16 @@ async function writeShiftMcpConfig(args) {
52790
52865
  }
52791
52866
  }
52792
52867
  };
52793
- await import_node_fs22.default.promises.mkdir(args.dataDir, { recursive: true });
52794
- await import_node_fs22.default.promises.writeFile(cfgPath, JSON.stringify(content, null, 2), "utf8");
52868
+ await import_node_fs23.default.promises.mkdir(args.dataDir, { recursive: true });
52869
+ await import_node_fs23.default.promises.writeFile(cfgPath, JSON.stringify(content, null, 2), "utf8");
52795
52870
  return cfgPath;
52796
52871
  }
52797
52872
 
52798
52873
  // src/inbox/mcp-config.ts
52799
- var import_node_fs23 = __toESM(require("fs"), 1);
52800
- var import_node_path23 = __toESM(require("path"), 1);
52874
+ var import_node_fs24 = __toESM(require("fs"), 1);
52875
+ var import_node_path24 = __toESM(require("path"), 1);
52801
52876
  function inboxMcpConfigPath(dataDir) {
52802
- return import_node_path23.default.join(dataDir, "inbox.mcp.json");
52877
+ return import_node_path24.default.join(dataDir, "inbox.mcp.json");
52803
52878
  }
52804
52879
  async function writeInboxMcpConfig(args) {
52805
52880
  const cfgPath = inboxMcpConfigPath(args.dataDir);
@@ -52818,16 +52893,16 @@ async function writeInboxMcpConfig(args) {
52818
52893
  }
52819
52894
  }
52820
52895
  };
52821
- await import_node_fs23.default.promises.mkdir(args.dataDir, { recursive: true });
52822
- await import_node_fs23.default.promises.writeFile(cfgPath, JSON.stringify(content, null, 2), "utf8");
52896
+ await import_node_fs24.default.promises.mkdir(args.dataDir, { recursive: true });
52897
+ await import_node_fs24.default.promises.writeFile(cfgPath, JSON.stringify(content, null, 2), "utf8");
52823
52898
  return cfgPath;
52824
52899
  }
52825
52900
 
52826
52901
  // src/peer-ops/mcp-config.ts
52827
- var import_node_fs24 = __toESM(require("fs"), 1);
52828
- var import_node_path24 = __toESM(require("path"), 1);
52902
+ var import_node_fs25 = __toESM(require("fs"), 1);
52903
+ var import_node_path25 = __toESM(require("path"), 1);
52829
52904
  function peerOpsMcpConfigPath(dataDir) {
52830
- return import_node_path24.default.join(dataDir, "peer-ops.mcp.json");
52905
+ return import_node_path25.default.join(dataDir, "peer-ops.mcp.json");
52831
52906
  }
52832
52907
  function writePeerOpsMcpConfig(args) {
52833
52908
  const cfgPath = peerOpsMcpConfigPath(args.dataDir);
@@ -52844,16 +52919,16 @@ function writePeerOpsMcpConfig(args) {
52844
52919
  }
52845
52920
  }
52846
52921
  };
52847
- import_node_fs24.default.mkdirSync(args.dataDir, { recursive: true });
52848
- import_node_fs24.default.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
52922
+ import_node_fs25.default.mkdirSync(args.dataDir, { recursive: true });
52923
+ import_node_fs25.default.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
52849
52924
  return cfgPath;
52850
52925
  }
52851
52926
 
52852
52927
  // src/rpc-tool/mcp-config.ts
52853
- var import_node_fs25 = __toESM(require("fs"), 1);
52854
- var import_node_path25 = __toESM(require("path"), 1);
52928
+ var import_node_fs26 = __toESM(require("fs"), 1);
52929
+ var import_node_path26 = __toESM(require("path"), 1);
52855
52930
  function rpcToolMcpConfigPath(dataDir) {
52856
- return import_node_path25.default.join(dataDir, "rpc-tool.mcp.json");
52931
+ return import_node_path26.default.join(dataDir, "rpc-tool.mcp.json");
52857
52932
  }
52858
52933
  function writeRpcToolMcpConfig(args) {
52859
52934
  const cfgPath = rpcToolMcpConfigPath(args.dataDir);
@@ -52872,18 +52947,18 @@ function writeRpcToolMcpConfig(args) {
52872
52947
  }
52873
52948
  }
52874
52949
  };
52875
- import_node_fs25.default.mkdirSync(args.dataDir, { recursive: true });
52876
- import_node_fs25.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
52950
+ import_node_fs26.default.mkdirSync(args.dataDir, { recursive: true });
52951
+ import_node_fs26.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
52877
52952
  return cfgPath;
52878
52953
  }
52879
52954
 
52880
52955
  // src/dispatch/source-transcript.ts
52881
- var import_node_path26 = __toESM(require("path"), 1);
52956
+ var import_node_path27 = __toESM(require("path"), 1);
52882
52957
  init_claude_history();
52883
52958
  var NO_SOURCE_TRANSCRIPT = "(no transcript yet \u2014 operate from the task description alone)";
52884
52959
  function resolveSourceJsonlPath(sourceFile, home) {
52885
52960
  if (!sourceFile?.toolSessionId) return NO_SOURCE_TRANSCRIPT;
52886
- return import_node_path26.default.join(
52961
+ return import_node_path27.default.join(
52887
52962
  home,
52888
52963
  ".claude",
52889
52964
  "projects",
@@ -52894,7 +52969,7 @@ function resolveSourceJsonlPath(sourceFile, home) {
52894
52969
 
52895
52970
  // src/shift/store.ts
52896
52971
  var import_promises3 = __toESM(require("fs/promises"), 1);
52897
- var import_node_path27 = __toESM(require("path"), 1);
52972
+ var import_node_path28 = __toESM(require("path"), 1);
52898
52973
  var import_node_crypto6 = require("crypto");
52899
52974
 
52900
52975
  // src/shift/schedule.ts
@@ -52969,7 +53044,7 @@ function createShiftStore(deps) {
52969
53044
  flushTimer = null;
52970
53045
  }
52971
53046
  const content = { version: 1, shifts };
52972
- await import_promises3.default.mkdir(import_node_path27.default.dirname(deps.filePath), { recursive: true });
53047
+ await import_promises3.default.mkdir(import_node_path28.default.dirname(deps.filePath), { recursive: true });
52973
53048
  const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
52974
53049
  await import_promises3.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
52975
53050
  await import_promises3.default.rename(tmp, deps.filePath);
@@ -53637,15 +53712,15 @@ async function refreshTunnelUrlOnStartup(deps) {
53637
53712
  }
53638
53713
 
53639
53714
  // src/lark-bot-connector/binding-store.ts
53640
- var import_node_fs26 = __toESM(require("fs"), 1);
53641
- var import_node_path28 = __toESM(require("path"), 1);
53715
+ var import_node_fs27 = __toESM(require("fs"), 1);
53716
+ var import_node_path29 = __toESM(require("path"), 1);
53642
53717
  function createLarkBotBindingStore(personaRoot) {
53643
- const filePath = (personaId2) => import_node_path28.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
53718
+ const filePath = (personaId2) => import_node_path29.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
53644
53719
  const read = (personaId2) => {
53645
53720
  const file = filePath(personaId2);
53646
- if (!import_node_fs26.default.existsSync(file)) return null;
53721
+ if (!import_node_fs27.default.existsSync(file)) return null;
53647
53722
  try {
53648
- const raw = JSON.parse(import_node_fs26.default.readFileSync(file, "utf8"));
53723
+ const raw = JSON.parse(import_node_fs27.default.readFileSync(file, "utf8"));
53649
53724
  if (typeof raw?.appId !== "string" || raw.appId.length === 0) return null;
53650
53725
  return raw;
53651
53726
  } catch {
@@ -53654,16 +53729,16 @@ function createLarkBotBindingStore(personaRoot) {
53654
53729
  };
53655
53730
  const write = (personaId2, meta) => {
53656
53731
  const file = filePath(personaId2);
53657
- import_node_fs26.default.mkdirSync(import_node_path28.default.dirname(file), { recursive: true });
53732
+ import_node_fs27.default.mkdirSync(import_node_path29.default.dirname(file), { recursive: true });
53658
53733
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
53659
- import_node_fs26.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
53660
- import_node_fs26.default.renameSync(tmp, file);
53734
+ import_node_fs27.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
53735
+ import_node_fs27.default.renameSync(tmp, file);
53661
53736
  };
53662
53737
  return {
53663
53738
  read,
53664
53739
  write,
53665
53740
  remove(personaId2) {
53666
- import_node_fs26.default.rmSync(filePath(personaId2), { force: true });
53741
+ import_node_fs27.default.rmSync(filePath(personaId2), { force: true });
53667
53742
  },
53668
53743
  addRemovedChat(personaId2, chatId) {
53669
53744
  const meta = read(personaId2);
@@ -53817,8 +53892,8 @@ function createLarkBotCloudClient(opts) {
53817
53892
  }
53818
53893
 
53819
53894
  // src/lark-bot-connector/chat-router.ts
53820
- var import_node_fs27 = __toESM(require("fs"), 1);
53821
- var import_node_path29 = __toESM(require("path"), 1);
53895
+ var import_node_fs28 = __toESM(require("fs"), 1);
53896
+ var import_node_path30 = __toESM(require("path"), 1);
53822
53897
  init_protocol();
53823
53898
  var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
53824
53899
  var LOCAL_TURN_RETRIES = 2;
@@ -53883,9 +53958,9 @@ function createLarkChatRouter(deps) {
53883
53958
  continue;
53884
53959
  }
53885
53960
  const dir = deps.mediaRootFor(env.chatId);
53886
- import_node_fs27.default.mkdirSync(dir, { recursive: true });
53887
- const p2 = import_node_path29.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}.${ext}`);
53888
- import_node_fs27.default.writeFileSync(p2, r.data);
53961
+ import_node_fs28.default.mkdirSync(dir, { recursive: true });
53962
+ const p2 = import_node_path30.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}.${ext}`);
53963
+ import_node_fs28.default.writeFileSync(p2, r.data);
53889
53964
  lines.push(`[\u56FE\u7247: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
53890
53965
  } catch (err) {
53891
53966
  deps.logger?.warn(`larkBot image fetch failed ${key}: ${err.message}`);
@@ -53906,9 +53981,9 @@ function createLarkChatRouter(deps) {
53906
53981
  continue;
53907
53982
  }
53908
53983
  const dir = deps.mediaRootFor(env.chatId);
53909
- import_node_fs27.default.mkdirSync(dir, { recursive: true });
53910
- const p2 = import_node_path29.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}-${safeAttachmentName(f.name)}`);
53911
- import_node_fs27.default.writeFileSync(p2, r.data);
53984
+ import_node_fs28.default.mkdirSync(dir, { recursive: true });
53985
+ const p2 = import_node_path30.default.join(dir, `${safeMediaName(ownerMessageId)}-${i}-${safeAttachmentName(f.name)}`);
53986
+ import_node_fs28.default.writeFileSync(p2, r.data);
53912
53987
  lines.push(`[\u6587\u4EF6: ${p2}]\uFF08\u7528 Read \u5DE5\u5177\u67E5\u770B\uFF09`);
53913
53988
  } catch (err) {
53914
53989
  deps.logger?.warn(`larkBot file fetch failed ${f.key}: ${err.message}`);
@@ -54227,16 +54302,11 @@ function buildPersonaDispatchHandlers(deps) {
54227
54302
  });
54228
54303
  }
54229
54304
  const args = DispatchRunArgsSchema.parse(rest);
54230
- if (args.model !== void 0) {
54231
- const targetPersona2 = args.targetPersona ?? (args.dispatchId ? deps.store.get(args.dispatchId)?.targetPersonaId : void 0);
54232
- const targetTool = (targetPersona2 ? deps.getPersonaDefaults?.(targetPersona2)?.tool : void 0) ?? "claude";
54233
- const allowed = targetTool === "codex" ? ((await deps.getCapabilities?.("codex"))?.models ?? []).map((m2) => m2.id).filter((id) => id !== "") : CLAUDE_MODEL_IDS;
54234
- if (!allowed.includes(args.model)) {
54235
- throw new ClawdError(
54236
- ERROR_CODES.INVALID_PARAM,
54237
- `model '${args.model}' not supported for tool '${targetTool}'; allowed: ${allowed.join(", ")}`
54238
- );
54239
- }
54305
+ if (args.tool !== void 0 && ctx?.principal.kind === "guest") {
54306
+ throw new ClawdError(
54307
+ ERROR_CODES.UNAUTHORIZED,
54308
+ "engine override cannot be requested by a guest"
54309
+ );
54240
54310
  }
54241
54311
  if (args.dispatchId) {
54242
54312
  if (ctx?.principal.kind === "guest") {
@@ -54304,6 +54374,19 @@ function buildPersonaDispatchHandlers(deps) {
54304
54374
  if (!targetPersona) {
54305
54375
  throw new ClawdError(ERROR_CODES.INVALID_PARAM, "targetPersona is required for a new dispatch");
54306
54376
  }
54377
+ const effectiveTool = args.tool ?? deps.getPersonaDefaults?.(targetPersona)?.tool ?? "claude";
54378
+ if (args.tool !== void 0 && deps.getCapabilities) {
54379
+ await deps.getCapabilities(args.tool);
54380
+ }
54381
+ if (args.model !== void 0) {
54382
+ const allowed = effectiveTool === "codex" ? ((await deps.getCapabilities?.("codex"))?.models ?? []).map((m2) => m2.id).filter((id) => id !== "") : CLAUDE_MODEL_IDS;
54383
+ if (!allowed.includes(args.model)) {
54384
+ throw new ClawdError(
54385
+ ERROR_CODES.INVALID_PARAM,
54386
+ `model '${args.model}' not supported for tool '${effectiveTool}'; allowed: ${allowed.join(", ")}`
54387
+ );
54388
+ }
54389
+ }
54307
54390
  if (args.targetDeviceId) {
54308
54391
  if (ctx?.principal.kind === "guest") {
54309
54392
  throw new ClawdError(
@@ -54402,6 +54485,8 @@ function buildPersonaDispatchHandlers(deps) {
54402
54485
  targetPersona,
54403
54486
  prompt: args.prompt,
54404
54487
  ...args.model ? { model: args.model } : {},
54488
+ // 一次性 engine override(spec 2026-08-24):只有本机 owner 入口能带(guest 已在上方拒)
54489
+ ...args.tool ? { tool: args.tool } : {},
54405
54490
  // butler 顶部入口(spec 2026-07-27):sessionLabel 落到 SessionFile.label 让 sidebar 显示
54406
54491
  ...args.sessionLabel ? { label: args.sessionLabel } : {}
54407
54492
  }).then(() => {
@@ -54938,7 +55023,7 @@ var CodexHistoryReader = class {
54938
55023
  };
54939
55024
 
54940
55025
  // src/tools/codex-skills.ts
54941
- var import_node_path30 = __toESM(require("path"), 1);
55026
+ var import_node_path31 = __toESM(require("path"), 1);
54942
55027
  function str3(v2) {
54943
55028
  return typeof v2 === "string" ? v2 : void 0;
54944
55029
  }
@@ -54953,13 +55038,13 @@ function mapSkillsListResponse(res) {
54953
55038
  const r = s ?? {};
54954
55039
  const name = str3(r.name);
54955
55040
  if (!name) continue;
54956
- const path89 = str3(r.path);
55041
+ const path90 = str3(r.path);
54957
55042
  const description = str3(r.description);
54958
55043
  const isPlugin = name.includes(":");
54959
55044
  out.push({
54960
55045
  name,
54961
55046
  source: isPlugin ? "plugin" : "project",
54962
- ...path89 ? { path: path89 } : {},
55047
+ ...path90 ? { path: path90 } : {},
54963
55048
  ...description ? { description } : {},
54964
55049
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
54965
55050
  });
@@ -54975,7 +55060,7 @@ async function listCodexSkills(cwd, deps = {}) {
54975
55060
  // 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
54976
55061
  // codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
54977
55062
  beforeRequest: (client) => {
54978
- void client.request("skills/extraRoots/set", { extraRoots: [import_node_path30.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
55063
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path31.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
54979
55064
  }
54980
55065
  });
54981
55066
  return mapSkillsListResponse(res);
@@ -55060,23 +55145,23 @@ function str4(v2) {
55060
55145
  }
55061
55146
 
55062
55147
  // src/workspace/browser.ts
55063
- var import_node_fs28 = __toESM(require("fs"), 1);
55148
+ var import_node_fs29 = __toESM(require("fs"), 1);
55064
55149
  var import_node_os8 = __toESM(require("os"), 1);
55065
- var import_node_path31 = __toESM(require("path"), 1);
55150
+ var import_node_path32 = __toESM(require("path"), 1);
55066
55151
  init_protocol();
55067
55152
  var MAX_FILE_BYTES2 = 2 * 1024 * 1024;
55068
55153
  function resolveInsideCwd(cwd, subpath) {
55069
- const absCwd = import_node_path31.default.resolve(cwd);
55070
- const joined = import_node_path31.default.resolve(absCwd, subpath ?? ".");
55071
- const rel = import_node_path31.default.relative(absCwd, joined);
55072
- if (rel.startsWith("..") || import_node_path31.default.isAbsolute(rel)) {
55154
+ const absCwd = import_node_path32.default.resolve(cwd);
55155
+ const joined = import_node_path32.default.resolve(absCwd, subpath ?? ".");
55156
+ const rel = import_node_path32.default.relative(absCwd, joined);
55157
+ if (rel.startsWith("..") || import_node_path32.default.isAbsolute(rel)) {
55073
55158
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
55074
55159
  }
55075
55160
  return joined;
55076
55161
  }
55077
55162
  function ensureCwd(cwd) {
55078
55163
  try {
55079
- const stat = import_node_fs28.default.statSync(cwd);
55164
+ const stat = import_node_fs29.default.statSync(cwd);
55080
55165
  if (!stat.isDirectory()) {
55081
55166
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
55082
55167
  }
@@ -55090,7 +55175,7 @@ var WorkspaceBrowser = class {
55090
55175
  const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os8.default.homedir();
55091
55176
  ensureCwd(cwd);
55092
55177
  const full = resolveInsideCwd(cwd, args.path);
55093
- const dirents = import_node_fs28.default.readdirSync(full, { withFileTypes: true });
55178
+ const dirents = import_node_fs29.default.readdirSync(full, { withFileTypes: true });
55094
55179
  const entries = [];
55095
55180
  for (const d of dirents) {
55096
55181
  if (!args.showHidden && d.name.startsWith(".")) continue;
@@ -55100,7 +55185,7 @@ var WorkspaceBrowser = class {
55100
55185
  mtime: ""
55101
55186
  };
55102
55187
  try {
55103
- const st = import_node_fs28.default.statSync(import_node_path31.default.join(full, d.name));
55188
+ const st = import_node_fs29.default.statSync(import_node_path32.default.join(full, d.name));
55104
55189
  entry.mtime = new Date(st.mtimeMs).toISOString();
55105
55190
  if (d.isFile()) entry.size = st.size;
55106
55191
  } catch {
@@ -55116,14 +55201,14 @@ var WorkspaceBrowser = class {
55116
55201
  read(args) {
55117
55202
  ensureCwd(args.cwd);
55118
55203
  const full = resolveInsideCwd(args.cwd, args.path);
55119
- const st = import_node_fs28.default.statSync(full);
55204
+ const st = import_node_fs29.default.statSync(full);
55120
55205
  if (!st.isFile()) {
55121
55206
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
55122
55207
  }
55123
55208
  if (st.size > MAX_FILE_BYTES2) {
55124
55209
  throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES2} bytes`);
55125
55210
  }
55126
- const buf = import_node_fs28.default.readFileSync(full);
55211
+ const buf = import_node_fs29.default.readFileSync(full);
55127
55212
  const isBinary = buf.includes(0);
55128
55213
  if (isBinary) {
55129
55214
  return {
@@ -55145,20 +55230,20 @@ var WorkspaceBrowser = class {
55145
55230
  };
55146
55231
 
55147
55232
  // src/skills/agents-scanner.ts
55148
- var import_node_fs29 = __toESM(require("fs"), 1);
55233
+ var import_node_fs30 = __toESM(require("fs"), 1);
55149
55234
  var import_node_os9 = __toESM(require("os"), 1);
55150
- var import_node_path32 = __toESM(require("path"), 1);
55235
+ var import_node_path33 = __toESM(require("path"), 1);
55151
55236
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
55152
55237
  function isDirLikeSync2(p2) {
55153
55238
  try {
55154
- return import_node_fs29.default.statSync(p2).isDirectory();
55239
+ return import_node_fs30.default.statSync(p2).isDirectory();
55155
55240
  } catch {
55156
55241
  return false;
55157
55242
  }
55158
55243
  }
55159
55244
  function fileExistsSync(p2) {
55160
55245
  try {
55161
- return import_node_fs29.default.statSync(p2).isFile();
55246
+ return import_node_fs30.default.statSync(p2).isFile();
55162
55247
  } catch {
55163
55248
  return false;
55164
55249
  }
@@ -55166,7 +55251,7 @@ function fileExistsSync(p2) {
55166
55251
  function parseAgentFile(filePath) {
55167
55252
  let content;
55168
55253
  try {
55169
- content = import_node_fs29.default.readFileSync(filePath, "utf8");
55254
+ content = import_node_fs30.default.readFileSync(filePath, "utf8");
55170
55255
  } catch {
55171
55256
  return {};
55172
55257
  }
@@ -55179,16 +55264,16 @@ function parseAgentFile(filePath) {
55179
55264
  function scanAgentsDir(dir, source, seen, out) {
55180
55265
  let entries;
55181
55266
  try {
55182
- entries = import_node_fs29.default.readdirSync(dir, { withFileTypes: true });
55267
+ entries = import_node_fs30.default.readdirSync(dir, { withFileTypes: true });
55183
55268
  } catch {
55184
55269
  return;
55185
55270
  }
55186
55271
  for (const ent of entries) {
55187
55272
  if (!ent.name.endsWith(".md")) continue;
55188
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path32.default.join(dir, ent.name)))) {
55273
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path33.default.join(dir, ent.name)))) {
55189
55274
  continue;
55190
55275
  }
55191
- const filePath = import_node_path32.default.join(dir, ent.name);
55276
+ const filePath = import_node_path33.default.join(dir, ent.name);
55192
55277
  const baseName = ent.name.replace(/\.md$/, "");
55193
55278
  if (seen.has(baseName)) continue;
55194
55279
  seen.add(baseName);
@@ -55206,12 +55291,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
55206
55291
  function walk2(dir, namespaces) {
55207
55292
  let entries;
55208
55293
  try {
55209
- entries = import_node_fs29.default.readdirSync(dir, { withFileTypes: true });
55294
+ entries = import_node_fs30.default.readdirSync(dir, { withFileTypes: true });
55210
55295
  } catch {
55211
55296
  return;
55212
55297
  }
55213
55298
  for (const ent of entries) {
55214
- const childPath = import_node_path32.default.join(dir, ent.name);
55299
+ const childPath = import_node_path33.default.join(dir, ent.name);
55215
55300
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
55216
55301
  walk2(childPath, [...namespaces, ent.name]);
55217
55302
  continue;
@@ -55236,13 +55321,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
55236
55321
  walk2(root, []);
55237
55322
  }
55238
55323
  function readInstalledPlugins2(home) {
55239
- const pluginsDir = import_node_path32.default.join(home, ".claude", "plugins");
55240
- const v2 = import_node_path32.default.join(pluginsDir, "installed_plugins_v2.json");
55241
- const v1 = import_node_path32.default.join(pluginsDir, "installed_plugins.json");
55324
+ const pluginsDir = import_node_path33.default.join(home, ".claude", "plugins");
55325
+ const v2 = import_node_path33.default.join(pluginsDir, "installed_plugins_v2.json");
55326
+ const v1 = import_node_path33.default.join(pluginsDir, "installed_plugins.json");
55242
55327
  let raw = null;
55243
55328
  for (const candidate of [v2, v1]) {
55244
55329
  try {
55245
- raw = import_node_fs29.default.readFileSync(candidate, "utf8");
55330
+ raw = import_node_fs30.default.readFileSync(candidate, "utf8");
55246
55331
  break;
55247
55332
  } catch {
55248
55333
  }
@@ -55267,19 +55352,19 @@ function readInstalledPlugins2(home) {
55267
55352
  return out;
55268
55353
  }
55269
55354
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
55270
- let cur = import_node_path32.default.resolve(startCwd);
55271
- const fsRoot = import_node_path32.default.parse(cur).root;
55355
+ let cur = import_node_path33.default.resolve(startCwd);
55356
+ const fsRoot = import_node_path33.default.parse(cur).root;
55272
55357
  while (true) {
55273
- scanAgentsDir(import_node_path32.default.join(cur, ".claude", "agents"), "project", seen, out);
55358
+ scanAgentsDir(import_node_path33.default.join(cur, ".claude", "agents"), "project", seen, out);
55274
55359
  let hasGit = false;
55275
55360
  try {
55276
- hasGit = import_node_fs29.default.existsSync(import_node_path32.default.join(cur, ".git"));
55361
+ hasGit = import_node_fs30.default.existsSync(import_node_path33.default.join(cur, ".git"));
55277
55362
  } catch {
55278
55363
  }
55279
55364
  if (hasGit) return;
55280
55365
  if (cur === home) return;
55281
55366
  if (cur === fsRoot) return;
55282
- const parent = import_node_path32.default.dirname(cur);
55367
+ const parent = import_node_path33.default.dirname(cur);
55283
55368
  if (parent === cur) return;
55284
55369
  cur = parent;
55285
55370
  }
@@ -55314,7 +55399,7 @@ var AgentsScanner = class {
55314
55399
  }
55315
55400
  const fsBlock = [];
55316
55401
  scanAgentsDir(
55317
- import_node_path32.default.join(this.home, ".claude", "agents"),
55402
+ import_node_path33.default.join(this.home, ".claude", "agents"),
55318
55403
  "global",
55319
55404
  seen,
55320
55405
  fsBlock
@@ -55328,7 +55413,7 @@ var AgentsScanner = class {
55328
55413
  ...this.extraPluginRoots
55329
55414
  ];
55330
55415
  for (const { name, root } of plugins) {
55331
- const agentsRoot = import_node_path32.default.join(root, "agents");
55416
+ const agentsRoot = import_node_path33.default.join(root, "agents");
55332
55417
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
55333
55418
  }
55334
55419
  return [...builtinBlock, ...fsBlock];
@@ -55336,15 +55421,15 @@ var AgentsScanner = class {
55336
55421
  };
55337
55422
 
55338
55423
  // src/observer/session-observer.ts
55339
- var import_node_fs31 = __toESM(require("fs"), 1);
55424
+ var import_node_fs32 = __toESM(require("fs"), 1);
55340
55425
  var import_node_os11 = __toESM(require("os"), 1);
55341
- var import_node_path34 = __toESM(require("path"), 1);
55426
+ var import_node_path35 = __toESM(require("path"), 1);
55342
55427
  init_claude_history();
55343
55428
 
55344
55429
  // src/observer/subagent-meta-observer.ts
55345
- var import_node_fs30 = __toESM(require("fs"), 1);
55430
+ var import_node_fs31 = __toESM(require("fs"), 1);
55346
55431
  var import_node_os10 = __toESM(require("os"), 1);
55347
- var import_node_path33 = __toESM(require("path"), 1);
55432
+ var import_node_path34 = __toESM(require("path"), 1);
55348
55433
  init_claude_history();
55349
55434
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
55350
55435
  var SubagentMetaObserver = class {
@@ -55357,7 +55442,7 @@ var SubagentMetaObserver = class {
55357
55442
  watches = /* @__PURE__ */ new Map();
55358
55443
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
55359
55444
  resolveSubagentDir(cwd, toolSessionId) {
55360
- return import_node_path33.default.join(
55445
+ return import_node_path34.default.join(
55361
55446
  this.home,
55362
55447
  ".claude",
55363
55448
  "projects",
@@ -55387,7 +55472,7 @@ var SubagentMetaObserver = class {
55387
55472
  attachWatcher(w2) {
55388
55473
  if (w2.watcher) return;
55389
55474
  try {
55390
- w2.watcher = import_node_fs30.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
55475
+ w2.watcher = import_node_fs31.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
55391
55476
  if (!name) return;
55392
55477
  const m2 = META_RE.exec(String(name));
55393
55478
  if (!m2) return;
@@ -55399,7 +55484,7 @@ var SubagentMetaObserver = class {
55399
55484
  scan(w2) {
55400
55485
  let entries;
55401
55486
  try {
55402
- entries = import_node_fs30.default.readdirSync(w2.dirPath);
55487
+ entries = import_node_fs31.default.readdirSync(w2.dirPath);
55403
55488
  } catch {
55404
55489
  return;
55405
55490
  }
@@ -55413,10 +55498,10 @@ var SubagentMetaObserver = class {
55413
55498
  if (!m2) return;
55414
55499
  const agentId = m2[1];
55415
55500
  if (w2.emitted.has(agentId)) return;
55416
- const file = import_node_path33.default.join(w2.dirPath, name);
55501
+ const file = import_node_path34.default.join(w2.dirPath, name);
55417
55502
  let raw;
55418
55503
  try {
55419
- raw = import_node_fs30.default.readFileSync(file, "utf8");
55504
+ raw = import_node_fs31.default.readFileSync(file, "utf8");
55420
55505
  } catch {
55421
55506
  return;
55422
55507
  }
@@ -55473,14 +55558,14 @@ var SessionObserver = class {
55473
55558
  metaObserver;
55474
55559
  resolveJsonlPath(cwd, toolSessionId, override) {
55475
55560
  if (override) return override;
55476
- return import_node_path34.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
55561
+ return import_node_path35.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
55477
55562
  }
55478
55563
  start(args) {
55479
55564
  this.stop(args.sessionId);
55480
55565
  const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
55481
55566
  let size = 0;
55482
55567
  try {
55483
- size = import_node_fs31.default.statSync(filePath).size;
55568
+ size = import_node_fs32.default.statSync(filePath).size;
55484
55569
  } catch {
55485
55570
  }
55486
55571
  const w2 = {
@@ -55493,16 +55578,16 @@ var SessionObserver = class {
55493
55578
  adapter: args.adapter,
55494
55579
  prevIsRejectSentinel: false,
55495
55580
  toolSessionId: args.toolSessionId,
55496
- sawFile: import_node_fs31.default.existsSync(filePath),
55581
+ sawFile: import_node_fs32.default.existsSync(filePath),
55497
55582
  lastRelocateScanMs: 0,
55498
55583
  pendingCwdDerive: false,
55499
55584
  lastDeriveMs: 0
55500
55585
  };
55501
55586
  try {
55502
- import_node_fs31.default.mkdirSync(import_node_path34.default.dirname(filePath), { recursive: true });
55587
+ import_node_fs32.default.mkdirSync(import_node_path35.default.dirname(filePath), { recursive: true });
55503
55588
  } catch {
55504
55589
  }
55505
- w2.watcher = import_node_fs31.default.watch(import_node_path34.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
55590
+ w2.watcher = import_node_fs32.default.watch(import_node_path35.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
55506
55591
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
55507
55592
  this.poll(w2);
55508
55593
  });
@@ -55525,7 +55610,7 @@ var SessionObserver = class {
55525
55610
  // 异常静默吞,不阻塞 watcher 启动
55526
55611
  hydrateMetaTail(w2, maxLines = 200) {
55527
55612
  try {
55528
- const raw = import_node_fs31.default.readFileSync(w2.filePath, "utf8");
55613
+ const raw = import_node_fs32.default.readFileSync(w2.filePath, "utf8");
55529
55614
  if (!raw) return;
55530
55615
  const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
55531
55616
  if (allLines.length === 0) return;
@@ -55549,7 +55634,7 @@ var SessionObserver = class {
55549
55634
  poll(w2) {
55550
55635
  let size = 0;
55551
55636
  try {
55552
- size = import_node_fs31.default.statSync(w2.filePath).size;
55637
+ size = import_node_fs32.default.statSync(w2.filePath).size;
55553
55638
  } catch {
55554
55639
  if (w2.sawFile) this.maybeRelocate(w2);
55555
55640
  return;
@@ -55560,11 +55645,11 @@ var SessionObserver = class {
55560
55645
  w2.buf = "";
55561
55646
  }
55562
55647
  if (size === w2.lastSize) return;
55563
- const fd = import_node_fs31.default.openSync(w2.filePath, "r");
55648
+ const fd = import_node_fs32.default.openSync(w2.filePath, "r");
55564
55649
  try {
55565
55650
  const len = size - w2.lastSize;
55566
55651
  const buf = Buffer.alloc(len);
55567
- import_node_fs31.default.readSync(fd, buf, 0, len, w2.lastSize);
55652
+ import_node_fs32.default.readSync(fd, buf, 0, len, w2.lastSize);
55568
55653
  w2.lastSize = size;
55569
55654
  w2.buf += buf.toString("utf8");
55570
55655
  let newlineIndex;
@@ -55587,7 +55672,7 @@ var SessionObserver = class {
55587
55672
  }
55588
55673
  }
55589
55674
  } finally {
55590
- import_node_fs31.default.closeSync(fd);
55675
+ import_node_fs32.default.closeSync(fd);
55591
55676
  }
55592
55677
  if (w2.pendingCwdDerive) this.maybeDeriveCwd(w2);
55593
55678
  }
@@ -55599,7 +55684,7 @@ var SessionObserver = class {
55599
55684
  const now = Date.now();
55600
55685
  if (now - w2.lastRelocateScanMs < 1e3) return;
55601
55686
  w2.lastRelocateScanMs = now;
55602
- const projectsRoot = import_node_path34.default.join(this.home, ".claude", "projects");
55687
+ const projectsRoot = import_node_path35.default.join(this.home, ".claude", "projects");
55603
55688
  const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
55604
55689
  if (!found || found === w2.filePath) return;
55605
55690
  try {
@@ -55608,7 +55693,7 @@ var SessionObserver = class {
55608
55693
  }
55609
55694
  w2.filePath = found;
55610
55695
  try {
55611
- w2.watcher = import_node_fs31.default.watch(import_node_path34.default.dirname(found), { persistent: false }, (_event, changedName) => {
55696
+ w2.watcher = import_node_fs32.default.watch(import_node_path35.default.dirname(found), { persistent: false }, (_event, changedName) => {
55612
55697
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
55613
55698
  this.poll(w2);
55614
55699
  });
@@ -55729,9 +55814,9 @@ function listRegistered() {
55729
55814
 
55730
55815
  // src/tools/title-generator.ts
55731
55816
  var import_node_child_process8 = require("child_process");
55732
- var import_node_fs32 = __toESM(require("fs"), 1);
55817
+ var import_node_fs33 = __toESM(require("fs"), 1);
55733
55818
  var import_node_os12 = __toESM(require("os"), 1);
55734
- var import_node_path35 = __toESM(require("path"), 1);
55819
+ var import_node_path36 = __toESM(require("path"), 1);
55735
55820
  var TITLE_GEN_DIR_PREFIX = "clawd-title-";
55736
55821
  var TITLE_MODEL_BY_TOOL = {
55737
55822
  claude: "haiku",
@@ -55802,21 +55887,21 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
55802
55887
  if (!text) return null;
55803
55888
  let workDir;
55804
55889
  try {
55805
- workDir = import_node_fs32.default.mkdtempSync(import_node_path35.default.join(import_node_os12.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
55890
+ workDir = import_node_fs33.default.mkdtempSync(import_node_path36.default.join(import_node_os12.default.tmpdir(), TITLE_GEN_DIR_PREFIX));
55806
55891
  } catch {
55807
55892
  return null;
55808
55893
  }
55809
55894
  const cleanupWorkDir = () => {
55810
55895
  try {
55811
- import_node_fs32.default.rmSync(workDir, { recursive: true, force: true });
55896
+ import_node_fs33.default.rmSync(workDir, { recursive: true, force: true });
55812
55897
  } catch {
55813
55898
  }
55814
55899
  };
55815
- const outFile = import_node_path35.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
55816
- const schemaFile = import_node_path35.default.join(workDir, "title-schema.json");
55900
+ const outFile = import_node_path36.default.join(workDir, `codex-title-${process.pid}-${++outFileSeq}-${Date.now()}.txt`);
55901
+ const schemaFile = import_node_path36.default.join(workDir, "title-schema.json");
55817
55902
  if (tool === "codex") {
55818
55903
  try {
55819
- import_node_fs32.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
55904
+ import_node_fs33.default.writeFileSync(schemaFile, CODEX_TITLE_SCHEMA);
55820
55905
  } catch {
55821
55906
  cleanupWorkDir();
55822
55907
  return null;
@@ -55866,7 +55951,7 @@ async function generateSessionTitle(tool, firstMessage, deps = {}) {
55866
55951
  if (tool === "claude") return finish(parseTitleJson(stdout));
55867
55952
  let fileText = "";
55868
55953
  try {
55869
- fileText = import_node_fs32.default.readFileSync(outFile, "utf8");
55954
+ fileText = import_node_fs33.default.readFileSync(outFile, "utf8");
55870
55955
  } catch {
55871
55956
  return finish(null);
55872
55957
  }
@@ -56551,8 +56636,8 @@ async function authenticate(token, deps) {
56551
56636
  }
56552
56637
 
56553
56638
  // src/legacy-cleanup.ts
56554
- var fs41 = __toESM(require("fs/promises"), 1);
56555
- var path43 = __toESM(require("path"), 1);
56639
+ var fs42 = __toESM(require("fs/promises"), 1);
56640
+ var path44 = __toESM(require("path"), 1);
56556
56641
  var LEGACY_FILES = [
56557
56642
  "personal-capability.json",
56558
56643
  "received-capabilities.json",
@@ -56561,9 +56646,9 @@ var LEGACY_FILES = [
56561
56646
  async function cleanupLegacyCapabilityFiles(dataDir, logger) {
56562
56647
  const removed = [];
56563
56648
  for (const name of LEGACY_FILES) {
56564
- const p2 = path43.join(dataDir, name);
56649
+ const p2 = path44.join(dataDir, name);
56565
56650
  try {
56566
- await fs41.unlink(p2);
56651
+ await fs42.unlink(p2);
56567
56652
  removed.push(name);
56568
56653
  logger.debug("legacy capability file removed", { file: name });
56569
56654
  } catch (err) {
@@ -56575,13 +56660,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
56575
56660
  }
56576
56661
 
56577
56662
  // src/inbox/inbox-store.ts
56578
- var fs42 = __toESM(require("fs"), 1);
56579
- var path44 = __toESM(require("path"), 1);
56663
+ var fs43 = __toESM(require("fs"), 1);
56664
+ var path45 = __toESM(require("path"), 1);
56580
56665
  var INBOX_SUBDIR = "inbox";
56581
56666
  var InboxStore = class {
56582
56667
  constructor(dataDir) {
56583
56668
  this.dataDir = dataDir;
56584
- fs42.mkdirSync(this.dirPath(), { recursive: true });
56669
+ fs43.mkdirSync(this.dirPath(), { recursive: true });
56585
56670
  }
56586
56671
  dataDir;
56587
56672
  /**
@@ -56593,7 +56678,7 @@ var InboxStore = class {
56593
56678
  const file = this.filePath(peerDeviceId);
56594
56679
  let raw;
56595
56680
  try {
56596
- raw = fs42.readFileSync(file, "utf8");
56681
+ raw = fs43.readFileSync(file, "utf8");
56597
56682
  } catch (err) {
56598
56683
  if (err?.code === "ENOENT") return [];
56599
56684
  return [];
@@ -56609,7 +56694,7 @@ var InboxStore = class {
56609
56694
  const dir = this.dirPath();
56610
56695
  let entries;
56611
56696
  try {
56612
- entries = fs42.readdirSync(dir);
56697
+ entries = fs43.readdirSync(dir);
56613
56698
  } catch (err) {
56614
56699
  if (err?.code === "ENOENT") return [];
56615
56700
  return [];
@@ -56625,9 +56710,9 @@ var InboxStore = class {
56625
56710
  if (existing.some((m2) => m2.id === message.id)) return;
56626
56711
  const file = this.filePath(message.peerDeviceId);
56627
56712
  const line = JSON.stringify(message) + "\n";
56628
- fs42.appendFileSync(file, line, { mode: 384 });
56713
+ fs43.appendFileSync(file, line, { mode: 384 });
56629
56714
  try {
56630
- fs42.chmodSync(file, 384);
56715
+ fs43.chmodSync(file, 384);
56631
56716
  } catch {
56632
56717
  }
56633
56718
  }
@@ -56657,7 +56742,7 @@ var InboxStore = class {
56657
56742
  removeByPeerDeviceId(peerDeviceId) {
56658
56743
  const file = this.filePath(peerDeviceId);
56659
56744
  try {
56660
- fs42.unlinkSync(file);
56745
+ fs43.unlinkSync(file);
56661
56746
  } catch (err) {
56662
56747
  if (err?.code === "ENOENT") return;
56663
56748
  }
@@ -56666,18 +56751,18 @@ var InboxStore = class {
56666
56751
  const file = this.filePath(peerDeviceId);
56667
56752
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
56668
56753
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
56669
- fs42.writeFileSync(tmp, content, { mode: 384 });
56670
- fs42.renameSync(tmp, file);
56754
+ fs43.writeFileSync(tmp, content, { mode: 384 });
56755
+ fs43.renameSync(tmp, file);
56671
56756
  try {
56672
- fs42.chmodSync(file, 384);
56757
+ fs43.chmodSync(file, 384);
56673
56758
  } catch {
56674
56759
  }
56675
56760
  }
56676
56761
  dirPath() {
56677
- return path44.join(this.dataDir, INBOX_SUBDIR);
56762
+ return path45.join(this.dataDir, INBOX_SUBDIR);
56678
56763
  }
56679
56764
  filePath(peerDeviceId) {
56680
- return path44.join(this.dirPath(), `${peerDeviceId}.jsonl`);
56765
+ return path45.join(this.dirPath(), `${peerDeviceId}.jsonl`);
56681
56766
  }
56682
56767
  };
56683
56768
  function parseAllLines(raw) {
@@ -56765,8 +56850,8 @@ var InboxManager = class {
56765
56850
  };
56766
56851
 
56767
56852
  // src/state/contact-store.ts
56768
- var fs43 = __toESM(require("fs"), 1);
56769
- var path45 = __toESM(require("path"), 1);
56853
+ var fs44 = __toESM(require("fs"), 1);
56854
+ var path46 = __toESM(require("path"), 1);
56770
56855
  var FILE_NAME = "contacts.json";
56771
56856
  var ContactStore = class {
56772
56857
  constructor(dataDir) {
@@ -56776,10 +56861,10 @@ var ContactStore = class {
56776
56861
  contacts = /* @__PURE__ */ new Map();
56777
56862
  load() {
56778
56863
  this.contacts.clear();
56779
- const file = path45.join(this.dataDir, FILE_NAME);
56864
+ const file = path46.join(this.dataDir, FILE_NAME);
56780
56865
  let raw;
56781
56866
  try {
56782
- raw = fs43.readFileSync(file, "utf8");
56867
+ raw = fs44.readFileSync(file, "utf8");
56783
56868
  } catch (err) {
56784
56869
  if (err?.code !== "ENOENT") this.renameBak(file);
56785
56870
  return;
@@ -56848,20 +56933,20 @@ var ContactStore = class {
56848
56933
  return true;
56849
56934
  }
56850
56935
  flush() {
56851
- const file = path45.join(this.dataDir, FILE_NAME);
56936
+ const file = path46.join(this.dataDir, FILE_NAME);
56852
56937
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
56853
56938
  const content = JSON.stringify(
56854
56939
  { contacts: Array.from(this.contacts.values()) },
56855
56940
  null,
56856
56941
  2
56857
56942
  );
56858
- fs43.mkdirSync(this.dataDir, { recursive: true });
56859
- fs43.writeFileSync(tmp, content, { mode: 384 });
56860
- fs43.renameSync(tmp, file);
56943
+ fs44.mkdirSync(this.dataDir, { recursive: true });
56944
+ fs44.writeFileSync(tmp, content, { mode: 384 });
56945
+ fs44.renameSync(tmp, file);
56861
56946
  }
56862
56947
  renameBak(file) {
56863
56948
  try {
56864
- fs43.renameSync(file, `${file}.bak`);
56949
+ fs44.renameSync(file, `${file}.bak`);
56865
56950
  } catch {
56866
56951
  }
56867
56952
  }
@@ -56969,61 +57054,61 @@ async function connectRemote(args) {
56969
57054
  }
56970
57055
 
56971
57056
  // src/migrations/2026-05-20-flatten-sessions.ts
56972
- var fs44 = __toESM(require("fs"), 1);
56973
- var path46 = __toESM(require("path"), 1);
57057
+ var fs45 = __toESM(require("fs"), 1);
57058
+ var path47 = __toESM(require("path"), 1);
56974
57059
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
56975
57060
  function migrateFlattenSessions(opts) {
56976
57061
  const dataDir = opts.dataDir;
56977
57062
  const now = opts.now ?? Date.now;
56978
- const sessionsDir = path46.join(dataDir, "sessions");
56979
- const flagPath = path46.join(sessionsDir, MIGRATION_FLAG_NAME);
57063
+ const sessionsDir = path47.join(dataDir, "sessions");
57064
+ const flagPath = path47.join(sessionsDir, MIGRATION_FLAG_NAME);
56980
57065
  if (existsSync3(flagPath)) {
56981
57066
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
56982
57067
  }
56983
57068
  let movedBare = 0;
56984
57069
  let movedVmOwner = 0;
56985
57070
  let archivedListener = 0;
56986
- const defaultDir = path46.join(sessionsDir, "default");
57071
+ const defaultDir = path47.join(sessionsDir, "default");
56987
57072
  if (existsSync3(defaultDir)) {
56988
57073
  for (const entry of readdirSafe(defaultDir)) {
56989
57074
  if (!entry.endsWith(".json")) continue;
56990
- const src = path46.join(defaultDir, entry);
56991
- const dst = path46.join(sessionsDir, entry);
56992
- fs44.renameSync(src, dst);
57075
+ const src = path47.join(defaultDir, entry);
57076
+ const dst = path47.join(sessionsDir, entry);
57077
+ fs45.renameSync(src, dst);
56993
57078
  movedBare += 1;
56994
57079
  }
56995
57080
  rmdirIfEmpty(defaultDir);
56996
57081
  }
56997
57082
  for (const pid of readdirSafe(sessionsDir)) {
56998
- const personaDir = path46.join(sessionsDir, pid);
57083
+ const personaDir = path47.join(sessionsDir, pid);
56999
57084
  if (!isDir(personaDir)) continue;
57000
57085
  if (pid === "default") continue;
57001
- const ownerSrc = path46.join(personaDir, "owner");
57086
+ const ownerSrc = path47.join(personaDir, "owner");
57002
57087
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
57003
- const ownerDst = path46.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
57004
- fs44.mkdirSync(ownerDst, { recursive: true });
57088
+ const ownerDst = path47.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
57089
+ fs45.mkdirSync(ownerDst, { recursive: true });
57005
57090
  for (const file of readdirSafe(ownerSrc)) {
57006
57091
  if (!file.endsWith(".json")) continue;
57007
- fs44.renameSync(path46.join(ownerSrc, file), path46.join(ownerDst, file));
57092
+ fs45.renameSync(path47.join(ownerSrc, file), path47.join(ownerDst, file));
57008
57093
  movedVmOwner += 1;
57009
57094
  }
57010
57095
  rmdirIfEmpty(ownerSrc);
57011
57096
  }
57012
- const listenerSrc = path46.join(personaDir, "listener");
57097
+ const listenerSrc = path47.join(personaDir, "listener");
57013
57098
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
57014
- const archiveDst = path46.join(dataDir, ".legacy", `listener-${pid}`);
57015
- fs44.mkdirSync(archiveDst, { recursive: true });
57099
+ const archiveDst = path47.join(dataDir, ".legacy", `listener-${pid}`);
57100
+ fs45.mkdirSync(archiveDst, { recursive: true });
57016
57101
  for (const file of readdirSafe(listenerSrc)) {
57017
57102
  if (!file.endsWith(".json")) continue;
57018
- fs44.renameSync(path46.join(listenerSrc, file), path46.join(archiveDst, file));
57103
+ fs45.renameSync(path47.join(listenerSrc, file), path47.join(archiveDst, file));
57019
57104
  archivedListener += 1;
57020
57105
  }
57021
57106
  rmdirIfEmpty(listenerSrc);
57022
57107
  }
57023
57108
  rmdirIfEmpty(personaDir);
57024
57109
  }
57025
- fs44.mkdirSync(sessionsDir, { recursive: true });
57026
- fs44.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
57110
+ fs45.mkdirSync(sessionsDir, { recursive: true });
57111
+ fs45.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
57027
57112
  return {
57028
57113
  skipped: false,
57029
57114
  flagWritten: true,
@@ -57034,7 +57119,7 @@ function migrateFlattenSessions(opts) {
57034
57119
  }
57035
57120
  function existsSync3(p2) {
57036
57121
  try {
57037
- fs44.statSync(p2);
57122
+ fs45.statSync(p2);
57038
57123
  return true;
57039
57124
  } catch {
57040
57125
  return false;
@@ -57042,61 +57127,61 @@ function existsSync3(p2) {
57042
57127
  }
57043
57128
  function isDir(p2) {
57044
57129
  try {
57045
- return fs44.statSync(p2).isDirectory();
57130
+ return fs45.statSync(p2).isDirectory();
57046
57131
  } catch {
57047
57132
  return false;
57048
57133
  }
57049
57134
  }
57050
57135
  function readdirSafe(p2) {
57051
57136
  try {
57052
- return fs44.readdirSync(p2);
57137
+ return fs45.readdirSync(p2);
57053
57138
  } catch {
57054
57139
  return [];
57055
57140
  }
57056
57141
  }
57057
57142
  function rmdirIfEmpty(p2) {
57058
57143
  try {
57059
- fs44.rmdirSync(p2);
57144
+ fs45.rmdirSync(p2);
57060
57145
  } catch {
57061
57146
  }
57062
57147
  }
57063
57148
 
57064
57149
  // src/migrations/2026-08-18-drop-seeded-projects.ts
57065
- var fs45 = __toESM(require("fs"), 1);
57066
- var path47 = __toESM(require("path"), 1);
57150
+ var fs46 = __toESM(require("fs"), 1);
57151
+ var path48 = __toESM(require("path"), 1);
57067
57152
  var DROP_SEEDED_PROJECTS_FLAG = ".projects-seed-dropped.v1.done";
57068
57153
  function dropSeededProjects(opts) {
57069
- fs45.mkdirSync(opts.dataDir, { recursive: true });
57070
- const flag = path47.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
57071
- if (fs45.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
57072
- const file = path47.join(opts.dataDir, "projects.json");
57154
+ fs46.mkdirSync(opts.dataDir, { recursive: true });
57155
+ const flag = path48.join(opts.dataDir, DROP_SEEDED_PROJECTS_FLAG);
57156
+ if (fs46.existsSync(flag)) return { skipped: true, dropped: 0, backup: null };
57157
+ const file = path48.join(opts.dataDir, "projects.json");
57073
57158
  let raw = null;
57074
57159
  let dropped = 0;
57075
57160
  try {
57076
- raw = fs45.readFileSync(file, "utf8");
57161
+ raw = fs46.readFileSync(file, "utf8");
57077
57162
  dropped = JSON.parse(raw).projects?.length ?? 0;
57078
57163
  } catch {
57079
57164
  }
57080
57165
  let backup = null;
57081
57166
  if (raw != null && dropped > 0) {
57082
- const dir = path47.join(opts.dataDir, "backups");
57083
- fs45.mkdirSync(dir, { recursive: true });
57084
- backup = path47.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
57085
- fs45.writeFileSync(backup, raw);
57167
+ const dir = path48.join(opts.dataDir, "backups");
57168
+ fs46.mkdirSync(dir, { recursive: true });
57169
+ backup = path48.join(dir, `projects.seed-dropped.${(opts.now ?? Date.now)()}.json`);
57170
+ fs46.writeFileSync(backup, raw);
57086
57171
  }
57087
57172
  if (raw != null || dropped > 0) {
57088
- fs45.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
57173
+ fs46.writeFileSync(file, JSON.stringify({ projects: [] }, null, 2));
57089
57174
  }
57090
- fs45.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
57175
+ fs46.writeFileSync(flag, (/* @__PURE__ */ new Date()).toISOString());
57091
57176
  return { skipped: false, dropped, backup };
57092
57177
  }
57093
57178
 
57094
57179
  // src/transport/http-router.ts
57095
- var import_node_fs34 = __toESM(require("fs"), 1);
57096
- var import_node_path39 = __toESM(require("path"), 1);
57180
+ var import_node_fs35 = __toESM(require("fs"), 1);
57181
+ var import_node_path40 = __toESM(require("path"), 1);
57097
57182
 
57098
57183
  // src/attachment/mime.ts
57099
- var import_node_path36 = __toESM(require("path"), 1);
57184
+ var import_node_path37 = __toESM(require("path"), 1);
57100
57185
  var TEXT_PLAIN = "text/plain; charset=utf-8";
57101
57186
  var EXT_TO_NATIVE_MIME = {
57102
57187
  // 图片
@@ -57203,7 +57288,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
57203
57288
  ".mk"
57204
57289
  ]);
57205
57290
  function lookupMime(filePathOrName) {
57206
- const ext = import_node_path36.default.extname(filePathOrName).toLowerCase();
57291
+ const ext = import_node_path37.default.extname(filePathOrName).toLowerCase();
57207
57292
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
57208
57293
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
57209
57294
  return "application/octet-stream";
@@ -57273,8 +57358,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
57273
57358
  }
57274
57359
 
57275
57360
  // src/attachment/upload.ts
57276
- var import_node_fs33 = __toESM(require("fs"), 1);
57277
- var import_node_path37 = __toESM(require("path"), 1);
57361
+ var import_node_fs34 = __toESM(require("fs"), 1);
57362
+ var import_node_path38 = __toESM(require("path"), 1);
57278
57363
  var import_node_crypto9 = __toESM(require("crypto"), 1);
57279
57364
  var import_promises5 = require("stream/promises");
57280
57365
  var UploadError = class extends Error {
@@ -57286,22 +57371,22 @@ var UploadError = class extends Error {
57286
57371
  code;
57287
57372
  };
57288
57373
  function assertValidFileName(fileName) {
57289
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path37.default.basename(fileName)) {
57374
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path38.default.basename(fileName)) {
57290
57375
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
57291
57376
  }
57292
57377
  }
57293
57378
  var HASH_PREFIX_LEN = 16;
57294
57379
  async function writeUploadedAttachment(args) {
57295
57380
  assertValidFileName(args.fileName);
57296
- const attachmentsRoot = import_node_path37.default.join(args.baseDir, ".attachments");
57381
+ const attachmentsRoot = import_node_path38.default.join(args.baseDir, ".attachments");
57297
57382
  try {
57298
- import_node_fs33.default.mkdirSync(attachmentsRoot, { recursive: true });
57383
+ import_node_fs34.default.mkdirSync(attachmentsRoot, { recursive: true });
57299
57384
  } catch (err) {
57300
57385
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
57301
57386
  }
57302
57387
  const hasher = import_node_crypto9.default.createHash("sha256");
57303
57388
  let actualSize = 0;
57304
- const tmpPath = import_node_path37.default.join(
57389
+ const tmpPath = import_node_path38.default.join(
57305
57390
  attachmentsRoot,
57306
57391
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto9.default.randomBytes(4).toString("hex")}`
57307
57392
  );
@@ -57316,18 +57401,18 @@ async function writeUploadedAttachment(args) {
57316
57401
  yield buf;
57317
57402
  }
57318
57403
  },
57319
- import_node_fs33.default.createWriteStream(tmpPath, { mode: 384 })
57404
+ import_node_fs34.default.createWriteStream(tmpPath, { mode: 384 })
57320
57405
  );
57321
57406
  } catch (err) {
57322
57407
  try {
57323
- import_node_fs33.default.unlinkSync(tmpPath);
57408
+ import_node_fs34.default.unlinkSync(tmpPath);
57324
57409
  } catch {
57325
57410
  }
57326
57411
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
57327
57412
  }
57328
57413
  if (actualSize !== args.contentLength) {
57329
57414
  try {
57330
- import_node_fs33.default.unlinkSync(tmpPath);
57415
+ import_node_fs34.default.unlinkSync(tmpPath);
57331
57416
  } catch {
57332
57417
  }
57333
57418
  throw new UploadError(
@@ -57336,34 +57421,34 @@ async function writeUploadedAttachment(args) {
57336
57421
  );
57337
57422
  }
57338
57423
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
57339
- const hashDir = import_node_path37.default.join(attachmentsRoot, attachmentId);
57424
+ const hashDir = import_node_path38.default.join(attachmentsRoot, attachmentId);
57340
57425
  let finalFileName;
57341
57426
  let hashDirExists = false;
57342
57427
  try {
57343
- hashDirExists = import_node_fs33.default.statSync(hashDir).isDirectory();
57428
+ hashDirExists = import_node_fs34.default.statSync(hashDir).isDirectory();
57344
57429
  } catch {
57345
57430
  }
57346
57431
  if (hashDirExists) {
57347
- const existing = import_node_fs33.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
57432
+ const existing = import_node_fs34.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
57348
57433
  finalFileName = existing[0] ?? args.fileName;
57349
57434
  try {
57350
- import_node_fs33.default.unlinkSync(tmpPath);
57435
+ import_node_fs34.default.unlinkSync(tmpPath);
57351
57436
  } catch {
57352
57437
  }
57353
57438
  } else {
57354
57439
  try {
57355
- import_node_fs33.default.mkdirSync(hashDir, { recursive: true });
57440
+ import_node_fs34.default.mkdirSync(hashDir, { recursive: true });
57356
57441
  finalFileName = args.fileName;
57357
- import_node_fs33.default.renameSync(tmpPath, import_node_path37.default.join(hashDir, finalFileName));
57442
+ import_node_fs34.default.renameSync(tmpPath, import_node_path38.default.join(hashDir, finalFileName));
57358
57443
  } catch (err) {
57359
57444
  try {
57360
- import_node_fs33.default.unlinkSync(tmpPath);
57445
+ import_node_fs34.default.unlinkSync(tmpPath);
57361
57446
  } catch {
57362
57447
  }
57363
57448
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
57364
57449
  }
57365
57450
  }
57366
- const absPath = import_node_path37.default.join(hashDir, finalFileName);
57451
+ const absPath = import_node_path38.default.join(hashDir, finalFileName);
57367
57452
  const relPath = absPath;
57368
57453
  args.groupFileStore.upsert(args.scope, args.sessionId, {
57369
57454
  relPath: absPath,
@@ -57378,7 +57463,7 @@ async function writeUploadedAttachment(args) {
57378
57463
 
57379
57464
  // src/extension/import.ts
57380
57465
  var import_promises6 = __toESM(require("fs/promises"), 1);
57381
- var import_node_path38 = __toESM(require("path"), 1);
57466
+ var import_node_path39 = __toESM(require("path"), 1);
57382
57467
  var import_node_os13 = __toESM(require("os"), 1);
57383
57468
  var import_jszip = __toESM(require_lib3(), 1);
57384
57469
  var ImportError = class extends Error {
@@ -57396,7 +57481,7 @@ async function importZip(buf, root) {
57396
57481
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
57397
57482
  }
57398
57483
  for (const name of Object.keys(zip.files)) {
57399
- if (name.includes("..") || name.startsWith("/") || import_node_path38.default.isAbsolute(name)) {
57484
+ if (name.includes("..") || name.startsWith("/") || import_node_path39.default.isAbsolute(name)) {
57400
57485
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
57401
57486
  }
57402
57487
  }
@@ -57429,7 +57514,7 @@ async function importZip(buf, root) {
57429
57514
  );
57430
57515
  }
57431
57516
  }
57432
- const destDir = import_node_path38.default.join(root, manifest.id);
57517
+ const destDir = import_node_path39.default.join(root, manifest.id);
57433
57518
  let destExists = false;
57434
57519
  try {
57435
57520
  await import_promises6.default.access(destDir);
@@ -57439,15 +57524,15 @@ async function importZip(buf, root) {
57439
57524
  if (destExists) {
57440
57525
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
57441
57526
  }
57442
- const stage = await import_promises6.default.mkdtemp(import_node_path38.default.join(import_node_os13.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
57527
+ const stage = await import_promises6.default.mkdtemp(import_node_path39.default.join(import_node_os13.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
57443
57528
  try {
57444
57529
  for (const [name, entry] of Object.entries(zip.files)) {
57445
- const dest = import_node_path38.default.join(stage, name);
57530
+ const dest = import_node_path39.default.join(stage, name);
57446
57531
  if (entry.dir) {
57447
57532
  await import_promises6.default.mkdir(dest, { recursive: true });
57448
57533
  continue;
57449
57534
  }
57450
- await import_promises6.default.mkdir(import_node_path38.default.dirname(dest), { recursive: true });
57535
+ await import_promises6.default.mkdir(import_node_path39.default.dirname(dest), { recursive: true });
57451
57536
  const content = await entry.async("nodebuffer");
57452
57537
  await import_promises6.default.writeFile(dest, content);
57453
57538
  }
@@ -57477,7 +57562,7 @@ var SHARE_UI_ASSET_MIME = {
57477
57562
  ".wasm": "application/wasm"
57478
57563
  };
57479
57564
  function shareUiAssetMime(filePath) {
57480
- const ext = import_node_path39.default.extname(filePath).toLowerCase();
57565
+ const ext = import_node_path40.default.extname(filePath).toLowerCase();
57481
57566
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
57482
57567
  }
57483
57568
  var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
@@ -57576,7 +57661,7 @@ function isValidUploadFileName(fileName) {
57576
57661
  if (fileName === "." || fileName === "..") return false;
57577
57662
  if (fileName.startsWith(".")) return false;
57578
57663
  if (fileName.includes("/") || fileName.includes("\\")) return false;
57579
- return fileName === import_node_path39.default.basename(fileName);
57664
+ return fileName === import_node_path40.default.basename(fileName);
57580
57665
  }
57581
57666
  function createHttpRouter(deps) {
57582
57667
  return async (req, res) => {
@@ -57664,7 +57749,7 @@ function createHttpRouter(deps) {
57664
57749
  }
57665
57750
  let buf;
57666
57751
  try {
57667
- buf = await import_node_fs34.default.promises.readFile(abs);
57752
+ buf = await import_node_fs35.default.promises.readFile(abs);
57668
57753
  } catch {
57669
57754
  sendJson(res, 404, { code: "NOT_FOUND", message: "asset not found" });
57670
57755
  return true;
@@ -57812,7 +57897,7 @@ function createHttpRouter(deps) {
57812
57897
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
57813
57898
  return true;
57814
57899
  }
57815
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path39.default.basename(r.absPath)));
57900
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path40.default.basename(r.absPath)));
57816
57901
  return true;
57817
57902
  }
57818
57903
  const ctx = deps.authResolver.resolveFromHeader(
@@ -57933,7 +58018,7 @@ function createHttpRouter(deps) {
57933
58018
  return true;
57934
58019
  }
57935
58020
  let absPath;
57936
- if (import_node_path39.default.isAbsolute(pathParam)) {
58021
+ if (import_node_path40.default.isAbsolute(pathParam)) {
57937
58022
  absPath = pathParam;
57938
58023
  } else if (deps.sessionStore) {
57939
58024
  const file = deps.sessionStore.read(sid);
@@ -57941,7 +58026,7 @@ function createHttpRouter(deps) {
57941
58026
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
57942
58027
  return true;
57943
58028
  }
57944
- absPath = import_node_path39.default.join(file.cwd, pathParam);
58029
+ absPath = import_node_path40.default.join(file.cwd, pathParam);
57945
58030
  } else {
57946
58031
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
57947
58032
  return true;
@@ -58028,7 +58113,7 @@ function withCtx(ctx, body) {
58028
58113
  function streamFile(res, absPath, logger) {
58029
58114
  let stat;
58030
58115
  try {
58031
- stat = import_node_fs34.default.statSync(absPath);
58116
+ stat = import_node_fs35.default.statSync(absPath);
58032
58117
  } catch (err) {
58033
58118
  const code = err?.code;
58034
58119
  if (code === "ENOENT") {
@@ -58043,7 +58128,7 @@ function streamFile(res, absPath, logger) {
58043
58128
  return;
58044
58129
  }
58045
58130
  const mime = lookupMime(absPath);
58046
- const basename2 = import_node_path39.default.basename(absPath);
58131
+ const basename2 = import_node_path40.default.basename(absPath);
58047
58132
  res.writeHead(200, {
58048
58133
  "Content-Type": mime,
58049
58134
  "Content-Length": String(stat.size),
@@ -58051,7 +58136,7 @@ function streamFile(res, absPath, logger) {
58051
58136
  // 防止浏览器把任意 mime 当 html 渲染
58052
58137
  "X-Content-Type-Options": "nosniff"
58053
58138
  });
58054
- const stream = import_node_fs34.default.createReadStream(absPath);
58139
+ const stream = import_node_fs35.default.createReadStream(absPath);
58055
58140
  stream.on("error", (err) => {
58056
58141
  logger?.warn("streamFile read error", { absPath, err: err.message });
58057
58142
  res.destroy();
@@ -58060,8 +58145,8 @@ function streamFile(res, absPath, logger) {
58060
58145
  }
58061
58146
 
58062
58147
  // src/attachment/gc.ts
58063
- var import_node_fs35 = __toESM(require("fs"), 1);
58064
- var import_node_path40 = __toESM(require("path"), 1);
58148
+ var import_node_fs36 = __toESM(require("fs"), 1);
58149
+ var import_node_path41 = __toESM(require("path"), 1);
58065
58150
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
58066
58151
  function runAttachmentGc(args) {
58067
58152
  const now = (args.now ?? Date.now)();
@@ -58070,12 +58155,12 @@ function runAttachmentGc(args) {
58070
58155
  for (const { scope, sessionId } of args.sessionScopes) {
58071
58156
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
58072
58157
  if (entry.stale) continue;
58073
- if (import_node_path40.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
58158
+ if (import_node_path41.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
58074
58159
  }
58075
58160
  }
58076
58161
  const visited = /* @__PURE__ */ new Set();
58077
58162
  for (const { scope, sessionId } of args.sessionScopes) {
58078
- const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path40.default.join(
58163
+ const legacyDir = args.getSessionCwd?.(sessionId) ?? import_node_path41.default.join(
58079
58164
  args.dataDir,
58080
58165
  "sessions",
58081
58166
  ...scopeSubPath(scope).map(safeFileName),
@@ -58088,28 +58173,28 @@ function runAttachmentGc(args) {
58088
58173
  return true;
58089
58174
  });
58090
58175
  for (const rootDir of roots) {
58091
- const attRoot = import_node_path40.default.join(rootDir, ".attachments");
58176
+ const attRoot = import_node_path41.default.join(rootDir, ".attachments");
58092
58177
  let hashDirs;
58093
58178
  try {
58094
- hashDirs = import_node_fs35.default.readdirSync(attRoot);
58179
+ hashDirs = import_node_fs36.default.readdirSync(attRoot);
58095
58180
  } catch (err) {
58096
58181
  if (err.code === "ENOENT") continue;
58097
58182
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
58098
58183
  continue;
58099
58184
  }
58100
58185
  for (const hashDir of hashDirs) {
58101
- const hashDirAbs = import_node_path40.default.join(attRoot, hashDir);
58186
+ const hashDirAbs = import_node_path41.default.join(attRoot, hashDir);
58102
58187
  let files;
58103
58188
  try {
58104
- files = import_node_fs35.default.readdirSync(hashDirAbs);
58189
+ files = import_node_fs36.default.readdirSync(hashDirAbs);
58105
58190
  } catch {
58106
58191
  continue;
58107
58192
  }
58108
58193
  for (const name of files) {
58109
- const file = import_node_path40.default.join(hashDirAbs, name);
58194
+ const file = import_node_path41.default.join(hashDirAbs, name);
58110
58195
  let stat;
58111
58196
  try {
58112
- stat = import_node_fs35.default.statSync(file);
58197
+ stat = import_node_fs36.default.statSync(file);
58113
58198
  } catch {
58114
58199
  continue;
58115
58200
  }
@@ -58118,18 +58203,18 @@ function runAttachmentGc(args) {
58118
58203
  if (age < ttlMs) continue;
58119
58204
  if (liveAbs.has(file)) continue;
58120
58205
  try {
58121
- import_node_fs35.default.unlinkSync(file);
58206
+ import_node_fs36.default.unlinkSync(file);
58122
58207
  } catch (err) {
58123
58208
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
58124
58209
  }
58125
58210
  }
58126
58211
  try {
58127
- if (import_node_fs35.default.readdirSync(hashDirAbs).length === 0) import_node_fs35.default.rmdirSync(hashDirAbs);
58212
+ if (import_node_fs36.default.readdirSync(hashDirAbs).length === 0) import_node_fs36.default.rmdirSync(hashDirAbs);
58128
58213
  } catch {
58129
58214
  }
58130
58215
  }
58131
58216
  try {
58132
- if (import_node_fs35.default.readdirSync(attRoot).length === 0) import_node_fs35.default.rmdirSync(attRoot);
58217
+ if (import_node_fs36.default.readdirSync(attRoot).length === 0) import_node_fs36.default.rmdirSync(attRoot);
58133
58218
  } catch {
58134
58219
  }
58135
58220
  }
@@ -58137,8 +58222,8 @@ function runAttachmentGc(args) {
58137
58222
  }
58138
58223
 
58139
58224
  // src/attachment/group.ts
58140
- var import_node_fs36 = __toESM(require("fs"), 1);
58141
- var import_node_path41 = __toESM(require("path"), 1);
58225
+ var import_node_fs37 = __toESM(require("fs"), 1);
58226
+ var import_node_path42 = __toESM(require("path"), 1);
58142
58227
  var import_node_crypto10 = __toESM(require("crypto"), 1);
58143
58228
  init_protocol();
58144
58229
  var GroupFileStore = class {
@@ -58150,11 +58235,11 @@ var GroupFileStore = class {
58150
58235
  this.logger = opts.logger;
58151
58236
  }
58152
58237
  rootForScope(scope) {
58153
- return import_node_path41.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
58238
+ return import_node_path42.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
58154
58239
  }
58155
58240
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
58156
58241
  filePath(scope, sessionId) {
58157
- return import_node_path41.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
58242
+ return import_node_path42.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
58158
58243
  }
58159
58244
  cacheKey(scope, sessionId) {
58160
58245
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -58163,7 +58248,7 @@ var GroupFileStore = class {
58163
58248
  readFile(scope, sessionId) {
58164
58249
  const file = this.filePath(scope, sessionId);
58165
58250
  try {
58166
- const raw = import_node_fs36.default.readFileSync(file, "utf8");
58251
+ const raw = import_node_fs37.default.readFileSync(file, "utf8");
58167
58252
  const parsed = JSON.parse(raw);
58168
58253
  if (!Array.isArray(parsed)) {
58169
58254
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -58189,10 +58274,10 @@ var GroupFileStore = class {
58189
58274
  }
58190
58275
  writeFile(scope, sessionId, entries) {
58191
58276
  const file = this.filePath(scope, sessionId);
58192
- import_node_fs36.default.mkdirSync(import_node_path41.default.dirname(file), { recursive: true });
58277
+ import_node_fs37.default.mkdirSync(import_node_path42.default.dirname(file), { recursive: true });
58193
58278
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
58194
- import_node_fs36.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
58195
- import_node_fs36.default.renameSync(tmp, file);
58279
+ import_node_fs37.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
58280
+ import_node_fs37.default.renameSync(tmp, file);
58196
58281
  }
58197
58282
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
58198
58283
  list(scope, sessionId) {
@@ -58278,10 +58363,10 @@ var GroupFileStore = class {
58278
58363
  };
58279
58364
 
58280
58365
  // src/discovery/state-file.ts
58281
- var import_node_fs37 = __toESM(require("fs"), 1);
58282
- var import_node_path42 = __toESM(require("path"), 1);
58366
+ var import_node_fs38 = __toESM(require("fs"), 1);
58367
+ var import_node_path43 = __toESM(require("path"), 1);
58283
58368
  function defaultStateFilePath(dataDir) {
58284
- return import_node_path42.default.join(dataDir, "state.json");
58369
+ return import_node_path43.default.join(dataDir, "state.json");
58285
58370
  }
58286
58371
  function isPidAlive(pid) {
58287
58372
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -58303,7 +58388,7 @@ var StateFileManager = class {
58303
58388
  }
58304
58389
  read() {
58305
58390
  try {
58306
- const raw = import_node_fs37.default.readFileSync(this.file, "utf8");
58391
+ const raw = import_node_fs38.default.readFileSync(this.file, "utf8");
58307
58392
  const parsed = JSON.parse(raw);
58308
58393
  return parsed;
58309
58394
  } catch {
@@ -58317,20 +58402,20 @@ var StateFileManager = class {
58317
58402
  return { status: "stale", existing };
58318
58403
  }
58319
58404
  write(state) {
58320
- import_node_fs37.default.mkdirSync(import_node_path42.default.dirname(this.file), { recursive: true });
58405
+ import_node_fs38.default.mkdirSync(import_node_path43.default.dirname(this.file), { recursive: true });
58321
58406
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
58322
- import_node_fs37.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
58323
- import_node_fs37.default.renameSync(tmp, this.file);
58407
+ import_node_fs38.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
58408
+ import_node_fs38.default.renameSync(tmp, this.file);
58324
58409
  if (process.platform !== "win32") {
58325
58410
  try {
58326
- import_node_fs37.default.chmodSync(this.file, 384);
58411
+ import_node_fs38.default.chmodSync(this.file, 384);
58327
58412
  } catch {
58328
58413
  }
58329
58414
  }
58330
58415
  }
58331
58416
  delete() {
58332
58417
  try {
58333
- import_node_fs37.default.unlinkSync(this.file);
58418
+ import_node_fs38.default.unlinkSync(this.file);
58334
58419
  } catch {
58335
58420
  }
58336
58421
  }
@@ -58344,14 +58429,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
58344
58429
  }
58345
58430
 
58346
58431
  // src/tunnel/tunnel-manager.ts
58347
- var import_node_fs41 = __toESM(require("fs"), 1);
58348
- var import_node_path46 = __toESM(require("path"), 1);
58432
+ var import_node_fs42 = __toESM(require("fs"), 1);
58433
+ var import_node_path47 = __toESM(require("path"), 1);
58349
58434
  var import_node_crypto11 = __toESM(require("crypto"), 1);
58350
58435
  var import_node_child_process11 = require("child_process");
58351
58436
 
58352
58437
  // src/tunnel/tunnel-store.ts
58353
- var import_node_fs38 = __toESM(require("fs"), 1);
58354
- var import_node_path43 = __toESM(require("path"), 1);
58438
+ var import_node_fs39 = __toESM(require("fs"), 1);
58439
+ var import_node_path44 = __toESM(require("path"), 1);
58355
58440
  var TunnelStore = class {
58356
58441
  constructor(filePath) {
58357
58442
  this.filePath = filePath;
@@ -58359,7 +58444,7 @@ var TunnelStore = class {
58359
58444
  filePath;
58360
58445
  async get() {
58361
58446
  try {
58362
- const raw = await import_node_fs38.default.promises.readFile(this.filePath, "utf8");
58447
+ const raw = await import_node_fs39.default.promises.readFile(this.filePath, "utf8");
58363
58448
  const obj = JSON.parse(raw);
58364
58449
  if (!isPersistedTunnel(obj)) return null;
58365
58450
  return obj;
@@ -58370,22 +58455,22 @@ var TunnelStore = class {
58370
58455
  }
58371
58456
  }
58372
58457
  async set(v2) {
58373
- const dir = import_node_path43.default.dirname(this.filePath);
58374
- await import_node_fs38.default.promises.mkdir(dir, { recursive: true });
58458
+ const dir = import_node_path44.default.dirname(this.filePath);
58459
+ await import_node_fs39.default.promises.mkdir(dir, { recursive: true });
58375
58460
  const data = JSON.stringify(v2, null, 2);
58376
58461
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
58377
- await import_node_fs38.default.promises.writeFile(tmp, data, { mode: 384 });
58462
+ await import_node_fs39.default.promises.writeFile(tmp, data, { mode: 384 });
58378
58463
  if (process.platform !== "win32") {
58379
58464
  try {
58380
- await import_node_fs38.default.promises.chmod(tmp, 384);
58465
+ await import_node_fs39.default.promises.chmod(tmp, 384);
58381
58466
  } catch {
58382
58467
  }
58383
58468
  }
58384
- await import_node_fs38.default.promises.rename(tmp, this.filePath);
58469
+ await import_node_fs39.default.promises.rename(tmp, this.filePath);
58385
58470
  }
58386
58471
  async clear() {
58387
58472
  try {
58388
- await import_node_fs38.default.promises.unlink(this.filePath);
58473
+ await import_node_fs39.default.promises.unlink(this.filePath);
58389
58474
  } catch (err) {
58390
58475
  const code = err?.code;
58391
58476
  if (code !== "ENOENT") throw err;
@@ -58480,9 +58565,9 @@ function escape(v2) {
58480
58565
  }
58481
58566
 
58482
58567
  // src/tunnel/frpc-binary.ts
58483
- var import_node_fs39 = __toESM(require("fs"), 1);
58568
+ var import_node_fs40 = __toESM(require("fs"), 1);
58484
58569
  var import_node_os14 = __toESM(require("os"), 1);
58485
- var import_node_path44 = __toESM(require("path"), 1);
58570
+ var import_node_path45 = __toESM(require("path"), 1);
58486
58571
  var import_node_child_process9 = require("child_process");
58487
58572
  var import_node_stream3 = require("stream");
58488
58573
  var import_promises7 = require("stream/promises");
@@ -58514,20 +58599,20 @@ function frpcDownloadUrl(version2, p2) {
58514
58599
  }
58515
58600
  async function ensureFrpcBinary(opts) {
58516
58601
  if (opts.override) {
58517
- if (!import_node_fs39.default.existsSync(opts.override)) {
58602
+ if (!import_node_fs40.default.existsSync(opts.override)) {
58518
58603
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
58519
58604
  }
58520
58605
  return opts.override;
58521
58606
  }
58522
58607
  const version2 = opts.version ?? FRPC_VERSION;
58523
58608
  const platform = opts.platform ?? detectPlatform();
58524
- const binDir = import_node_path44.default.join(opts.dataDir, "bin");
58525
- import_node_fs39.default.mkdirSync(binDir, { recursive: true });
58609
+ const binDir = import_node_path45.default.join(opts.dataDir, "bin");
58610
+ import_node_fs40.default.mkdirSync(binDir, { recursive: true });
58526
58611
  cleanupStaleArtifacts(binDir);
58527
- const stableBin = import_node_path44.default.join(binDir, "frpc");
58528
- if (import_node_fs39.default.existsSync(stableBin)) return stableBin;
58612
+ const stableBin = import_node_path45.default.join(binDir, "frpc");
58613
+ if (import_node_fs40.default.existsSync(stableBin)) return stableBin;
58529
58614
  const partialBin = `${stableBin}.partial`;
58530
- const tarballPath = import_node_path44.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
58615
+ const tarballPath = import_node_path45.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
58531
58616
  try {
58532
58617
  const url = frpcDownloadUrl(version2, platform);
58533
58618
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -58536,8 +58621,8 @@ async function ensureFrpcBinary(opts) {
58536
58621
  } else {
58537
58622
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
58538
58623
  }
58539
- import_node_fs39.default.chmodSync(partialBin, 493);
58540
- import_node_fs39.default.renameSync(partialBin, stableBin);
58624
+ import_node_fs40.default.chmodSync(partialBin, 493);
58625
+ import_node_fs40.default.renameSync(partialBin, stableBin);
58541
58626
  } finally {
58542
58627
  safeUnlink(tarballPath);
58543
58628
  safeUnlink(partialBin);
@@ -58547,15 +58632,15 @@ async function ensureFrpcBinary(opts) {
58547
58632
  function cleanupStaleArtifacts(binDir) {
58548
58633
  let entries;
58549
58634
  try {
58550
- entries = import_node_fs39.default.readdirSync(binDir);
58635
+ entries = import_node_fs40.default.readdirSync(binDir);
58551
58636
  } catch {
58552
58637
  return;
58553
58638
  }
58554
58639
  for (const name of entries) {
58555
58640
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
58556
- const full = import_node_path44.default.join(binDir, name);
58641
+ const full = import_node_path45.default.join(binDir, name);
58557
58642
  try {
58558
- import_node_fs39.default.rmSync(full, { recursive: true, force: true });
58643
+ import_node_fs40.default.rmSync(full, { recursive: true, force: true });
58559
58644
  } catch {
58560
58645
  }
58561
58646
  }
@@ -58563,7 +58648,7 @@ function cleanupStaleArtifacts(binDir) {
58563
58648
  }
58564
58649
  function safeUnlink(p2) {
58565
58650
  try {
58566
- import_node_fs39.default.unlinkSync(p2);
58651
+ import_node_fs40.default.unlinkSync(p2);
58567
58652
  } catch {
58568
58653
  }
58569
58654
  }
@@ -58574,13 +58659,13 @@ async function downloadToFile(url, dest, fetchImpl) {
58574
58659
  if (!res.ok || !res.body) {
58575
58660
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
58576
58661
  }
58577
- const out = import_node_fs39.default.createWriteStream(dest);
58662
+ const out = import_node_fs40.default.createWriteStream(dest);
58578
58663
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
58579
58664
  await (0, import_promises7.pipeline)(nodeStream, out);
58580
58665
  }
58581
58666
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
58582
- const work = import_node_path44.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
58583
- import_node_fs39.default.mkdirSync(work, { recursive: true });
58667
+ const work = import_node_path45.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
58668
+ import_node_fs40.default.mkdirSync(work, { recursive: true });
58584
58669
  try {
58585
58670
  await new Promise((resolve9, reject) => {
58586
58671
  const proc = (0, import_node_child_process9.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -58588,32 +58673,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
58588
58673
  proc.on("exit", (code) => code === 0 ? resolve9() : reject(new Error(`tar exited ${code}`)));
58589
58674
  });
58590
58675
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
58591
- const src = import_node_path44.default.join(work, dirName, "frpc");
58592
- if (!import_node_fs39.default.existsSync(src)) {
58676
+ const src = import_node_path45.default.join(work, dirName, "frpc");
58677
+ if (!import_node_fs40.default.existsSync(src)) {
58593
58678
  throw new Error(`frpc not found inside tarball at ${src}`);
58594
58679
  }
58595
- import_node_fs39.default.copyFileSync(src, destBin);
58680
+ import_node_fs40.default.copyFileSync(src, destBin);
58596
58681
  } finally {
58597
- import_node_fs39.default.rmSync(work, { recursive: true, force: true });
58682
+ import_node_fs40.default.rmSync(work, { recursive: true, force: true });
58598
58683
  }
58599
58684
  }
58600
58685
 
58601
58686
  // src/tunnel/frpc-process.ts
58602
- var import_node_fs40 = __toESM(require("fs"), 1);
58603
- var import_node_path45 = __toESM(require("path"), 1);
58687
+ var import_node_fs41 = __toESM(require("fs"), 1);
58688
+ var import_node_path46 = __toESM(require("path"), 1);
58604
58689
  var import_node_child_process10 = require("child_process");
58605
58690
  function frpcPidFilePath(dataDir) {
58606
- return import_node_path45.default.join(dataDir, "frpc.pid");
58691
+ return import_node_path46.default.join(dataDir, "frpc.pid");
58607
58692
  }
58608
58693
  function writeFrpcPid(dataDir, pid) {
58609
58694
  try {
58610
- import_node_fs40.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
58695
+ import_node_fs41.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
58611
58696
  } catch {
58612
58697
  }
58613
58698
  }
58614
58699
  function clearFrpcPid(dataDir) {
58615
58700
  try {
58616
- import_node_fs40.default.unlinkSync(frpcPidFilePath(dataDir));
58701
+ import_node_fs41.default.unlinkSync(frpcPidFilePath(dataDir));
58617
58702
  } catch {
58618
58703
  }
58619
58704
  }
@@ -58629,7 +58714,7 @@ function defaultIsPidAlive(pid) {
58629
58714
  }
58630
58715
  function defaultReadPidFile(file) {
58631
58716
  try {
58632
- return import_node_fs40.default.readFileSync(file, "utf8");
58717
+ return import_node_fs41.default.readFileSync(file, "utf8");
58633
58718
  } catch {
58634
58719
  return null;
58635
58720
  }
@@ -58645,7 +58730,7 @@ function defaultSleep2(ms) {
58645
58730
  }
58646
58731
  async function killStaleFrpc(deps) {
58647
58732
  const pidFile = frpcPidFilePath(deps.dataDir);
58648
- const tomlPath = import_node_path45.default.join(deps.dataDir, "frpc.toml");
58733
+ const tomlPath = import_node_path46.default.join(deps.dataDir, "frpc.toml");
58649
58734
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
58650
58735
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
58651
58736
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -58669,7 +58754,7 @@ async function killStaleFrpc(deps) {
58669
58754
  }
58670
58755
  if (victims.size === 0) {
58671
58756
  try {
58672
- import_node_fs40.default.unlinkSync(pidFile);
58757
+ import_node_fs41.default.unlinkSync(pidFile);
58673
58758
  } catch {
58674
58759
  }
58675
58760
  return;
@@ -58680,7 +58765,7 @@ async function killStaleFrpc(deps) {
58680
58765
  }
58681
58766
  await sleep2(deps.reapWaitMs ?? 300);
58682
58767
  try {
58683
- import_node_fs40.default.unlinkSync(pidFile);
58768
+ import_node_fs41.default.unlinkSync(pidFile);
58684
58769
  } catch {
58685
58770
  }
58686
58771
  }
@@ -58717,7 +58802,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
58717
58802
  var TunnelManager = class {
58718
58803
  constructor(deps) {
58719
58804
  this.deps = deps;
58720
- this.store = deps.store ?? new TunnelStore(import_node_path46.default.join(deps.dataDir, "tunnel.json"));
58805
+ this.store = deps.store ?? new TunnelStore(import_node_path47.default.join(deps.dataDir, "tunnel.json"));
58721
58806
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
58722
58807
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
58723
58808
  }
@@ -58844,7 +58929,7 @@ var TunnelManager = class {
58844
58929
  dataDir: this.deps.dataDir,
58845
58930
  override: this.deps.frpcBinaryOverride ?? void 0
58846
58931
  });
58847
- const tomlPath = import_node_path46.default.join(this.deps.dataDir, "frpc.toml");
58932
+ const tomlPath = import_node_path47.default.join(this.deps.dataDir, "frpc.toml");
58848
58933
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto11.default.randomBytes(3).toString("hex")}`;
58849
58934
  const toml = buildFrpcToml({
58850
58935
  serverAddr: t.frpsHost,
@@ -58855,14 +58940,14 @@ var TunnelManager = class {
58855
58940
  localPort,
58856
58941
  logLevel: "info"
58857
58942
  });
58858
- await import_node_fs41.default.promises.writeFile(tomlPath, toml, { mode: 384 });
58943
+ await import_node_fs42.default.promises.writeFile(tomlPath, toml, { mode: 384 });
58859
58944
  const proc = (this.deps.spawnImpl ?? import_node_child_process11.spawn)(frpcBin, ["-c", tomlPath], {
58860
58945
  stdio: ["ignore", "pipe", "pipe"]
58861
58946
  });
58862
- const logDir = import_node_path46.default.join(this.deps.dataDir, "log");
58863
- import_node_fs41.default.mkdirSync(logDir, { recursive: true });
58864
- const logFilePath = import_node_path46.default.join(logDir, "frpc.log");
58865
- const logStream = import_node_fs41.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
58947
+ const logDir = import_node_path47.default.join(this.deps.dataDir, "log");
58948
+ import_node_fs42.default.mkdirSync(logDir, { recursive: true });
58949
+ const logFilePath = import_node_path47.default.join(logDir, "frpc.log");
58950
+ const logStream = import_node_fs42.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
58866
58951
  logStream.on("error", () => {
58867
58952
  });
58868
58953
  const tee = (chunk) => {
@@ -58945,27 +59030,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
58945
59030
 
58946
59031
  // src/tunnel/device-key.ts
58947
59032
  var import_node_os15 = __toESM(require("os"), 1);
58948
- var import_node_path47 = __toESM(require("path"), 1);
59033
+ var import_node_path48 = __toESM(require("path"), 1);
58949
59034
  var import_node_crypto12 = __toESM(require("crypto"), 1);
58950
59035
  var DERIVE_SALT = "clawd-tunnel-device-v1";
58951
59036
  function deriveStableDeviceKey(opts = {}) {
58952
59037
  const hostname = opts.hostname ?? import_node_os15.default.hostname();
58953
59038
  const uid = opts.uid ?? (typeof import_node_os15.default.userInfo === "function" ? import_node_os15.default.userInfo().uid : 0);
58954
59039
  const home = opts.home ?? import_node_os15.default.homedir();
58955
- const defaultDataDir = import_node_path47.default.resolve(import_node_path47.default.join(home, ".clawd"));
58956
- const normalizedDataDir = opts.dataDir ? import_node_path47.default.resolve(opts.dataDir) : null;
59040
+ const defaultDataDir = import_node_path48.default.resolve(import_node_path48.default.join(home, ".clawd"));
59041
+ const normalizedDataDir = opts.dataDir ? import_node_path48.default.resolve(opts.dataDir) : null;
58957
59042
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
58958
59043
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
58959
59044
  return import_node_crypto12.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
58960
59045
  }
58961
59046
 
58962
59047
  // src/auth-store.ts
58963
- var import_node_fs42 = __toESM(require("fs"), 1);
58964
- var import_node_path48 = __toESM(require("path"), 1);
59048
+ var import_node_fs43 = __toESM(require("fs"), 1);
59049
+ var import_node_path49 = __toESM(require("path"), 1);
58965
59050
  var import_node_crypto13 = __toESM(require("crypto"), 1);
58966
59051
  var AUTH_FILE_NAME = "auth.json";
58967
59052
  function authFilePath(dataDir) {
58968
- return import_node_path48.default.join(dataDir, AUTH_FILE_NAME);
59053
+ return import_node_path49.default.join(dataDir, AUTH_FILE_NAME);
58969
59054
  }
58970
59055
  function loadOrCreateAuthFile(opts) {
58971
59056
  const file = authFilePath(opts.dataDir);
@@ -58997,7 +59082,7 @@ function defaultGenerateOwnerPrincipalId() {
58997
59082
  }
58998
59083
  function readAuthFile(file) {
58999
59084
  try {
59000
- const raw = import_node_fs42.default.readFileSync(file, "utf8");
59085
+ const raw = import_node_fs43.default.readFileSync(file, "utf8");
59001
59086
  const parsed = JSON.parse(raw);
59002
59087
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
59003
59088
  return null;
@@ -59017,26 +59102,26 @@ function readAuthFile(file) {
59017
59102
  }
59018
59103
  }
59019
59104
  function writeAuthFile(file, content) {
59020
- import_node_fs42.default.mkdirSync(import_node_path48.default.dirname(file), { recursive: true });
59021
- import_node_fs42.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
59105
+ import_node_fs43.default.mkdirSync(import_node_path49.default.dirname(file), { recursive: true });
59106
+ import_node_fs43.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
59022
59107
  try {
59023
- import_node_fs42.default.chmodSync(file, 384);
59108
+ import_node_fs43.default.chmodSync(file, 384);
59024
59109
  } catch {
59025
59110
  }
59026
59111
  }
59027
59112
 
59028
59113
  // src/owner-profile.ts
59029
- var import_node_fs43 = __toESM(require("fs"), 1);
59114
+ var import_node_fs44 = __toESM(require("fs"), 1);
59030
59115
  var import_node_os16 = __toESM(require("os"), 1);
59031
- var import_node_path49 = __toESM(require("path"), 1);
59116
+ var import_node_path50 = __toESM(require("path"), 1);
59032
59117
  var PROFILE_FILENAME = "profile.json";
59033
59118
  function profilePath(dataDir) {
59034
- return import_node_path49.default.join(dataDir, PROFILE_FILENAME);
59119
+ return import_node_path50.default.join(dataDir, PROFILE_FILENAME);
59035
59120
  }
59036
59121
  function loadOwnerProfile(dataDir) {
59037
59122
  let raw;
59038
59123
  try {
59039
- raw = import_node_fs43.default.readFileSync(profilePath(dataDir), "utf8");
59124
+ raw = import_node_fs44.default.readFileSync(profilePath(dataDir), "utf8");
59040
59125
  } catch {
59041
59126
  return {};
59042
59127
  }
@@ -59052,7 +59137,7 @@ function loadOwnerProfile(dataDir) {
59052
59137
  }
59053
59138
  function patchOwnerProfile(dataDir, patch) {
59054
59139
  const merged = { ...loadOwnerProfile(dataDir), ...patch };
59055
- import_node_fs43.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
59140
+ import_node_fs44.default.writeFileSync(profilePath(dataDir), JSON.stringify(merged, null, 2), { encoding: "utf8", mode: 384 });
59056
59141
  return merged;
59057
59142
  }
59058
59143
  function loadOwnerDisplayName(dataDir) {
@@ -59068,18 +59153,18 @@ function loadOwnerDisplayName(dataDir) {
59068
59153
  }
59069
59154
 
59070
59155
  // src/feishu-auth/owner-identity-store.ts
59071
- var import_node_fs44 = __toESM(require("fs"), 1);
59072
- var import_node_path50 = __toESM(require("path"), 1);
59156
+ var import_node_fs45 = __toESM(require("fs"), 1);
59157
+ var import_node_path51 = __toESM(require("path"), 1);
59073
59158
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
59074
59159
  var OwnerIdentityStore = class {
59075
59160
  file;
59076
59161
  constructor(dataDir) {
59077
- this.file = import_node_path50.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
59162
+ this.file = import_node_path51.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
59078
59163
  }
59079
59164
  read() {
59080
59165
  let raw;
59081
59166
  try {
59082
- raw = import_node_fs44.default.readFileSync(this.file, "utf8");
59167
+ raw = import_node_fs45.default.readFileSync(this.file, "utf8");
59083
59168
  } catch {
59084
59169
  return null;
59085
59170
  }
@@ -59107,16 +59192,16 @@ var OwnerIdentityStore = class {
59107
59192
  };
59108
59193
  }
59109
59194
  write(record3) {
59110
- import_node_fs44.default.mkdirSync(import_node_path50.default.dirname(this.file), { recursive: true });
59111
- import_node_fs44.default.writeFileSync(this.file, JSON.stringify(record3, null, 2), { mode: 384 });
59195
+ import_node_fs45.default.mkdirSync(import_node_path51.default.dirname(this.file), { recursive: true });
59196
+ import_node_fs45.default.writeFileSync(this.file, JSON.stringify(record3, null, 2), { mode: 384 });
59112
59197
  try {
59113
- import_node_fs44.default.chmodSync(this.file, 384);
59198
+ import_node_fs45.default.chmodSync(this.file, 384);
59114
59199
  } catch {
59115
59200
  }
59116
59201
  }
59117
59202
  clear() {
59118
59203
  try {
59119
- import_node_fs44.default.unlinkSync(this.file);
59204
+ import_node_fs45.default.unlinkSync(this.file);
59120
59205
  } catch (err) {
59121
59206
  const code = err?.code;
59122
59207
  if (code !== "ENOENT") throw err;
@@ -59253,9 +59338,9 @@ var CentralClientError = class extends Error {
59253
59338
  code;
59254
59339
  cause;
59255
59340
  };
59256
- async function centralRequest(opts, path89, init) {
59341
+ async function centralRequest(opts, path90, init) {
59257
59342
  const f = opts.fetchImpl ?? globalThis.fetch;
59258
- const url = `${opts.api.replace(/\/+$/, "")}${path89}`;
59343
+ const url = `${opts.api.replace(/\/+$/, "")}${path90}`;
59259
59344
  const ctrl = new AbortController();
59260
59345
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
59261
59346
  let res;
@@ -59449,8 +59534,8 @@ function verifyConnectToken(args) {
59449
59534
  }
59450
59535
 
59451
59536
  // src/feishu-auth/server-key.ts
59452
- var fs59 = __toESM(require("fs"), 1);
59453
- var path63 = __toESM(require("path"), 1);
59537
+ var fs60 = __toESM(require("fs"), 1);
59538
+ var path64 = __toESM(require("path"), 1);
59454
59539
  var FILE_NAME2 = "server-signing-key.json";
59455
59540
  var ServerKeyStore = class {
59456
59541
  constructor(dataDir) {
@@ -59458,12 +59543,12 @@ var ServerKeyStore = class {
59458
59543
  }
59459
59544
  dataDir;
59460
59545
  filePath() {
59461
- return path63.join(this.dataDir, FILE_NAME2);
59546
+ return path64.join(this.dataDir, FILE_NAME2);
59462
59547
  }
59463
59548
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
59464
59549
  read() {
59465
59550
  try {
59466
- const raw = fs59.readFileSync(this.filePath(), "utf8");
59551
+ const raw = fs60.readFileSync(this.filePath(), "utf8");
59467
59552
  const parsed = JSON.parse(raw);
59468
59553
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
59469
59554
  return parsed.publicKeyPem;
@@ -59478,12 +59563,12 @@ var ServerKeyStore = class {
59478
59563
  publicKeyPem,
59479
59564
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
59480
59565
  };
59481
- fs59.mkdirSync(this.dataDir, { recursive: true });
59482
- fs59.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
59566
+ fs60.mkdirSync(this.dataDir, { recursive: true });
59567
+ fs60.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
59483
59568
  }
59484
59569
  clear() {
59485
59570
  try {
59486
- fs59.unlinkSync(this.filePath());
59571
+ fs60.unlinkSync(this.filePath());
59487
59572
  } catch {
59488
59573
  }
59489
59574
  }
@@ -59493,18 +59578,18 @@ var ServerKeyStore = class {
59493
59578
  init_protocol();
59494
59579
 
59495
59580
  // src/handlers/index.ts
59496
- var import_node_path66 = __toESM(require("path"), 1);
59581
+ var import_node_path67 = __toESM(require("path"), 1);
59497
59582
 
59498
59583
  // src/handlers/session.ts
59499
59584
  init_protocol();
59500
59585
 
59501
59586
  // src/session/fork.ts
59502
- var import_node_fs45 = __toESM(require("fs"), 1);
59587
+ var import_node_fs46 = __toESM(require("fs"), 1);
59503
59588
  var import_node_os17 = __toESM(require("os"), 1);
59504
- var import_node_path51 = __toESM(require("path"), 1);
59589
+ var import_node_path52 = __toESM(require("path"), 1);
59505
59590
  init_claude_history();
59506
59591
  function readJsonlEntries(file) {
59507
- const raw = import_node_fs45.default.readFileSync(file, "utf8");
59592
+ const raw = import_node_fs46.default.readFileSync(file, "utf8");
59508
59593
  const out = [];
59509
59594
  for (const line of raw.split("\n")) {
59510
59595
  const t = line.trim();
@@ -59517,19 +59602,19 @@ function readJsonlEntries(file) {
59517
59602
  return out;
59518
59603
  }
59519
59604
  function forkSession(input) {
59520
- const baseDir = input.baseDir ?? import_node_path51.default.join(import_node_os17.default.homedir(), ".claude");
59521
- let projectDir = import_node_path51.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
59522
- let sourceFile = import_node_path51.default.join(projectDir, `${input.toolSessionId}.jsonl`);
59523
- if (!import_node_fs45.default.existsSync(sourceFile)) {
59605
+ const baseDir = input.baseDir ?? import_node_path52.default.join(import_node_os17.default.homedir(), ".claude");
59606
+ let projectDir = import_node_path52.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
59607
+ let sourceFile = import_node_path52.default.join(projectDir, `${input.toolSessionId}.jsonl`);
59608
+ if (!import_node_fs46.default.existsSync(sourceFile)) {
59524
59609
  const found = findTranscriptByToolSessionId(
59525
- import_node_path51.default.join(baseDir, "projects"),
59610
+ import_node_path52.default.join(baseDir, "projects"),
59526
59611
  input.toolSessionId
59527
59612
  );
59528
59613
  if (!found) {
59529
59614
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
59530
59615
  }
59531
59616
  sourceFile = found;
59532
- projectDir = import_node_path51.default.dirname(found);
59617
+ projectDir = import_node_path52.default.dirname(found);
59533
59618
  }
59534
59619
  const entries = readJsonlEntries(sourceFile);
59535
59620
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -59558,27 +59643,27 @@ function forkSession(input) {
59558
59643
  }
59559
59644
  forkedLines.push(JSON.stringify(forked));
59560
59645
  }
59561
- const outDir = input.targetCwd ? import_node_path51.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
59562
- const forkedFilePath = import_node_path51.default.join(outDir, `${forkedToolSessionId}.jsonl`);
59563
- import_node_fs45.default.mkdirSync(outDir, { recursive: true });
59564
- import_node_fs45.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
59646
+ const outDir = input.targetCwd ? import_node_path52.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
59647
+ const forkedFilePath = import_node_path52.default.join(outDir, `${forkedToolSessionId}.jsonl`);
59648
+ import_node_fs46.default.mkdirSync(outDir, { recursive: true });
59649
+ import_node_fs46.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
59565
59650
  return { forkedToolSessionId, forkedFilePath };
59566
59651
  }
59567
59652
 
59568
59653
  // src/session/external-scan.ts
59569
- var import_node_fs46 = __toESM(require("fs"), 1);
59654
+ var import_node_fs47 = __toESM(require("fs"), 1);
59570
59655
  var import_promises8 = __toESM(require("fs/promises"), 1);
59571
59656
  var import_node_os18 = __toESM(require("os"), 1);
59572
- var import_node_path52 = __toESM(require("path"), 1);
59657
+ var import_node_path53 = __toESM(require("path"), 1);
59573
59658
  var import_node_module = require("module");
59574
59659
  var import_node_child_process12 = require("child_process");
59575
59660
  var import_meta4 = {};
59576
59661
  function defaultRoots() {
59577
59662
  const home = import_node_os18.default.homedir();
59578
59663
  return {
59579
- claudeProjectsDir: import_node_path52.default.join(home, ".claude", "projects"),
59580
- codexDir: import_node_path52.default.join(home, ".codex"),
59581
- clawdDir: import_node_path52.default.join(home, ".clawd")
59664
+ claudeProjectsDir: import_node_path53.default.join(home, ".claude", "projects"),
59665
+ codexDir: import_node_path53.default.join(home, ".codex"),
59666
+ clawdDir: import_node_path53.default.join(home, ".clawd")
59582
59667
  };
59583
59668
  }
59584
59669
  function width(s) {
@@ -59629,7 +59714,7 @@ function userText(msg) {
59629
59714
  }
59630
59715
  function isDir2(p2) {
59631
59716
  try {
59632
- return import_node_fs46.default.statSync(p2).isDirectory();
59717
+ return import_node_fs47.default.statSync(p2).isDirectory();
59633
59718
  } catch {
59634
59719
  return false;
59635
59720
  }
@@ -59638,7 +59723,7 @@ async function scanClaude(roots) {
59638
59723
  const out = [];
59639
59724
  let dirs;
59640
59725
  try {
59641
- dirs = import_node_fs46.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
59726
+ dirs = import_node_fs47.default.readdirSync(roots.claudeProjectsDir, { withFileTypes: true });
59642
59727
  } catch {
59643
59728
  return out;
59644
59729
  }
@@ -59646,16 +59731,16 @@ async function scanClaude(roots) {
59646
59731
  if (!d.isDirectory()) continue;
59647
59732
  let files;
59648
59733
  try {
59649
- files = import_node_fs46.default.readdirSync(import_node_path52.default.join(roots.claudeProjectsDir, d.name));
59734
+ files = import_node_fs47.default.readdirSync(import_node_path53.default.join(roots.claudeProjectsDir, d.name));
59650
59735
  } catch {
59651
59736
  continue;
59652
59737
  }
59653
59738
  for (const name of files) {
59654
59739
  if (!name.endsWith(".jsonl")) continue;
59655
- const file = import_node_path52.default.join(roots.claudeProjectsDir, d.name, name);
59740
+ const file = import_node_path53.default.join(roots.claudeProjectsDir, d.name, name);
59656
59741
  let st;
59657
59742
  try {
59658
- st = import_node_fs46.default.statSync(file);
59743
+ st = import_node_fs47.default.statSync(file);
59659
59744
  } catch {
59660
59745
  continue;
59661
59746
  }
@@ -59708,7 +59793,7 @@ async function scanClaude(roots) {
59708
59793
  return out;
59709
59794
  }
59710
59795
  async function countCodexTurns(rolloutPath) {
59711
- if (!rolloutPath || !import_node_fs46.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
59796
+ if (!rolloutPath || !import_node_fs47.default.existsSync(rolloutPath)) return { turns: 0, first: "" };
59712
59797
  let turns = 0;
59713
59798
  let first = "";
59714
59799
  for await (const rec4 of jsonLines(rolloutPath)) {
@@ -59782,7 +59867,7 @@ async function codexFromRows(rows) {
59782
59867
  async function scanCodex(roots) {
59783
59868
  let dbs = [];
59784
59869
  try {
59785
- dbs = import_node_fs46.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path52.default.join(roots.codexDir, n));
59870
+ dbs = import_node_fs47.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path53.default.join(roots.codexDir, n));
59786
59871
  } catch {
59787
59872
  }
59788
59873
  if (!dbs.length) return [];
@@ -59791,14 +59876,14 @@ async function scanCodex(roots) {
59791
59876
  }
59792
59877
  async function scanExternalSessions(rootsIn) {
59793
59878
  const roots = { ...defaultRoots(), ...rootsIn };
59794
- const personaRoot = import_node_path52.default.join(roots.clawdDir, "personas");
59879
+ const personaRoot = import_node_path53.default.join(roots.clawdDir, "personas");
59795
59880
  const all = [...await scanClaude(roots), ...await scanCodex(roots)];
59796
59881
  const out = [];
59797
59882
  for (const c of all) {
59798
59883
  if (c.skip) continue;
59799
59884
  if (c.turns < 1) continue;
59800
59885
  if (!c.cwd || !isDir2(c.cwd)) continue;
59801
- if (c.cwd === roots.clawdDir || c.cwd === personaRoot || c.cwd.startsWith(personaRoot + import_node_path52.default.sep) || c.cwd.startsWith(roots.clawdDir + import_node_path52.default.sep)) {
59886
+ if (c.cwd === roots.clawdDir || c.cwd === personaRoot || c.cwd.startsWith(personaRoot + import_node_path53.default.sep) || c.cwd.startsWith(roots.clawdDir + import_node_path53.default.sep)) {
59802
59887
  continue;
59803
59888
  }
59804
59889
  out.push({
@@ -59815,13 +59900,13 @@ async function scanExternalSessions(rootsIn) {
59815
59900
  }
59816
59901
 
59817
59902
  // src/session/import-ledger.ts
59818
- var import_node_fs47 = __toESM(require("fs"), 1);
59819
- var import_node_path53 = __toESM(require("path"), 1);
59903
+ var import_node_fs48 = __toESM(require("fs"), 1);
59904
+ var import_node_path54 = __toESM(require("path"), 1);
59820
59905
  var LEDGER_FILENAME = "session-import-ledger.json";
59821
59906
  function readImportLedger(dataDir) {
59822
59907
  try {
59823
59908
  const parsed = JSON.parse(
59824
- import_node_fs47.default.readFileSync(import_node_path53.default.join(dataDir, LEDGER_FILENAME), "utf8")
59909
+ import_node_fs48.default.readFileSync(import_node_path54.default.join(dataDir, LEDGER_FILENAME), "utf8")
59825
59910
  );
59826
59911
  return Array.isArray(parsed) ? parsed : [];
59827
59912
  } catch {
@@ -59829,10 +59914,10 @@ function readImportLedger(dataDir) {
59829
59914
  }
59830
59915
  }
59831
59916
  function appendImportLedger(dataDir, entry) {
59832
- const file = import_node_path53.default.join(dataDir, LEDGER_FILENAME);
59917
+ const file = import_node_path54.default.join(dataDir, LEDGER_FILENAME);
59833
59918
  const entries = readImportLedger(dataDir);
59834
59919
  entries.push(entry);
59835
- import_node_fs47.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
59920
+ import_node_fs48.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
59836
59921
  }
59837
59922
 
59838
59923
  // src/handlers/session.ts
@@ -60335,7 +60420,7 @@ function buildPermissionHandlers(deps) {
60335
60420
  }
60336
60421
 
60337
60422
  // src/handlers/history.ts
60338
- var path68 = __toESM(require("path"), 1);
60423
+ var path69 = __toESM(require("path"), 1);
60339
60424
  init_protocol();
60340
60425
 
60341
60426
  // src/session/recent-dirs.ts
@@ -60353,7 +60438,7 @@ function listRecentDirs(store, limit = 50) {
60353
60438
  }
60354
60439
 
60355
60440
  // src/permission/persona-paths.ts
60356
- var path67 = __toESM(require("path"), 1);
60441
+ var path68 = __toESM(require("path"), 1);
60357
60442
  function getAllowedPersonaIds(grants, action) {
60358
60443
  const ids = /* @__PURE__ */ new Set();
60359
60444
  for (const g2 of grants) {
@@ -60366,42 +60451,42 @@ function getAllowedPersonaIds(grants, action) {
60366
60451
  return ids;
60367
60452
  }
60368
60453
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
60369
- const target = path67.resolve(absPath);
60454
+ const target = path68.resolve(absPath);
60370
60455
  if (userWorkDir) {
60371
- const u = path67.resolve(userWorkDir);
60372
- const usep = u.endsWith(path67.sep) ? "" : path67.sep;
60456
+ const u = path68.resolve(userWorkDir);
60457
+ const usep = u.endsWith(path68.sep) ? "" : path68.sep;
60373
60458
  if (target === u || target.startsWith(u + usep)) return true;
60374
60459
  }
60375
- const root = path67.resolve(personaRoot);
60376
- const sep4 = root.endsWith(path67.sep) ? "" : path67.sep;
60460
+ const root = path68.resolve(personaRoot);
60461
+ const sep4 = root.endsWith(path68.sep) ? "" : path68.sep;
60377
60462
  if (!target.startsWith(root + sep4)) return false;
60378
- const rel = path67.relative(root, target);
60463
+ const rel = path68.relative(root, target);
60379
60464
  if (!rel || rel.startsWith("..")) return false;
60380
- const personaId2 = rel.split(path67.sep)[0];
60465
+ const personaId2 = rel.split(path68.sep)[0];
60381
60466
  if (!personaId2) return false;
60382
60467
  const allowed = getAllowedPersonaIds(grants, action);
60383
60468
  if (allowed === "*") return true;
60384
60469
  return allowed.has(personaId2);
60385
60470
  }
60386
60471
  function personaIdFromPath(absPath, personaRoot) {
60387
- const root = path67.resolve(personaRoot);
60388
- const target = path67.resolve(absPath);
60389
- const sep4 = root.endsWith(path67.sep) ? "" : path67.sep;
60472
+ const root = path68.resolve(personaRoot);
60473
+ const target = path68.resolve(absPath);
60474
+ const sep4 = root.endsWith(path68.sep) ? "" : path68.sep;
60390
60475
  if (!target.startsWith(root + sep4)) return null;
60391
- const rel = path67.relative(root, target);
60476
+ const rel = path68.relative(root, target);
60392
60477
  if (!rel || rel.startsWith("..")) return null;
60393
- const id = rel.split(path67.sep)[0];
60478
+ const id = rel.split(path68.sep)[0];
60394
60479
  return id || null;
60395
60480
  }
60396
60481
  function isPathWithin(dir, absPath) {
60397
- const d = path67.resolve(dir);
60398
- const t = path67.resolve(absPath);
60399
- const sep4 = d.endsWith(path67.sep) ? "" : path67.sep;
60482
+ const d = path68.resolve(dir);
60483
+ const t = path68.resolve(absPath);
60484
+ const sep4 = d.endsWith(path68.sep) ? "" : path68.sep;
60400
60485
  return t === d || t.startsWith(d + sep4);
60401
60486
  }
60402
60487
  function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
60403
60488
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
60404
- return personaIdFromPath(path67.resolve(absPath), personaRoot) === personaId2;
60489
+ return personaIdFromPath(path68.resolve(absPath), personaRoot) === personaId2;
60405
60490
  }
60406
60491
 
60407
60492
  // src/handlers/history.ts
@@ -60454,7 +60539,7 @@ function buildHistoryHandlers(deps) {
60454
60539
  if (!pid) return false;
60455
60540
  return isGuestPathAllowed(
60456
60541
  ctx.grants,
60457
- path68.join(personaRoot, pid),
60542
+ path69.join(personaRoot, pid),
60458
60543
  personaRoot,
60459
60544
  "read",
60460
60545
  userWorkDir
@@ -60466,7 +60551,7 @@ function buildHistoryHandlers(deps) {
60466
60551
  };
60467
60552
  const list = async (frame, _client, ctx) => {
60468
60553
  const args = HistoryListArgs.parse(frame);
60469
- assertGuestPath(ctx, path68.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
60554
+ assertGuestPath(ctx, path69.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
60470
60555
  const sessions = await history.listSessions(args);
60471
60556
  return { response: { type: "history:list", sessions } };
60472
60557
  };
@@ -60514,14 +60599,14 @@ function buildHistoryHandlers(deps) {
60514
60599
  };
60515
60600
  const subagents = async (frame, _client, ctx) => {
60516
60601
  const args = HistorySubagentsArgs.parse(frame);
60517
- assertGuestPath(ctx, path68.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
60602
+ assertGuestPath(ctx, path69.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
60518
60603
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagents");
60519
60604
  const subs = await historyReaderForToolSession(args.toolSessionId).listSubagents(args);
60520
60605
  return { response: { type: "history:subagents", subagents: subs } };
60521
60606
  };
60522
60607
  const subagentRead = async (frame, _client, ctx) => {
60523
60608
  const args = HistorySubagentReadArgs.parse(frame);
60524
- assertGuestPath(ctx, path68.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
60609
+ assertGuestPath(ctx, path69.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
60525
60610
  assertGuestOwnsToolSession(ctx, args.toolSessionId, "history:subagent-read");
60526
60611
  const res = await historyReaderForToolSession(args.toolSessionId).readSubagent(args);
60527
60612
  return { response: { type: "history:subagent-read", ...res } };
@@ -60531,7 +60616,7 @@ function buildHistoryHandlers(deps) {
60531
60616
  if (ctx?.principal.kind === "guest" && personaRoot) {
60532
60617
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
60533
60618
  const filtered = dirs.filter(
60534
- (d) => isGuestPathAllowed(ctx.grants, path68.resolve(d.cwd), personaRoot, "read", userWorkDir)
60619
+ (d) => isGuestPathAllowed(ctx.grants, path69.resolve(d.cwd), personaRoot, "read", userWorkDir)
60535
60620
  );
60536
60621
  return { response: { type: "history:recentDirs", dirs: filtered } };
60537
60622
  }
@@ -60548,17 +60633,17 @@ function buildHistoryHandlers(deps) {
60548
60633
  }
60549
60634
 
60550
60635
  // src/handlers/projects.ts
60551
- var fs63 = __toESM(require("fs"), 1);
60636
+ var fs64 = __toESM(require("fs"), 1);
60552
60637
  var os20 = __toESM(require("os"), 1);
60553
- var path69 = __toESM(require("path"), 1);
60638
+ var path70 = __toESM(require("path"), 1);
60554
60639
  var import_node_child_process13 = require("child_process");
60555
60640
  init_protocol();
60556
- var DEFAULT_PROJECTS_ROOT = path69.join(os20.homedir(), "Documents", "ChatGPT");
60641
+ var DEFAULT_PROJECTS_ROOT = path70.join(os20.homedir(), "Documents", "ChatGPT");
60557
60642
  function allocateDir(root, name) {
60558
- let candidate = path69.join(root, name);
60643
+ let candidate = path70.join(root, name);
60559
60644
  let n = 2;
60560
- while (fs63.existsSync(candidate)) {
60561
- candidate = path69.join(root, `${name} ${n}`);
60645
+ while (fs64.existsSync(candidate)) {
60646
+ candidate = path70.join(root, `${name} ${n}`);
60562
60647
  n += 1;
60563
60648
  }
60564
60649
  return candidate;
@@ -60586,7 +60671,7 @@ function buildProjectHandlers(deps) {
60586
60671
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "project:reveal \u4EC5\u652F\u6301 macOS");
60587
60672
  }
60588
60673
  try {
60589
- if (!fs63.statSync(args.path).isDirectory()) throw new Error("not dir");
60674
+ if (!fs64.statSync(args.path).isDirectory()) throw new Error("not dir");
60590
60675
  } catch {
60591
60676
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
60592
60677
  }
@@ -60602,7 +60687,7 @@ function buildProjectHandlers(deps) {
60602
60687
  let target;
60603
60688
  if (args.path) {
60604
60689
  try {
60605
- if (!fs63.statSync(args.path).isDirectory()) throw new Error("not dir");
60690
+ if (!fs64.statSync(args.path).isDirectory()) throw new Error("not dir");
60606
60691
  } catch {
60607
60692
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${args.path}`);
60608
60693
  }
@@ -60610,15 +60695,15 @@ function buildProjectHandlers(deps) {
60610
60695
  } else {
60611
60696
  const name = args.name;
60612
60697
  try {
60613
- fs63.mkdirSync(root, { recursive: true });
60698
+ fs64.mkdirSync(root, { recursive: true });
60614
60699
  target = allocateDir(root, name);
60615
- fs63.mkdirSync(target);
60700
+ fs64.mkdirSync(target);
60616
60701
  } catch (err) {
60617
60702
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `\u521B\u5EFA\u9879\u76EE\u76EE\u5F55\u5931\u8D25: ${String(err)}`);
60618
60703
  }
60619
60704
  const git = (0, import_node_child_process13.spawnSync)("git", ["init"], { cwd: target, stdio: "ignore" });
60620
60705
  if (git.status !== 0) {
60621
- fs63.rmSync(target, { recursive: true, force: true });
60706
+ fs64.rmSync(target, { recursive: true, force: true });
60622
60707
  throw new ClawdError(
60623
60708
  ERROR_CODES.INVALID_CWD,
60624
60709
  `git init \u5931\u8D25\uFF08${git.error ? String(git.error) : `exit ${git.status}`}\uFF09: ${target}`
@@ -60643,7 +60728,7 @@ function buildProjectHandlers(deps) {
60643
60728
  }
60644
60729
 
60645
60730
  // src/handlers/workspace.ts
60646
- var path70 = __toESM(require("path"), 1);
60731
+ var path71 = __toESM(require("path"), 1);
60647
60732
  var os21 = __toESM(require("os"), 1);
60648
60733
  init_protocol();
60649
60734
  init_protocol();
@@ -60685,22 +60770,22 @@ function buildWorkspaceHandlers(deps) {
60685
60770
  const args = WorkspaceListArgs.parse(frame);
60686
60771
  const isGuest = ctx?.principal.kind === "guest";
60687
60772
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os21.homedir();
60688
- const resolvedCwd = path70.resolve(args.cwd ?? fallbackCwd);
60689
- const target = args.path ? path70.resolve(resolvedCwd, args.path) : resolvedCwd;
60773
+ const resolvedCwd = path71.resolve(args.cwd ?? fallbackCwd);
60774
+ const target = args.path ? path71.resolve(resolvedCwd, args.path) : resolvedCwd;
60690
60775
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
60691
60776
  const res = workspace.list({ ...args, cwd: resolvedCwd });
60692
60777
  return { response: { type: "workspace:list", ...res } };
60693
60778
  };
60694
60779
  const read = async (frame, _client, ctx) => {
60695
60780
  const args = WorkspaceReadArgs.parse(frame);
60696
- const target = path70.isAbsolute(args.path) ? path70.resolve(args.path) : path70.resolve(args.cwd, args.path);
60781
+ const target = path71.isAbsolute(args.path) ? path71.resolve(args.path) : path71.resolve(args.cwd, args.path);
60697
60782
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
60698
60783
  const res = workspace.read(args);
60699
60784
  return { response: { type: "workspace:read", ...res } };
60700
60785
  };
60701
60786
  const skillsList = async (frame, _client, ctx) => {
60702
60787
  const args = SkillsListArgs.parse(frame);
60703
- const cwdAbs = path70.resolve(args.cwd);
60788
+ const cwdAbs = path71.resolve(args.cwd);
60704
60789
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
60705
60790
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
60706
60791
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -60712,7 +60797,7 @@ function buildWorkspaceHandlers(deps) {
60712
60797
  };
60713
60798
  const agentsList = async (frame, _client, ctx) => {
60714
60799
  const args = AgentsListArgs.parse(frame);
60715
- const cwdAbs = path70.resolve(args.cwd);
60800
+ const cwdAbs = path71.resolve(args.cwd);
60716
60801
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
60717
60802
  if (args.tool === "codex") {
60718
60803
  return { response: { type: "agents:list", agents: [] } };
@@ -60734,20 +60819,20 @@ function buildWorkspaceHandlers(deps) {
60734
60819
  }
60735
60820
 
60736
60821
  // src/handlers/git.ts
60737
- var path72 = __toESM(require("path"), 1);
60822
+ var path73 = __toESM(require("path"), 1);
60738
60823
  init_protocol();
60739
60824
  init_protocol();
60740
60825
 
60741
60826
  // src/workspace/git.ts
60742
60827
  var import_node_child_process14 = require("child_process");
60743
- var import_node_fs48 = __toESM(require("fs"), 1);
60744
- var import_node_path54 = __toESM(require("path"), 1);
60828
+ var import_node_fs49 = __toESM(require("fs"), 1);
60829
+ var import_node_path55 = __toESM(require("path"), 1);
60745
60830
  var import_node_util = require("util");
60746
60831
  var pexec = (0, import_node_util.promisify)(import_node_child_process14.execFile);
60747
60832
  function normalizePath(p2) {
60748
- const resolved = import_node_path54.default.resolve(p2);
60833
+ const resolved = import_node_path55.default.resolve(p2);
60749
60834
  try {
60750
- return import_node_fs48.default.realpathSync(resolved);
60835
+ return import_node_fs49.default.realpathSync(resolved);
60751
60836
  } catch {
60752
60837
  return resolved;
60753
60838
  }
@@ -60821,7 +60906,7 @@ async function listGitBranches(cwd) {
60821
60906
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
60822
60907
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
60823
60908
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
60824
- if (!isGuestPathAllowed(ctx.grants, path72.resolve(cwd), personaRoot, "read", userWorkDir)) {
60909
+ if (!isGuestPathAllowed(ctx.grants, path73.resolve(cwd), personaRoot, "read", userWorkDir)) {
60825
60910
  throw new ClawdError(
60826
60911
  ERROR_CODES.UNAUTHORIZED,
60827
60912
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -61740,21 +61825,21 @@ function computeMethodAccess(args) {
61740
61825
  }
61741
61826
 
61742
61827
  // src/version.ts
61743
- var version = "0.2.383".length > 0 ? "0.2.383" : "dev";
61828
+ var version = "0.2.384".length > 0 ? "0.2.384" : "dev";
61744
61829
 
61745
61830
  // src/cli-probe/probe.ts
61746
- var fs65 = __toESM(require("fs"), 1);
61747
- var path73 = __toESM(require("path"), 1);
61831
+ var fs66 = __toESM(require("fs"), 1);
61832
+ var path74 = __toESM(require("path"), 1);
61748
61833
  var PKG_NAME = "@clawos-dev/clawd";
61749
61834
  var BIN_NAME = "clawd";
61750
61835
  var MAX_PARENT_HOPS = 5;
61751
61836
  function probeGlobalCli(pathEnv) {
61752
61837
  if (!pathEnv) return null;
61753
- for (const dir of pathEnv.split(path73.delimiter)) {
61838
+ for (const dir of pathEnv.split(path74.delimiter)) {
61754
61839
  if (!dir) continue;
61755
61840
  let real;
61756
61841
  try {
61757
- real = fs65.realpathSync(path73.join(dir, BIN_NAME));
61842
+ real = fs66.realpathSync(path74.join(dir, BIN_NAME));
61758
61843
  } catch {
61759
61844
  continue;
61760
61845
  }
@@ -61764,15 +61849,15 @@ function probeGlobalCli(pathEnv) {
61764
61849
  return null;
61765
61850
  }
61766
61851
  function readOwnPackageVersion(entryPath) {
61767
- let dir = path73.dirname(entryPath);
61852
+ let dir = path74.dirname(entryPath);
61768
61853
  for (let i = 0; i < MAX_PARENT_HOPS; i++) {
61769
61854
  try {
61770
- const raw = fs65.readFileSync(path73.join(dir, "package.json"), "utf8");
61855
+ const raw = fs66.readFileSync(path74.join(dir, "package.json"), "utf8");
61771
61856
  const pkg = JSON.parse(raw);
61772
61857
  if (pkg.name !== PKG_NAME) return null;
61773
61858
  return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
61774
61859
  } catch {
61775
- const parent = path73.dirname(dir);
61860
+ const parent = path74.dirname(dir);
61776
61861
  if (parent === dir) return null;
61777
61862
  dir = parent;
61778
61863
  }
@@ -61935,7 +62020,7 @@ function buildPersonaHandlers(deps) {
61935
62020
  }
61936
62021
 
61937
62022
  // src/handlers/attachment.ts
61938
- var import_node_path55 = __toESM(require("path"), 1);
62023
+ var import_node_path56 = __toESM(require("path"), 1);
61939
62024
  init_protocol();
61940
62025
  init_protocol();
61941
62026
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -62015,12 +62100,12 @@ function buildAttachmentHandlers(deps) {
62015
62100
  `session ${args.sessionId} scope unresolved`
62016
62101
  );
62017
62102
  }
62018
- const cwdAbs = import_node_path55.default.resolve(sessionFile.cwd);
62019
- const candidateAbs = import_node_path55.default.isAbsolute(args.relPath) ? import_node_path55.default.resolve(args.relPath) : import_node_path55.default.resolve(cwdAbs, args.relPath);
62103
+ const cwdAbs = import_node_path56.default.resolve(sessionFile.cwd);
62104
+ const candidateAbs = import_node_path56.default.isAbsolute(args.relPath) ? import_node_path56.default.resolve(args.relPath) : import_node_path56.default.resolve(cwdAbs, args.relPath);
62020
62105
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
62021
62106
  const entries = deps.groupFileStore.list(scope, args.sessionId);
62022
62107
  const entry = entries.find((e) => {
62023
- const storedAbs = import_node_path55.default.isAbsolute(e.relPath) ? import_node_path55.default.resolve(e.relPath) : import_node_path55.default.resolve(cwdAbs, e.relPath);
62108
+ const storedAbs = import_node_path56.default.isAbsolute(e.relPath) ? import_node_path56.default.resolve(e.relPath) : import_node_path56.default.resolve(cwdAbs, e.relPath);
62024
62109
  return storedAbs === candidateAbs && !e.stale;
62025
62110
  });
62026
62111
  if (!entry) {
@@ -62045,7 +62130,7 @@ function buildAttachmentHandlers(deps) {
62045
62130
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
62046
62131
  const f = deps.sessionStore.read(sessionId);
62047
62132
  if (!f) return;
62048
- assertGuestAttachmentPath(ctx, import_node_path55.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
62133
+ assertGuestAttachmentPath(ctx, import_node_path56.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
62049
62134
  }
62050
62135
  const groupAdd = async (frame, _client, ctx) => {
62051
62136
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -62060,8 +62145,8 @@ function buildAttachmentHandlers(deps) {
62060
62145
  if (!scope) {
62061
62146
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
62062
62147
  }
62063
- const cwdAbs = import_node_path55.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
62064
- const candidateAbs = import_node_path55.default.isAbsolute(args.relPath) ? import_node_path55.default.resolve(args.relPath) : import_node_path55.default.resolve(cwdAbs, args.relPath);
62148
+ const cwdAbs = import_node_path56.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
62149
+ const candidateAbs = import_node_path56.default.isAbsolute(args.relPath) ? import_node_path56.default.resolve(args.relPath) : import_node_path56.default.resolve(cwdAbs, args.relPath);
62065
62150
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
62066
62151
  const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
62067
62152
  const size = 0;
@@ -62120,19 +62205,19 @@ function buildAttachmentHandlers(deps) {
62120
62205
 
62121
62206
  // src/handlers/extension.ts
62122
62207
  var import_promises12 = __toESM(require("fs/promises"), 1);
62123
- var import_node_path60 = __toESM(require("path"), 1);
62208
+ var import_node_path61 = __toESM(require("path"), 1);
62124
62209
  init_protocol();
62125
62210
 
62126
62211
  // src/extension/bundle-zip.ts
62127
62212
  var import_promises9 = __toESM(require("fs/promises"), 1);
62128
- var import_node_path56 = __toESM(require("path"), 1);
62213
+ var import_node_path57 = __toESM(require("path"), 1);
62129
62214
  var import_node_crypto15 = __toESM(require("crypto"), 1);
62130
62215
  var import_jszip2 = __toESM(require_lib3(), 1);
62131
62216
  async function bundleExtensionDir(dir) {
62132
62217
  const entries = await listFilesSorted(dir);
62133
62218
  const zip = new import_jszip2.default();
62134
62219
  for (const rel of entries) {
62135
- const abs = import_node_path56.default.join(dir, rel);
62220
+ const abs = import_node_path57.default.join(dir, rel);
62136
62221
  const content = await import_promises9.default.readFile(abs);
62137
62222
  zip.file(rel, content, { date: FIXED_DATE });
62138
62223
  }
@@ -62153,7 +62238,7 @@ async function listFilesSorted(rootDir) {
62153
62238
  return out;
62154
62239
  }
62155
62240
  async function walk(absRoot, relPrefix, out) {
62156
- const dirAbs = import_node_path56.default.join(absRoot, relPrefix);
62241
+ const dirAbs = import_node_path57.default.join(absRoot, relPrefix);
62157
62242
  const entries = await import_promises9.default.readdir(dirAbs, { withFileTypes: true });
62158
62243
  for (const e of entries) {
62159
62244
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -62207,25 +62292,25 @@ function computePublishCheck(args) {
62207
62292
 
62208
62293
  // src/extension/install-flow.ts
62209
62294
  var import_promises10 = __toESM(require("fs/promises"), 1);
62210
- var import_node_path58 = __toESM(require("path"), 1);
62295
+ var import_node_path59 = __toESM(require("path"), 1);
62211
62296
  var import_node_os21 = __toESM(require("os"), 1);
62212
62297
  var import_node_crypto16 = __toESM(require("crypto"), 1);
62213
62298
  var import_jszip3 = __toESM(require_lib3(), 1);
62214
62299
 
62215
62300
  // src/extension/paths.ts
62216
62301
  var import_node_os20 = __toESM(require("os"), 1);
62217
- var import_node_path57 = __toESM(require("path"), 1);
62302
+ var import_node_path58 = __toESM(require("path"), 1);
62218
62303
  function clawdHomeRoot(override) {
62219
- return override ?? process.env.CLAWD_HOME ?? import_node_path57.default.join(import_node_os20.default.homedir(), ".clawd");
62304
+ return override ?? process.env.CLAWD_HOME ?? import_node_path58.default.join(import_node_os20.default.homedir(), ".clawd");
62220
62305
  }
62221
62306
  function extensionsRoot(override) {
62222
- return import_node_path57.default.join(clawdHomeRoot(override), "extensions");
62307
+ return import_node_path58.default.join(clawdHomeRoot(override), "extensions");
62223
62308
  }
62224
62309
  function publishedChannelsFile(override) {
62225
- return import_node_path57.default.join(clawdHomeRoot(override), "extensions-published.json");
62310
+ return import_node_path58.default.join(clawdHomeRoot(override), "extensions-published.json");
62226
62311
  }
62227
62312
  function bundleCacheRoot(override) {
62228
- return import_node_path57.default.join(clawdHomeRoot(override), "extension-bundles");
62313
+ return import_node_path58.default.join(clawdHomeRoot(override), "extension-bundles");
62229
62314
  }
62230
62315
 
62231
62316
  // src/extension/install-flow.ts
@@ -62252,7 +62337,7 @@ async function installFromChannel(args, deps) {
62252
62337
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
62253
62338
  }
62254
62339
  for (const name of Object.keys(zip.files)) {
62255
- if (name.includes("..") || name.startsWith("/") || import_node_path58.default.isAbsolute(name)) {
62340
+ if (name.includes("..") || name.startsWith("/") || import_node_path59.default.isAbsolute(name)) {
62256
62341
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
62257
62342
  }
62258
62343
  }
@@ -62284,7 +62369,7 @@ async function installFromChannel(args, deps) {
62284
62369
  );
62285
62370
  }
62286
62371
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
62287
- const destDir = import_node_path58.default.join(deps.extensionsRoot, localExtId);
62372
+ const destDir = import_node_path59.default.join(deps.extensionsRoot, localExtId);
62288
62373
  let destExists = false;
62289
62374
  try {
62290
62375
  await import_promises10.default.access(destDir);
@@ -62298,16 +62383,16 @@ async function installFromChannel(args, deps) {
62298
62383
  );
62299
62384
  }
62300
62385
  const stage = await import_promises10.default.mkdtemp(
62301
- import_node_path58.default.join(import_node_os21.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
62386
+ import_node_path59.default.join(import_node_os21.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
62302
62387
  );
62303
62388
  try {
62304
62389
  for (const [name, entry] of Object.entries(zip.files)) {
62305
- const dest = import_node_path58.default.join(stage, name);
62390
+ const dest = import_node_path59.default.join(stage, name);
62306
62391
  if (entry.dir) {
62307
62392
  await import_promises10.default.mkdir(dest, { recursive: true });
62308
62393
  continue;
62309
62394
  }
62310
- await import_promises10.default.mkdir(import_node_path58.default.dirname(dest), { recursive: true });
62395
+ await import_promises10.default.mkdir(import_node_path59.default.dirname(dest), { recursive: true });
62311
62396
  if (name === "manifest.json") {
62312
62397
  const rewritten = { ...parsed.data, id: localExtId };
62313
62398
  await import_promises10.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -62328,7 +62413,7 @@ async function installFromChannel(args, deps) {
62328
62413
 
62329
62414
  // src/extension/update-flow.ts
62330
62415
  var import_promises11 = __toESM(require("fs/promises"), 1);
62331
- var import_node_path59 = __toESM(require("path"), 1);
62416
+ var import_node_path60 = __toESM(require("path"), 1);
62332
62417
  var import_node_os22 = __toESM(require("os"), 1);
62333
62418
  var import_node_crypto17 = __toESM(require("crypto"), 1);
62334
62419
  var import_jszip4 = __toESM(require_lib3(), 1);
@@ -62345,11 +62430,11 @@ async function updateFromChannel(args, deps) {
62345
62430
  channelRef.extId,
62346
62431
  channelRef.ownerPrincipalId
62347
62432
  );
62348
- const liveDir = import_node_path59.default.join(deps.extensionsRoot, localExtId);
62433
+ const liveDir = import_node_path60.default.join(deps.extensionsRoot, localExtId);
62349
62434
  const prevDir = `${liveDir}.prev`;
62350
62435
  let existingVersion;
62351
62436
  try {
62352
- const raw = await import_promises11.default.readFile(import_node_path59.default.join(liveDir, "manifest.json"), "utf8");
62437
+ const raw = await import_promises11.default.readFile(import_node_path60.default.join(liveDir, "manifest.json"), "utf8");
62353
62438
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
62354
62439
  if (!parsed2.success) {
62355
62440
  throw new UpdateError(
@@ -62382,7 +62467,7 @@ async function updateFromChannel(args, deps) {
62382
62467
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
62383
62468
  }
62384
62469
  for (const name of Object.keys(zip.files)) {
62385
- if (name.includes("..") || name.startsWith("/") || import_node_path59.default.isAbsolute(name)) {
62470
+ if (name.includes("..") || name.startsWith("/") || import_node_path60.default.isAbsolute(name)) {
62386
62471
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
62387
62472
  }
62388
62473
  }
@@ -62417,16 +62502,16 @@ async function updateFromChannel(args, deps) {
62417
62502
  await import_promises11.default.rm(prevDir, { recursive: true, force: true });
62418
62503
  await import_promises11.default.rename(liveDir, prevDir);
62419
62504
  const stage = await import_promises11.default.mkdtemp(
62420
- import_node_path59.default.join(import_node_os22.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
62505
+ import_node_path60.default.join(import_node_os22.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
62421
62506
  );
62422
62507
  try {
62423
62508
  for (const [name, entry] of Object.entries(zip.files)) {
62424
- const dest = import_node_path59.default.join(stage, name);
62509
+ const dest = import_node_path60.default.join(stage, name);
62425
62510
  if (entry.dir) {
62426
62511
  await import_promises11.default.mkdir(dest, { recursive: true });
62427
62512
  continue;
62428
62513
  }
62429
- await import_promises11.default.mkdir(import_node_path59.default.dirname(dest), { recursive: true });
62514
+ await import_promises11.default.mkdir(import_node_path60.default.dirname(dest), { recursive: true });
62430
62515
  if (name === "manifest.json") {
62431
62516
  const rewritten = { ...parsed.data, id: localExtId };
62432
62517
  await import_promises11.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -62493,7 +62578,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
62493
62578
  );
62494
62579
  }
62495
62580
  }
62496
- const manifestPath = import_node_path60.default.join(root, extId, "manifest.json");
62581
+ const manifestPath = import_node_path61.default.join(root, extId, "manifest.json");
62497
62582
  const manifest = await readManifest(root, extId);
62498
62583
  const next = { ...manifest, version: newVersion };
62499
62584
  const tmp = `${manifestPath}.tmp`;
@@ -62501,7 +62586,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
62501
62586
  await import_promises12.default.rename(tmp, manifestPath);
62502
62587
  }
62503
62588
  async function readManifest(root, extId) {
62504
- const file = import_node_path60.default.join(root, extId, "manifest.json");
62589
+ const file = import_node_path61.default.join(root, extId, "manifest.json");
62505
62590
  let raw;
62506
62591
  try {
62507
62592
  raw = await import_promises12.default.readFile(file, "utf8");
@@ -62585,7 +62670,7 @@ function buildExtensionHandlers(deps) {
62585
62670
  };
62586
62671
  async function buildSnapshotMeta(extId) {
62587
62672
  const manifest = await readManifest(deps.root, extId);
62588
- const { sha256, buffer } = await bundleExtensionDir(import_node_path60.default.join(deps.root, extId));
62673
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path61.default.join(deps.root, extId));
62589
62674
  return { manifest, contentHash: sha256, buffer };
62590
62675
  }
62591
62676
  const publish = async (frame, _client, ctx) => {
@@ -62760,9 +62845,9 @@ function buildExtensionHandlers(deps) {
62760
62845
  }
62761
62846
 
62762
62847
  // src/app-builder/project-store.ts
62763
- var import_node_fs49 = require("fs");
62848
+ var import_node_fs50 = require("fs");
62764
62849
  var import_node_child_process15 = require("child_process");
62765
- var import_node_path61 = require("path");
62850
+ var import_node_path62 = require("path");
62766
62851
  init_protocol();
62767
62852
  var PROJECTS_DIR = "projects";
62768
62853
  var META_FILE = ".clawd-project.json";
@@ -62776,19 +62861,19 @@ var ProjectStore = class {
62776
62861
  root;
62777
62862
  /** projects/<name>/.clawd-project.json 路径 */
62778
62863
  metaPath(name) {
62779
- return (0, import_node_path61.join)(this.projectsRoot(), name, META_FILE);
62864
+ return (0, import_node_path62.join)(this.projectsRoot(), name, META_FILE);
62780
62865
  }
62781
62866
  /** projects/<name>/ 目录路径(cwd 用) */
62782
62867
  projectDir(name) {
62783
- return (0, import_node_path61.join)(this.projectsRoot(), name);
62868
+ return (0, import_node_path62.join)(this.projectsRoot(), name);
62784
62869
  }
62785
62870
  projectsRoot() {
62786
- return (0, import_node_path61.join)(this.root, PROJECTS_DIR);
62871
+ return (0, import_node_path62.join)(this.root, PROJECTS_DIR);
62787
62872
  }
62788
62873
  async list() {
62789
62874
  let entries;
62790
62875
  try {
62791
- entries = await import_node_fs49.promises.readdir(this.projectsRoot());
62876
+ entries = await import_node_fs50.promises.readdir(this.projectsRoot());
62792
62877
  } catch (err) {
62793
62878
  if (err.code === "ENOENT") return [];
62794
62879
  throw err;
@@ -62796,7 +62881,7 @@ var ProjectStore = class {
62796
62881
  const out = [];
62797
62882
  for (const name of entries) {
62798
62883
  try {
62799
- const raw = await import_node_fs49.promises.readFile(this.metaPath(name), "utf8");
62884
+ const raw = await import_node_fs50.promises.readFile(this.metaPath(name), "utf8");
62800
62885
  const json = JSON.parse(raw);
62801
62886
  let migrated = false;
62802
62887
  if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
@@ -62807,7 +62892,7 @@ var ProjectStore = class {
62807
62892
  if (parsed.success) {
62808
62893
  out.push(parsed.data);
62809
62894
  if (migrated) {
62810
- void import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
62895
+ void import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
62811
62896
  });
62812
62897
  }
62813
62898
  }
@@ -62851,8 +62936,8 @@ var ProjectStore = class {
62851
62936
  throw new Error(`invalid name "${name}": ${validated.error.message}`);
62852
62937
  }
62853
62938
  const dir = this.projectDir(name);
62854
- await import_node_fs49.promises.mkdir(dir, { recursive: true });
62855
- await import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
62939
+ await import_node_fs50.promises.mkdir(dir, { recursive: true });
62940
+ await import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
62856
62941
  return meta;
62857
62942
  }
62858
62943
  /**
@@ -62895,7 +62980,7 @@ var ProjectStore = class {
62895
62980
  }
62896
62981
  async delete(name) {
62897
62982
  const dir = this.projectDir(name);
62898
- await import_node_fs49.promises.rm(dir, { recursive: true, force: true });
62983
+ await import_node_fs50.promises.rm(dir, { recursive: true, force: true });
62899
62984
  }
62900
62985
  async updatePort(name, newPort) {
62901
62986
  if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
@@ -62911,7 +62996,7 @@ var ProjectStore = class {
62911
62996
  throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
62912
62997
  }
62913
62998
  const updated = { ...target, port: newPort };
62914
- await import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
62999
+ await import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
62915
63000
  return updated;
62916
63001
  }
62917
63002
  /**
@@ -62928,7 +63013,7 @@ var ProjectStore = class {
62928
63013
  if (!validated.success) {
62929
63014
  throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
62930
63015
  }
62931
- await import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
63016
+ await import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
62932
63017
  return validated.data;
62933
63018
  }
62934
63019
  /**
@@ -62949,7 +63034,7 @@ var ProjectStore = class {
62949
63034
  if (!validated.success) {
62950
63035
  throw new Error(`invalid publishJob: ${validated.error.message}`);
62951
63036
  }
62952
- await import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
63037
+ await import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
62953
63038
  return validated.data;
62954
63039
  }
62955
63040
  /** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
@@ -62964,7 +63049,7 @@ var ProjectStore = class {
62964
63049
  if (!validated.success) {
62965
63050
  throw new Error(`failed to clear publishJob: ${validated.error.message}`);
62966
63051
  }
62967
- await import_node_fs49.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
63052
+ await import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
62968
63053
  return validated.data;
62969
63054
  }
62970
63055
  };
@@ -63085,8 +63170,8 @@ var PublishJobRegistry = class {
63085
63170
 
63086
63171
  // src/app-builder/publish-job-runner.ts
63087
63172
  var import_node_child_process17 = require("child_process");
63088
- var import_node_fs50 = require("fs");
63089
- var import_node_path62 = require("path");
63173
+ var import_node_fs51 = require("fs");
63174
+ var import_node_path63 = require("path");
63090
63175
 
63091
63176
  // src/app-builder/publish-stage-parser.ts
63092
63177
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -63118,10 +63203,10 @@ async function startPublishJob(deps, args) {
63118
63203
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
63119
63204
  }
63120
63205
  const projDir = projectDir(args.name);
63121
- const logPath = (0, import_node_path62.join)(projDir, ".publish.log");
63206
+ const logPath = (0, import_node_path63.join)(projDir, ".publish.log");
63122
63207
  let logStream = null;
63123
63208
  try {
63124
- logStream = (0, import_node_fs50.createWriteStream)(logPath, { flags: "w" });
63209
+ logStream = (0, import_node_fs51.createWriteStream)(logPath, { flags: "w" });
63125
63210
  } catch {
63126
63211
  logStream = null;
63127
63212
  }
@@ -63378,8 +63463,8 @@ async function recoverInterruptedJobs(deps) {
63378
63463
 
63379
63464
  // src/handlers/app-builder.ts
63380
63465
  init_protocol();
63381
- var import_node_path63 = require("path");
63382
- var import_node_fs51 = require("fs");
63466
+ var import_node_path64 = require("path");
63467
+ var import_node_fs52 = require("fs");
63383
63468
  var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
63384
63469
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
63385
63470
  async function recoverInterruptedPublishJobs(store, logger) {
@@ -63460,7 +63545,7 @@ function buildAppBuilderHandlers(deps) {
63460
63545
  async function listAllUsersProjects() {
63461
63546
  if (!deps.usersRoot || !deps.getStore) return [];
63462
63547
  const getStore = deps.getStore;
63463
- const userIds = await import_node_fs51.promises.readdir(deps.usersRoot).catch(() => []);
63548
+ const userIds = await import_node_fs52.promises.readdir(deps.usersRoot).catch(() => []);
63464
63549
  const perUser = await Promise.all(
63465
63550
  userIds.map((uid) => getStore(uid).list().catch(() => []))
63466
63551
  );
@@ -63529,8 +63614,8 @@ function buildAppBuilderHandlers(deps) {
63529
63614
  const project = await userStore.create(f.name, reservedPorts);
63530
63615
  try {
63531
63616
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
63532
- const templateSrcDir = (0, import_node_path63.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
63533
- const scaffoldScript = (0, import_node_path63.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
63617
+ const templateSrcDir = (0, import_node_path64.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
63618
+ const scaffoldScript = (0, import_node_path64.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
63534
63619
  const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
63535
63620
  deps.logger?.info("app-builder.scaffold.done", {
63536
63621
  name: project.name,
@@ -63734,7 +63819,7 @@ function buildAppBuilderHandlers(deps) {
63734
63819
  await userStore.clearPublishJob(args.name);
63735
63820
  }
63736
63821
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
63737
- const scriptPath = (0, import_node_path63.join)(deps.deployKitRoot, "scripts", "publish.sh");
63822
+ const scriptPath = (0, import_node_path64.join)(deps.deployKitRoot, "scripts", "publish.sh");
63738
63823
  deps.logger?.info("app-builder.publish.start", {
63739
63824
  name: args.name,
63740
63825
  sessionId: boundSession.sessionId,
@@ -64575,7 +64660,7 @@ function buildVisitorHandlers(deps) {
64575
64660
 
64576
64661
  // src/extension/registry.ts
64577
64662
  var import_promises14 = __toESM(require("fs/promises"), 1);
64578
- var import_node_path64 = __toESM(require("path"), 1);
64663
+ var import_node_path65 = __toESM(require("path"), 1);
64579
64664
  async function loadAll(root) {
64580
64665
  let entries;
64581
64666
  try {
@@ -64588,13 +64673,13 @@ async function loadAll(root) {
64588
64673
  for (const ent of entries) {
64589
64674
  if (!ent.isDirectory()) continue;
64590
64675
  if (ent.name.startsWith(".")) continue;
64591
- records.push(await loadOne(import_node_path64.default.join(root, ent.name), ent.name));
64676
+ records.push(await loadOne(import_node_path65.default.join(root, ent.name), ent.name));
64592
64677
  }
64593
64678
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
64594
64679
  return records;
64595
64680
  }
64596
64681
  async function loadOne(dir, dirName) {
64597
- const manifestPath = import_node_path64.default.join(dir, "manifest.json");
64682
+ const manifestPath = import_node_path65.default.join(dir, "manifest.json");
64598
64683
  let raw;
64599
64684
  try {
64600
64685
  raw = await import_promises14.default.readFile(manifestPath, "utf8");
@@ -64639,7 +64724,7 @@ async function loadOne(dir, dirName) {
64639
64724
 
64640
64725
  // src/extension/uninstall.ts
64641
64726
  var import_promises15 = __toESM(require("fs/promises"), 1);
64642
- var import_node_path65 = __toESM(require("path"), 1);
64727
+ var import_node_path66 = __toESM(require("path"), 1);
64643
64728
  var UninstallError = class extends Error {
64644
64729
  constructor(code, message) {
64645
64730
  super(message);
@@ -64648,7 +64733,7 @@ var UninstallError = class extends Error {
64648
64733
  code;
64649
64734
  };
64650
64735
  async function uninstall(deps) {
64651
- const dir = import_node_path65.default.join(deps.root, deps.extId);
64736
+ const dir = import_node_path66.default.join(deps.root, deps.extId);
64652
64737
  try {
64653
64738
  await import_promises15.default.access(dir);
64654
64739
  } catch {
@@ -64876,7 +64961,7 @@ function buildMethodHandlers(deps) {
64876
64961
  }),
64877
64962
  ...buildChannelHandlers({ channelStore: deps.channelStore, topicStore: deps.topicStore }),
64878
64963
  ...buildMasterHandlers({
64879
- authorityTablePath: import_node_path66.default.join(deps.masterDataDir, "master-authority.json")
64964
+ authorityTablePath: import_node_path67.default.join(deps.masterDataDir, "master-authority.json")
64880
64965
  }),
64881
64966
  ...buildLineHandlers({
64882
64967
  dispatchStore: deps.dispatchStore,
@@ -65317,7 +65402,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
65317
65402
 
65318
65403
  // src/extension/runtime.ts
65319
65404
  var import_node_child_process21 = require("child_process");
65320
- var import_node_path67 = __toESM(require("path"), 1);
65405
+ var import_node_path68 = __toESM(require("path"), 1);
65321
65406
  var import_promises16 = require("timers/promises");
65322
65407
 
65323
65408
  // src/extension/port-allocator.ts
@@ -65418,7 +65503,7 @@ var Runtime = class {
65418
65503
  /\$CLAWOS_EXT_PORT/g,
65419
65504
  String(port)
65420
65505
  );
65421
- const dir = import_node_path67.default.join(this.root, extId);
65506
+ const dir = import_node_path68.default.join(this.root, extId);
65422
65507
  const env = {
65423
65508
  ...process.env,
65424
65509
  CLAWOS_EXT_PORT: String(port),
@@ -65530,7 +65615,7 @@ ${handle.stderrTail}`
65530
65615
 
65531
65616
  // src/extension/published-channels.ts
65532
65617
  var import_promises17 = __toESM(require("fs/promises"), 1);
65533
- var import_node_path68 = __toESM(require("path"), 1);
65618
+ var import_node_path69 = __toESM(require("path"), 1);
65534
65619
  init_zod();
65535
65620
  var PublishedChannelsError = class extends Error {
65536
65621
  constructor(code, message) {
@@ -65629,7 +65714,7 @@ var PublishedChannelStore = class {
65629
65714
  )
65630
65715
  };
65631
65716
  const tmp = `${this.filePath}.tmp`;
65632
- await import_promises17.default.mkdir(import_node_path68.default.dirname(this.filePath), { recursive: true });
65717
+ await import_promises17.default.mkdir(import_node_path69.default.dirname(this.filePath), { recursive: true });
65633
65718
  await import_promises17.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
65634
65719
  await import_promises17.default.rename(tmp, this.filePath);
65635
65720
  }
@@ -65637,7 +65722,7 @@ var PublishedChannelStore = class {
65637
65722
 
65638
65723
  // src/extension/bundle-cache.ts
65639
65724
  var import_promises18 = __toESM(require("fs/promises"), 1);
65640
- var import_node_path69 = __toESM(require("path"), 1);
65725
+ var import_node_path70 = __toESM(require("path"), 1);
65641
65726
  var BundleCache = class {
65642
65727
  constructor(rootDir) {
65643
65728
  this.rootDir = rootDir;
@@ -65646,14 +65731,14 @@ var BundleCache = class {
65646
65731
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
65647
65732
  async write(snapshotHash, buffer) {
65648
65733
  await import_promises18.default.mkdir(this.rootDir, { recursive: true });
65649
- const file = import_node_path69.default.join(this.rootDir, `${snapshotHash}.zip`);
65734
+ const file = import_node_path70.default.join(this.rootDir, `${snapshotHash}.zip`);
65650
65735
  const tmp = `${file}.tmp`;
65651
65736
  await import_promises18.default.writeFile(tmp, buffer, { mode: 384 });
65652
65737
  await import_promises18.default.rename(tmp, file);
65653
65738
  }
65654
65739
  /** Returns the bundle bytes, or null when the file doesn't exist. */
65655
65740
  async read(snapshotHash) {
65656
- const file = import_node_path69.default.join(this.rootDir, `${snapshotHash}.zip`);
65741
+ const file = import_node_path70.default.join(this.rootDir, `${snapshotHash}.zip`);
65657
65742
  try {
65658
65743
  return await import_promises18.default.readFile(file);
65659
65744
  } catch (e) {
@@ -65663,7 +65748,7 @@ var BundleCache = class {
65663
65748
  }
65664
65749
  /** Idempotent — missing file is not an error. */
65665
65750
  async delete(snapshotHash) {
65666
- const file = import_node_path69.default.join(this.rootDir, `${snapshotHash}.zip`);
65751
+ const file = import_node_path70.default.join(this.rootDir, `${snapshotHash}.zip`);
65667
65752
  await import_promises18.default.rm(file, { force: true });
65668
65753
  }
65669
65754
  };
@@ -65686,24 +65771,24 @@ async function startDaemon(config) {
65686
65771
  sampling: logShippingCfg.sampling,
65687
65772
  homeDir: import_node_os24.default.homedir()
65688
65773
  });
65689
- const logDir = import_node_path70.default.join(config.dataDir, "log");
65690
- import_node_fs52.default.mkdirSync(logDir, { recursive: true });
65774
+ const logDir = import_node_path71.default.join(config.dataDir, "log");
65775
+ import_node_fs53.default.mkdirSync(logDir, { recursive: true });
65691
65776
  const logger = createLogger({
65692
65777
  level: config.logLevel,
65693
- file: import_node_path70.default.join(logDir, "clawd.log"),
65778
+ file: import_node_path71.default.join(logDir, "clawd.log"),
65694
65779
  logClient
65695
65780
  });
65696
65781
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
65697
65782
  const screenIdleProbeLogger = createFileOnlyLogger({
65698
- file: import_node_path70.default.join(logDir, "screen-idle-probe.log"),
65783
+ file: import_node_path71.default.join(logDir, "screen-idle-probe.log"),
65699
65784
  level: "debug"
65700
65785
  });
65701
65786
  logger.info("screen-idle probe logger enabled", {
65702
- file: import_node_path70.default.join(logDir, "screen-idle-probe.log")
65787
+ file: import_node_path71.default.join(logDir, "screen-idle-probe.log")
65703
65788
  });
65704
65789
  const CAP_TARGETS = [
65705
- import_node_path70.default.join(logDir, "clawd.log"),
65706
- import_node_path70.default.join(logDir, "screen-idle-probe.log")
65790
+ import_node_path71.default.join(logDir, "clawd.log"),
65791
+ import_node_path71.default.join(logDir, "screen-idle-probe.log")
65707
65792
  ];
65708
65793
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
65709
65794
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -65799,8 +65884,8 @@ async function startDaemon(config) {
65799
65884
  const agents = new AgentsScanner();
65800
65885
  const history = new ClaudeHistoryReader();
65801
65886
  let transport = null;
65802
- const personaStore = new PersonaStore(import_node_path70.default.join(config.dataDir, "personas"));
65803
- const usersRoot = import_node_path70.default.join(config.dataDir, "users");
65887
+ const personaStore = new PersonaStore(import_node_path71.default.join(config.dataDir, "personas"));
65888
+ const usersRoot = import_node_path71.default.join(config.dataDir, "users");
65804
65889
  const defaultsRoot = findDefaultsRoot(logger);
65805
65890
  if (defaultsRoot) {
65806
65891
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -65823,7 +65908,7 @@ async function startDaemon(config) {
65823
65908
  retirePersonaBuilder({ store: personaStore, logger });
65824
65909
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
65825
65910
  const dispatchStore = createDispatchStore({
65826
- filePath: import_node_path70.default.join(config.dataDir, "dispatch.json"),
65911
+ filePath: import_node_path71.default.join(config.dataDir, "dispatch.json"),
65827
65912
  now: () => Date.now(),
65828
65913
  onFlushError: (err) => logger.error("dispatch store flush failed", {
65829
65914
  reason: err instanceof Error ? err.message : String(err)
@@ -65832,7 +65917,7 @@ async function startDaemon(config) {
65832
65917
  await dispatchStore.load();
65833
65918
  dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
65834
65919
  const channelStore = createChannelStore({
65835
- filePath: import_node_path70.default.join(config.dataDir, "channels.json"),
65920
+ filePath: import_node_path71.default.join(config.dataDir, "channels.json"),
65836
65921
  now: () => Date.now(),
65837
65922
  genId: () => `ch-${v4_default().slice(0, 8)}`,
65838
65923
  onFlushError: (err) => logger.error("channel store flush failed", {
@@ -65841,7 +65926,7 @@ async function startDaemon(config) {
65841
65926
  });
65842
65927
  await channelStore.load();
65843
65928
  const topicStore = createTopicStore({
65844
- filePath: import_node_path70.default.join(config.dataDir, "topics.json"),
65929
+ filePath: import_node_path71.default.join(config.dataDir, "topics.json"),
65845
65930
  now: () => Date.now(),
65846
65931
  genId: () => `tp-${v4_default().slice(0, 8)}`,
65847
65932
  onFlushError: (err) => logger.error("topic store flush failed", {
@@ -65856,18 +65941,18 @@ async function startDaemon(config) {
65856
65941
  now: () => Date.now(),
65857
65942
  onCompleted: (sid) => deliverPendingRef?.(sid)
65858
65943
  });
65859
- const here = typeof __dirname === "string" ? __dirname : import_node_path70.default.dirname((0, import_node_url4.fileURLToPath)(import_meta7.url));
65944
+ const here = typeof __dirname === "string" ? __dirname : import_node_path71.default.dirname((0, import_node_url4.fileURLToPath)(import_meta7.url));
65860
65945
  const mcpConfigs = [];
65861
65946
  const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
65862
65947
  const dispatchServerCandidates = [
65863
- import_node_path70.default.join(here, "dispatch", "mcp-server.cjs"),
65948
+ import_node_path71.default.join(here, "dispatch", "mcp-server.cjs"),
65864
65949
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
65865
- import_node_path70.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
65950
+ import_node_path71.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
65866
65951
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
65867
65952
  ];
65868
- const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
65953
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
65869
65954
  if (dispatchServerScriptPath) {
65870
- const dispatchLogPath = import_node_path70.default.join(logDir, "dispatch-mcp-server.log");
65955
+ const dispatchLogPath = import_node_path71.default.join(logDir, "dispatch-mcp-server.log");
65871
65956
  const dispatchCfgPath = writeDispatchMcpConfig({
65872
65957
  dataDir: config.dataDir,
65873
65958
  serverScriptPath: dispatchServerScriptPath,
@@ -65887,12 +65972,12 @@ async function startDaemon(config) {
65887
65972
  });
65888
65973
  }
65889
65974
  const ticketServerCandidates = [
65890
- import_node_path70.default.join(here, "ticket", "mcp-server.cjs"),
65891
- import_node_path70.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
65975
+ import_node_path71.default.join(here, "ticket", "mcp-server.cjs"),
65976
+ import_node_path71.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
65892
65977
  ];
65893
- const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
65978
+ const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
65894
65979
  if (ticketServerScriptPath) {
65895
- const ticketLogPath = import_node_path70.default.join(logDir, "ticket-mcp-server.log");
65980
+ const ticketLogPath = import_node_path71.default.join(logDir, "ticket-mcp-server.log");
65896
65981
  const ticketCfgPath = writeTicketMcpConfig({
65897
65982
  dataDir: config.dataDir,
65898
65983
  serverScriptPath: ticketServerScriptPath,
@@ -65914,12 +65999,12 @@ async function startDaemon(config) {
65914
65999
  });
65915
66000
  }
65916
66001
  const shiftServerCandidates = [
65917
- import_node_path70.default.join(here, "shift", "mcp-server.cjs"),
65918
- import_node_path70.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
66002
+ import_node_path71.default.join(here, "shift", "mcp-server.cjs"),
66003
+ import_node_path71.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
65919
66004
  ];
65920
- const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
66005
+ const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
65921
66006
  if (shiftServerScriptPath) {
65922
- const shiftLogPath = import_node_path70.default.join(logDir, "shift-mcp-server.log");
66007
+ const shiftLogPath = import_node_path71.default.join(logDir, "shift-mcp-server.log");
65923
66008
  const shiftCfgPath = await writeShiftMcpConfig({
65924
66009
  dataDir: config.dataDir,
65925
66010
  serverScriptPath: shiftServerScriptPath,
@@ -65940,12 +66025,12 @@ async function startDaemon(config) {
65940
66025
  );
65941
66026
  }
65942
66027
  const inboxServerCandidates = [
65943
- import_node_path70.default.join(here, "inbox", "mcp-server.cjs"),
65944
- import_node_path70.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
66028
+ import_node_path71.default.join(here, "inbox", "mcp-server.cjs"),
66029
+ import_node_path71.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
65945
66030
  ];
65946
- const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
66031
+ const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
65947
66032
  if (inboxServerScriptPath) {
65948
- const inboxLogPath = import_node_path70.default.join(logDir, "inbox-mcp-server.log");
66033
+ const inboxLogPath = import_node_path71.default.join(logDir, "inbox-mcp-server.log");
65949
66034
  const inboxCfgPath = await writeInboxMcpConfig({
65950
66035
  dataDir: config.dataDir,
65951
66036
  serverScriptPath: inboxServerScriptPath,
@@ -65966,10 +66051,10 @@ async function startDaemon(config) {
65966
66051
  );
65967
66052
  }
65968
66053
  const peerOpsServerCandidates = [
65969
- import_node_path70.default.join(here, "peer-ops", "mcp-server.cjs"),
65970
- import_node_path70.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
66054
+ import_node_path71.default.join(here, "peer-ops", "mcp-server.cjs"),
66055
+ import_node_path71.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
65971
66056
  ];
65972
- const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
66057
+ const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
65973
66058
  if (peerOpsServerScriptPath) {
65974
66059
  const peerOpsCfgPath = writePeerOpsMcpConfig({
65975
66060
  dataDir: config.dataDir,
@@ -65989,12 +66074,12 @@ async function startDaemon(config) {
65989
66074
  );
65990
66075
  }
65991
66076
  const rpcToolServerCandidates = [
65992
- import_node_path70.default.join(here, "rpc-tool", "mcp-server.cjs"),
65993
- import_node_path70.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
66077
+ import_node_path71.default.join(here, "rpc-tool", "mcp-server.cjs"),
66078
+ import_node_path71.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
65994
66079
  ];
65995
- const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs52.default.existsSync(p2));
66080
+ const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs53.default.existsSync(p2));
65996
66081
  if (rpcToolServerScriptPath) {
65997
- const rpcToolLogPath = import_node_path70.default.join(logDir, "rpc-tool-mcp-server.log");
66082
+ const rpcToolLogPath = import_node_path71.default.join(logDir, "rpc-tool-mcp-server.log");
65998
66083
  const rpcToolCfgPath = writeRpcToolMcpConfig({
65999
66084
  dataDir: config.dataDir,
66000
66085
  serverScriptPath: rpcToolServerScriptPath,
@@ -66015,7 +66100,7 @@ async function startDaemon(config) {
66015
66100
  );
66016
66101
  }
66017
66102
  const shiftStore = createShiftStore({
66018
- filePath: import_node_path70.default.join(config.dataDir, "shift.json"),
66103
+ filePath: import_node_path71.default.join(config.dataDir, "shift.json"),
66019
66104
  ownerIdProvider: () => ownerPrincipalId,
66020
66105
  now: () => Date.now()
66021
66106
  });
@@ -66037,7 +66122,7 @@ async function startDaemon(config) {
66037
66122
  getAdapter,
66038
66123
  historyReader: history,
66039
66124
  dataDir: config.dataDir,
66040
- personaRoot: import_node_path70.default.join(config.dataDir, "personas"),
66125
+ personaRoot: import_node_path71.default.join(config.dataDir, "personas"),
66041
66126
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
66042
66127
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
66043
66128
  getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
@@ -66091,10 +66176,10 @@ async function startDaemon(config) {
66091
66176
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
66092
66177
  attachmentGroup: {
66093
66178
  onFileEdit: (input) => {
66094
- const absPath = import_node_path70.default.isAbsolute(input.relPath) ? input.relPath : import_node_path70.default.join(input.cwd, input.relPath);
66179
+ const absPath = import_node_path71.default.isAbsolute(input.relPath) ? input.relPath : import_node_path71.default.join(input.cwd, input.relPath);
66095
66180
  let size = 0;
66096
66181
  try {
66097
- size = import_node_fs52.default.statSync(absPath).size;
66182
+ size = import_node_fs53.default.statSync(absPath).size;
66098
66183
  } catch (err) {
66099
66184
  logger.warn("attachment.onFileEdit stat failed", {
66100
66185
  sessionId: input.sessionId,
@@ -66124,9 +66209,9 @@ async function startDaemon(config) {
66124
66209
  logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
66125
66210
  }
66126
66211
  const projectsStore = new ProjectsStore({
66127
- file: import_node_path70.default.join(config.dataDir, "projects.json"),
66212
+ file: import_node_path71.default.join(config.dataDir, "projects.json"),
66128
66213
  clawdDir: config.dataDir,
66129
- codexStateFile: import_node_path70.default.join(import_node_os24.default.homedir(), ".codex", ".codex-global-state.json"),
66214
+ codexStateFile: import_node_path71.default.join(import_node_os24.default.homedir(), ".codex", ".codex-global-state.json"),
66130
66215
  logger
66131
66216
  });
66132
66217
  const observer = new SessionObserver({
@@ -66186,13 +66271,13 @@ async function startDaemon(config) {
66186
66271
  screenIdleProbeLogger
66187
66272
  }) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
66188
66273
  registerAdapter("claude", claudeAdapter);
66189
- const codexIsolatedHome = import_node_path70.default.join(config.dataDir, "codex-home");
66274
+ const codexIsolatedHome = import_node_path71.default.join(config.dataDir, "codex-home");
66190
66275
  try {
66191
- import_node_fs52.default.mkdirSync(codexIsolatedHome, { recursive: true });
66276
+ import_node_fs53.default.mkdirSync(codexIsolatedHome, { recursive: true });
66192
66277
  for (const f of ["auth.json", "config.toml"]) {
66193
- const link = import_node_path70.default.join(codexIsolatedHome, f);
66194
- const target = import_node_path70.default.join(import_node_os24.default.homedir(), ".codex", f);
66195
- if (!import_node_fs52.default.existsSync(link) && import_node_fs52.default.existsSync(target)) import_node_fs52.default.symlinkSync(target, link);
66278
+ const link = import_node_path71.default.join(codexIsolatedHome, f);
66279
+ const target = import_node_path71.default.join(import_node_os24.default.homedir(), ".codex", f);
66280
+ if (!import_node_fs53.default.existsSync(link) && import_node_fs53.default.existsSync(target)) import_node_fs53.default.symlinkSync(target, link);
66196
66281
  }
66197
66282
  } catch (err) {
66198
66283
  logger.warn("codex isolated home setup failed", { err: String(err) });
@@ -66205,11 +66290,11 @@ async function startDaemon(config) {
66205
66290
  // projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
66206
66291
  codexHomeFor: (cwd) => resolveCodexHome({
66207
66292
  cwd,
66208
- personaRoot: import_node_path70.default.join(config.dataDir, "personas"),
66293
+ personaRoot: import_node_path71.default.join(config.dataDir, "personas"),
66209
66294
  // 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
66210
66295
  // Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
66211
66296
  projectPaths: projectsStore.listMerged().map((x) => x.path),
66212
- sharedHome: import_node_path70.default.join(import_node_os24.default.homedir(), ".codex"),
66297
+ sharedHome: import_node_path71.default.join(import_node_os24.default.homedir(), ".codex"),
66213
66298
  isolatedHome: codexIsolatedHome
66214
66299
  })
66215
66300
  })
@@ -66423,11 +66508,11 @@ async function startDaemon(config) {
66423
66508
  // 'persona/<pid>/owner',default 走 'default'。
66424
66509
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
66425
66510
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
66426
- personaRoot: import_node_path70.default.join(config.dataDir, "personas"),
66511
+ personaRoot: import_node_path71.default.join(config.dataDir, "personas"),
66427
66512
  usersRoot
66428
66513
  },
66429
66514
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
66430
- personaRoot: import_node_path70.default.join(config.dataDir, "personas"),
66515
+ personaRoot: import_node_path71.default.join(config.dataDir, "personas"),
66431
66516
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
66432
66517
  usersRoot,
66433
66518
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
@@ -66560,11 +66645,11 @@ async function startDaemon(config) {
66560
66645
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
66561
66646
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
66562
66647
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
66563
- appBuilderPersonaRoot: import_node_path70.default.join(config.dataDir, "personas", "persona-app-builder"),
66648
+ appBuilderPersonaRoot: import_node_path71.default.join(config.dataDir, "personas", "persona-app-builder"),
66564
66649
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
66565
- deployKitRoot: import_node_path70.default.join(config.dataDir, "deploy-kit"),
66650
+ deployKitRoot: import_node_path71.default.join(config.dataDir, "deploy-kit"),
66566
66651
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
66567
- resolvePersonaRoot: (personaId2) => import_node_path70.default.join(config.dataDir, "personas", personaId2),
66652
+ resolvePersonaRoot: (personaId2) => import_node_path71.default.join(config.dataDir, "personas", personaId2),
66568
66653
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
66569
66654
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
66570
66655
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -66626,6 +66711,8 @@ async function startDaemon(config) {
66626
66711
  guestFeishuUnionId: args.guestFeishuUnionId,
66627
66712
  // T-20: 可选 model override 透到 SessionFile.model
66628
66713
  ...args.model ? { model: args.model } : {},
66714
+ // 一次性 engine override(spec 2026-08-24)透到 SessionFile.tool
66715
+ ...args.tool ? { tool: args.tool } : {},
66629
66716
  // butler 顶部入口(spec 2026-07-27):可选 label 透到 SessionFile.label(sidebar 显示)
66630
66717
  ...args.label ? { label: args.label } : {}
66631
66718
  });
@@ -66669,7 +66756,7 @@ async function startDaemon(config) {
66669
66756
  });
66670
66757
  shiftScheduler.start();
66671
66758
  logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
66672
- const larkBotStore = createLarkBotBindingStore(import_node_path70.default.join(config.dataDir, "personas"));
66759
+ const larkBotStore = createLarkBotBindingStore(import_node_path71.default.join(config.dataDir, "personas"));
66673
66760
  const larkBotCloud = createLarkBotCloudClient({
66674
66761
  api: config.clawosApi ?? DEFAULT_CLAWOS_API,
66675
66762
  apiKey: resolveClawdTicketsApiKey(),
@@ -66683,7 +66770,7 @@ async function startDaemon(config) {
66683
66770
  store: larkBotStore,
66684
66771
  fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
66685
66772
  // 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
66686
- mediaRootFor: (chatId) => import_node_path70.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
66773
+ mediaRootFor: (chatId) => import_node_path71.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
66687
66774
  isShuttingDown: () => larkDraining,
66688
66775
  logger: {
66689
66776
  warn: (msg) => logger.warn(msg),
@@ -66988,8 +67075,8 @@ async function startDaemon(config) {
66988
67075
  const lines = [
66989
67076
  `Tunnel: ${r.url}`,
66990
67077
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
66991
- `Frpc config: ${import_node_path70.default.join(config.dataDir, "frpc.toml")}`,
66992
- `Frpc log: ${import_node_path70.default.join(logDir, "frpc.log")}`
67078
+ `Frpc config: ${import_node_path71.default.join(config.dataDir, "frpc.toml")}`,
67079
+ `Frpc log: ${import_node_path71.default.join(logDir, "frpc.log")}`
66993
67080
  ];
66994
67081
  const width2 = Math.max(...lines.map((l) => l.length));
66995
67082
  const bar = "\u2550".repeat(width2 + 4);
@@ -67002,8 +67089,8 @@ ${bar}
67002
67089
 
67003
67090
  `);
67004
67091
  try {
67005
- const connectPath = import_node_path70.default.join(config.dataDir, "connect.txt");
67006
- import_node_fs52.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
67092
+ const connectPath = import_node_path71.default.join(config.dataDir, "connect.txt");
67093
+ import_node_fs53.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
67007
67094
  } catch {
67008
67095
  }
67009
67096
  } catch (err) {
@@ -67089,9 +67176,9 @@ ${bar}
67089
67176
  };
67090
67177
  }
67091
67178
  function migrateDropPersonsDir(dataDir) {
67092
- const dir = import_node_path70.default.join(dataDir, "persons");
67179
+ const dir = import_node_path71.default.join(dataDir, "persons");
67093
67180
  try {
67094
- import_node_fs52.default.rmSync(dir, { recursive: true, force: true });
67181
+ import_node_fs53.default.rmSync(dir, { recursive: true, force: true });
67095
67182
  } catch {
67096
67183
  }
67097
67184
  }