@clawos-dev/clawd 0.2.247 → 0.2.249

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
@@ -751,8 +751,8 @@ var init_parseUtil = __esm({
751
751
  init_errors2();
752
752
  init_en();
753
753
  makeIssue = (params) => {
754
- const { data, path: path70, errorMaps, issueData } = params;
755
- const fullPath = [...path70, ...issueData.path || []];
754
+ const { data, path: path71, errorMaps, issueData } = params;
755
+ const fullPath = [...path71, ...issueData.path || []];
756
756
  const fullIssue = {
757
757
  ...issueData,
758
758
  path: fullPath
@@ -1063,11 +1063,11 @@ var init_types = __esm({
1063
1063
  init_parseUtil();
1064
1064
  init_util();
1065
1065
  ParseInputLazyPath = class {
1066
- constructor(parent, value, path70, key) {
1066
+ constructor(parent, value, path71, key) {
1067
1067
  this._cachedPath = [];
1068
1068
  this.parent = parent;
1069
1069
  this.data = value;
1070
- this._path = path70;
1070
+ this._path = path71;
1071
1071
  this._key = key;
1072
1072
  }
1073
1073
  get path() {
@@ -5132,12 +5132,21 @@ var init_schemas = __esm({
5132
5132
  SessionListArgs = external_exports.object({
5133
5133
  /** true = 只返回 mirror(originOwnerPrincipalId 非空,即「我在朋友 daemon 上创建」的本机存证)。 */
5134
5134
  originOnly: external_exports.boolean().optional(),
5135
+ /**
5136
+ * 按 own persona 窄化(2026-07-21 self-persona-sessions 追加):只留
5137
+ * `s.ownerPersonaId === args.ownerPersonaId` 的 sessions。
5138
+ * - mirror 行(`ownerPersonaId` 恒 null)天然排除
5139
+ * - 与 `originOnly=true` 同传恒返 0
5140
+ * - 老 daemon 不识别时忽略字段返回全量,客户端消费侧本就自带过滤/截断,天然向后兼容
5141
+ */
5142
+ ownerPersonaId: external_exports.string().min(1).optional(),
5135
5143
  /** 按 updatedAt desc(list 的既有排序)截断前 N 条。 */
5136
5144
  limit: external_exports.number().int().positive().optional(),
5137
5145
  /**
5138
- * 分页起点(2026-07-18 android-tasks-tab 迭代追加):originOnly 过滤后、limit 截断前跳过
5139
- * N 条。与 limit 组合 = updatedAt desc 序上的一页。响应带 total(过滤后总数,见 handler)
5140
- * 供客户端判 hasMore。老 daemon 不识别时忽略 → 回全量,客户端按全量兼容。
5146
+ * 分页起点(2026-07-18 android-tasks-tab 迭代追加):originOnly / ownerPersonaId 过滤后、
5147
+ * limit 截断前跳过前 N 条。与 limit 组合 = updatedAt desc 序上的一页。响应带 total
5148
+ * (过滤后总数,见 handler)供客户端判 hasMore。老 daemon 不识别时忽略 → 回全量,
5149
+ * 客户端按全量兼容。
5141
5150
  */
5142
5151
  offset: external_exports.number().int().nonnegative().optional()
5143
5152
  });
@@ -6187,7 +6196,7 @@ var init_feishu_auth = __esm({
6187
6196
  });
6188
6197
 
6189
6198
  // ../protocol/src/dispatch.ts
6190
- var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema;
6199
+ var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema, DISPATCH_STATUSES, DispatchStatusSchema, DispatchRecordSchema, DispatchListArgsSchema, DispatchListResultSchema;
6191
6200
  var init_dispatch = __esm({
6192
6201
  "../protocol/src/dispatch.ts"() {
6193
6202
  "use strict";
@@ -6219,6 +6228,32 @@ var init_dispatch = __esm({
6219
6228
  dispatchId: external_exports.string().min(1),
6220
6229
  outcome: DispatchOutcomeSchema
6221
6230
  });
6231
+ DISPATCH_STATUSES = ["running", "completed", "failed"];
6232
+ DispatchStatusSchema = external_exports.enum(DISPATCH_STATUSES);
6233
+ DispatchRecordSchema = external_exports.object({
6234
+ dispatchId: external_exports.string().min(1),
6235
+ sourceSessionId: external_exports.string().min(1),
6236
+ sourcePersonaId: external_exports.string().min(1).optional(),
6237
+ targetPersonaId: external_exports.string().min(1),
6238
+ /** B 的 sessionId;registerBSession 后回填 */
6239
+ workerSessionId: external_exports.string().min(1).optional(),
6240
+ /** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
6241
+ taskText: external_exports.string(),
6242
+ status: DispatchStatusSchema,
6243
+ outcome: DispatchOutcomeSchema.optional(),
6244
+ /** 上层消费者语义(如司礼监的口谕/验收状态),daemon 不解释 */
6245
+ meta: external_exports.record(external_exports.unknown()).optional(),
6246
+ createdAt: external_exports.string().min(1),
6247
+ completedAt: external_exports.string().min(1).optional(),
6248
+ /** 结果注入 source session 成功时戳,兼当投递 dedup 标记 */
6249
+ deliveredAt: external_exports.string().min(1).optional()
6250
+ });
6251
+ DispatchListArgsSchema = external_exports.object({
6252
+ sourceSessionId: external_exports.string().min(1).optional()
6253
+ });
6254
+ DispatchListResultSchema = external_exports.object({
6255
+ records: external_exports.array(DispatchRecordSchema)
6256
+ });
6222
6257
  }
6223
6258
  });
6224
6259
 
@@ -6571,8 +6606,8 @@ var require_req = __commonJS({
6571
6606
  if (req.originalUrl) {
6572
6607
  _req.url = req.originalUrl;
6573
6608
  } else {
6574
- const path70 = req.path;
6575
- _req.url = typeof path70 === "string" ? path70 : req.url ? req.url.path || req.url : void 0;
6609
+ const path71 = req.path;
6610
+ _req.url = typeof path71 === "string" ? path71 : req.url ? req.url.path || req.url : void 0;
6576
6611
  }
6577
6612
  if (req.query) {
6578
6613
  _req.query = req.query;
@@ -6737,14 +6772,14 @@ var require_redact = __commonJS({
6737
6772
  }
6738
6773
  return obj;
6739
6774
  }
6740
- function parsePath(path70) {
6775
+ function parsePath(path71) {
6741
6776
  const parts = [];
6742
6777
  let current = "";
6743
6778
  let inBrackets = false;
6744
6779
  let inQuotes = false;
6745
6780
  let quoteChar = "";
6746
- for (let i = 0; i < path70.length; i++) {
6747
- const char = path70[i];
6781
+ for (let i = 0; i < path71.length; i++) {
6782
+ const char = path71[i];
6748
6783
  if (!inBrackets && char === ".") {
6749
6784
  if (current) {
6750
6785
  parts.push(current);
@@ -6875,10 +6910,10 @@ var require_redact = __commonJS({
6875
6910
  return current;
6876
6911
  }
6877
6912
  function redactPaths(obj, paths, censor, remove = false) {
6878
- for (const path70 of paths) {
6879
- const parts = parsePath(path70);
6913
+ for (const path71 of paths) {
6914
+ const parts = parsePath(path71);
6880
6915
  if (parts.includes("*")) {
6881
- redactWildcardPath(obj, parts, censor, path70, remove);
6916
+ redactWildcardPath(obj, parts, censor, path71, remove);
6882
6917
  } else {
6883
6918
  if (remove) {
6884
6919
  removeKey(obj, parts);
@@ -6963,8 +6998,8 @@ var require_redact = __commonJS({
6963
6998
  }
6964
6999
  } else {
6965
7000
  if (afterWildcard.includes("*")) {
6966
- const wrappedCensor = typeof censor === "function" ? (value, path70) => {
6967
- const fullPath = [...pathArray.slice(0, pathLength), ...path70];
7001
+ const wrappedCensor = typeof censor === "function" ? (value, path71) => {
7002
+ const fullPath = [...pathArray.slice(0, pathLength), ...path71];
6968
7003
  return censor(value, fullPath);
6969
7004
  } : censor;
6970
7005
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -6999,8 +7034,8 @@ var require_redact = __commonJS({
6999
7034
  return null;
7000
7035
  }
7001
7036
  const pathStructure = /* @__PURE__ */ new Map();
7002
- for (const path70 of pathsToClone) {
7003
- const parts = parsePath(path70);
7037
+ for (const path71 of pathsToClone) {
7038
+ const parts = parsePath(path71);
7004
7039
  let current = pathStructure;
7005
7040
  for (let i = 0; i < parts.length; i++) {
7006
7041
  const part = parts[i];
@@ -7052,24 +7087,24 @@ var require_redact = __commonJS({
7052
7087
  }
7053
7088
  return cloneSelectively(obj, pathStructure);
7054
7089
  }
7055
- function validatePath(path70) {
7056
- if (typeof path70 !== "string") {
7090
+ function validatePath(path71) {
7091
+ if (typeof path71 !== "string") {
7057
7092
  throw new Error("Paths must be (non-empty) strings");
7058
7093
  }
7059
- if (path70 === "") {
7094
+ if (path71 === "") {
7060
7095
  throw new Error("Invalid redaction path ()");
7061
7096
  }
7062
- if (path70.includes("..")) {
7063
- throw new Error(`Invalid redaction path (${path70})`);
7097
+ if (path71.includes("..")) {
7098
+ throw new Error(`Invalid redaction path (${path71})`);
7064
7099
  }
7065
- if (path70.includes(",")) {
7066
- throw new Error(`Invalid redaction path (${path70})`);
7100
+ if (path71.includes(",")) {
7101
+ throw new Error(`Invalid redaction path (${path71})`);
7067
7102
  }
7068
7103
  let bracketCount = 0;
7069
7104
  let inQuotes = false;
7070
7105
  let quoteChar = "";
7071
- for (let i = 0; i < path70.length; i++) {
7072
- const char = path70[i];
7106
+ for (let i = 0; i < path71.length; i++) {
7107
+ const char = path71[i];
7073
7108
  if ((char === '"' || char === "'") && bracketCount > 0) {
7074
7109
  if (!inQuotes) {
7075
7110
  inQuotes = true;
@@ -7083,20 +7118,20 @@ var require_redact = __commonJS({
7083
7118
  } else if (char === "]" && !inQuotes) {
7084
7119
  bracketCount--;
7085
7120
  if (bracketCount < 0) {
7086
- throw new Error(`Invalid redaction path (${path70})`);
7121
+ throw new Error(`Invalid redaction path (${path71})`);
7087
7122
  }
7088
7123
  }
7089
7124
  }
7090
7125
  if (bracketCount !== 0) {
7091
- throw new Error(`Invalid redaction path (${path70})`);
7126
+ throw new Error(`Invalid redaction path (${path71})`);
7092
7127
  }
7093
7128
  }
7094
7129
  function validatePaths(paths) {
7095
7130
  if (!Array.isArray(paths)) {
7096
7131
  throw new TypeError("paths must be an array");
7097
7132
  }
7098
- for (const path70 of paths) {
7099
- validatePath(path70);
7133
+ for (const path71 of paths) {
7134
+ validatePath(path71);
7100
7135
  }
7101
7136
  }
7102
7137
  function slowRedact(options = {}) {
@@ -7264,8 +7299,8 @@ var require_redaction = __commonJS({
7264
7299
  if (shape[k2] === null) {
7265
7300
  o[k2] = (value) => topCensor(value, [k2]);
7266
7301
  } else {
7267
- const wrappedCensor = typeof censor === "function" ? (value, path70) => {
7268
- return censor(value, [k2, ...path70]);
7302
+ const wrappedCensor = typeof censor === "function" ? (value, path71) => {
7303
+ return censor(value, [k2, ...path71]);
7269
7304
  } : censor;
7270
7305
  o[k2] = Redact({
7271
7306
  paths: shape[k2],
@@ -7483,10 +7518,10 @@ var require_atomic_sleep = __commonJS({
7483
7518
  var require_sonic_boom = __commonJS({
7484
7519
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
7485
7520
  "use strict";
7486
- var fs64 = require("fs");
7521
+ var fs65 = require("fs");
7487
7522
  var EventEmitter3 = require("events");
7488
7523
  var inherits = require("util").inherits;
7489
- var path70 = require("path");
7524
+ var path71 = require("path");
7490
7525
  var sleep2 = require_atomic_sleep();
7491
7526
  var assert = require("assert");
7492
7527
  var BUSY_WRITE_TIMEOUT = 100;
@@ -7540,20 +7575,20 @@ var require_sonic_boom = __commonJS({
7540
7575
  const mode = sonic.mode;
7541
7576
  if (sonic.sync) {
7542
7577
  try {
7543
- if (sonic.mkdir) fs64.mkdirSync(path70.dirname(file), { recursive: true });
7544
- const fd = fs64.openSync(file, flags, mode);
7578
+ if (sonic.mkdir) fs65.mkdirSync(path71.dirname(file), { recursive: true });
7579
+ const fd = fs65.openSync(file, flags, mode);
7545
7580
  fileOpened(null, fd);
7546
7581
  } catch (err) {
7547
7582
  fileOpened(err);
7548
7583
  throw err;
7549
7584
  }
7550
7585
  } else if (sonic.mkdir) {
7551
- fs64.mkdir(path70.dirname(file), { recursive: true }, (err) => {
7586
+ fs65.mkdir(path71.dirname(file), { recursive: true }, (err) => {
7552
7587
  if (err) return fileOpened(err);
7553
- fs64.open(file, flags, mode, fileOpened);
7588
+ fs65.open(file, flags, mode, fileOpened);
7554
7589
  });
7555
7590
  } else {
7556
- fs64.open(file, flags, mode, fileOpened);
7591
+ fs65.open(file, flags, mode, fileOpened);
7557
7592
  }
7558
7593
  }
7559
7594
  function SonicBoom(opts) {
@@ -7594,8 +7629,8 @@ var require_sonic_boom = __commonJS({
7594
7629
  this.flush = flushBuffer;
7595
7630
  this.flushSync = flushBufferSync;
7596
7631
  this._actualWrite = actualWriteBuffer;
7597
- fsWriteSync = () => fs64.writeSync(this.fd, this._writingBuf);
7598
- fsWrite = () => fs64.write(this.fd, this._writingBuf, this.release);
7632
+ fsWriteSync = () => fs65.writeSync(this.fd, this._writingBuf);
7633
+ fsWrite = () => fs65.write(this.fd, this._writingBuf, this.release);
7599
7634
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
7600
7635
  this._writingBuf = "";
7601
7636
  this.write = write;
@@ -7604,15 +7639,15 @@ var require_sonic_boom = __commonJS({
7604
7639
  this._actualWrite = actualWrite;
7605
7640
  fsWriteSync = () => {
7606
7641
  if (Buffer.isBuffer(this._writingBuf)) {
7607
- return fs64.writeSync(this.fd, this._writingBuf);
7642
+ return fs65.writeSync(this.fd, this._writingBuf);
7608
7643
  }
7609
- return fs64.writeSync(this.fd, this._writingBuf, "utf8");
7644
+ return fs65.writeSync(this.fd, this._writingBuf, "utf8");
7610
7645
  };
7611
7646
  fsWrite = () => {
7612
7647
  if (Buffer.isBuffer(this._writingBuf)) {
7613
- return fs64.write(this.fd, this._writingBuf, this.release);
7648
+ return fs65.write(this.fd, this._writingBuf, this.release);
7614
7649
  }
7615
- return fs64.write(this.fd, this._writingBuf, "utf8", this.release);
7650
+ return fs65.write(this.fd, this._writingBuf, "utf8", this.release);
7616
7651
  };
7617
7652
  } else {
7618
7653
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -7669,7 +7704,7 @@ var require_sonic_boom = __commonJS({
7669
7704
  }
7670
7705
  }
7671
7706
  if (this._fsync) {
7672
- fs64.fsyncSync(this.fd);
7707
+ fs65.fsyncSync(this.fd);
7673
7708
  }
7674
7709
  const len = this._len;
7675
7710
  if (this._reopening) {
@@ -7783,7 +7818,7 @@ var require_sonic_boom = __commonJS({
7783
7818
  const onDrain = () => {
7784
7819
  if (!this._fsync) {
7785
7820
  try {
7786
- fs64.fsync(this.fd, (err) => {
7821
+ fs65.fsync(this.fd, (err) => {
7787
7822
  this._flushPending = false;
7788
7823
  cb(err);
7789
7824
  });
@@ -7885,7 +7920,7 @@ var require_sonic_boom = __commonJS({
7885
7920
  const fd = this.fd;
7886
7921
  this.once("ready", () => {
7887
7922
  if (fd !== this.fd) {
7888
- fs64.close(fd, (err) => {
7923
+ fs65.close(fd, (err) => {
7889
7924
  if (err) {
7890
7925
  return this.emit("error", err);
7891
7926
  }
@@ -7934,7 +7969,7 @@ var require_sonic_boom = __commonJS({
7934
7969
  buf = this._bufs[0];
7935
7970
  }
7936
7971
  try {
7937
- const n = Buffer.isBuffer(buf) ? fs64.writeSync(this.fd, buf) : fs64.writeSync(this.fd, buf, "utf8");
7972
+ const n = Buffer.isBuffer(buf) ? fs65.writeSync(this.fd, buf) : fs65.writeSync(this.fd, buf, "utf8");
7938
7973
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
7939
7974
  buf = releasedBufObj.writingBuf;
7940
7975
  this._len = releasedBufObj.len;
@@ -7950,7 +7985,7 @@ var require_sonic_boom = __commonJS({
7950
7985
  }
7951
7986
  }
7952
7987
  try {
7953
- fs64.fsyncSync(this.fd);
7988
+ fs65.fsyncSync(this.fd);
7954
7989
  } catch {
7955
7990
  }
7956
7991
  }
@@ -7971,7 +8006,7 @@ var require_sonic_boom = __commonJS({
7971
8006
  buf = mergeBuf(this._bufs[0], this._lens[0]);
7972
8007
  }
7973
8008
  try {
7974
- const n = fs64.writeSync(this.fd, buf);
8009
+ const n = fs65.writeSync(this.fd, buf);
7975
8010
  buf = buf.subarray(n);
7976
8011
  this._len = Math.max(this._len - n, 0);
7977
8012
  if (buf.length <= 0) {
@@ -7999,13 +8034,13 @@ var require_sonic_boom = __commonJS({
7999
8034
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
8000
8035
  if (this.sync) {
8001
8036
  try {
8002
- const written = Buffer.isBuffer(this._writingBuf) ? fs64.writeSync(this.fd, this._writingBuf) : fs64.writeSync(this.fd, this._writingBuf, "utf8");
8037
+ const written = Buffer.isBuffer(this._writingBuf) ? fs65.writeSync(this.fd, this._writingBuf) : fs65.writeSync(this.fd, this._writingBuf, "utf8");
8003
8038
  release(null, written);
8004
8039
  } catch (err) {
8005
8040
  release(err);
8006
8041
  }
8007
8042
  } else {
8008
- fs64.write(this.fd, this._writingBuf, release);
8043
+ fs65.write(this.fd, this._writingBuf, release);
8009
8044
  }
8010
8045
  }
8011
8046
  function actualWriteBuffer() {
@@ -8014,7 +8049,7 @@ var require_sonic_boom = __commonJS({
8014
8049
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
8015
8050
  if (this.sync) {
8016
8051
  try {
8017
- const written = fs64.writeSync(this.fd, this._writingBuf);
8052
+ const written = fs65.writeSync(this.fd, this._writingBuf);
8018
8053
  release(null, written);
8019
8054
  } catch (err) {
8020
8055
  release(err);
@@ -8023,7 +8058,7 @@ var require_sonic_boom = __commonJS({
8023
8058
  if (kCopyBuffer) {
8024
8059
  this._writingBuf = Buffer.from(this._writingBuf);
8025
8060
  }
8026
- fs64.write(this.fd, this._writingBuf, release);
8061
+ fs65.write(this.fd, this._writingBuf, release);
8027
8062
  }
8028
8063
  }
8029
8064
  function actualClose(sonic) {
@@ -8039,12 +8074,12 @@ var require_sonic_boom = __commonJS({
8039
8074
  sonic._lens = [];
8040
8075
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
8041
8076
  try {
8042
- fs64.fsync(sonic.fd, closeWrapped);
8077
+ fs65.fsync(sonic.fd, closeWrapped);
8043
8078
  } catch {
8044
8079
  }
8045
8080
  function closeWrapped() {
8046
8081
  if (sonic.fd !== 1 && sonic.fd !== 2) {
8047
- fs64.close(sonic.fd, done);
8082
+ fs65.close(sonic.fd, done);
8048
8083
  } else {
8049
8084
  done();
8050
8085
  }
@@ -11179,11 +11214,11 @@ var init_lib = __esm({
11179
11214
  }
11180
11215
  }
11181
11216
  },
11182
- addToPath: function addToPath(path70, added, removed, oldPosInc, options) {
11183
- var last = path70.lastComponent;
11217
+ addToPath: function addToPath(path71, added, removed, oldPosInc, options) {
11218
+ var last = path71.lastComponent;
11184
11219
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
11185
11220
  return {
11186
- oldPos: path70.oldPos + oldPosInc,
11221
+ oldPos: path71.oldPos + oldPosInc,
11187
11222
  lastComponent: {
11188
11223
  count: last.count + 1,
11189
11224
  added,
@@ -11193,7 +11228,7 @@ var init_lib = __esm({
11193
11228
  };
11194
11229
  } else {
11195
11230
  return {
11196
- oldPos: path70.oldPos + oldPosInc,
11231
+ oldPos: path71.oldPos + oldPosInc,
11197
11232
  lastComponent: {
11198
11233
  count: 1,
11199
11234
  added,
@@ -11702,10 +11737,10 @@ function attachmentToHistoryMessage(o, ts) {
11702
11737
  const memories = raw.map((m2) => {
11703
11738
  if (!m2 || typeof m2 !== "object") return null;
11704
11739
  const rec3 = m2;
11705
- const path70 = typeof rec3.path === "string" ? rec3.path : null;
11740
+ const path71 = typeof rec3.path === "string" ? rec3.path : null;
11706
11741
  const content = typeof rec3.content === "string" ? rec3.content : null;
11707
- if (!path70 || content == null) return null;
11708
- const entry = { path: path70, content };
11742
+ if (!path71 || content == null) return null;
11743
+ const entry = { path: path71, content };
11709
11744
  if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
11710
11745
  return entry;
11711
11746
  }).filter((m2) => m2 !== null);
@@ -12508,10 +12543,10 @@ function parseAttachment(obj) {
12508
12543
  const memories = raw.map((m2) => {
12509
12544
  if (!m2 || typeof m2 !== "object") return null;
12510
12545
  const rec3 = m2;
12511
- const path70 = typeof rec3.path === "string" ? rec3.path : null;
12546
+ const path71 = typeof rec3.path === "string" ? rec3.path : null;
12512
12547
  const content = typeof rec3.content === "string" ? rec3.content : null;
12513
- if (!path70 || content == null) return null;
12514
- const out = { path: path70, content };
12548
+ if (!path71 || content == null) return null;
12549
+ const out = { path: path71, content };
12515
12550
  if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
12516
12551
  return out;
12517
12552
  }).filter((m2) => m2 !== null);
@@ -33480,8 +33515,8 @@ var require_utils = __commonJS({
33480
33515
  var result = transform[inputType][outputType](input);
33481
33516
  return result;
33482
33517
  };
33483
- exports2.resolve = function(path70) {
33484
- var parts = path70.split("/");
33518
+ exports2.resolve = function(path71) {
33519
+ var parts = path71.split("/");
33485
33520
  var result = [];
33486
33521
  for (var index = 0; index < parts.length; index++) {
33487
33522
  var part = parts[index];
@@ -39334,18 +39369,18 @@ var require_object = __commonJS({
39334
39369
  var object = new ZipObject(name, zipObjectContent, o);
39335
39370
  this.files[name] = object;
39336
39371
  };
39337
- var parentFolder = function(path70) {
39338
- if (path70.slice(-1) === "/") {
39339
- path70 = path70.substring(0, path70.length - 1);
39372
+ var parentFolder = function(path71) {
39373
+ if (path71.slice(-1) === "/") {
39374
+ path71 = path71.substring(0, path71.length - 1);
39340
39375
  }
39341
- var lastSlash = path70.lastIndexOf("/");
39342
- return lastSlash > 0 ? path70.substring(0, lastSlash) : "";
39376
+ var lastSlash = path71.lastIndexOf("/");
39377
+ return lastSlash > 0 ? path71.substring(0, lastSlash) : "";
39343
39378
  };
39344
- var forceTrailingSlash = function(path70) {
39345
- if (path70.slice(-1) !== "/") {
39346
- path70 += "/";
39379
+ var forceTrailingSlash = function(path71) {
39380
+ if (path71.slice(-1) !== "/") {
39381
+ path71 += "/";
39347
39382
  }
39348
- return path70;
39383
+ return path71;
39349
39384
  };
39350
39385
  var folderAdd = function(name, createFolders) {
39351
39386
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -40347,7 +40382,7 @@ var require_lib3 = __commonJS({
40347
40382
  // src/run-case/recorder.ts
40348
40383
  function startRunCaseRecorder(opts) {
40349
40384
  const now = opts.now ?? Date.now;
40350
- const dir = import_node_path58.default.dirname(opts.recordPath);
40385
+ const dir = import_node_path59.default.dirname(opts.recordPath);
40351
40386
  let stream = null;
40352
40387
  let closing = false;
40353
40388
  let closedSettled = false;
@@ -40387,12 +40422,12 @@ function startRunCaseRecorder(opts) {
40387
40422
  };
40388
40423
  return { tap, close, closed };
40389
40424
  }
40390
- var import_node_fs46, import_node_path58;
40425
+ var import_node_fs46, import_node_path59;
40391
40426
  var init_recorder = __esm({
40392
40427
  "src/run-case/recorder.ts"() {
40393
40428
  "use strict";
40394
40429
  import_node_fs46 = __toESM(require("fs"), 1);
40395
- import_node_path58 = __toESM(require("path"), 1);
40430
+ import_node_path59 = __toESM(require("path"), 1);
40396
40431
  }
40397
40432
  });
40398
40433
 
@@ -40435,7 +40470,7 @@ var init_wire = __esm({
40435
40470
  // src/run-case/controller.ts
40436
40471
  async function runController(opts) {
40437
40472
  const now = opts.now ?? Date.now;
40438
- const cwd = opts.cwd ?? (0, import_node_fs47.mkdtempSync)(import_node_path59.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
40473
+ const cwd = opts.cwd ?? (0, import_node_fs47.mkdtempSync)(import_node_path60.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
40439
40474
  const ownsCwd = opts.cwd === void 0;
40440
40475
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
40441
40476
  const spawnCtx = { cwd };
@@ -40602,13 +40637,13 @@ async function runController(opts) {
40602
40637
  }
40603
40638
  return exitCode ?? 0;
40604
40639
  }
40605
- var import_node_fs47, import_node_os23, import_node_path59;
40640
+ var import_node_fs47, import_node_os23, import_node_path60;
40606
40641
  var init_controller = __esm({
40607
40642
  "src/run-case/controller.ts"() {
40608
40643
  "use strict";
40609
40644
  import_node_fs47 = require("fs");
40610
40645
  import_node_os23 = __toESM(require("os"), 1);
40611
- import_node_path59 = __toESM(require("path"), 1);
40646
+ import_node_path60 = __toESM(require("path"), 1);
40612
40647
  init_claude();
40613
40648
  init_stdout_splitter();
40614
40649
  init_permission_stdio();
@@ -40870,7 +40905,7 @@ Env (advanced):
40870
40905
  `;
40871
40906
 
40872
40907
  // src/index.ts
40873
- var import_node_path57 = __toESM(require("path"), 1);
40908
+ var import_node_path58 = __toESM(require("path"), 1);
40874
40909
  var import_node_fs45 = __toESM(require("fs"), 1);
40875
40910
  var import_node_os22 = __toESM(require("os"), 1);
40876
40911
 
@@ -41735,6 +41770,28 @@ function dispatchShiftEnd(info, settle, killImpl) {
41735
41770
  throw new Error(`dispatchShiftEnd: unhandled kind ${JSON.stringify(_exhaustive)}`);
41736
41771
  }
41737
41772
 
41773
+ // src/dispatch/delivery.ts
41774
+ function selectPendingForDelivery(records, sourceSessionId) {
41775
+ return records.filter(
41776
+ (r) => r.sourceSessionId === sourceSessionId && (r.status === "completed" || r.status === "failed") && !r.deliveredAt
41777
+ ).slice().sort((a, b2) => a.createdAt < b2.createdAt ? -1 : a.createdAt > b2.createdAt ? 1 : 0);
41778
+ }
41779
+ function formatDeliveryText(records) {
41780
+ const blocks = records.map((r) => {
41781
+ const head = `[dispatch ${r.dispatchId} \u2192 ${r.targetPersonaId}]`;
41782
+ if (r.outcome?.kind === "success") {
41783
+ const files = r.outcome.filePaths && r.outcome.filePaths.length > 0 ? `
41784
+ Related files:
41785
+ ${r.outcome.filePaths.map((p2) => `- ${p2}`).join("\n")}` : "";
41786
+ return `${head} \u5B8C\u6210\uFF1A
41787
+ ${r.outcome.text}${files}`;
41788
+ }
41789
+ const reason = r.outcome?.kind === "failure" ? r.outcome.reason : "unknown failure";
41790
+ return `${head} \u5931\u8D25\uFF1A${reason}`;
41791
+ });
41792
+ return ["\u4F60\u4E4B\u524D\u59D4\u6D3E\u51FA\u53BB\u7684\u4EFB\u52A1\u6709\u4E86\u7ED3\u679C\uFF1A", "", blocks.join("\n\n")].join("\n");
41793
+ }
41794
+
41738
41795
  // src/session/runner.ts
41739
41796
  var import_node_os4 = __toESM(require("os"), 1);
41740
41797
  var import_node_path7 = __toESM(require("path"), 1);
@@ -41862,7 +41919,7 @@ var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A perso
41862
41919
  - \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
41863
41920
  - \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
41864
41921
 
41865
- tool \u4F1A\u963B\u585E\u6302\u8D77\u7B49\u5BF9\u65B9\u4EBA\u683C\u5E72\u5B8C\uFF0C\u628A outcome\uFF08\u542B text + \u53EF\u9009 filePaths\uFF09\u4F5C\u4E3A tool_result \u56DE\u7ED9\u4F60\uFF0C\u4F60\u518D\u7EFC\u5408\u56DE\u5E94\u7528\u6237\u3002
41922
+ tool \u4F1A**\u7ACB\u5373\u8FD4\u56DE** dispatchId\uFF08\u5F02\u6B65\u59D4\u6D3E\uFF09\uFF0C\u5BF9\u65B9\u4EBA\u683C\u5728\u540E\u53F0\u5E72\u6D3B\u3002\u4F60\u544A\u8BC9\u7528\u6237"\u4EFB\u52A1\u5DF2\u4EA4\u529E"\u5373\u53EF\u7ED3\u675F\u672C\u8F6E\u2014\u2014**\u4E0D\u8981\u7B49\u5F85\u3001\u4E0D\u8981\u8F6E\u8BE2**\u3002\u5BF9\u65B9\u5E72\u5B8C\u540E\uFF0C\u7ED3\u679C\u4F1A\u4F5C\u4E3A\u4E00\u6761\u65B0\u6D88\u606F\u81EA\u52A8\u6CE8\u5165\u56DE\u4F60\u7684 session\uFF0C\u4F60\u5C4A\u65F6\u518D\u7EFC\u5408\u8F6C\u8FBE\u7ED9\u7528\u6237\u3002\u60F3\u67E5\u8FDB\u5C55\u65F6\uFF08\u7528\u6237\u95EE\u8D77\uFF09\u8C03 \`mcp__clawd-dispatch__personaDispatchList\`\u3002
41866
41923
 
41867
41924
  - **\u4E0D\u8981**\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF08\u4F60\u4E0D\u662F\u90A3\u4E2A persona\uFF09
41868
41925
  - **\u4E0D\u8981** in-place \u6A21\u4EFF\u5BF9\u65B9\u4EBA\u683C \u2014\u2014 dispatch \u662F\u771F\u5207\u5230\u53E6\u4E00\u4E2A\u72EC\u7ACB session
@@ -41875,7 +41932,7 @@ tool \u4F1A\u963B\u585E\u6302\u8D77\u7B49\u5BF9\u65B9\u4EBA\u683C\u5E72\u5B8C\uF
41875
41932
 
41876
41933
  - \`targetDeviceId = <token \u7B2C\u4E8C\u6BB5\u7684 deviceId\uFF0C\u539F\u6837\u586B>\`
41877
41934
 
41878
- deviceId \u76F4\u63A5\u53D6\u81EA token\uFF0C\u4E0D\u8981\u6539\u5199\u6216\u731C\u6D4B\u3002\u5BF9\u65B9\u4E0D\u53EF\u8FBE / \u76EE\u6807 persona \u672A\u516C\u5F00\u4F1A\u8FD4\u56DE\u660E\u786E\u9519\u8BEF\uFF0C\u7167\u5E38\u628A\u9519\u8BEF\u8F6C\u8FF0\u7ED9\u7528\u6237\u5373\u53EF\u3002\u5176\u4F59\u884C\u4E3A\uFF08\u963B\u585E\u7B49\u7ED3\u679C\u3001\u5931\u8D25\u4E0D\u91CD\u8BD5\uFF09\u4E0E\u672C\u5730\u59D4\u6D3E\u4E00\u81F4\u3002
41935
+ deviceId \u76F4\u63A5\u53D6\u81EA token\uFF0C\u4E0D\u8981\u6539\u5199\u6216\u731C\u6D4B\u3002\u5BF9\u65B9\u4E0D\u53EF\u8FBE / \u76EE\u6807 persona \u672A\u516C\u5F00\u4F1A\u5728\u7ED3\u679C\u56DE\u6D41\u65F6\u62A5\u5931\u8D25\uFF0C\u7167\u5E38\u8F6C\u8FF0\u7ED9\u7528\u6237\u5373\u53EF\u3002\u5176\u4F59\u884C\u4E3A\uFF08\u79D2\u56DE dispatchId\u3001\u7ED3\u679C\u81EA\u52A8\u6CE8\u5165\u3001\u5931\u8D25\u4E0D\u91CD\u8BD5\uFF09\u4E0E\u672C\u5730\u59D4\u6D3E\u4E00\u81F4\u3002
41879
41936
 
41880
41937
  ## \u88AB dispatch \u63A5\u5230\u4EFB\u52A1
41881
41938
 
@@ -43725,6 +43782,13 @@ var SessionManager = class {
43725
43782
  }
43726
43783
  }
43727
43784
  }
43785
+ if (compressed.type === "session:status" && this.deps.dispatchStore) {
43786
+ const s = compressed;
43787
+ if (s.sessionId && s.status !== "running") {
43788
+ const sid = s.sessionId;
43789
+ setTimeout(() => this.deliverPending(sid), 0);
43790
+ }
43791
+ }
43728
43792
  if (this.currentCollector) {
43729
43793
  this.currentCollector.push({ frame: compressed, target });
43730
43794
  return;
@@ -44051,6 +44115,67 @@ var SessionManager = class {
44051
44115
  });
44052
44116
  return { response: { ok: true }, broadcast };
44053
44117
  }
44118
+ /**
44119
+ * Dispatch 结果投递(spec 2026-07-20 §5):查台账里该 source session 名下已完成
44120
+ * 且未投递的行,合并成一段 plain text 结果包注入回 source session。
44121
+ *
44122
+ * 触发点两个:complete 钩子(PersonaDispatchManager.onCompleted)+ source turn-end
44123
+ * 兜底 sweep(routeFromRunner 的 session:status 钩子)。幂等:投递成功盖 deliveredAt,
44124
+ * 再次调用查无未投递行直接返回。
44125
+ *
44126
+ * 判定口径:source 当前 running(含 reducer spawning,压缩后同 running)→ 不打扰,
44127
+ * 结果躺台账等下次 sweep。send 抛错(session 已删等)→ 记 log 不盖 deliveredAt,
44128
+ * 下次 sweep 自然重试。注入直接走 runner.input(无 collector),frames 经
44129
+ * routeFromRunner 正常广播上 wire。
44130
+ */
44131
+ deliverPending(sourceSessionId) {
44132
+ const store = this.deps.dispatchStore;
44133
+ if (!store) return;
44134
+ const pending = selectPendingForDelivery(store.list({ sourceSessionId }), sourceSessionId);
44135
+ if (pending.length === 0) return;
44136
+ const state = this.tryGetState(sourceSessionId);
44137
+ if (state && compressStatus(state.status) === "running") return;
44138
+ if (!this.deps.ownerPrincipalId) {
44139
+ this.deps.logger?.warn("dispatch.deliver.no-owner-principal", { sourceSessionId });
44140
+ return;
44141
+ }
44142
+ const sender = principalToSender(
44143
+ makeOwnerPrincipal(
44144
+ this.deps.ownerPrincipalId,
44145
+ this.deps.ownerDisplayName ?? "Owner",
44146
+ this.deps.ownerFeishuUnionId
44147
+ )
44148
+ );
44149
+ try {
44150
+ const file = this.findOwnedSession(sourceSessionId);
44151
+ if (!file) {
44152
+ this.deps.logger?.info("dispatch.deliver.source-gone", { sourceSessionId });
44153
+ return;
44154
+ }
44155
+ const runner = this.ensureRunnerForScope(file, this.scopeForFile(file));
44156
+ runner.input({
44157
+ kind: "command",
44158
+ command: {
44159
+ kind: "send",
44160
+ text: formatDeliveryText(pending),
44161
+ senderPrincipal: sender
44162
+ }
44163
+ });
44164
+ } catch (err) {
44165
+ this.deps.logger?.warn("dispatch.deliver.send-failed", {
44166
+ sourceSessionId,
44167
+ reason: err instanceof Error ? err.message : String(err)
44168
+ });
44169
+ return;
44170
+ }
44171
+ const nowIso3 = new Date(this.deps.now?.() ?? Date.now()).toISOString();
44172
+ for (const r of pending) store.update(r.dispatchId, { deliveredAt: nowIso3 });
44173
+ this.deps.logger?.info("dispatch.deliver.ok", {
44174
+ sourceSessionId,
44175
+ count: pending.length,
44176
+ dispatchIds: pending.map((r) => r.dispatchId)
44177
+ });
44178
+ }
44054
44179
  /**
44055
44180
  * 只读拿 SessionState;session 不存在返 null(不 throw)。
44056
44181
  * handlers/session.ts:currentTurnSender 用(loopback HTTP RPC 绝对不能因不存在的 sid 崩)。
@@ -46657,8 +46782,8 @@ function turnStartInput(text) {
46657
46782
  const items = [];
46658
46783
  let leftover = text;
46659
46784
  for (const m2 of text.matchAll(SKILL_RE)) {
46660
- const [marker, name, path70] = m2;
46661
- items.push({ type: "skill", name, path: path70 });
46785
+ const [marker, name, path71] = m2;
46786
+ items.push({ type: "skill", name, path: path71 });
46662
46787
  leftover = leftover.replace(marker, "");
46663
46788
  }
46664
46789
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -48157,35 +48282,60 @@ var PersonaDispatchManager = class {
48157
48282
  dispatchId,
48158
48283
  sourceSessionId: args.sourceSessionId,
48159
48284
  targetPersona: args.targetPersona,
48160
- waiters: [],
48161
- outcome: null
48285
+ waiters: []
48286
+ });
48287
+ this.deps.store.add({
48288
+ dispatchId,
48289
+ sourceSessionId: args.sourceSessionId,
48290
+ ...args.sourcePersonaId ? { sourcePersonaId: args.sourcePersonaId } : {},
48291
+ targetPersonaId: args.targetPersona,
48292
+ taskText: args.taskText
48162
48293
  });
48163
48294
  return { dispatchId };
48164
48295
  }
48165
48296
  get(dispatchId) {
48166
48297
  return this.map.get(dispatchId);
48167
48298
  }
48168
- async wait(dispatchId) {
48299
+ complete(dispatchId, outcome) {
48169
48300
  const state = this.map.get(dispatchId);
48170
- if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
48171
- if (state.outcome) return state.outcome;
48301
+ const status = outcome.kind === "success" ? "completed" : "failed";
48302
+ const updated = this.deps.store.update(dispatchId, {
48303
+ status,
48304
+ outcome,
48305
+ completedAt: new Date(this.deps.now()).toISOString()
48306
+ });
48307
+ if (state) {
48308
+ const waiters = state.waiters;
48309
+ state.waiters = [];
48310
+ for (const w2 of waiters) w2.resolve(outcome);
48311
+ this.map.delete(dispatchId);
48312
+ }
48313
+ const sourceSessionId = updated?.sourceSessionId ?? state?.sourceSessionId;
48314
+ if (sourceSessionId) this.deps.onCompleted?.(sourceSessionId);
48315
+ }
48316
+ /**
48317
+ * mesh B 角色 hold 专用(跨设备 dispatch 的 peer 侧):guest B-role handler 用它
48318
+ * 挂住 /rpc HTTP 响应直到 complete,把 outcome 回传给 A 侧 daemon 的 forwardToPeer
48319
+ * (A 侧后台 await,A 的 tool call 不受影响照样秒回)。
48320
+ * 本地 dispatch 链路**不用**这个——本地 outcome 只走台账 + deliverPending。
48321
+ */
48322
+ async waitForOutcome(dispatchId) {
48323
+ const state = this.map.get(dispatchId);
48324
+ if (!state) {
48325
+ const rec3 = this.deps.store.get(dispatchId);
48326
+ if (rec3?.outcome) return rec3.outcome;
48327
+ throw new Error(`unknown dispatchId: ${dispatchId}`);
48328
+ }
48172
48329
  const d = defer();
48173
48330
  state.waiters.push(d);
48174
48331
  return d.promise;
48175
48332
  }
48176
- complete(dispatchId, outcome) {
48177
- const state = this.map.get(dispatchId);
48178
- if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
48179
- state.outcome = outcome;
48180
- const waiters = state.waiters;
48181
- state.waiters = [];
48182
- for (const w2 of waiters) w2.resolve(outcome);
48183
- }
48184
48333
  /** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
48185
48334
  registerBSession(dispatchId, bSessionId) {
48186
48335
  const state = this.map.get(dispatchId);
48187
48336
  if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
48188
48337
  state.bSessionId = bSessionId;
48338
+ this.deps.store.update(dispatchId, { workerSessionId: bSessionId });
48189
48339
  }
48190
48340
  /** reducer buildSpawnContext 调,按 B 的 sessionId 反查 dispatchId(用于注 CLAWD_DISPATCH_ID env) */
48191
48341
  lookupDispatchByBSessionId(bSessionId) {
@@ -48196,11 +48346,112 @@ var PersonaDispatchManager = class {
48196
48346
  }
48197
48347
  };
48198
48348
 
48349
+ // src/dispatch/store.ts
48350
+ var import_promises = __toESM(require("fs/promises"), 1);
48351
+ var import_node_path16 = __toESM(require("path"), 1);
48352
+
48353
+ // src/shift/constants.ts
48354
+ var MAX_RUNS_PER_SHIFT = 30;
48355
+ var DEFAULT_TIMEOUT_MS = 30 * 6e4;
48356
+ var CONSECUTIVE_ERROR_THRESHOLD = 5;
48357
+ var TICK_INTERVAL_MS = 1e4;
48358
+ var STORE_FLUSH_DEBOUNCE_MS = 500;
48359
+ var CLOCK_JUMP_THRESHOLD_MS = 5 * 6e4;
48360
+
48361
+ // src/dispatch/store.ts
48362
+ var TASK_TEXT_MAX = 500;
48363
+ function createDispatchStore(deps) {
48364
+ let records = [];
48365
+ let flushTimer = null;
48366
+ async function load() {
48367
+ let raw;
48368
+ try {
48369
+ raw = await import_promises.default.readFile(deps.filePath, "utf8");
48370
+ } catch (e) {
48371
+ if (e.code === "ENOENT") {
48372
+ records = [];
48373
+ return;
48374
+ }
48375
+ throw e;
48376
+ }
48377
+ const parsed = JSON.parse(raw);
48378
+ if (parsed.version !== 1) {
48379
+ throw new Error(`dispatch.json: unsupported version ${parsed.version}`);
48380
+ }
48381
+ records = parsed.records ?? [];
48382
+ }
48383
+ async function flushNow() {
48384
+ if (flushTimer) {
48385
+ clearTimeout(flushTimer);
48386
+ flushTimer = null;
48387
+ }
48388
+ const content = { version: 1, records };
48389
+ await import_promises.default.mkdir(import_node_path16.default.dirname(deps.filePath), { recursive: true });
48390
+ const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
48391
+ await import_promises.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
48392
+ await import_promises.default.rename(tmp, deps.filePath);
48393
+ }
48394
+ function scheduleFlush() {
48395
+ if (flushTimer) return;
48396
+ flushTimer = setTimeout(() => {
48397
+ flushTimer = null;
48398
+ flushNow().catch((err) => {
48399
+ deps.onFlushError?.(err);
48400
+ });
48401
+ }, STORE_FLUSH_DEBOUNCE_MS);
48402
+ }
48403
+ function get(dispatchId) {
48404
+ return records.find((r) => r.dispatchId === dispatchId);
48405
+ }
48406
+ function add(input) {
48407
+ const rec3 = {
48408
+ dispatchId: input.dispatchId,
48409
+ sourceSessionId: input.sourceSessionId,
48410
+ ...input.sourcePersonaId ? { sourcePersonaId: input.sourcePersonaId } : {},
48411
+ targetPersonaId: input.targetPersonaId,
48412
+ taskText: input.taskText.slice(0, TASK_TEXT_MAX),
48413
+ status: "running",
48414
+ ...input.meta ? { meta: input.meta } : {},
48415
+ createdAt: new Date(deps.now()).toISOString()
48416
+ };
48417
+ records.push(rec3);
48418
+ scheduleFlush();
48419
+ return rec3;
48420
+ }
48421
+ function update(dispatchId, patch) {
48422
+ const idx = records.findIndex((r) => r.dispatchId === dispatchId);
48423
+ if (idx < 0) return void 0;
48424
+ const merged = { ...records[idx], ...patch };
48425
+ records[idx] = merged;
48426
+ scheduleFlush();
48427
+ return merged;
48428
+ }
48429
+ function list(filter) {
48430
+ return records.filter((r) => !filter?.sourceSessionId || r.sourceSessionId === filter.sourceSessionId).slice().sort((a, b2) => a.createdAt < b2.createdAt ? 1 : a.createdAt > b2.createdAt ? -1 : 0);
48431
+ }
48432
+ function markInterruptedAsFailed(nowIso3) {
48433
+ let touched = false;
48434
+ for (const r of records) {
48435
+ if (r.status === "running") {
48436
+ r.status = "failed";
48437
+ r.outcome = {
48438
+ kind: "failure",
48439
+ reason: "daemon restarted while dispatch in flight"
48440
+ };
48441
+ r.completedAt = nowIso3;
48442
+ touched = true;
48443
+ }
48444
+ }
48445
+ if (touched) scheduleFlush();
48446
+ }
48447
+ return { load, flushNow, add, update, list, get, markInterruptedAsFailed };
48448
+ }
48449
+
48199
48450
  // src/dispatch/mcp-config.ts
48200
48451
  var import_node_fs19 = __toESM(require("fs"), 1);
48201
- var import_node_path16 = __toESM(require("path"), 1);
48452
+ var import_node_path17 = __toESM(require("path"), 1);
48202
48453
  function dispatchMcpConfigPath(dataDir) {
48203
- return import_node_path16.default.join(dataDir, "dispatch.mcp.json");
48454
+ return import_node_path17.default.join(dataDir, "dispatch.mcp.json");
48204
48455
  }
48205
48456
  function writeDispatchMcpConfig(args) {
48206
48457
  const cfgPath = dispatchMcpConfigPath(args.dataDir);
@@ -48222,9 +48473,9 @@ function writeDispatchMcpConfig(args) {
48222
48473
 
48223
48474
  // src/ticket/mcp-config.ts
48224
48475
  var import_node_fs20 = __toESM(require("fs"), 1);
48225
- var import_node_path17 = __toESM(require("path"), 1);
48476
+ var import_node_path18 = __toESM(require("path"), 1);
48226
48477
  function ticketMcpConfigPath(dataDir) {
48227
- return import_node_path17.default.join(dataDir, "ticket.mcp.json");
48478
+ return import_node_path18.default.join(dataDir, "ticket.mcp.json");
48228
48479
  }
48229
48480
  function writeTicketMcpConfig(args) {
48230
48481
  const cfgPath = ticketMcpConfigPath(args.dataDir);
@@ -48251,9 +48502,9 @@ function writeTicketMcpConfig(args) {
48251
48502
 
48252
48503
  // src/shift/mcp-config.ts
48253
48504
  var import_node_fs21 = __toESM(require("fs"), 1);
48254
- var import_node_path18 = __toESM(require("path"), 1);
48505
+ var import_node_path19 = __toESM(require("path"), 1);
48255
48506
  function shiftMcpConfigPath(dataDir) {
48256
- return import_node_path18.default.join(dataDir, "shift.mcp.json");
48507
+ return import_node_path19.default.join(dataDir, "shift.mcp.json");
48257
48508
  }
48258
48509
  async function writeShiftMcpConfig(args) {
48259
48510
  const cfgPath = shiftMcpConfigPath(args.dataDir);
@@ -48275,9 +48526,9 @@ async function writeShiftMcpConfig(args) {
48275
48526
 
48276
48527
  // src/inbox/mcp-config.ts
48277
48528
  var import_node_fs22 = __toESM(require("fs"), 1);
48278
- var import_node_path19 = __toESM(require("path"), 1);
48529
+ var import_node_path20 = __toESM(require("path"), 1);
48279
48530
  function inboxMcpConfigPath(dataDir) {
48280
- return import_node_path19.default.join(dataDir, "inbox.mcp.json");
48531
+ return import_node_path20.default.join(dataDir, "inbox.mcp.json");
48281
48532
  }
48282
48533
  async function writeInboxMcpConfig(args) {
48283
48534
  const cfgPath = inboxMcpConfigPath(args.dataDir);
@@ -48299,9 +48550,9 @@ async function writeInboxMcpConfig(args) {
48299
48550
 
48300
48551
  // src/peer-ops/mcp-config.ts
48301
48552
  var import_node_fs23 = __toESM(require("fs"), 1);
48302
- var import_node_path20 = __toESM(require("path"), 1);
48553
+ var import_node_path21 = __toESM(require("path"), 1);
48303
48554
  function peerOpsMcpConfigPath(dataDir) {
48304
- return import_node_path20.default.join(dataDir, "peer-ops.mcp.json");
48555
+ return import_node_path21.default.join(dataDir, "peer-ops.mcp.json");
48305
48556
  }
48306
48557
  function writePeerOpsMcpConfig(args) {
48307
48558
  const cfgPath = peerOpsMcpConfigPath(args.dataDir);
@@ -48320,18 +48571,10 @@ function writePeerOpsMcpConfig(args) {
48320
48571
  }
48321
48572
 
48322
48573
  // src/shift/store.ts
48323
- var import_promises = __toESM(require("fs/promises"), 1);
48324
- var import_node_path21 = __toESM(require("path"), 1);
48574
+ var import_promises2 = __toESM(require("fs/promises"), 1);
48575
+ var import_node_path22 = __toESM(require("path"), 1);
48325
48576
  var import_node_crypto6 = require("crypto");
48326
48577
 
48327
- // src/shift/constants.ts
48328
- var MAX_RUNS_PER_SHIFT = 30;
48329
- var DEFAULT_TIMEOUT_MS = 30 * 6e4;
48330
- var CONSECUTIVE_ERROR_THRESHOLD = 5;
48331
- var TICK_INTERVAL_MS = 1e4;
48332
- var STORE_FLUSH_DEBOUNCE_MS = 500;
48333
- var CLOCK_JUMP_THRESHOLD_MS = 5 * 6e4;
48334
-
48335
48578
  // src/shift/schedule.ts
48336
48579
  var import_cron_parser = __toESM(require_dist(), 1);
48337
48580
  function computeNextRunAtMs(schedule, fromMs) {
@@ -48376,7 +48619,7 @@ function createShiftStore(deps) {
48376
48619
  async function load() {
48377
48620
  let raw;
48378
48621
  try {
48379
- raw = await import_promises.default.readFile(deps.filePath, "utf8");
48622
+ raw = await import_promises2.default.readFile(deps.filePath, "utf8");
48380
48623
  } catch (e) {
48381
48624
  if (e.code === "ENOENT") {
48382
48625
  shifts = [];
@@ -48404,10 +48647,10 @@ function createShiftStore(deps) {
48404
48647
  flushTimer = null;
48405
48648
  }
48406
48649
  const content = { version: 1, shifts };
48407
- await import_promises.default.mkdir(import_node_path21.default.dirname(deps.filePath), { recursive: true });
48650
+ await import_promises2.default.mkdir(import_node_path22.default.dirname(deps.filePath), { recursive: true });
48408
48651
  const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
48409
- await import_promises.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
48410
- await import_promises.default.rename(tmp, deps.filePath);
48652
+ await import_promises2.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
48653
+ await import_promises2.default.rename(tmp, deps.filePath);
48411
48654
  }
48412
48655
  function scheduleFlush() {
48413
48656
  if (flushTimer) return;
@@ -48842,18 +49085,33 @@ function buildPersonaDispatchHandlers(deps) {
48842
49085
  if (!deps.forwardToPeer) {
48843
49086
  throw new Error("cross-device dispatch not wired (forwardToPeer missing)");
48844
49087
  }
49088
+ if (!sourceSessionId) {
49089
+ throw new Error(
49090
+ "personaDispatch:run requires sessionId (caller must pass x-clawd-session-id header)"
49091
+ );
49092
+ }
49093
+ const { dispatchId: dispatchId2 } = mgr.start({
49094
+ sourceSessionId,
49095
+ targetPersona: args.targetPersona,
49096
+ taskText: args.prompt
49097
+ });
48845
49098
  logger?.info("dispatch.run.forward", {
49099
+ dispatchId: dispatchId2,
48846
49100
  targetDeviceId: args.targetDeviceId,
48847
49101
  targetPersona: args.targetPersona
48848
49102
  });
48849
- const outcome2 = await deps.forwardToPeer({
49103
+ void deps.forwardToPeer({
48850
49104
  targetDeviceId: args.targetDeviceId,
48851
49105
  targetPersona: args.targetPersona,
48852
49106
  prompt: args.prompt,
48853
49107
  ...args.model ? { model: args.model } : {}
49108
+ }).then((outcome) => mgr.complete(dispatchId2, outcome)).catch((err) => {
49109
+ const reason = err instanceof Error ? err.message : String(err);
49110
+ logger?.warn("dispatch.forward.failed", { dispatchId: dispatchId2, reason });
49111
+ mgr.complete(dispatchId2, { kind: "failure", reason });
48854
49112
  });
48855
49113
  return {
48856
- response: { type: "personaDispatch:run:ok", outcome: outcome2 }
49114
+ response: { type: "personaDispatch:run:ok", dispatchId: dispatchId2 }
48857
49115
  };
48858
49116
  }
48859
49117
  if (ctx?.principal.kind === "guest") {
@@ -48866,7 +49124,8 @@ function buildPersonaDispatchHandlers(deps) {
48866
49124
  }
48867
49125
  const { dispatchId: dispatchId2 } = mgr.start({
48868
49126
  sourceSessionId: ctx.principal.id,
48869
- targetPersona: args.targetPersona
49127
+ targetPersona: args.targetPersona,
49128
+ taskText: args.prompt
48870
49129
  });
48871
49130
  logger?.info("dispatch.run.received.guest", {
48872
49131
  dispatchId: dispatchId2,
@@ -48892,9 +49151,9 @@ function buildPersonaDispatchHandlers(deps) {
48892
49151
  reason: `failed to spawn B: ${reason}`
48893
49152
  });
48894
49153
  });
48895
- const outcome2 = await mgr.wait(dispatchId2);
49154
+ const outcome = await mgr.waitForOutcome(dispatchId2);
48896
49155
  return {
48897
- response: { type: "personaDispatch:run:ok", outcome: outcome2 }
49156
+ response: { type: "personaDispatch:run:ok", outcome }
48898
49157
  };
48899
49158
  }
48900
49159
  if (!sourceSessionId) {
@@ -48904,7 +49163,8 @@ function buildPersonaDispatchHandlers(deps) {
48904
49163
  }
48905
49164
  const { dispatchId } = mgr.start({
48906
49165
  sourceSessionId,
48907
- targetPersona: args.targetPersona
49166
+ targetPersona: args.targetPersona,
49167
+ taskText: args.prompt
48908
49168
  });
48909
49169
  logger?.info("dispatch.run.received", {
48910
49170
  dispatchId,
@@ -48928,14 +49188,8 @@ function buildPersonaDispatchHandlers(deps) {
48928
49188
  reason: `failed to spawn B: ${reason}`
48929
49189
  });
48930
49190
  });
48931
- logger?.info("dispatch.run.waiting", { dispatchId });
48932
- const outcome = await mgr.wait(dispatchId);
48933
- logger?.info("dispatch.run.resolved", {
48934
- dispatchId,
48935
- outcomeKind: outcome.kind
48936
- });
48937
49191
  return {
48938
- response: { type: "personaDispatch:run:ok", outcome }
49192
+ response: { type: "personaDispatch:run:ok", dispatchId }
48939
49193
  };
48940
49194
  };
48941
49195
  const complete = async (frame) => {
@@ -48950,9 +49204,20 @@ function buildPersonaDispatchHandlers(deps) {
48950
49204
  response: { type: "personaDispatch:complete:ok" }
48951
49205
  };
48952
49206
  };
49207
+ const list = async (frame) => {
49208
+ const { type: _t, requestId: _r, ...rest } = frame;
49209
+ const args = DispatchListArgsSchema.parse(rest);
49210
+ const records = deps.store.list(
49211
+ args.sourceSessionId ? { sourceSessionId: args.sourceSessionId } : void 0
49212
+ );
49213
+ return {
49214
+ response: { type: "personaDispatch:list:ok", records }
49215
+ };
49216
+ };
48953
49217
  return {
48954
49218
  "personaDispatch:run": run,
48955
- "personaDispatch:complete": complete
49219
+ "personaDispatch:complete": complete,
49220
+ "personaDispatch:list": list
48956
49221
  };
48957
49222
  }
48958
49223
 
@@ -49258,13 +49523,13 @@ function mapSkillsListResponse(res) {
49258
49523
  const r = s ?? {};
49259
49524
  const name = str3(r.name);
49260
49525
  if (!name) continue;
49261
- const path70 = str3(r.path);
49526
+ const path71 = str3(r.path);
49262
49527
  const description = str3(r.description);
49263
49528
  const isPlugin = name.includes(":");
49264
49529
  out.push({
49265
49530
  name,
49266
49531
  source: isPlugin ? "plugin" : "project",
49267
- ...path70 ? { path: path70 } : {},
49532
+ ...path71 ? { path: path71 } : {},
49268
49533
  ...description ? { description } : {},
49269
49534
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
49270
49535
  });
@@ -49305,14 +49570,14 @@ async function listCodexSkills(cwd, deps = {}) {
49305
49570
  // src/workspace/browser.ts
49306
49571
  var import_node_fs24 = __toESM(require("fs"), 1);
49307
49572
  var import_node_os8 = __toESM(require("os"), 1);
49308
- var import_node_path22 = __toESM(require("path"), 1);
49573
+ var import_node_path23 = __toESM(require("path"), 1);
49309
49574
  init_protocol();
49310
49575
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
49311
49576
  function resolveInsideCwd(cwd, subpath) {
49312
- const absCwd = import_node_path22.default.resolve(cwd);
49313
- const joined = import_node_path22.default.resolve(absCwd, subpath ?? ".");
49314
- const rel = import_node_path22.default.relative(absCwd, joined);
49315
- if (rel.startsWith("..") || import_node_path22.default.isAbsolute(rel)) {
49577
+ const absCwd = import_node_path23.default.resolve(cwd);
49578
+ const joined = import_node_path23.default.resolve(absCwd, subpath ?? ".");
49579
+ const rel = import_node_path23.default.relative(absCwd, joined);
49580
+ if (rel.startsWith("..") || import_node_path23.default.isAbsolute(rel)) {
49316
49581
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
49317
49582
  }
49318
49583
  return joined;
@@ -49343,7 +49608,7 @@ var WorkspaceBrowser = class {
49343
49608
  mtime: ""
49344
49609
  };
49345
49610
  try {
49346
- const st = import_node_fs24.default.statSync(import_node_path22.default.join(full, d.name));
49611
+ const st = import_node_fs24.default.statSync(import_node_path23.default.join(full, d.name));
49347
49612
  entry.mtime = new Date(st.mtimeMs).toISOString();
49348
49613
  if (d.isFile()) entry.size = st.size;
49349
49614
  } catch {
@@ -49390,7 +49655,7 @@ var WorkspaceBrowser = class {
49390
49655
  // src/skills/agents-scanner.ts
49391
49656
  var import_node_fs25 = __toESM(require("fs"), 1);
49392
49657
  var import_node_os9 = __toESM(require("os"), 1);
49393
- var import_node_path23 = __toESM(require("path"), 1);
49658
+ var import_node_path24 = __toESM(require("path"), 1);
49394
49659
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
49395
49660
  function isDirLikeSync2(p2) {
49396
49661
  try {
@@ -49428,10 +49693,10 @@ function scanAgentsDir(dir, source, seen, out) {
49428
49693
  }
49429
49694
  for (const ent of entries) {
49430
49695
  if (!ent.name.endsWith(".md")) continue;
49431
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path23.default.join(dir, ent.name)))) {
49696
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path24.default.join(dir, ent.name)))) {
49432
49697
  continue;
49433
49698
  }
49434
- const filePath = import_node_path23.default.join(dir, ent.name);
49699
+ const filePath = import_node_path24.default.join(dir, ent.name);
49435
49700
  const baseName = ent.name.replace(/\.md$/, "");
49436
49701
  if (seen.has(baseName)) continue;
49437
49702
  seen.add(baseName);
@@ -49454,7 +49719,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
49454
49719
  return;
49455
49720
  }
49456
49721
  for (const ent of entries) {
49457
- const childPath = import_node_path23.default.join(dir, ent.name);
49722
+ const childPath = import_node_path24.default.join(dir, ent.name);
49458
49723
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
49459
49724
  walk2(childPath, [...namespaces, ent.name]);
49460
49725
  continue;
@@ -49479,9 +49744,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
49479
49744
  walk2(root, []);
49480
49745
  }
49481
49746
  function readInstalledPlugins2(home) {
49482
- const pluginsDir = import_node_path23.default.join(home, ".claude", "plugins");
49483
- const v2 = import_node_path23.default.join(pluginsDir, "installed_plugins_v2.json");
49484
- const v1 = import_node_path23.default.join(pluginsDir, "installed_plugins.json");
49747
+ const pluginsDir = import_node_path24.default.join(home, ".claude", "plugins");
49748
+ const v2 = import_node_path24.default.join(pluginsDir, "installed_plugins_v2.json");
49749
+ const v1 = import_node_path24.default.join(pluginsDir, "installed_plugins.json");
49485
49750
  let raw = null;
49486
49751
  for (const candidate of [v2, v1]) {
49487
49752
  try {
@@ -49510,19 +49775,19 @@ function readInstalledPlugins2(home) {
49510
49775
  return out;
49511
49776
  }
49512
49777
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
49513
- let cur = import_node_path23.default.resolve(startCwd);
49514
- const fsRoot = import_node_path23.default.parse(cur).root;
49778
+ let cur = import_node_path24.default.resolve(startCwd);
49779
+ const fsRoot = import_node_path24.default.parse(cur).root;
49515
49780
  while (true) {
49516
- scanAgentsDir(import_node_path23.default.join(cur, ".claude", "agents"), "project", seen, out);
49781
+ scanAgentsDir(import_node_path24.default.join(cur, ".claude", "agents"), "project", seen, out);
49517
49782
  let hasGit = false;
49518
49783
  try {
49519
- hasGit = import_node_fs25.default.existsSync(import_node_path23.default.join(cur, ".git"));
49784
+ hasGit = import_node_fs25.default.existsSync(import_node_path24.default.join(cur, ".git"));
49520
49785
  } catch {
49521
49786
  }
49522
49787
  if (hasGit) return;
49523
49788
  if (cur === home) return;
49524
49789
  if (cur === fsRoot) return;
49525
- const parent = import_node_path23.default.dirname(cur);
49790
+ const parent = import_node_path24.default.dirname(cur);
49526
49791
  if (parent === cur) return;
49527
49792
  cur = parent;
49528
49793
  }
@@ -49557,7 +49822,7 @@ var AgentsScanner = class {
49557
49822
  }
49558
49823
  const fsBlock = [];
49559
49824
  scanAgentsDir(
49560
- import_node_path23.default.join(this.home, ".claude", "agents"),
49825
+ import_node_path24.default.join(this.home, ".claude", "agents"),
49561
49826
  "global",
49562
49827
  seen,
49563
49828
  fsBlock
@@ -49571,7 +49836,7 @@ var AgentsScanner = class {
49571
49836
  ...this.extraPluginRoots
49572
49837
  ];
49573
49838
  for (const { name, root } of plugins) {
49574
- const agentsRoot = import_node_path23.default.join(root, "agents");
49839
+ const agentsRoot = import_node_path24.default.join(root, "agents");
49575
49840
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
49576
49841
  }
49577
49842
  return [...builtinBlock, ...fsBlock];
@@ -49581,13 +49846,13 @@ var AgentsScanner = class {
49581
49846
  // src/observer/session-observer.ts
49582
49847
  var import_node_fs27 = __toESM(require("fs"), 1);
49583
49848
  var import_node_os11 = __toESM(require("os"), 1);
49584
- var import_node_path25 = __toESM(require("path"), 1);
49849
+ var import_node_path26 = __toESM(require("path"), 1);
49585
49850
  init_claude_history();
49586
49851
 
49587
49852
  // src/observer/subagent-meta-observer.ts
49588
49853
  var import_node_fs26 = __toESM(require("fs"), 1);
49589
49854
  var import_node_os10 = __toESM(require("os"), 1);
49590
- var import_node_path24 = __toESM(require("path"), 1);
49855
+ var import_node_path25 = __toESM(require("path"), 1);
49591
49856
  init_claude_history();
49592
49857
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
49593
49858
  var SubagentMetaObserver = class {
@@ -49600,7 +49865,7 @@ var SubagentMetaObserver = class {
49600
49865
  watches = /* @__PURE__ */ new Map();
49601
49866
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
49602
49867
  resolveSubagentDir(cwd, toolSessionId) {
49603
- return import_node_path24.default.join(
49868
+ return import_node_path25.default.join(
49604
49869
  this.home,
49605
49870
  ".claude",
49606
49871
  "projects",
@@ -49656,7 +49921,7 @@ var SubagentMetaObserver = class {
49656
49921
  if (!m2) return;
49657
49922
  const agentId = m2[1];
49658
49923
  if (w2.emitted.has(agentId)) return;
49659
- const file = import_node_path24.default.join(w2.dirPath, name);
49924
+ const file = import_node_path25.default.join(w2.dirPath, name);
49660
49925
  let raw;
49661
49926
  try {
49662
49927
  raw = import_node_fs26.default.readFileSync(file, "utf8");
@@ -49716,7 +49981,7 @@ var SessionObserver = class {
49716
49981
  metaObserver;
49717
49982
  resolveJsonlPath(cwd, toolSessionId, override) {
49718
49983
  if (override) return override;
49719
- return import_node_path25.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
49984
+ return import_node_path26.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
49720
49985
  }
49721
49986
  start(args) {
49722
49987
  this.stop(args.sessionId);
@@ -49742,10 +50007,10 @@ var SessionObserver = class {
49742
50007
  lastDeriveMs: 0
49743
50008
  };
49744
50009
  try {
49745
- import_node_fs27.default.mkdirSync(import_node_path25.default.dirname(filePath), { recursive: true });
50010
+ import_node_fs27.default.mkdirSync(import_node_path26.default.dirname(filePath), { recursive: true });
49746
50011
  } catch {
49747
50012
  }
49748
- w2.watcher = import_node_fs27.default.watch(import_node_path25.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
50013
+ w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
49749
50014
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
49750
50015
  this.poll(w2);
49751
50016
  });
@@ -49842,7 +50107,7 @@ var SessionObserver = class {
49842
50107
  const now = Date.now();
49843
50108
  if (now - w2.lastRelocateScanMs < 1e3) return;
49844
50109
  w2.lastRelocateScanMs = now;
49845
- const projectsRoot = import_node_path25.default.join(this.home, ".claude", "projects");
50110
+ const projectsRoot = import_node_path26.default.join(this.home, ".claude", "projects");
49846
50111
  const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
49847
50112
  if (!found || found === w2.filePath) return;
49848
50113
  try {
@@ -49851,7 +50116,7 @@ var SessionObserver = class {
49851
50116
  }
49852
50117
  w2.filePath = found;
49853
50118
  try {
49854
- w2.watcher = import_node_fs27.default.watch(import_node_path25.default.dirname(found), { persistent: false }, (_event, changedName) => {
50119
+ w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(found), { persistent: false }, (_event, changedName) => {
49855
50120
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
49856
50121
  this.poll(w2);
49857
50122
  });
@@ -50435,13 +50700,13 @@ var EXPOSED_RPC_METHODS = [
50435
50700
  // dataclaw-builder:persona 建页时取建页人身份(含 union_id)写进生成 app 的配置。
50436
50701
  // 路由到 handlers['auth:getIdentity'],只返 identity、绝不带 ttcToken(见 handlers/feishu-auth.ts)。
50437
50702
  "auth.getIdentity",
50438
- // Persona dispatch (Task 4): A 端 dispatch MCP server 调 run(hold-and-wait 一次);
50439
- // B dispatch MCP server complete(带 outcome 触发 run 端 resolve)。详见
50440
- // protocol/src/dispatch.ts。
50703
+ // Persona dispatch(异步,spec 2026-07-20):A 端 dispatch MCP server 调 run(秒回 dispatchId);
50704
+ // B 端调 complete(带 outcome 台账 + 投递);发起方调 list 查台账。详见 protocol/src/dispatch.ts。
50441
50705
  "personaDispatch.run",
50442
50706
  // 跨设备 exec(spec 2026-07-16):A 侧本地 cc 经 /api/rpc 调,带 peerDeviceId → daemon forward。
50443
50707
  "peerExec.run",
50444
50708
  "personaDispatch.complete",
50709
+ "personaDispatch.list",
50445
50710
  // clawd-shift v1 (spec 2026-06-24-clawd-shift):cc 子进程内的 shift MCP server 调
50446
50711
  // 这 5 个 method 管理 owner 的 shift(fire-and-forget 排班)。鉴权靠 body.personaId
50447
50712
  // (mcp-server 从 process.env.CLAWD_PERSONA_ID 读,源 = SessionFile.ownerPersonaId)。
@@ -50706,14 +50971,14 @@ async function authenticate(token, deps) {
50706
50971
  }
50707
50972
 
50708
50973
  // src/permission/capability-store.ts
50709
- var fs31 = __toESM(require("fs"), 1);
50710
- var path30 = __toESM(require("path"), 1);
50974
+ var fs32 = __toESM(require("fs"), 1);
50975
+ var path31 = __toESM(require("path"), 1);
50711
50976
  var CAPABILITIES_FILE_NAME = "capabilities.json";
50712
50977
  var FILE_VERSION = 1;
50713
50978
  var CapabilityStore = class {
50714
50979
  constructor(dataDir) {
50715
50980
  this.dataDir = dataDir;
50716
- fs31.mkdirSync(dataDir, { recursive: true });
50981
+ fs32.mkdirSync(dataDir, { recursive: true });
50717
50982
  this.cache = this.readFromDisk();
50718
50983
  }
50719
50984
  dataDir;
@@ -50737,13 +51002,13 @@ var CapabilityStore = class {
50737
51002
  this.flush();
50738
51003
  }
50739
51004
  filePath() {
50740
- return path30.join(this.dataDir, CAPABILITIES_FILE_NAME);
51005
+ return path31.join(this.dataDir, CAPABILITIES_FILE_NAME);
50741
51006
  }
50742
51007
  readFromDisk() {
50743
51008
  const file = this.filePath();
50744
51009
  let raw;
50745
51010
  try {
50746
- raw = fs31.readFileSync(file, "utf8");
51011
+ raw = fs32.readFileSync(file, "utf8");
50747
51012
  } catch (err) {
50748
51013
  if (err?.code === "ENOENT") return [];
50749
51014
  return [];
@@ -50771,10 +51036,10 @@ var CapabilityStore = class {
50771
51036
  }
50772
51037
  atomicWrite(file, content) {
50773
51038
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
50774
- fs31.writeFileSync(tmp, content, { mode: 384 });
50775
- fs31.renameSync(tmp, file);
51039
+ fs32.writeFileSync(tmp, content, { mode: 384 });
51040
+ fs32.renameSync(tmp, file);
50776
51041
  try {
50777
- fs31.chmodSync(file, 384);
51042
+ fs32.chmodSync(file, 384);
50778
51043
  } catch {
50779
51044
  }
50780
51045
  }
@@ -50867,14 +51132,14 @@ var CapabilityManager = class {
50867
51132
  };
50868
51133
 
50869
51134
  // src/permission/cleanup.ts
50870
- var fs32 = __toESM(require("fs"), 1);
51135
+ var fs33 = __toESM(require("fs"), 1);
50871
51136
  function cleanupGuestSessionsForCapability(cap, factory) {
50872
51137
  const removed = [];
50873
51138
  for (const g2 of cap.grants) {
50874
51139
  if (g2.resource.type !== "persona") continue;
50875
51140
  const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
50876
51141
  try {
50877
- fs32.rmSync(dir, { recursive: true, force: true });
51142
+ fs33.rmSync(dir, { recursive: true, force: true });
50878
51143
  removed.push(dir);
50879
51144
  } catch {
50880
51145
  }
@@ -50883,13 +51148,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
50883
51148
  }
50884
51149
 
50885
51150
  // src/inbox/inbox-store.ts
50886
- var fs33 = __toESM(require("fs"), 1);
50887
- var path31 = __toESM(require("path"), 1);
51151
+ var fs34 = __toESM(require("fs"), 1);
51152
+ var path32 = __toESM(require("path"), 1);
50888
51153
  var INBOX_SUBDIR = "inbox";
50889
51154
  var InboxStore = class {
50890
51155
  constructor(dataDir) {
50891
51156
  this.dataDir = dataDir;
50892
- fs33.mkdirSync(this.dirPath(), { recursive: true });
51157
+ fs34.mkdirSync(this.dirPath(), { recursive: true });
50893
51158
  }
50894
51159
  dataDir;
50895
51160
  /**
@@ -50901,7 +51166,7 @@ var InboxStore = class {
50901
51166
  const file = this.filePath(peerDeviceId);
50902
51167
  let raw;
50903
51168
  try {
50904
- raw = fs33.readFileSync(file, "utf8");
51169
+ raw = fs34.readFileSync(file, "utf8");
50905
51170
  } catch (err) {
50906
51171
  if (err?.code === "ENOENT") return [];
50907
51172
  return [];
@@ -50917,7 +51182,7 @@ var InboxStore = class {
50917
51182
  const dir = this.dirPath();
50918
51183
  let entries;
50919
51184
  try {
50920
- entries = fs33.readdirSync(dir);
51185
+ entries = fs34.readdirSync(dir);
50921
51186
  } catch (err) {
50922
51187
  if (err?.code === "ENOENT") return [];
50923
51188
  return [];
@@ -50933,9 +51198,9 @@ var InboxStore = class {
50933
51198
  if (existing.some((m2) => m2.id === message.id)) return;
50934
51199
  const file = this.filePath(message.peerDeviceId);
50935
51200
  const line = JSON.stringify(message) + "\n";
50936
- fs33.appendFileSync(file, line, { mode: 384 });
51201
+ fs34.appendFileSync(file, line, { mode: 384 });
50937
51202
  try {
50938
- fs33.chmodSync(file, 384);
51203
+ fs34.chmodSync(file, 384);
50939
51204
  } catch {
50940
51205
  }
50941
51206
  }
@@ -50965,7 +51230,7 @@ var InboxStore = class {
50965
51230
  removeByPeerDeviceId(peerDeviceId) {
50966
51231
  const file = this.filePath(peerDeviceId);
50967
51232
  try {
50968
- fs33.unlinkSync(file);
51233
+ fs34.unlinkSync(file);
50969
51234
  } catch (err) {
50970
51235
  if (err?.code === "ENOENT") return;
50971
51236
  }
@@ -50974,18 +51239,18 @@ var InboxStore = class {
50974
51239
  const file = this.filePath(peerDeviceId);
50975
51240
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
50976
51241
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
50977
- fs33.writeFileSync(tmp, content, { mode: 384 });
50978
- fs33.renameSync(tmp, file);
51242
+ fs34.writeFileSync(tmp, content, { mode: 384 });
51243
+ fs34.renameSync(tmp, file);
50979
51244
  try {
50980
- fs33.chmodSync(file, 384);
51245
+ fs34.chmodSync(file, 384);
50981
51246
  } catch {
50982
51247
  }
50983
51248
  }
50984
51249
  dirPath() {
50985
- return path31.join(this.dataDir, INBOX_SUBDIR);
51250
+ return path32.join(this.dataDir, INBOX_SUBDIR);
50986
51251
  }
50987
51252
  filePath(peerDeviceId) {
50988
- return path31.join(this.dirPath(), `${peerDeviceId}.jsonl`);
51253
+ return path32.join(this.dirPath(), `${peerDeviceId}.jsonl`);
50989
51254
  }
50990
51255
  };
50991
51256
  function parseAllLines(raw) {
@@ -51073,8 +51338,8 @@ var InboxManager = class {
51073
51338
  };
51074
51339
 
51075
51340
  // src/state/contact-store.ts
51076
- var fs34 = __toESM(require("fs"), 1);
51077
- var path32 = __toESM(require("path"), 1);
51341
+ var fs35 = __toESM(require("fs"), 1);
51342
+ var path33 = __toESM(require("path"), 1);
51078
51343
  var FILE_NAME = "contacts.json";
51079
51344
  var ContactStore = class {
51080
51345
  constructor(dataDir) {
@@ -51084,10 +51349,10 @@ var ContactStore = class {
51084
51349
  contacts = /* @__PURE__ */ new Map();
51085
51350
  load() {
51086
51351
  this.contacts.clear();
51087
- const file = path32.join(this.dataDir, FILE_NAME);
51352
+ const file = path33.join(this.dataDir, FILE_NAME);
51088
51353
  let raw;
51089
51354
  try {
51090
- raw = fs34.readFileSync(file, "utf8");
51355
+ raw = fs35.readFileSync(file, "utf8");
51091
51356
  } catch (err) {
51092
51357
  if (err?.code !== "ENOENT") this.renameBak(file);
51093
51358
  return;
@@ -51156,20 +51421,20 @@ var ContactStore = class {
51156
51421
  return true;
51157
51422
  }
51158
51423
  flush() {
51159
- const file = path32.join(this.dataDir, FILE_NAME);
51424
+ const file = path33.join(this.dataDir, FILE_NAME);
51160
51425
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
51161
51426
  const content = JSON.stringify(
51162
51427
  { contacts: Array.from(this.contacts.values()) },
51163
51428
  null,
51164
51429
  2
51165
51430
  );
51166
- fs34.mkdirSync(this.dataDir, { recursive: true });
51167
- fs34.writeFileSync(tmp, content, { mode: 384 });
51168
- fs34.renameSync(tmp, file);
51431
+ fs35.mkdirSync(this.dataDir, { recursive: true });
51432
+ fs35.writeFileSync(tmp, content, { mode: 384 });
51433
+ fs35.renameSync(tmp, file);
51169
51434
  }
51170
51435
  renameBak(file) {
51171
51436
  try {
51172
- fs34.renameSync(file, `${file}.bak`);
51437
+ fs35.renameSync(file, `${file}.bak`);
51173
51438
  } catch {
51174
51439
  }
51175
51440
  }
@@ -51322,61 +51587,61 @@ async function autoReverseContact(args) {
51322
51587
  }
51323
51588
 
51324
51589
  // src/migrations/2026-05-20-flatten-sessions.ts
51325
- var fs35 = __toESM(require("fs"), 1);
51326
- var path33 = __toESM(require("path"), 1);
51590
+ var fs36 = __toESM(require("fs"), 1);
51591
+ var path34 = __toESM(require("path"), 1);
51327
51592
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
51328
51593
  function migrateFlattenSessions(opts) {
51329
51594
  const dataDir = opts.dataDir;
51330
51595
  const now = opts.now ?? Date.now;
51331
- const sessionsDir = path33.join(dataDir, "sessions");
51332
- const flagPath = path33.join(sessionsDir, MIGRATION_FLAG_NAME);
51596
+ const sessionsDir = path34.join(dataDir, "sessions");
51597
+ const flagPath = path34.join(sessionsDir, MIGRATION_FLAG_NAME);
51333
51598
  if (existsSync3(flagPath)) {
51334
51599
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
51335
51600
  }
51336
51601
  let movedBare = 0;
51337
51602
  let movedVmOwner = 0;
51338
51603
  let archivedListener = 0;
51339
- const defaultDir = path33.join(sessionsDir, "default");
51604
+ const defaultDir = path34.join(sessionsDir, "default");
51340
51605
  if (existsSync3(defaultDir)) {
51341
51606
  for (const entry of readdirSafe(defaultDir)) {
51342
51607
  if (!entry.endsWith(".json")) continue;
51343
- const src = path33.join(defaultDir, entry);
51344
- const dst = path33.join(sessionsDir, entry);
51345
- fs35.renameSync(src, dst);
51608
+ const src = path34.join(defaultDir, entry);
51609
+ const dst = path34.join(sessionsDir, entry);
51610
+ fs36.renameSync(src, dst);
51346
51611
  movedBare += 1;
51347
51612
  }
51348
51613
  rmdirIfEmpty(defaultDir);
51349
51614
  }
51350
51615
  for (const pid of readdirSafe(sessionsDir)) {
51351
- const personaDir = path33.join(sessionsDir, pid);
51616
+ const personaDir = path34.join(sessionsDir, pid);
51352
51617
  if (!isDir(personaDir)) continue;
51353
51618
  if (pid === "default") continue;
51354
- const ownerSrc = path33.join(personaDir, "owner");
51619
+ const ownerSrc = path34.join(personaDir, "owner");
51355
51620
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
51356
- const ownerDst = path33.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
51357
- fs35.mkdirSync(ownerDst, { recursive: true });
51621
+ const ownerDst = path34.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
51622
+ fs36.mkdirSync(ownerDst, { recursive: true });
51358
51623
  for (const file of readdirSafe(ownerSrc)) {
51359
51624
  if (!file.endsWith(".json")) continue;
51360
- fs35.renameSync(path33.join(ownerSrc, file), path33.join(ownerDst, file));
51625
+ fs36.renameSync(path34.join(ownerSrc, file), path34.join(ownerDst, file));
51361
51626
  movedVmOwner += 1;
51362
51627
  }
51363
51628
  rmdirIfEmpty(ownerSrc);
51364
51629
  }
51365
- const listenerSrc = path33.join(personaDir, "listener");
51630
+ const listenerSrc = path34.join(personaDir, "listener");
51366
51631
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
51367
- const archiveDst = path33.join(dataDir, ".legacy", `listener-${pid}`);
51368
- fs35.mkdirSync(archiveDst, { recursive: true });
51632
+ const archiveDst = path34.join(dataDir, ".legacy", `listener-${pid}`);
51633
+ fs36.mkdirSync(archiveDst, { recursive: true });
51369
51634
  for (const file of readdirSafe(listenerSrc)) {
51370
51635
  if (!file.endsWith(".json")) continue;
51371
- fs35.renameSync(path33.join(listenerSrc, file), path33.join(archiveDst, file));
51636
+ fs36.renameSync(path34.join(listenerSrc, file), path34.join(archiveDst, file));
51372
51637
  archivedListener += 1;
51373
51638
  }
51374
51639
  rmdirIfEmpty(listenerSrc);
51375
51640
  }
51376
51641
  rmdirIfEmpty(personaDir);
51377
51642
  }
51378
- fs35.mkdirSync(sessionsDir, { recursive: true });
51379
- fs35.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
51643
+ fs36.mkdirSync(sessionsDir, { recursive: true });
51644
+ fs36.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
51380
51645
  return {
51381
51646
  skipped: false,
51382
51647
  flagWritten: true,
@@ -51387,7 +51652,7 @@ function migrateFlattenSessions(opts) {
51387
51652
  }
51388
51653
  function existsSync3(p2) {
51389
51654
  try {
51390
- fs35.statSync(p2);
51655
+ fs36.statSync(p2);
51391
51656
  return true;
51392
51657
  } catch {
51393
51658
  return false;
@@ -51395,31 +51660,31 @@ function existsSync3(p2) {
51395
51660
  }
51396
51661
  function isDir(p2) {
51397
51662
  try {
51398
- return fs35.statSync(p2).isDirectory();
51663
+ return fs36.statSync(p2).isDirectory();
51399
51664
  } catch {
51400
51665
  return false;
51401
51666
  }
51402
51667
  }
51403
51668
  function readdirSafe(p2) {
51404
51669
  try {
51405
- return fs35.readdirSync(p2);
51670
+ return fs36.readdirSync(p2);
51406
51671
  } catch {
51407
51672
  return [];
51408
51673
  }
51409
51674
  }
51410
51675
  function rmdirIfEmpty(p2) {
51411
51676
  try {
51412
- fs35.rmdirSync(p2);
51677
+ fs36.rmdirSync(p2);
51413
51678
  } catch {
51414
51679
  }
51415
51680
  }
51416
51681
 
51417
51682
  // src/transport/http-router.ts
51418
51683
  var import_node_fs29 = __toESM(require("fs"), 1);
51419
- var import_node_path29 = __toESM(require("path"), 1);
51684
+ var import_node_path30 = __toESM(require("path"), 1);
51420
51685
 
51421
51686
  // src/attachment/mime.ts
51422
- var import_node_path26 = __toESM(require("path"), 1);
51687
+ var import_node_path27 = __toESM(require("path"), 1);
51423
51688
  var TEXT_PLAIN = "text/plain; charset=utf-8";
51424
51689
  var EXT_TO_NATIVE_MIME = {
51425
51690
  // 图片
@@ -51526,7 +51791,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
51526
51791
  ".mk"
51527
51792
  ]);
51528
51793
  function lookupMime(filePathOrName) {
51529
- const ext = import_node_path26.default.extname(filePathOrName).toLowerCase();
51794
+ const ext = import_node_path27.default.extname(filePathOrName).toLowerCase();
51530
51795
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
51531
51796
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
51532
51797
  return "application/octet-stream";
@@ -51596,9 +51861,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
51596
51861
 
51597
51862
  // src/attachment/upload.ts
51598
51863
  var import_node_fs28 = __toESM(require("fs"), 1);
51599
- var import_node_path27 = __toESM(require("path"), 1);
51864
+ var import_node_path28 = __toESM(require("path"), 1);
51600
51865
  var import_node_crypto8 = __toESM(require("crypto"), 1);
51601
- var import_promises2 = require("stream/promises");
51866
+ var import_promises3 = require("stream/promises");
51602
51867
  var UploadError = class extends Error {
51603
51868
  constructor(code, message) {
51604
51869
  super(message);
@@ -51608,14 +51873,14 @@ var UploadError = class extends Error {
51608
51873
  code;
51609
51874
  };
51610
51875
  function assertValidFileName(fileName) {
51611
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path27.default.basename(fileName)) {
51876
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path28.default.basename(fileName)) {
51612
51877
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
51613
51878
  }
51614
51879
  }
51615
51880
  var HASH_PREFIX_LEN = 16;
51616
51881
  async function writeUploadedAttachment(args) {
51617
51882
  assertValidFileName(args.fileName);
51618
- const attachmentsRoot = import_node_path27.default.join(args.sessionDir, ".attachments");
51883
+ const attachmentsRoot = import_node_path28.default.join(args.sessionDir, ".attachments");
51619
51884
  try {
51620
51885
  import_node_fs28.default.mkdirSync(attachmentsRoot, { recursive: true });
51621
51886
  } catch (err) {
@@ -51623,12 +51888,12 @@ async function writeUploadedAttachment(args) {
51623
51888
  }
51624
51889
  const hasher = import_node_crypto8.default.createHash("sha256");
51625
51890
  let actualSize = 0;
51626
- const tmpPath = import_node_path27.default.join(
51891
+ const tmpPath = import_node_path28.default.join(
51627
51892
  attachmentsRoot,
51628
51893
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
51629
51894
  );
51630
51895
  try {
51631
- await (0, import_promises2.pipeline)(
51896
+ await (0, import_promises3.pipeline)(
51632
51897
  args.body,
51633
51898
  async function* (source) {
51634
51899
  for await (const chunk of source) {
@@ -51658,7 +51923,7 @@ async function writeUploadedAttachment(args) {
51658
51923
  );
51659
51924
  }
51660
51925
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
51661
- const hashDir = import_node_path27.default.join(attachmentsRoot, attachmentId);
51926
+ const hashDir = import_node_path28.default.join(attachmentsRoot, attachmentId);
51662
51927
  let finalFileName;
51663
51928
  let hashDirExists = false;
51664
51929
  try {
@@ -51676,7 +51941,7 @@ async function writeUploadedAttachment(args) {
51676
51941
  try {
51677
51942
  import_node_fs28.default.mkdirSync(hashDir, { recursive: true });
51678
51943
  finalFileName = args.fileName;
51679
- import_node_fs28.default.renameSync(tmpPath, import_node_path27.default.join(hashDir, finalFileName));
51944
+ import_node_fs28.default.renameSync(tmpPath, import_node_path28.default.join(hashDir, finalFileName));
51680
51945
  } catch (err) {
51681
51946
  try {
51682
51947
  import_node_fs28.default.unlinkSync(tmpPath);
@@ -51685,8 +51950,8 @@ async function writeUploadedAttachment(args) {
51685
51950
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
51686
51951
  }
51687
51952
  }
51688
- const absPath = import_node_path27.default.join(hashDir, finalFileName);
51689
- const relPath = import_node_path27.default.relative(args.sessionDir, absPath);
51953
+ const absPath = import_node_path28.default.join(hashDir, finalFileName);
51954
+ const relPath = import_node_path28.default.relative(args.sessionDir, absPath);
51690
51955
  args.groupFileStore.upsert(args.scope, args.sessionId, {
51691
51956
  relPath: absPath,
51692
51957
  // 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
@@ -51699,8 +51964,8 @@ async function writeUploadedAttachment(args) {
51699
51964
  }
51700
51965
 
51701
51966
  // src/extension/import.ts
51702
- var import_promises3 = __toESM(require("fs/promises"), 1);
51703
- var import_node_path28 = __toESM(require("path"), 1);
51967
+ var import_promises4 = __toESM(require("fs/promises"), 1);
51968
+ var import_node_path29 = __toESM(require("path"), 1);
51704
51969
  var import_node_os12 = __toESM(require("os"), 1);
51705
51970
  var import_jszip = __toESM(require_lib3(), 1);
51706
51971
  var ImportError = class extends Error {
@@ -51718,7 +51983,7 @@ async function importZip(buf, root) {
51718
51983
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
51719
51984
  }
51720
51985
  for (const name of Object.keys(zip.files)) {
51721
- if (name.includes("..") || name.startsWith("/") || import_node_path28.default.isAbsolute(name)) {
51986
+ if (name.includes("..") || name.startsWith("/") || import_node_path29.default.isAbsolute(name)) {
51722
51987
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
51723
51988
  }
51724
51989
  }
@@ -51751,33 +52016,33 @@ async function importZip(buf, root) {
51751
52016
  );
51752
52017
  }
51753
52018
  }
51754
- const destDir = import_node_path28.default.join(root, manifest.id);
52019
+ const destDir = import_node_path29.default.join(root, manifest.id);
51755
52020
  let destExists = false;
51756
52021
  try {
51757
- await import_promises3.default.access(destDir);
52022
+ await import_promises4.default.access(destDir);
51758
52023
  destExists = true;
51759
52024
  } catch {
51760
52025
  }
51761
52026
  if (destExists) {
51762
52027
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
51763
52028
  }
51764
- const stage = await import_promises3.default.mkdtemp(import_node_path28.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
52029
+ const stage = await import_promises4.default.mkdtemp(import_node_path29.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
51765
52030
  try {
51766
52031
  for (const [name, entry] of Object.entries(zip.files)) {
51767
- const dest = import_node_path28.default.join(stage, name);
52032
+ const dest = import_node_path29.default.join(stage, name);
51768
52033
  if (entry.dir) {
51769
- await import_promises3.default.mkdir(dest, { recursive: true });
52034
+ await import_promises4.default.mkdir(dest, { recursive: true });
51770
52035
  continue;
51771
52036
  }
51772
- await import_promises3.default.mkdir(import_node_path28.default.dirname(dest), { recursive: true });
52037
+ await import_promises4.default.mkdir(import_node_path29.default.dirname(dest), { recursive: true });
51773
52038
  const content = await entry.async("nodebuffer");
51774
- await import_promises3.default.writeFile(dest, content);
52039
+ await import_promises4.default.writeFile(dest, content);
51775
52040
  }
51776
- await import_promises3.default.mkdir(root, { recursive: true });
51777
- await import_promises3.default.rename(stage, destDir);
52041
+ await import_promises4.default.mkdir(root, { recursive: true });
52042
+ await import_promises4.default.rename(stage, destDir);
51778
52043
  return { extId: manifest.id };
51779
52044
  } catch (e) {
51780
- await import_promises3.default.rm(stage, { recursive: true, force: true }).catch(() => {
52045
+ await import_promises4.default.rm(stage, { recursive: true, force: true }).catch(() => {
51781
52046
  });
51782
52047
  throw e;
51783
52048
  }
@@ -51800,7 +52065,7 @@ var SHARE_UI_ASSET_MIME = {
51800
52065
  ".wasm": "application/wasm"
51801
52066
  };
51802
52067
  function shareUiAssetMime(filePath) {
51803
- const ext = import_node_path29.default.extname(filePath).toLowerCase();
52068
+ const ext = import_node_path30.default.extname(filePath).toLowerCase();
51804
52069
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
51805
52070
  }
51806
52071
  var DISPATCH_HEARTBEAT_MS = 25e3;
@@ -51887,7 +52152,7 @@ function isValidUploadFileName(fileName) {
51887
52152
  if (fileName === "." || fileName === "..") return false;
51888
52153
  if (fileName.startsWith(".")) return false;
51889
52154
  if (fileName.includes("/") || fileName.includes("\\")) return false;
51890
- return fileName === import_node_path29.default.basename(fileName);
52155
+ return fileName === import_node_path30.default.basename(fileName);
51891
52156
  }
51892
52157
  function createHttpRouter(deps) {
51893
52158
  return async (req, res) => {
@@ -52183,7 +52448,7 @@ function createHttpRouter(deps) {
52183
52448
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
52184
52449
  return true;
52185
52450
  }
52186
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path29.default.basename(r.absPath)));
52451
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path30.default.basename(r.absPath)));
52187
52452
  return true;
52188
52453
  }
52189
52454
  const ctx = deps.authResolver.resolveFromHeader(
@@ -52304,7 +52569,7 @@ function createHttpRouter(deps) {
52304
52569
  return true;
52305
52570
  }
52306
52571
  let absPath;
52307
- if (import_node_path29.default.isAbsolute(pathParam)) {
52572
+ if (import_node_path30.default.isAbsolute(pathParam)) {
52308
52573
  absPath = pathParam;
52309
52574
  } else if (deps.sessionStore) {
52310
52575
  const file = deps.sessionStore.read(sid);
@@ -52312,7 +52577,7 @@ function createHttpRouter(deps) {
52312
52577
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
52313
52578
  return true;
52314
52579
  }
52315
- absPath = import_node_path29.default.join(file.cwd, pathParam);
52580
+ absPath = import_node_path30.default.join(file.cwd, pathParam);
52316
52581
  } else {
52317
52582
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
52318
52583
  return true;
@@ -52414,7 +52679,7 @@ function streamFile(res, absPath, logger) {
52414
52679
  return;
52415
52680
  }
52416
52681
  const mime = lookupMime(absPath);
52417
- const basename = import_node_path29.default.basename(absPath);
52682
+ const basename = import_node_path30.default.basename(absPath);
52418
52683
  res.writeHead(200, {
52419
52684
  "Content-Type": mime,
52420
52685
  "Content-Length": String(stat.size),
@@ -52432,7 +52697,7 @@ function streamFile(res, absPath, logger) {
52432
52697
 
52433
52698
  // src/attachment/gc.ts
52434
52699
  var import_node_fs30 = __toESM(require("fs"), 1);
52435
- var import_node_path30 = __toESM(require("path"), 1);
52700
+ var import_node_path31 = __toESM(require("path"), 1);
52436
52701
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
52437
52702
  function runAttachmentGc(args) {
52438
52703
  const now = (args.now ?? Date.now)();
@@ -52441,17 +52706,17 @@ function runAttachmentGc(args) {
52441
52706
  for (const { scope, sessionId } of args.sessionScopes) {
52442
52707
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
52443
52708
  if (entry.stale) continue;
52444
- if (import_node_path30.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
52709
+ if (import_node_path31.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
52445
52710
  }
52446
52711
  }
52447
52712
  for (const { scope, sessionId } of args.sessionScopes) {
52448
- const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path30.default.join(
52713
+ const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path31.default.join(
52449
52714
  args.dataDir,
52450
52715
  "sessions",
52451
52716
  ...scopeSubPath(scope).map(safeFileName),
52452
52717
  safeFileName(sessionId)
52453
52718
  );
52454
- const attRoot = import_node_path30.default.join(sessionDir, ".attachments");
52719
+ const attRoot = import_node_path31.default.join(sessionDir, ".attachments");
52455
52720
  let hashDirs;
52456
52721
  try {
52457
52722
  hashDirs = import_node_fs30.default.readdirSync(attRoot);
@@ -52461,7 +52726,7 @@ function runAttachmentGc(args) {
52461
52726
  continue;
52462
52727
  }
52463
52728
  for (const hashDir of hashDirs) {
52464
- const hashDirAbs = import_node_path30.default.join(attRoot, hashDir);
52729
+ const hashDirAbs = import_node_path31.default.join(attRoot, hashDir);
52465
52730
  let files;
52466
52731
  try {
52467
52732
  files = import_node_fs30.default.readdirSync(hashDirAbs);
@@ -52469,7 +52734,7 @@ function runAttachmentGc(args) {
52469
52734
  continue;
52470
52735
  }
52471
52736
  for (const name of files) {
52472
- const file = import_node_path30.default.join(hashDirAbs, name);
52737
+ const file = import_node_path31.default.join(hashDirAbs, name);
52473
52738
  let stat;
52474
52739
  try {
52475
52740
  stat = import_node_fs30.default.statSync(file);
@@ -52500,7 +52765,7 @@ function runAttachmentGc(args) {
52500
52765
 
52501
52766
  // src/attachment/group.ts
52502
52767
  var import_node_fs31 = __toESM(require("fs"), 1);
52503
- var import_node_path31 = __toESM(require("path"), 1);
52768
+ var import_node_path32 = __toESM(require("path"), 1);
52504
52769
  var import_node_crypto9 = __toESM(require("crypto"), 1);
52505
52770
  init_protocol();
52506
52771
  var GroupFileStore = class {
@@ -52512,11 +52777,11 @@ var GroupFileStore = class {
52512
52777
  this.logger = opts.logger;
52513
52778
  }
52514
52779
  rootForScope(scope) {
52515
- return import_node_path31.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
52780
+ return import_node_path32.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
52516
52781
  }
52517
52782
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
52518
52783
  filePath(scope, sessionId) {
52519
- return import_node_path31.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
52784
+ return import_node_path32.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
52520
52785
  }
52521
52786
  cacheKey(scope, sessionId) {
52522
52787
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -52551,7 +52816,7 @@ var GroupFileStore = class {
52551
52816
  }
52552
52817
  writeFile(scope, sessionId, entries) {
52553
52818
  const file = this.filePath(scope, sessionId);
52554
- import_node_fs31.default.mkdirSync(import_node_path31.default.dirname(file), { recursive: true });
52819
+ import_node_fs31.default.mkdirSync(import_node_path32.default.dirname(file), { recursive: true });
52555
52820
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
52556
52821
  import_node_fs31.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
52557
52822
  import_node_fs31.default.renameSync(tmp, file);
@@ -52641,9 +52906,9 @@ var GroupFileStore = class {
52641
52906
 
52642
52907
  // src/discovery/state-file.ts
52643
52908
  var import_node_fs32 = __toESM(require("fs"), 1);
52644
- var import_node_path32 = __toESM(require("path"), 1);
52909
+ var import_node_path33 = __toESM(require("path"), 1);
52645
52910
  function defaultStateFilePath(dataDir) {
52646
- return import_node_path32.default.join(dataDir, "state.json");
52911
+ return import_node_path33.default.join(dataDir, "state.json");
52647
52912
  }
52648
52913
  function isPidAlive(pid) {
52649
52914
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -52679,7 +52944,7 @@ var StateFileManager = class {
52679
52944
  return { status: "stale", existing };
52680
52945
  }
52681
52946
  write(state) {
52682
- import_node_fs32.default.mkdirSync(import_node_path32.default.dirname(this.file), { recursive: true });
52947
+ import_node_fs32.default.mkdirSync(import_node_path33.default.dirname(this.file), { recursive: true });
52683
52948
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
52684
52949
  import_node_fs32.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
52685
52950
  import_node_fs32.default.renameSync(tmp, this.file);
@@ -52707,13 +52972,13 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
52707
52972
 
52708
52973
  // src/tunnel/tunnel-manager.ts
52709
52974
  var import_node_fs36 = __toESM(require("fs"), 1);
52710
- var import_node_path36 = __toESM(require("path"), 1);
52975
+ var import_node_path37 = __toESM(require("path"), 1);
52711
52976
  var import_node_crypto10 = __toESM(require("crypto"), 1);
52712
52977
  var import_node_child_process9 = require("child_process");
52713
52978
 
52714
52979
  // src/tunnel/tunnel-store.ts
52715
52980
  var import_node_fs33 = __toESM(require("fs"), 1);
52716
- var import_node_path33 = __toESM(require("path"), 1);
52981
+ var import_node_path34 = __toESM(require("path"), 1);
52717
52982
  var TunnelStore = class {
52718
52983
  constructor(filePath) {
52719
52984
  this.filePath = filePath;
@@ -52732,7 +52997,7 @@ var TunnelStore = class {
52732
52997
  }
52733
52998
  }
52734
52999
  async set(v2) {
52735
- const dir = import_node_path33.default.dirname(this.filePath);
53000
+ const dir = import_node_path34.default.dirname(this.filePath);
52736
53001
  await import_node_fs33.default.promises.mkdir(dir, { recursive: true });
52737
53002
  const data = JSON.stringify(v2, null, 2);
52738
53003
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
@@ -52844,10 +53109,10 @@ function escape(v2) {
52844
53109
  // src/tunnel/frpc-binary.ts
52845
53110
  var import_node_fs34 = __toESM(require("fs"), 1);
52846
53111
  var import_node_os13 = __toESM(require("os"), 1);
52847
- var import_node_path34 = __toESM(require("path"), 1);
53112
+ var import_node_path35 = __toESM(require("path"), 1);
52848
53113
  var import_node_child_process7 = require("child_process");
52849
53114
  var import_node_stream3 = require("stream");
52850
- var import_promises4 = require("stream/promises");
53115
+ var import_promises5 = require("stream/promises");
52851
53116
  var FRPC_VERSION = "0.68.0";
52852
53117
  var UnsupportedPlatformError = class extends Error {
52853
53118
  constructor(platform, arch) {
@@ -52883,13 +53148,13 @@ async function ensureFrpcBinary(opts) {
52883
53148
  }
52884
53149
  const version2 = opts.version ?? FRPC_VERSION;
52885
53150
  const platform = opts.platform ?? detectPlatform();
52886
- const binDir = import_node_path34.default.join(opts.dataDir, "bin");
53151
+ const binDir = import_node_path35.default.join(opts.dataDir, "bin");
52887
53152
  import_node_fs34.default.mkdirSync(binDir, { recursive: true });
52888
53153
  cleanupStaleArtifacts(binDir);
52889
- const stableBin = import_node_path34.default.join(binDir, "frpc");
53154
+ const stableBin = import_node_path35.default.join(binDir, "frpc");
52890
53155
  if (import_node_fs34.default.existsSync(stableBin)) return stableBin;
52891
53156
  const partialBin = `${stableBin}.partial`;
52892
- const tarballPath = import_node_path34.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
53157
+ const tarballPath = import_node_path35.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
52893
53158
  try {
52894
53159
  const url = frpcDownloadUrl(version2, platform);
52895
53160
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -52915,7 +53180,7 @@ function cleanupStaleArtifacts(binDir) {
52915
53180
  }
52916
53181
  for (const name of entries) {
52917
53182
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
52918
- const full = import_node_path34.default.join(binDir, name);
53183
+ const full = import_node_path35.default.join(binDir, name);
52919
53184
  try {
52920
53185
  import_node_fs34.default.rmSync(full, { recursive: true, force: true });
52921
53186
  } catch {
@@ -52938,10 +53203,10 @@ async function downloadToFile(url, dest, fetchImpl) {
52938
53203
  }
52939
53204
  const out = import_node_fs34.default.createWriteStream(dest);
52940
53205
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
52941
- await (0, import_promises4.pipeline)(nodeStream, out);
53206
+ await (0, import_promises5.pipeline)(nodeStream, out);
52942
53207
  }
52943
53208
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
52944
- const work = import_node_path34.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
53209
+ const work = import_node_path35.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
52945
53210
  import_node_fs34.default.mkdirSync(work, { recursive: true });
52946
53211
  try {
52947
53212
  await new Promise((resolve6, reject) => {
@@ -52950,7 +53215,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
52950
53215
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
52951
53216
  });
52952
53217
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
52953
- const src = import_node_path34.default.join(work, dirName, "frpc");
53218
+ const src = import_node_path35.default.join(work, dirName, "frpc");
52954
53219
  if (!import_node_fs34.default.existsSync(src)) {
52955
53220
  throw new Error(`frpc not found inside tarball at ${src}`);
52956
53221
  }
@@ -52962,10 +53227,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
52962
53227
 
52963
53228
  // src/tunnel/frpc-process.ts
52964
53229
  var import_node_fs35 = __toESM(require("fs"), 1);
52965
- var import_node_path35 = __toESM(require("path"), 1);
53230
+ var import_node_path36 = __toESM(require("path"), 1);
52966
53231
  var import_node_child_process8 = require("child_process");
52967
53232
  function frpcPidFilePath(dataDir) {
52968
- return import_node_path35.default.join(dataDir, "frpc.pid");
53233
+ return import_node_path36.default.join(dataDir, "frpc.pid");
52969
53234
  }
52970
53235
  function writeFrpcPid(dataDir, pid) {
52971
53236
  try {
@@ -53007,7 +53272,7 @@ function defaultSleep(ms) {
53007
53272
  }
53008
53273
  async function killStaleFrpc(deps) {
53009
53274
  const pidFile = frpcPidFilePath(deps.dataDir);
53010
- const tomlPath = import_node_path35.default.join(deps.dataDir, "frpc.toml");
53275
+ const tomlPath = import_node_path36.default.join(deps.dataDir, "frpc.toml");
53011
53276
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
53012
53277
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
53013
53278
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -53079,7 +53344,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
53079
53344
  var TunnelManager = class {
53080
53345
  constructor(deps) {
53081
53346
  this.deps = deps;
53082
- this.store = deps.store ?? new TunnelStore(import_node_path36.default.join(deps.dataDir, "tunnel.json"));
53347
+ this.store = deps.store ?? new TunnelStore(import_node_path37.default.join(deps.dataDir, "tunnel.json"));
53083
53348
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
53084
53349
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
53085
53350
  }
@@ -53206,7 +53471,7 @@ var TunnelManager = class {
53206
53471
  dataDir: this.deps.dataDir,
53207
53472
  override: this.deps.frpcBinaryOverride ?? void 0
53208
53473
  });
53209
- const tomlPath = import_node_path36.default.join(this.deps.dataDir, "frpc.toml");
53474
+ const tomlPath = import_node_path37.default.join(this.deps.dataDir, "frpc.toml");
53210
53475
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
53211
53476
  const toml = buildFrpcToml({
53212
53477
  serverAddr: t.frpsHost,
@@ -53221,9 +53486,9 @@ var TunnelManager = class {
53221
53486
  const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
53222
53487
  stdio: ["ignore", "pipe", "pipe"]
53223
53488
  });
53224
- const logDir = import_node_path36.default.join(this.deps.dataDir, "log");
53489
+ const logDir = import_node_path37.default.join(this.deps.dataDir, "log");
53225
53490
  import_node_fs36.default.mkdirSync(logDir, { recursive: true });
53226
- const logFilePath = import_node_path36.default.join(logDir, "frpc.log");
53491
+ const logFilePath = import_node_path37.default.join(logDir, "frpc.log");
53227
53492
  const logStream = import_node_fs36.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
53228
53493
  logStream.on("error", () => {
53229
53494
  });
@@ -53307,15 +53572,15 @@ async function waitForFrpcReady(proc, timeoutMs) {
53307
53572
 
53308
53573
  // src/tunnel/device-key.ts
53309
53574
  var import_node_os14 = __toESM(require("os"), 1);
53310
- var import_node_path37 = __toESM(require("path"), 1);
53575
+ var import_node_path38 = __toESM(require("path"), 1);
53311
53576
  var import_node_crypto11 = __toESM(require("crypto"), 1);
53312
53577
  var DERIVE_SALT = "clawd-tunnel-device-v1";
53313
53578
  function deriveStableDeviceKey(opts = {}) {
53314
53579
  const hostname = opts.hostname ?? import_node_os14.default.hostname();
53315
53580
  const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
53316
53581
  const home = opts.home ?? import_node_os14.default.homedir();
53317
- const defaultDataDir = import_node_path37.default.resolve(import_node_path37.default.join(home, ".clawd"));
53318
- const normalizedDataDir = opts.dataDir ? import_node_path37.default.resolve(opts.dataDir) : null;
53582
+ const defaultDataDir = import_node_path38.default.resolve(import_node_path38.default.join(home, ".clawd"));
53583
+ const normalizedDataDir = opts.dataDir ? import_node_path38.default.resolve(opts.dataDir) : null;
53319
53584
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
53320
53585
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
53321
53586
  return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
@@ -53323,11 +53588,11 @@ function deriveStableDeviceKey(opts = {}) {
53323
53588
 
53324
53589
  // src/auth-store.ts
53325
53590
  var import_node_fs37 = __toESM(require("fs"), 1);
53326
- var import_node_path38 = __toESM(require("path"), 1);
53591
+ var import_node_path39 = __toESM(require("path"), 1);
53327
53592
  var import_node_crypto12 = __toESM(require("crypto"), 1);
53328
53593
  var AUTH_FILE_NAME = "auth.json";
53329
53594
  function authFilePath(dataDir) {
53330
- return import_node_path38.default.join(dataDir, AUTH_FILE_NAME);
53595
+ return import_node_path39.default.join(dataDir, AUTH_FILE_NAME);
53331
53596
  }
53332
53597
  function loadOrCreateAuthFile(opts) {
53333
53598
  const file = authFilePath(opts.dataDir);
@@ -53383,7 +53648,7 @@ function readAuthFile(file) {
53383
53648
  }
53384
53649
  }
53385
53650
  function writeAuthFile(file, content) {
53386
- import_node_fs37.default.mkdirSync(import_node_path38.default.dirname(file), { recursive: true });
53651
+ import_node_fs37.default.mkdirSync(import_node_path39.default.dirname(file), { recursive: true });
53387
53652
  import_node_fs37.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
53388
53653
  try {
53389
53654
  import_node_fs37.default.chmodSync(file, 384);
@@ -53394,11 +53659,11 @@ function writeAuthFile(file, content) {
53394
53659
  // src/owner-profile.ts
53395
53660
  var import_node_fs38 = __toESM(require("fs"), 1);
53396
53661
  var import_node_os15 = __toESM(require("os"), 1);
53397
- var import_node_path39 = __toESM(require("path"), 1);
53662
+ var import_node_path40 = __toESM(require("path"), 1);
53398
53663
  var PROFILE_FILENAME = "profile.json";
53399
53664
  function loadOwnerDisplayName(dataDir) {
53400
53665
  const fallback = import_node_os15.default.userInfo().username;
53401
- const profilePath = import_node_path39.default.join(dataDir, PROFILE_FILENAME);
53666
+ const profilePath = import_node_path40.default.join(dataDir, PROFILE_FILENAME);
53402
53667
  let raw;
53403
53668
  try {
53404
53669
  raw = import_node_fs38.default.readFileSync(profilePath, "utf8");
@@ -53425,12 +53690,12 @@ function loadOwnerDisplayName(dataDir) {
53425
53690
 
53426
53691
  // src/feishu-auth/owner-identity-store.ts
53427
53692
  var import_node_fs39 = __toESM(require("fs"), 1);
53428
- var import_node_path40 = __toESM(require("path"), 1);
53693
+ var import_node_path41 = __toESM(require("path"), 1);
53429
53694
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
53430
53695
  var OwnerIdentityStore = class {
53431
53696
  file;
53432
53697
  constructor(dataDir) {
53433
- this.file = import_node_path40.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
53698
+ this.file = import_node_path41.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
53434
53699
  }
53435
53700
  read() {
53436
53701
  let raw;
@@ -53463,7 +53728,7 @@ var OwnerIdentityStore = class {
53463
53728
  };
53464
53729
  }
53465
53730
  write(record) {
53466
- import_node_fs39.default.mkdirSync(import_node_path40.default.dirname(this.file), { recursive: true });
53731
+ import_node_fs39.default.mkdirSync(import_node_path41.default.dirname(this.file), { recursive: true });
53467
53732
  import_node_fs39.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
53468
53733
  try {
53469
53734
  import_node_fs39.default.chmodSync(this.file, 384);
@@ -53609,9 +53874,9 @@ var CentralClientError = class extends Error {
53609
53874
  code;
53610
53875
  cause;
53611
53876
  };
53612
- async function centralRequest(opts, path70, init) {
53877
+ async function centralRequest(opts, path71, init) {
53613
53878
  const f = opts.fetchImpl ?? globalThis.fetch;
53614
- const url = `${opts.api.replace(/\/+$/, "")}${path70}`;
53879
+ const url = `${opts.api.replace(/\/+$/, "")}${path71}`;
53615
53880
  const ctrl = new AbortController();
53616
53881
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
53617
53882
  let res;
@@ -53805,8 +54070,8 @@ function verifyConnectToken(args) {
53805
54070
  }
53806
54071
 
53807
54072
  // src/feishu-auth/server-key.ts
53808
- var fs49 = __toESM(require("fs"), 1);
53809
- var path49 = __toESM(require("path"), 1);
54073
+ var fs50 = __toESM(require("fs"), 1);
54074
+ var path50 = __toESM(require("path"), 1);
53810
54075
  var FILE_NAME2 = "server-signing-key.json";
53811
54076
  var ServerKeyStore = class {
53812
54077
  constructor(dataDir) {
@@ -53814,12 +54079,12 @@ var ServerKeyStore = class {
53814
54079
  }
53815
54080
  dataDir;
53816
54081
  filePath() {
53817
- return path49.join(this.dataDir, FILE_NAME2);
54082
+ return path50.join(this.dataDir, FILE_NAME2);
53818
54083
  }
53819
54084
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
53820
54085
  read() {
53821
54086
  try {
53822
- const raw = fs49.readFileSync(this.filePath(), "utf8");
54087
+ const raw = fs50.readFileSync(this.filePath(), "utf8");
53823
54088
  const parsed = JSON.parse(raw);
53824
54089
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
53825
54090
  return parsed.publicKeyPem;
@@ -53834,12 +54099,12 @@ var ServerKeyStore = class {
53834
54099
  publicKeyPem,
53835
54100
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
53836
54101
  };
53837
- fs49.mkdirSync(this.dataDir, { recursive: true });
53838
- fs49.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
54102
+ fs50.mkdirSync(this.dataDir, { recursive: true });
54103
+ fs50.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
53839
54104
  }
53840
54105
  clear() {
53841
54106
  try {
53842
- fs49.unlinkSync(this.filePath());
54107
+ fs50.unlinkSync(this.filePath());
53843
54108
  } catch {
53844
54109
  }
53845
54110
  }
@@ -53854,7 +54119,7 @@ init_protocol();
53854
54119
  // src/session/fork.ts
53855
54120
  var import_node_fs40 = __toESM(require("fs"), 1);
53856
54121
  var import_node_os16 = __toESM(require("os"), 1);
53857
- var import_node_path41 = __toESM(require("path"), 1);
54122
+ var import_node_path42 = __toESM(require("path"), 1);
53858
54123
  init_claude_history();
53859
54124
  function readJsonlEntries(file) {
53860
54125
  const raw = import_node_fs40.default.readFileSync(file, "utf8");
@@ -53870,19 +54135,19 @@ function readJsonlEntries(file) {
53870
54135
  return out;
53871
54136
  }
53872
54137
  function forkSession(input) {
53873
- const baseDir = input.baseDir ?? import_node_path41.default.join(import_node_os16.default.homedir(), ".claude");
53874
- let projectDir = import_node_path41.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
53875
- let sourceFile = import_node_path41.default.join(projectDir, `${input.toolSessionId}.jsonl`);
54138
+ const baseDir = input.baseDir ?? import_node_path42.default.join(import_node_os16.default.homedir(), ".claude");
54139
+ let projectDir = import_node_path42.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
54140
+ let sourceFile = import_node_path42.default.join(projectDir, `${input.toolSessionId}.jsonl`);
53876
54141
  if (!import_node_fs40.default.existsSync(sourceFile)) {
53877
54142
  const found = findTranscriptByToolSessionId(
53878
- import_node_path41.default.join(baseDir, "projects"),
54143
+ import_node_path42.default.join(baseDir, "projects"),
53879
54144
  input.toolSessionId
53880
54145
  );
53881
54146
  if (!found) {
53882
54147
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
53883
54148
  }
53884
54149
  sourceFile = found;
53885
- projectDir = import_node_path41.default.dirname(found);
54150
+ projectDir = import_node_path42.default.dirname(found);
53886
54151
  }
53887
54152
  const entries = readJsonlEntries(sourceFile);
53888
54153
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -53911,7 +54176,7 @@ function forkSession(input) {
53911
54176
  }
53912
54177
  forkedLines.push(JSON.stringify(forked));
53913
54178
  }
53914
- const forkedFilePath = import_node_path41.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
54179
+ const forkedFilePath = import_node_path42.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
53915
54180
  import_node_fs40.default.mkdirSync(projectDir, { recursive: true });
53916
54181
  import_node_fs40.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
53917
54182
  return { forkedToolSessionId, forkedFilePath };
@@ -53971,6 +54236,7 @@ function buildSessionHandlers(deps) {
53971
54236
  const narrow = (sessions) => {
53972
54237
  let out = sessions;
53973
54238
  if (args.originOnly) out = out.filter((s) => s.originOwnerPrincipalId != null);
54239
+ if (args.ownerPersonaId) out = out.filter((s) => s.ownerPersonaId === args.ownerPersonaId);
53974
54240
  const total = out.length;
53975
54241
  const offset = args.offset ?? 0;
53976
54242
  if (offset > 0 || args.limit != null) {
@@ -54311,7 +54577,7 @@ function buildPermissionHandlers(deps) {
54311
54577
  }
54312
54578
 
54313
54579
  // src/handlers/history.ts
54314
- var path52 = __toESM(require("path"), 1);
54580
+ var path53 = __toESM(require("path"), 1);
54315
54581
  init_protocol();
54316
54582
 
54317
54583
  // src/session/recent-dirs.ts
@@ -54329,7 +54595,7 @@ function listRecentDirs(store, limit = 50) {
54329
54595
  }
54330
54596
 
54331
54597
  // src/permission/persona-paths.ts
54332
- var path51 = __toESM(require("path"), 1);
54598
+ var path52 = __toESM(require("path"), 1);
54333
54599
  function getAllowedPersonaIds(grants, action) {
54334
54600
  const ids = /* @__PURE__ */ new Set();
54335
54601
  for (const g2 of grants) {
@@ -54342,42 +54608,42 @@ function getAllowedPersonaIds(grants, action) {
54342
54608
  return ids;
54343
54609
  }
54344
54610
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
54345
- const target = path51.resolve(absPath);
54611
+ const target = path52.resolve(absPath);
54346
54612
  if (userWorkDir) {
54347
- const u = path51.resolve(userWorkDir);
54348
- const usep = u.endsWith(path51.sep) ? "" : path51.sep;
54613
+ const u = path52.resolve(userWorkDir);
54614
+ const usep = u.endsWith(path52.sep) ? "" : path52.sep;
54349
54615
  if (target === u || target.startsWith(u + usep)) return true;
54350
54616
  }
54351
- const root = path51.resolve(personaRoot);
54352
- const sep3 = root.endsWith(path51.sep) ? "" : path51.sep;
54617
+ const root = path52.resolve(personaRoot);
54618
+ const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
54353
54619
  if (!target.startsWith(root + sep3)) return false;
54354
- const rel = path51.relative(root, target);
54620
+ const rel = path52.relative(root, target);
54355
54621
  if (!rel || rel.startsWith("..")) return false;
54356
- const personaId = rel.split(path51.sep)[0];
54622
+ const personaId = rel.split(path52.sep)[0];
54357
54623
  if (!personaId) return false;
54358
54624
  const allowed = getAllowedPersonaIds(grants, action);
54359
54625
  if (allowed === "*") return true;
54360
54626
  return allowed.has(personaId);
54361
54627
  }
54362
54628
  function personaIdFromPath(absPath, personaRoot) {
54363
- const root = path51.resolve(personaRoot);
54364
- const target = path51.resolve(absPath);
54365
- const sep3 = root.endsWith(path51.sep) ? "" : path51.sep;
54629
+ const root = path52.resolve(personaRoot);
54630
+ const target = path52.resolve(absPath);
54631
+ const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
54366
54632
  if (!target.startsWith(root + sep3)) return null;
54367
- const rel = path51.relative(root, target);
54633
+ const rel = path52.relative(root, target);
54368
54634
  if (!rel || rel.startsWith("..")) return null;
54369
- const id = rel.split(path51.sep)[0];
54635
+ const id = rel.split(path52.sep)[0];
54370
54636
  return id || null;
54371
54637
  }
54372
54638
  function isPathWithin(dir, absPath) {
54373
- const d = path51.resolve(dir);
54374
- const t = path51.resolve(absPath);
54375
- const sep3 = d.endsWith(path51.sep) ? "" : path51.sep;
54639
+ const d = path52.resolve(dir);
54640
+ const t = path52.resolve(absPath);
54641
+ const sep3 = d.endsWith(path52.sep) ? "" : path52.sep;
54376
54642
  return t === d || t.startsWith(d + sep3);
54377
54643
  }
54378
54644
  function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
54379
54645
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
54380
- return personaIdFromPath(path51.resolve(absPath), personaRoot) === personaId;
54646
+ return personaIdFromPath(path52.resolve(absPath), personaRoot) === personaId;
54381
54647
  }
54382
54648
 
54383
54649
  // src/handlers/history.ts
@@ -54429,7 +54695,7 @@ function buildHistoryHandlers(deps) {
54429
54695
  if (!pid) return false;
54430
54696
  return isGuestPathAllowed(
54431
54697
  ctx.grants,
54432
- path52.join(personaRoot, pid),
54698
+ path53.join(personaRoot, pid),
54433
54699
  personaRoot,
54434
54700
  "read",
54435
54701
  userWorkDir
@@ -54441,7 +54707,7 @@ function buildHistoryHandlers(deps) {
54441
54707
  };
54442
54708
  const list = async (frame, _client, ctx) => {
54443
54709
  const args = HistoryListArgs.parse(frame);
54444
- assertGuestPath(ctx, path52.resolve(args.projectPath), personaRoot, "history:list");
54710
+ assertGuestPath(ctx, path53.resolve(args.projectPath), personaRoot, "history:list");
54445
54711
  const sessions = await history.listSessions(args);
54446
54712
  return { response: { type: "history:list", sessions } };
54447
54713
  };
@@ -54474,13 +54740,13 @@ function buildHistoryHandlers(deps) {
54474
54740
  };
54475
54741
  const subagents = async (frame, _client, ctx) => {
54476
54742
  const args = HistorySubagentsArgs.parse(frame);
54477
- assertGuestPath(ctx, path52.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
54743
+ assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
54478
54744
  const subs = await history.listSubagents(args);
54479
54745
  return { response: { type: "history:subagents", subagents: subs } };
54480
54746
  };
54481
54747
  const subagentRead = async (frame, _client, ctx) => {
54482
54748
  const args = HistorySubagentReadArgs.parse(frame);
54483
- assertGuestPath(ctx, path52.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
54749
+ assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
54484
54750
  const res = await history.readSubagent(args);
54485
54751
  return { response: { type: "history:subagent-read", ...res } };
54486
54752
  };
@@ -54489,7 +54755,7 @@ function buildHistoryHandlers(deps) {
54489
54755
  if (ctx?.principal.kind === "guest" && personaRoot) {
54490
54756
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
54491
54757
  const filtered = dirs.filter(
54492
- (d) => isGuestPathAllowed(ctx.grants, path52.resolve(d.cwd), personaRoot, "read", userWorkDir)
54758
+ (d) => isGuestPathAllowed(ctx.grants, path53.resolve(d.cwd), personaRoot, "read", userWorkDir)
54493
54759
  );
54494
54760
  return { response: { type: "history:recentDirs", dirs: filtered } };
54495
54761
  }
@@ -54506,7 +54772,7 @@ function buildHistoryHandlers(deps) {
54506
54772
  }
54507
54773
 
54508
54774
  // src/handlers/workspace.ts
54509
- var path53 = __toESM(require("path"), 1);
54775
+ var path54 = __toESM(require("path"), 1);
54510
54776
  var os16 = __toESM(require("os"), 1);
54511
54777
  init_protocol();
54512
54778
  init_protocol();
@@ -54548,22 +54814,22 @@ function buildWorkspaceHandlers(deps) {
54548
54814
  const args = WorkspaceListArgs.parse(frame);
54549
54815
  const isGuest = ctx?.principal.kind === "guest";
54550
54816
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
54551
- const resolvedCwd = path53.resolve(args.cwd ?? fallbackCwd);
54552
- const target = args.path ? path53.resolve(resolvedCwd, args.path) : resolvedCwd;
54817
+ const resolvedCwd = path54.resolve(args.cwd ?? fallbackCwd);
54818
+ const target = args.path ? path54.resolve(resolvedCwd, args.path) : resolvedCwd;
54553
54819
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
54554
54820
  const res = workspace.list({ ...args, cwd: resolvedCwd });
54555
54821
  return { response: { type: "workspace:list", ...res } };
54556
54822
  };
54557
54823
  const read = async (frame, _client, ctx) => {
54558
54824
  const args = WorkspaceReadArgs.parse(frame);
54559
- const target = path53.isAbsolute(args.path) ? path53.resolve(args.path) : path53.resolve(args.cwd, args.path);
54825
+ const target = path54.isAbsolute(args.path) ? path54.resolve(args.path) : path54.resolve(args.cwd, args.path);
54560
54826
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
54561
54827
  const res = workspace.read(args);
54562
54828
  return { response: { type: "workspace:read", ...res } };
54563
54829
  };
54564
54830
  const skillsList = async (frame, _client, ctx) => {
54565
54831
  const args = SkillsListArgs.parse(frame);
54566
- const cwdAbs = path53.resolve(args.cwd);
54832
+ const cwdAbs = path54.resolve(args.cwd);
54567
54833
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
54568
54834
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
54569
54835
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -54575,7 +54841,7 @@ function buildWorkspaceHandlers(deps) {
54575
54841
  };
54576
54842
  const agentsList = async (frame, _client, ctx) => {
54577
54843
  const args = AgentsListArgs.parse(frame);
54578
- const cwdAbs = path53.resolve(args.cwd);
54844
+ const cwdAbs = path54.resolve(args.cwd);
54579
54845
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
54580
54846
  if (args.tool === "codex") {
54581
54847
  return { response: { type: "agents:list", agents: [] } };
@@ -54597,18 +54863,18 @@ function buildWorkspaceHandlers(deps) {
54597
54863
  }
54598
54864
 
54599
54865
  // src/handlers/git.ts
54600
- var path55 = __toESM(require("path"), 1);
54866
+ var path56 = __toESM(require("path"), 1);
54601
54867
  init_protocol();
54602
54868
  init_protocol();
54603
54869
 
54604
54870
  // src/workspace/git.ts
54605
54871
  var import_node_child_process10 = require("child_process");
54606
54872
  var import_node_fs41 = __toESM(require("fs"), 1);
54607
- var import_node_path42 = __toESM(require("path"), 1);
54873
+ var import_node_path43 = __toESM(require("path"), 1);
54608
54874
  var import_node_util = require("util");
54609
54875
  var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
54610
54876
  function normalizePath(p2) {
54611
- const resolved = import_node_path42.default.resolve(p2);
54877
+ const resolved = import_node_path43.default.resolve(p2);
54612
54878
  try {
54613
54879
  return import_node_fs41.default.realpathSync(resolved);
54614
54880
  } catch {
@@ -54684,7 +54950,7 @@ async function listGitBranches(cwd) {
54684
54950
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
54685
54951
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
54686
54952
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
54687
- if (!isGuestPathAllowed(ctx.grants, path55.resolve(cwd), personaRoot, "read", userWorkDir)) {
54953
+ if (!isGuestPathAllowed(ctx.grants, path56.resolve(cwd), personaRoot, "read", userWorkDir)) {
54688
54954
  throw new ClawdError(
54689
54955
  ERROR_CODES.UNAUTHORIZED,
54690
54956
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -55370,7 +55636,7 @@ function buildPersonaHandlers(deps) {
55370
55636
  }
55371
55637
 
55372
55638
  // src/handlers/attachment.ts
55373
- var import_node_path43 = __toESM(require("path"), 1);
55639
+ var import_node_path44 = __toESM(require("path"), 1);
55374
55640
  init_protocol();
55375
55641
  init_protocol();
55376
55642
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -55450,12 +55716,12 @@ function buildAttachmentHandlers(deps) {
55450
55716
  `session ${args.sessionId} scope unresolved`
55451
55717
  );
55452
55718
  }
55453
- const cwdAbs = import_node_path43.default.resolve(sessionFile.cwd);
55454
- const candidateAbs = import_node_path43.default.isAbsolute(args.relPath) ? import_node_path43.default.resolve(args.relPath) : import_node_path43.default.resolve(cwdAbs, args.relPath);
55719
+ const cwdAbs = import_node_path44.default.resolve(sessionFile.cwd);
55720
+ const candidateAbs = import_node_path44.default.isAbsolute(args.relPath) ? import_node_path44.default.resolve(args.relPath) : import_node_path44.default.resolve(cwdAbs, args.relPath);
55455
55721
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
55456
55722
  const entries = deps.groupFileStore.list(scope, args.sessionId);
55457
55723
  const entry = entries.find((e) => {
55458
- const storedAbs = import_node_path43.default.isAbsolute(e.relPath) ? import_node_path43.default.resolve(e.relPath) : import_node_path43.default.resolve(cwdAbs, e.relPath);
55724
+ const storedAbs = import_node_path44.default.isAbsolute(e.relPath) ? import_node_path44.default.resolve(e.relPath) : import_node_path44.default.resolve(cwdAbs, e.relPath);
55459
55725
  return storedAbs === candidateAbs && !e.stale;
55460
55726
  });
55461
55727
  if (!entry) {
@@ -55480,7 +55746,7 @@ function buildAttachmentHandlers(deps) {
55480
55746
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
55481
55747
  const f = deps.sessionStore.read(sessionId);
55482
55748
  if (!f) return;
55483
- assertGuestAttachmentPath(ctx, import_node_path43.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
55749
+ assertGuestAttachmentPath(ctx, import_node_path44.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
55484
55750
  }
55485
55751
  const groupAdd = async (frame, _client, ctx) => {
55486
55752
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -55495,8 +55761,8 @@ function buildAttachmentHandlers(deps) {
55495
55761
  if (!scope) {
55496
55762
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
55497
55763
  }
55498
- const cwdAbs = import_node_path43.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
55499
- const candidateAbs = import_node_path43.default.isAbsolute(args.relPath) ? import_node_path43.default.resolve(args.relPath) : import_node_path43.default.resolve(cwdAbs, args.relPath);
55764
+ const cwdAbs = import_node_path44.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
55765
+ const candidateAbs = import_node_path44.default.isAbsolute(args.relPath) ? import_node_path44.default.resolve(args.relPath) : import_node_path44.default.resolve(cwdAbs, args.relPath);
55500
55766
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
55501
55767
  const from = ctx?.principal.kind === "owner" ? "owner" : "agent";
55502
55768
  const size = 0;
@@ -55554,21 +55820,21 @@ function buildAttachmentHandlers(deps) {
55554
55820
  }
55555
55821
 
55556
55822
  // src/handlers/extension.ts
55557
- var import_promises8 = __toESM(require("fs/promises"), 1);
55558
- var import_node_path48 = __toESM(require("path"), 1);
55823
+ var import_promises9 = __toESM(require("fs/promises"), 1);
55824
+ var import_node_path49 = __toESM(require("path"), 1);
55559
55825
  init_protocol();
55560
55826
 
55561
55827
  // src/extension/bundle-zip.ts
55562
- var import_promises5 = __toESM(require("fs/promises"), 1);
55563
- var import_node_path44 = __toESM(require("path"), 1);
55828
+ var import_promises6 = __toESM(require("fs/promises"), 1);
55829
+ var import_node_path45 = __toESM(require("path"), 1);
55564
55830
  var import_node_crypto14 = __toESM(require("crypto"), 1);
55565
55831
  var import_jszip2 = __toESM(require_lib3(), 1);
55566
55832
  async function bundleExtensionDir(dir) {
55567
55833
  const entries = await listFilesSorted(dir);
55568
55834
  const zip = new import_jszip2.default();
55569
55835
  for (const rel of entries) {
55570
- const abs = import_node_path44.default.join(dir, rel);
55571
- const content = await import_promises5.default.readFile(abs);
55836
+ const abs = import_node_path45.default.join(dir, rel);
55837
+ const content = await import_promises6.default.readFile(abs);
55572
55838
  zip.file(rel, content, { date: FIXED_DATE });
55573
55839
  }
55574
55840
  const buffer = await zip.generateAsync({
@@ -55588,8 +55854,8 @@ async function listFilesSorted(rootDir) {
55588
55854
  return out;
55589
55855
  }
55590
55856
  async function walk(absRoot, relPrefix, out) {
55591
- const dirAbs = import_node_path44.default.join(absRoot, relPrefix);
55592
- const entries = await import_promises5.default.readdir(dirAbs, { withFileTypes: true });
55857
+ const dirAbs = import_node_path45.default.join(absRoot, relPrefix);
55858
+ const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
55593
55859
  for (const e of entries) {
55594
55860
  if (IGNORE_BASENAMES.has(e.name)) continue;
55595
55861
  const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
@@ -55641,26 +55907,26 @@ function computePublishCheck(args) {
55641
55907
  }
55642
55908
 
55643
55909
  // src/extension/install-flow.ts
55644
- var import_promises6 = __toESM(require("fs/promises"), 1);
55645
- var import_node_path46 = __toESM(require("path"), 1);
55910
+ var import_promises7 = __toESM(require("fs/promises"), 1);
55911
+ var import_node_path47 = __toESM(require("path"), 1);
55646
55912
  var import_node_os19 = __toESM(require("os"), 1);
55647
55913
  var import_node_crypto15 = __toESM(require("crypto"), 1);
55648
55914
  var import_jszip3 = __toESM(require_lib3(), 1);
55649
55915
 
55650
55916
  // src/extension/paths.ts
55651
55917
  var import_node_os18 = __toESM(require("os"), 1);
55652
- var import_node_path45 = __toESM(require("path"), 1);
55918
+ var import_node_path46 = __toESM(require("path"), 1);
55653
55919
  function clawdHomeRoot(override) {
55654
- return override ?? process.env.CLAWD_HOME ?? import_node_path45.default.join(import_node_os18.default.homedir(), ".clawd");
55920
+ return override ?? process.env.CLAWD_HOME ?? import_node_path46.default.join(import_node_os18.default.homedir(), ".clawd");
55655
55921
  }
55656
55922
  function extensionsRoot(override) {
55657
- return import_node_path45.default.join(clawdHomeRoot(override), "extensions");
55923
+ return import_node_path46.default.join(clawdHomeRoot(override), "extensions");
55658
55924
  }
55659
55925
  function publishedChannelsFile(override) {
55660
- return import_node_path45.default.join(clawdHomeRoot(override), "extensions-published.json");
55926
+ return import_node_path46.default.join(clawdHomeRoot(override), "extensions-published.json");
55661
55927
  }
55662
55928
  function bundleCacheRoot(override) {
55663
- return import_node_path45.default.join(clawdHomeRoot(override), "extension-bundles");
55929
+ return import_node_path46.default.join(clawdHomeRoot(override), "extension-bundles");
55664
55930
  }
55665
55931
 
55666
55932
  // src/extension/install-flow.ts
@@ -55687,7 +55953,7 @@ async function installFromChannel(args, deps) {
55687
55953
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
55688
55954
  }
55689
55955
  for (const name of Object.keys(zip.files)) {
55690
- if (name.includes("..") || name.startsWith("/") || import_node_path46.default.isAbsolute(name)) {
55956
+ if (name.includes("..") || name.startsWith("/") || import_node_path47.default.isAbsolute(name)) {
55691
55957
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
55692
55958
  }
55693
55959
  }
@@ -55719,10 +55985,10 @@ async function installFromChannel(args, deps) {
55719
55985
  );
55720
55986
  }
55721
55987
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
55722
- const destDir = import_node_path46.default.join(deps.extensionsRoot, localExtId);
55988
+ const destDir = import_node_path47.default.join(deps.extensionsRoot, localExtId);
55723
55989
  let destExists = false;
55724
55990
  try {
55725
- await import_promises6.default.access(destDir);
55991
+ await import_promises7.default.access(destDir);
55726
55992
  destExists = true;
55727
55993
  } catch {
55728
55994
  }
@@ -55732,28 +55998,28 @@ async function installFromChannel(args, deps) {
55732
55998
  `extension ${localExtId} already installed locally (from owner ${channelRef.ownerPrincipalId})`
55733
55999
  );
55734
56000
  }
55735
- const stage = await import_promises6.default.mkdtemp(
55736
- import_node_path46.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
56001
+ const stage = await import_promises7.default.mkdtemp(
56002
+ import_node_path47.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
55737
56003
  );
55738
56004
  try {
55739
56005
  for (const [name, entry] of Object.entries(zip.files)) {
55740
- const dest = import_node_path46.default.join(stage, name);
56006
+ const dest = import_node_path47.default.join(stage, name);
55741
56007
  if (entry.dir) {
55742
- await import_promises6.default.mkdir(dest, { recursive: true });
56008
+ await import_promises7.default.mkdir(dest, { recursive: true });
55743
56009
  continue;
55744
56010
  }
55745
- await import_promises6.default.mkdir(import_node_path46.default.dirname(dest), { recursive: true });
56011
+ await import_promises7.default.mkdir(import_node_path47.default.dirname(dest), { recursive: true });
55746
56012
  if (name === "manifest.json") {
55747
56013
  const rewritten = { ...parsed.data, id: localExtId };
55748
- await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
56014
+ await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
55749
56015
  } else {
55750
- await import_promises6.default.writeFile(dest, await entry.async("nodebuffer"));
56016
+ await import_promises7.default.writeFile(dest, await entry.async("nodebuffer"));
55751
56017
  }
55752
56018
  }
55753
- await import_promises6.default.mkdir(deps.extensionsRoot, { recursive: true });
55754
- await import_promises6.default.rename(stage, destDir);
56019
+ await import_promises7.default.mkdir(deps.extensionsRoot, { recursive: true });
56020
+ await import_promises7.default.rename(stage, destDir);
55755
56021
  } catch (e) {
55756
- await import_promises6.default.rm(stage, { recursive: true, force: true }).catch(() => {
56022
+ await import_promises7.default.rm(stage, { recursive: true, force: true }).catch(() => {
55757
56023
  });
55758
56024
  throw e;
55759
56025
  }
@@ -55762,8 +56028,8 @@ async function installFromChannel(args, deps) {
55762
56028
  }
55763
56029
 
55764
56030
  // src/extension/update-flow.ts
55765
- var import_promises7 = __toESM(require("fs/promises"), 1);
55766
- var import_node_path47 = __toESM(require("path"), 1);
56031
+ var import_promises8 = __toESM(require("fs/promises"), 1);
56032
+ var import_node_path48 = __toESM(require("path"), 1);
55767
56033
  var import_node_os20 = __toESM(require("os"), 1);
55768
56034
  var import_node_crypto16 = __toESM(require("crypto"), 1);
55769
56035
  var import_jszip4 = __toESM(require_lib3(), 1);
@@ -55780,11 +56046,11 @@ async function updateFromChannel(args, deps) {
55780
56046
  channelRef.extId,
55781
56047
  channelRef.ownerPrincipalId
55782
56048
  );
55783
- const liveDir = import_node_path47.default.join(deps.extensionsRoot, localExtId);
56049
+ const liveDir = import_node_path48.default.join(deps.extensionsRoot, localExtId);
55784
56050
  const prevDir = `${liveDir}.prev`;
55785
56051
  let existingVersion;
55786
56052
  try {
55787
- const raw = await import_promises7.default.readFile(import_node_path47.default.join(liveDir, "manifest.json"), "utf8");
56053
+ const raw = await import_promises8.default.readFile(import_node_path48.default.join(liveDir, "manifest.json"), "utf8");
55788
56054
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
55789
56055
  if (!parsed2.success) {
55790
56056
  throw new UpdateError(
@@ -55817,7 +56083,7 @@ async function updateFromChannel(args, deps) {
55817
56083
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
55818
56084
  }
55819
56085
  for (const name of Object.keys(zip.files)) {
55820
- if (name.includes("..") || name.startsWith("/") || import_node_path47.default.isAbsolute(name)) {
56086
+ if (name.includes("..") || name.startsWith("/") || import_node_path48.default.isAbsolute(name)) {
55821
56087
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
55822
56088
  }
55823
56089
  }
@@ -55849,31 +56115,31 @@ async function updateFromChannel(args, deps) {
55849
56115
  );
55850
56116
  }
55851
56117
  await deps.runtime.close(localExtId);
55852
- await import_promises7.default.rm(prevDir, { recursive: true, force: true });
55853
- await import_promises7.default.rename(liveDir, prevDir);
55854
- const stage = await import_promises7.default.mkdtemp(
55855
- import_node_path47.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
56118
+ await import_promises8.default.rm(prevDir, { recursive: true, force: true });
56119
+ await import_promises8.default.rename(liveDir, prevDir);
56120
+ const stage = await import_promises8.default.mkdtemp(
56121
+ import_node_path48.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
55856
56122
  );
55857
56123
  try {
55858
56124
  for (const [name, entry] of Object.entries(zip.files)) {
55859
- const dest = import_node_path47.default.join(stage, name);
56125
+ const dest = import_node_path48.default.join(stage, name);
55860
56126
  if (entry.dir) {
55861
- await import_promises7.default.mkdir(dest, { recursive: true });
56127
+ await import_promises8.default.mkdir(dest, { recursive: true });
55862
56128
  continue;
55863
56129
  }
55864
- await import_promises7.default.mkdir(import_node_path47.default.dirname(dest), { recursive: true });
56130
+ await import_promises8.default.mkdir(import_node_path48.default.dirname(dest), { recursive: true });
55865
56131
  if (name === "manifest.json") {
55866
56132
  const rewritten = { ...parsed.data, id: localExtId };
55867
- await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
56133
+ await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
55868
56134
  } else {
55869
- await import_promises7.default.writeFile(dest, await entry.async("nodebuffer"));
56135
+ await import_promises8.default.writeFile(dest, await entry.async("nodebuffer"));
55870
56136
  }
55871
56137
  }
55872
- await import_promises7.default.rename(stage, liveDir);
56138
+ await import_promises8.default.rename(stage, liveDir);
55873
56139
  } catch (e) {
55874
- await import_promises7.default.rm(stage, { recursive: true, force: true }).catch(() => {
56140
+ await import_promises8.default.rm(stage, { recursive: true, force: true }).catch(() => {
55875
56141
  });
55876
- await import_promises7.default.rename(prevDir, liveDir).catch(() => {
56142
+ await import_promises8.default.rename(prevDir, liveDir).catch(() => {
55877
56143
  });
55878
56144
  await deps.runtime.open(localExtId).catch(() => {
55879
56145
  });
@@ -55895,7 +56161,7 @@ async function updateFromChannel(args, deps) {
55895
56161
  reason: e.message
55896
56162
  };
55897
56163
  }
55898
- await import_promises7.default.rm(prevDir, { recursive: true, force: true });
56164
+ await import_promises8.default.rm(prevDir, { recursive: true, force: true });
55899
56165
  return {
55900
56166
  kind: "updated",
55901
56167
  extId: localExtId,
@@ -55903,9 +56169,9 @@ async function updateFromChannel(args, deps) {
55903
56169
  };
55904
56170
  }
55905
56171
  async function rollback(deps, localExtId, liveDir, prevDir) {
55906
- await import_promises7.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
56172
+ await import_promises8.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
55907
56173
  });
55908
- await import_promises7.default.rename(prevDir, liveDir).catch(() => {
56174
+ await import_promises8.default.rename(prevDir, liveDir).catch(() => {
55909
56175
  });
55910
56176
  await deps.runtime.open(localExtId).catch(() => {
55911
56177
  });
@@ -55954,18 +56220,18 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
55954
56220
  );
55955
56221
  }
55956
56222
  }
55957
- const manifestPath = import_node_path48.default.join(root, extId, "manifest.json");
56223
+ const manifestPath = import_node_path49.default.join(root, extId, "manifest.json");
55958
56224
  const manifest = await readManifest(root, extId);
55959
56225
  const next = { ...manifest, version: newVersion };
55960
56226
  const tmp = `${manifestPath}.tmp`;
55961
- await import_promises8.default.writeFile(tmp, JSON.stringify(next, null, 2));
55962
- await import_promises8.default.rename(tmp, manifestPath);
56227
+ await import_promises9.default.writeFile(tmp, JSON.stringify(next, null, 2));
56228
+ await import_promises9.default.rename(tmp, manifestPath);
55963
56229
  }
55964
56230
  async function readManifest(root, extId) {
55965
- const file = import_node_path48.default.join(root, extId, "manifest.json");
56231
+ const file = import_node_path49.default.join(root, extId, "manifest.json");
55966
56232
  let raw;
55967
56233
  try {
55968
- raw = await import_promises8.default.readFile(file, "utf8");
56234
+ raw = await import_promises9.default.readFile(file, "utf8");
55969
56235
  } catch (e) {
55970
56236
  if (e.code === "ENOENT") {
55971
56237
  throw new ClawdError(ERROR_CODES.INVALID_PARAM, `extension ${extId} not installed`);
@@ -56053,7 +56319,7 @@ function buildExtensionHandlers(deps) {
56053
56319
  };
56054
56320
  async function buildSnapshotMeta(extId) {
56055
56321
  const manifest = await readManifest(deps.root, extId);
56056
- const { sha256, buffer } = await bundleExtensionDir(import_node_path48.default.join(deps.root, extId));
56322
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path49.default.join(deps.root, extId));
56057
56323
  return { manifest, contentHash: sha256, buffer };
56058
56324
  }
56059
56325
  const publish = async (frame, _client, ctx) => {
@@ -56236,7 +56502,7 @@ function buildExtensionHandlers(deps) {
56236
56502
  // src/app-builder/project-store.ts
56237
56503
  var import_node_fs42 = require("fs");
56238
56504
  var import_node_child_process11 = require("child_process");
56239
- var import_node_path49 = require("path");
56505
+ var import_node_path50 = require("path");
56240
56506
  init_protocol();
56241
56507
  var PROJECTS_DIR = "projects";
56242
56508
  var META_FILE = ".clawd-project.json";
@@ -56250,14 +56516,14 @@ var ProjectStore = class {
56250
56516
  root;
56251
56517
  /** projects/<name>/.clawd-project.json 路径 */
56252
56518
  metaPath(name) {
56253
- return (0, import_node_path49.join)(this.projectsRoot(), name, META_FILE);
56519
+ return (0, import_node_path50.join)(this.projectsRoot(), name, META_FILE);
56254
56520
  }
56255
56521
  /** projects/<name>/ 目录路径(cwd 用) */
56256
56522
  projectDir(name) {
56257
- return (0, import_node_path49.join)(this.projectsRoot(), name);
56523
+ return (0, import_node_path50.join)(this.projectsRoot(), name);
56258
56524
  }
56259
56525
  projectsRoot() {
56260
- return (0, import_node_path49.join)(this.root, PROJECTS_DIR);
56526
+ return (0, import_node_path50.join)(this.root, PROJECTS_DIR);
56261
56527
  }
56262
56528
  async list() {
56263
56529
  let entries;
@@ -56560,7 +56826,7 @@ var PublishJobRegistry = class {
56560
56826
  // src/app-builder/publish-job-runner.ts
56561
56827
  var import_node_child_process13 = require("child_process");
56562
56828
  var import_node_fs43 = require("fs");
56563
- var import_node_path50 = require("path");
56829
+ var import_node_path51 = require("path");
56564
56830
 
56565
56831
  // src/app-builder/publish-stage-parser.ts
56566
56832
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -56592,7 +56858,7 @@ async function startPublishJob(deps, args) {
56592
56858
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
56593
56859
  }
56594
56860
  const projDir = projectDir(args.name);
56595
- const logPath = (0, import_node_path50.join)(projDir, ".publish.log");
56861
+ const logPath = (0, import_node_path51.join)(projDir, ".publish.log");
56596
56862
  let logStream = null;
56597
56863
  try {
56598
56864
  logStream = (0, import_node_fs43.createWriteStream)(logPath, { flags: "w" });
@@ -56852,7 +57118,7 @@ async function recoverInterruptedJobs(deps) {
56852
57118
 
56853
57119
  // src/handlers/app-builder.ts
56854
57120
  init_protocol();
56855
- var import_node_path51 = require("path");
57121
+ var import_node_path52 = require("path");
56856
57122
  var import_node_fs44 = require("fs");
56857
57123
  var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
56858
57124
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
@@ -57010,8 +57276,8 @@ function buildAppBuilderHandlers(deps) {
57010
57276
  const project = await userStore.create(f.name, reservedPorts);
57011
57277
  try {
57012
57278
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
57013
- const templateSrcDir = (0, import_node_path51.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
57014
- const scaffoldScript = (0, import_node_path51.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
57279
+ const templateSrcDir = (0, import_node_path52.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
57280
+ const scaffoldScript = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
57015
57281
  const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
57016
57282
  deps.logger?.info("app-builder.scaffold.done", {
57017
57283
  name: project.name,
@@ -57232,7 +57498,7 @@ function buildAppBuilderHandlers(deps) {
57232
57498
  await userStore.clearPublishJob(args.name);
57233
57499
  }
57234
57500
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
57235
- const scriptPath = (0, import_node_path51.join)(deps.deployKitRoot, "scripts", "publish.sh");
57501
+ const scriptPath = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "publish.sh");
57236
57502
  deps.logger?.info("app-builder.publish.start", {
57237
57503
  name: args.name,
57238
57504
  sessionId: boundSession.sessionId,
@@ -57407,12 +57673,12 @@ function buildVisitorHandlers(deps) {
57407
57673
  }
57408
57674
 
57409
57675
  // src/extension/registry.ts
57410
- var import_promises9 = __toESM(require("fs/promises"), 1);
57411
- var import_node_path52 = __toESM(require("path"), 1);
57676
+ var import_promises10 = __toESM(require("fs/promises"), 1);
57677
+ var import_node_path53 = __toESM(require("path"), 1);
57412
57678
  async function loadAll(root) {
57413
57679
  let entries;
57414
57680
  try {
57415
- entries = await import_promises9.default.readdir(root, { withFileTypes: true });
57681
+ entries = await import_promises10.default.readdir(root, { withFileTypes: true });
57416
57682
  } catch (e) {
57417
57683
  if (e.code === "ENOENT") return [];
57418
57684
  throw e;
@@ -57421,16 +57687,16 @@ async function loadAll(root) {
57421
57687
  for (const ent of entries) {
57422
57688
  if (!ent.isDirectory()) continue;
57423
57689
  if (ent.name.startsWith(".")) continue;
57424
- records.push(await loadOne(import_node_path52.default.join(root, ent.name), ent.name));
57690
+ records.push(await loadOne(import_node_path53.default.join(root, ent.name), ent.name));
57425
57691
  }
57426
57692
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
57427
57693
  return records;
57428
57694
  }
57429
57695
  async function loadOne(dir, dirName) {
57430
- const manifestPath = import_node_path52.default.join(dir, "manifest.json");
57696
+ const manifestPath = import_node_path53.default.join(dir, "manifest.json");
57431
57697
  let raw;
57432
57698
  try {
57433
- raw = await import_promises9.default.readFile(manifestPath, "utf8");
57699
+ raw = await import_promises10.default.readFile(manifestPath, "utf8");
57434
57700
  } catch {
57435
57701
  return {
57436
57702
  extId: dirName,
@@ -57471,8 +57737,8 @@ async function loadOne(dir, dirName) {
57471
57737
  }
57472
57738
 
57473
57739
  // src/extension/uninstall.ts
57474
- var import_promises10 = __toESM(require("fs/promises"), 1);
57475
- var import_node_path53 = __toESM(require("path"), 1);
57740
+ var import_promises11 = __toESM(require("fs/promises"), 1);
57741
+ var import_node_path54 = __toESM(require("path"), 1);
57476
57742
  var UninstallError = class extends Error {
57477
57743
  constructor(code, message) {
57478
57744
  super(message);
@@ -57481,14 +57747,14 @@ var UninstallError = class extends Error {
57481
57747
  code;
57482
57748
  };
57483
57749
  async function uninstall(deps) {
57484
- const dir = import_node_path53.default.join(deps.root, deps.extId);
57750
+ const dir = import_node_path54.default.join(deps.root, deps.extId);
57485
57751
  try {
57486
- await import_promises10.default.access(dir);
57752
+ await import_promises11.default.access(dir);
57487
57753
  } catch {
57488
57754
  throw new UninstallError("NOT_FOUND", `extension ${deps.extId} not installed`);
57489
57755
  }
57490
57756
  await deps.runtime.close(deps.extId);
57491
- await import_promises10.default.rm(dir, { recursive: true, force: true });
57757
+ await import_promises11.default.rm(dir, { recursive: true, force: true });
57492
57758
  }
57493
57759
 
57494
57760
  // src/handlers/index.ts
@@ -58201,8 +58467,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
58201
58467
 
58202
58468
  // src/extension/runtime.ts
58203
58469
  var import_node_child_process16 = require("child_process");
58204
- var import_node_path54 = __toESM(require("path"), 1);
58205
- var import_promises11 = require("timers/promises");
58470
+ var import_node_path55 = __toESM(require("path"), 1);
58471
+ var import_promises12 = require("timers/promises");
58206
58472
 
58207
58473
  // src/extension/port-allocator.ts
58208
58474
  var import_node_net2 = __toESM(require("net"), 1);
@@ -58302,7 +58568,7 @@ var Runtime = class {
58302
58568
  /\$CLAWOS_EXT_PORT/g,
58303
58569
  String(port)
58304
58570
  );
58305
- const dir = import_node_path54.default.join(this.root, extId);
58571
+ const dir = import_node_path55.default.join(this.root, extId);
58306
58572
  const env = {
58307
58573
  ...process.env,
58308
58574
  CLAWOS_EXT_PORT: String(port),
@@ -58378,7 +58644,7 @@ ${handle.stderrTail}`
58378
58644
  if (res.ok) return;
58379
58645
  } catch {
58380
58646
  }
58381
- await (0, import_promises11.setTimeout)(this.healthzIntervalMs);
58647
+ await (0, import_promises12.setTimeout)(this.healthzIntervalMs);
58382
58648
  }
58383
58649
  throw new RuntimeError(
58384
58650
  "HEALTHZ_FAILED",
@@ -58403,7 +58669,7 @@ ${handle.stderrTail}`
58403
58669
  };
58404
58670
  killGroup("SIGTERM");
58405
58671
  const exited = new Promise((resolve6) => child.once("exit", () => resolve6()));
58406
- const timed = (0, import_promises11.setTimeout)(5e3).then(() => "timeout");
58672
+ const timed = (0, import_promises12.setTimeout)(5e3).then(() => "timeout");
58407
58673
  const winner = await Promise.race([exited.then(() => "exited"), timed]);
58408
58674
  if (winner === "timeout" && child.exitCode === null) {
58409
58675
  killGroup("SIGKILL");
@@ -58413,8 +58679,8 @@ ${handle.stderrTail}`
58413
58679
  };
58414
58680
 
58415
58681
  // src/extension/published-channels.ts
58416
- var import_promises12 = __toESM(require("fs/promises"), 1);
58417
- var import_node_path55 = __toESM(require("path"), 1);
58682
+ var import_promises13 = __toESM(require("fs/promises"), 1);
58683
+ var import_node_path56 = __toESM(require("path"), 1);
58418
58684
  init_zod();
58419
58685
  var PublishedChannelsError = class extends Error {
58420
58686
  constructor(code, message) {
@@ -58444,7 +58710,7 @@ var PublishedChannelStore = class {
58444
58710
  this.channels.clear();
58445
58711
  let raw;
58446
58712
  try {
58447
- raw = await import_promises12.default.readFile(this.filePath, "utf8");
58713
+ raw = await import_promises13.default.readFile(this.filePath, "utf8");
58448
58714
  } catch (e) {
58449
58715
  if (e.code === "ENOENT") {
58450
58716
  this.loaded = true;
@@ -58513,15 +58779,15 @@ var PublishedChannelStore = class {
58513
58779
  )
58514
58780
  };
58515
58781
  const tmp = `${this.filePath}.tmp`;
58516
- await import_promises12.default.mkdir(import_node_path55.default.dirname(this.filePath), { recursive: true });
58517
- await import_promises12.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
58518
- await import_promises12.default.rename(tmp, this.filePath);
58782
+ await import_promises13.default.mkdir(import_node_path56.default.dirname(this.filePath), { recursive: true });
58783
+ await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
58784
+ await import_promises13.default.rename(tmp, this.filePath);
58519
58785
  }
58520
58786
  };
58521
58787
 
58522
58788
  // src/extension/bundle-cache.ts
58523
- var import_promises13 = __toESM(require("fs/promises"), 1);
58524
- var import_node_path56 = __toESM(require("path"), 1);
58789
+ var import_promises14 = __toESM(require("fs/promises"), 1);
58790
+ var import_node_path57 = __toESM(require("path"), 1);
58525
58791
  var BundleCache = class {
58526
58792
  constructor(rootDir) {
58527
58793
  this.rootDir = rootDir;
@@ -58529,17 +58795,17 @@ var BundleCache = class {
58529
58795
  rootDir;
58530
58796
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
58531
58797
  async write(snapshotHash, buffer) {
58532
- await import_promises13.default.mkdir(this.rootDir, { recursive: true });
58533
- const file = import_node_path56.default.join(this.rootDir, `${snapshotHash}.zip`);
58798
+ await import_promises14.default.mkdir(this.rootDir, { recursive: true });
58799
+ const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
58534
58800
  const tmp = `${file}.tmp`;
58535
- await import_promises13.default.writeFile(tmp, buffer, { mode: 384 });
58536
- await import_promises13.default.rename(tmp, file);
58801
+ await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
58802
+ await import_promises14.default.rename(tmp, file);
58537
58803
  }
58538
58804
  /** Returns the bundle bytes, or null when the file doesn't exist. */
58539
58805
  async read(snapshotHash) {
58540
- const file = import_node_path56.default.join(this.rootDir, `${snapshotHash}.zip`);
58806
+ const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
58541
58807
  try {
58542
- return await import_promises13.default.readFile(file);
58808
+ return await import_promises14.default.readFile(file);
58543
58809
  } catch (e) {
58544
58810
  if (e.code === "ENOENT") return null;
58545
58811
  throw e;
@@ -58547,8 +58813,8 @@ var BundleCache = class {
58547
58813
  }
58548
58814
  /** Idempotent — missing file is not an error. */
58549
58815
  async delete(snapshotHash) {
58550
- const file = import_node_path56.default.join(this.rootDir, `${snapshotHash}.zip`);
58551
- await import_promises13.default.rm(file, { force: true });
58816
+ const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
58817
+ await import_promises14.default.rm(file, { force: true });
58552
58818
  }
58553
58819
  };
58554
58820
 
@@ -58570,24 +58836,24 @@ async function startDaemon(config) {
58570
58836
  sampling: logShippingCfg.sampling,
58571
58837
  homeDir: import_node_os22.default.homedir()
58572
58838
  });
58573
- const logDir = import_node_path57.default.join(config.dataDir, "log");
58839
+ const logDir = import_node_path58.default.join(config.dataDir, "log");
58574
58840
  import_node_fs45.default.mkdirSync(logDir, { recursive: true });
58575
58841
  const logger = createLogger({
58576
58842
  level: config.logLevel,
58577
- file: import_node_path57.default.join(logDir, "clawd.log"),
58843
+ file: import_node_path58.default.join(logDir, "clawd.log"),
58578
58844
  logClient
58579
58845
  });
58580
58846
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
58581
58847
  const screenIdleProbeLogger = createFileOnlyLogger({
58582
- file: import_node_path57.default.join(logDir, "screen-idle-probe.log"),
58848
+ file: import_node_path58.default.join(logDir, "screen-idle-probe.log"),
58583
58849
  level: "debug"
58584
58850
  });
58585
58851
  logger.info("screen-idle probe logger enabled", {
58586
- file: import_node_path57.default.join(logDir, "screen-idle-probe.log")
58852
+ file: import_node_path58.default.join(logDir, "screen-idle-probe.log")
58587
58853
  });
58588
58854
  const CAP_TARGETS = [
58589
- import_node_path57.default.join(logDir, "clawd.log"),
58590
- import_node_path57.default.join(logDir, "screen-idle-probe.log")
58855
+ import_node_path58.default.join(logDir, "clawd.log"),
58856
+ import_node_path58.default.join(logDir, "screen-idle-probe.log")
58591
58857
  ];
58592
58858
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
58593
58859
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -58741,8 +59007,8 @@ async function startDaemon(config) {
58741
59007
  const agents = new AgentsScanner();
58742
59008
  const history = new ClaudeHistoryReader();
58743
59009
  let transport = null;
58744
- const personaStore = new PersonaStore(import_node_path57.default.join(config.dataDir, "personas"));
58745
- const usersRoot = import_node_path57.default.join(config.dataDir, "users");
59010
+ const personaStore = new PersonaStore(import_node_path58.default.join(config.dataDir, "personas"));
59011
+ const usersRoot = import_node_path58.default.join(config.dataDir, "users");
58746
59012
  const defaultsRoot = findDefaultsRoot(logger);
58747
59013
  if (defaultsRoot) {
58748
59014
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -58761,18 +59027,33 @@ async function startDaemon(config) {
58761
59027
  migrateAgentsMirror({ store: personaStore, logger });
58762
59028
  migrateCodexSandbox({ store: personaStore, logger });
58763
59029
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
58764
- const personaDispatchManager = new PersonaDispatchManager({ genId: () => v4_default() });
58765
- const here = typeof __dirname === "string" ? __dirname : import_node_path57.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
59030
+ const dispatchStore = createDispatchStore({
59031
+ filePath: import_node_path58.default.join(config.dataDir, "dispatch.json"),
59032
+ now: () => Date.now(),
59033
+ onFlushError: (err) => logger.error("dispatch store flush failed", {
59034
+ reason: err instanceof Error ? err.message : String(err)
59035
+ })
59036
+ });
59037
+ await dispatchStore.load();
59038
+ dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
59039
+ let deliverPendingRef;
59040
+ const personaDispatchManager = new PersonaDispatchManager({
59041
+ genId: () => v4_default(),
59042
+ store: dispatchStore,
59043
+ now: () => Date.now(),
59044
+ onCompleted: (sid) => deliverPendingRef?.(sid)
59045
+ });
59046
+ const here = typeof __dirname === "string" ? __dirname : import_node_path58.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
58766
59047
  const mcpConfigs = [];
58767
59048
  const dispatchServerCandidates = [
58768
- import_node_path57.default.join(here, "dispatch", "mcp-server.cjs"),
59049
+ import_node_path58.default.join(here, "dispatch", "mcp-server.cjs"),
58769
59050
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
58770
- import_node_path57.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
59051
+ import_node_path58.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
58771
59052
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
58772
59053
  ];
58773
59054
  const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
58774
59055
  if (dispatchServerScriptPath) {
58775
- const dispatchLogPath = import_node_path57.default.join(logDir, "dispatch-mcp-server.log");
59056
+ const dispatchLogPath = import_node_path58.default.join(logDir, "dispatch-mcp-server.log");
58776
59057
  const dispatchCfgPath = writeDispatchMcpConfig({
58777
59058
  dataDir: config.dataDir,
58778
59059
  serverScriptPath: dispatchServerScriptPath,
@@ -58790,12 +59071,12 @@ async function startDaemon(config) {
58790
59071
  });
58791
59072
  }
58792
59073
  const ticketServerCandidates = [
58793
- import_node_path57.default.join(here, "ticket", "mcp-server.cjs"),
58794
- import_node_path57.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
59074
+ import_node_path58.default.join(here, "ticket", "mcp-server.cjs"),
59075
+ import_node_path58.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
58795
59076
  ];
58796
59077
  const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
58797
59078
  if (ticketServerScriptPath) {
58798
- const ticketLogPath = import_node_path57.default.join(logDir, "ticket-mcp-server.log");
59079
+ const ticketLogPath = import_node_path58.default.join(logDir, "ticket-mcp-server.log");
58799
59080
  const ticketCfgPath = writeTicketMcpConfig({
58800
59081
  dataDir: config.dataDir,
58801
59082
  serverScriptPath: ticketServerScriptPath,
@@ -58815,12 +59096,12 @@ async function startDaemon(config) {
58815
59096
  });
58816
59097
  }
58817
59098
  const shiftServerCandidates = [
58818
- import_node_path57.default.join(here, "shift", "mcp-server.cjs"),
58819
- import_node_path57.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
59099
+ import_node_path58.default.join(here, "shift", "mcp-server.cjs"),
59100
+ import_node_path58.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
58820
59101
  ];
58821
59102
  const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
58822
59103
  if (shiftServerScriptPath) {
58823
- const shiftLogPath = import_node_path57.default.join(logDir, "shift-mcp-server.log");
59104
+ const shiftLogPath = import_node_path58.default.join(logDir, "shift-mcp-server.log");
58824
59105
  const shiftCfgPath = await writeShiftMcpConfig({
58825
59106
  dataDir: config.dataDir,
58826
59107
  serverScriptPath: shiftServerScriptPath,
@@ -58839,12 +59120,12 @@ async function startDaemon(config) {
58839
59120
  );
58840
59121
  }
58841
59122
  const inboxServerCandidates = [
58842
- import_node_path57.default.join(here, "inbox", "mcp-server.cjs"),
58843
- import_node_path57.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
59123
+ import_node_path58.default.join(here, "inbox", "mcp-server.cjs"),
59124
+ import_node_path58.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
58844
59125
  ];
58845
59126
  const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
58846
59127
  if (inboxServerScriptPath) {
58847
- const inboxLogPath = import_node_path57.default.join(logDir, "inbox-mcp-server.log");
59128
+ const inboxLogPath = import_node_path58.default.join(logDir, "inbox-mcp-server.log");
58848
59129
  const inboxCfgPath = await writeInboxMcpConfig({
58849
59130
  dataDir: config.dataDir,
58850
59131
  serverScriptPath: inboxServerScriptPath,
@@ -58863,8 +59144,8 @@ async function startDaemon(config) {
58863
59144
  );
58864
59145
  }
58865
59146
  const peerOpsServerCandidates = [
58866
- import_node_path57.default.join(here, "peer-ops", "mcp-server.cjs"),
58867
- import_node_path57.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
59147
+ import_node_path58.default.join(here, "peer-ops", "mcp-server.cjs"),
59148
+ import_node_path58.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
58868
59149
  ];
58869
59150
  const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
58870
59151
  if (peerOpsServerScriptPath) {
@@ -58884,7 +59165,7 @@ async function startDaemon(config) {
58884
59165
  );
58885
59166
  }
58886
59167
  const shiftStore = createShiftStore({
58887
- filePath: import_node_path57.default.join(config.dataDir, "shift.json"),
59168
+ filePath: import_node_path58.default.join(config.dataDir, "shift.json"),
58888
59169
  ownerIdProvider: () => ownerPrincipalId,
58889
59170
  now: () => Date.now()
58890
59171
  });
@@ -58906,7 +59187,7 @@ async function startDaemon(config) {
58906
59187
  getAdapter,
58907
59188
  historyReader: history,
58908
59189
  dataDir: config.dataDir,
58909
- personaRoot: import_node_path57.default.join(config.dataDir, "personas"),
59190
+ personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
58910
59191
  usersRoot,
58911
59192
  personaStore,
58912
59193
  ownerDisplayName,
@@ -58922,6 +59203,8 @@ async function startDaemon(config) {
58922
59203
  // Persona dispatch (Task 8): manager.createDispatchedSession 用 personaDispatchManager
58923
59204
  // registerBSession;reducer 通过闭包反查 dispatchId 注 CLAWD_DISPATCH_ID env。
58924
59205
  personaDispatchManager,
59206
+ // Dispatch 结果投递:deliverPending 查台账 + turn-end sweep(spec 2026-07-20 §5)。
59207
+ dispatchStore,
58925
59208
  // daemon 级 MCP server 登记表(dispatch / ticket / shift / inbox / ...,上方各 writer
58926
59209
  // 块写盘成功即登记);reducer 透传到 SpawnContext.mcpConfigs,cc spawn 逐项 --mcp-config。
58927
59210
  mcpConfigs,
@@ -58944,7 +59227,7 @@ async function startDaemon(config) {
58944
59227
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
58945
59228
  attachmentGroup: {
58946
59229
  onFileEdit: (input) => {
58947
- const absPath = import_node_path57.default.isAbsolute(input.relPath) ? input.relPath : import_node_path57.default.join(input.cwd, input.relPath);
59230
+ const absPath = import_node_path58.default.isAbsolute(input.relPath) ? input.relPath : import_node_path58.default.join(input.cwd, input.relPath);
58948
59231
  let size = 0;
58949
59232
  try {
58950
59233
  size = import_node_fs45.default.statSync(absPath).size;
@@ -59010,6 +59293,7 @@ async function startDaemon(config) {
59010
59293
  }
59011
59294
  });
59012
59295
  manager.attachObserver(observer);
59296
+ deliverPendingRef = (sid) => manager.deliverPending(sid);
59013
59297
  const claudeAdapter = config.mode === "tui" ? new ClaudeTuiAdapter({
59014
59298
  logger,
59015
59299
  historyReader: new ClaudeHistoryReader(),
@@ -59176,11 +59460,11 @@ async function startDaemon(config) {
59176
59460
  // 'persona/<pid>/owner',default 走 'default'。
59177
59461
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
59178
59462
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
59179
- personaRoot: import_node_path57.default.join(config.dataDir, "personas"),
59463
+ personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
59180
59464
  usersRoot
59181
59465
  },
59182
59466
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
59183
- personaRoot: import_node_path57.default.join(config.dataDir, "personas"),
59467
+ personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
59184
59468
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
59185
59469
  usersRoot,
59186
59470
  // capability:list / delete handler 依赖
@@ -59291,11 +59575,11 @@ async function startDaemon(config) {
59291
59575
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
59292
59576
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
59293
59577
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
59294
- appBuilderPersonaRoot: import_node_path57.default.join(config.dataDir, "personas", "persona-app-builder"),
59578
+ appBuilderPersonaRoot: import_node_path58.default.join(config.dataDir, "personas", "persona-app-builder"),
59295
59579
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
59296
- deployKitRoot: import_node_path57.default.join(config.dataDir, "deploy-kit"),
59580
+ deployKitRoot: import_node_path58.default.join(config.dataDir, "deploy-kit"),
59297
59581
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
59298
- resolvePersonaRoot: (personaId) => import_node_path57.default.join(config.dataDir, "personas", personaId),
59582
+ resolvePersonaRoot: (personaId) => import_node_path58.default.join(config.dataDir, "personas", personaId),
59299
59583
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
59300
59584
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
59301
59585
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -59325,6 +59609,7 @@ async function startDaemon(config) {
59325
59609
  let handlers = makeHandlers();
59326
59610
  const dispatchHandlers = buildPersonaDispatchHandlers({
59327
59611
  personaDispatchManager,
59612
+ store: dispatchStore,
59328
59613
  logger,
59329
59614
  spawnB: async (args) => {
59330
59615
  logger.info("dispatch.spawnB.start", {
@@ -59338,7 +59623,7 @@ async function startDaemon(config) {
59338
59623
  }
59339
59624
  let sourceJsonlPath = "(no transcript yet \u2014 operate from the task description alone)";
59340
59625
  if (sourceFile && sourceFile.toolSessionId) {
59341
- sourceJsonlPath = import_node_path57.default.join(
59626
+ sourceJsonlPath = import_node_path58.default.join(
59342
59627
  import_node_os22.default.homedir(),
59343
59628
  ".claude",
59344
59629
  "projects",
@@ -59656,8 +59941,8 @@ async function startDaemon(config) {
59656
59941
  const lines = [
59657
59942
  `Tunnel: ${r.url}`,
59658
59943
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
59659
- `Frpc config: ${import_node_path57.default.join(config.dataDir, "frpc.toml")}`,
59660
- `Frpc log: ${import_node_path57.default.join(logDir, "frpc.log")}`
59944
+ `Frpc config: ${import_node_path58.default.join(config.dataDir, "frpc.toml")}`,
59945
+ `Frpc log: ${import_node_path58.default.join(logDir, "frpc.log")}`
59661
59946
  ];
59662
59947
  const width = Math.max(...lines.map((l) => l.length));
59663
59948
  const bar = "\u2550".repeat(width + 4);
@@ -59670,7 +59955,7 @@ ${bar}
59670
59955
 
59671
59956
  `);
59672
59957
  try {
59673
- const connectPath = import_node_path57.default.join(config.dataDir, "connect.txt");
59958
+ const connectPath = import_node_path58.default.join(config.dataDir, "connect.txt");
59674
59959
  import_node_fs45.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
59675
59960
  } catch {
59676
59961
  }
@@ -59743,7 +60028,7 @@ ${bar}
59743
60028
  };
59744
60029
  }
59745
60030
  function migrateDropPersonsDir(dataDir) {
59746
- const dir = import_node_path57.default.join(dataDir, "persons");
60031
+ const dir = import_node_path58.default.join(dataDir, "persons");
59747
60032
  try {
59748
60033
  import_node_fs45.default.rmSync(dir, { recursive: true, force: true });
59749
60034
  } catch {