@clawos-dev/clawd 0.2.247 → 0.2.248

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() {
@@ -6187,7 +6187,7 @@ var init_feishu_auth = __esm({
6187
6187
  });
6188
6188
 
6189
6189
  // ../protocol/src/dispatch.ts
6190
- var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema;
6190
+ var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema, DISPATCH_STATUSES, DispatchStatusSchema, DispatchRecordSchema, DispatchListArgsSchema, DispatchListResultSchema;
6191
6191
  var init_dispatch = __esm({
6192
6192
  "../protocol/src/dispatch.ts"() {
6193
6193
  "use strict";
@@ -6219,6 +6219,32 @@ var init_dispatch = __esm({
6219
6219
  dispatchId: external_exports.string().min(1),
6220
6220
  outcome: DispatchOutcomeSchema
6221
6221
  });
6222
+ DISPATCH_STATUSES = ["running", "completed", "failed"];
6223
+ DispatchStatusSchema = external_exports.enum(DISPATCH_STATUSES);
6224
+ DispatchRecordSchema = external_exports.object({
6225
+ dispatchId: external_exports.string().min(1),
6226
+ sourceSessionId: external_exports.string().min(1),
6227
+ sourcePersonaId: external_exports.string().min(1).optional(),
6228
+ targetPersonaId: external_exports.string().min(1),
6229
+ /** B 的 sessionId;registerBSession 后回填 */
6230
+ workerSessionId: external_exports.string().min(1).optional(),
6231
+ /** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
6232
+ taskText: external_exports.string(),
6233
+ status: DispatchStatusSchema,
6234
+ outcome: DispatchOutcomeSchema.optional(),
6235
+ /** 上层消费者语义(如司礼监的口谕/验收状态),daemon 不解释 */
6236
+ meta: external_exports.record(external_exports.unknown()).optional(),
6237
+ createdAt: external_exports.string().min(1),
6238
+ completedAt: external_exports.string().min(1).optional(),
6239
+ /** 结果注入 source session 成功时戳,兼当投递 dedup 标记 */
6240
+ deliveredAt: external_exports.string().min(1).optional()
6241
+ });
6242
+ DispatchListArgsSchema = external_exports.object({
6243
+ sourceSessionId: external_exports.string().min(1).optional()
6244
+ });
6245
+ DispatchListResultSchema = external_exports.object({
6246
+ records: external_exports.array(DispatchRecordSchema)
6247
+ });
6222
6248
  }
6223
6249
  });
6224
6250
 
@@ -6571,8 +6597,8 @@ var require_req = __commonJS({
6571
6597
  if (req.originalUrl) {
6572
6598
  _req.url = req.originalUrl;
6573
6599
  } else {
6574
- const path70 = req.path;
6575
- _req.url = typeof path70 === "string" ? path70 : req.url ? req.url.path || req.url : void 0;
6600
+ const path71 = req.path;
6601
+ _req.url = typeof path71 === "string" ? path71 : req.url ? req.url.path || req.url : void 0;
6576
6602
  }
6577
6603
  if (req.query) {
6578
6604
  _req.query = req.query;
@@ -6737,14 +6763,14 @@ var require_redact = __commonJS({
6737
6763
  }
6738
6764
  return obj;
6739
6765
  }
6740
- function parsePath(path70) {
6766
+ function parsePath(path71) {
6741
6767
  const parts = [];
6742
6768
  let current = "";
6743
6769
  let inBrackets = false;
6744
6770
  let inQuotes = false;
6745
6771
  let quoteChar = "";
6746
- for (let i = 0; i < path70.length; i++) {
6747
- const char = path70[i];
6772
+ for (let i = 0; i < path71.length; i++) {
6773
+ const char = path71[i];
6748
6774
  if (!inBrackets && char === ".") {
6749
6775
  if (current) {
6750
6776
  parts.push(current);
@@ -6875,10 +6901,10 @@ var require_redact = __commonJS({
6875
6901
  return current;
6876
6902
  }
6877
6903
  function redactPaths(obj, paths, censor, remove = false) {
6878
- for (const path70 of paths) {
6879
- const parts = parsePath(path70);
6904
+ for (const path71 of paths) {
6905
+ const parts = parsePath(path71);
6880
6906
  if (parts.includes("*")) {
6881
- redactWildcardPath(obj, parts, censor, path70, remove);
6907
+ redactWildcardPath(obj, parts, censor, path71, remove);
6882
6908
  } else {
6883
6909
  if (remove) {
6884
6910
  removeKey(obj, parts);
@@ -6963,8 +6989,8 @@ var require_redact = __commonJS({
6963
6989
  }
6964
6990
  } else {
6965
6991
  if (afterWildcard.includes("*")) {
6966
- const wrappedCensor = typeof censor === "function" ? (value, path70) => {
6967
- const fullPath = [...pathArray.slice(0, pathLength), ...path70];
6992
+ const wrappedCensor = typeof censor === "function" ? (value, path71) => {
6993
+ const fullPath = [...pathArray.slice(0, pathLength), ...path71];
6968
6994
  return censor(value, fullPath);
6969
6995
  } : censor;
6970
6996
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -6999,8 +7025,8 @@ var require_redact = __commonJS({
6999
7025
  return null;
7000
7026
  }
7001
7027
  const pathStructure = /* @__PURE__ */ new Map();
7002
- for (const path70 of pathsToClone) {
7003
- const parts = parsePath(path70);
7028
+ for (const path71 of pathsToClone) {
7029
+ const parts = parsePath(path71);
7004
7030
  let current = pathStructure;
7005
7031
  for (let i = 0; i < parts.length; i++) {
7006
7032
  const part = parts[i];
@@ -7052,24 +7078,24 @@ var require_redact = __commonJS({
7052
7078
  }
7053
7079
  return cloneSelectively(obj, pathStructure);
7054
7080
  }
7055
- function validatePath(path70) {
7056
- if (typeof path70 !== "string") {
7081
+ function validatePath(path71) {
7082
+ if (typeof path71 !== "string") {
7057
7083
  throw new Error("Paths must be (non-empty) strings");
7058
7084
  }
7059
- if (path70 === "") {
7085
+ if (path71 === "") {
7060
7086
  throw new Error("Invalid redaction path ()");
7061
7087
  }
7062
- if (path70.includes("..")) {
7063
- throw new Error(`Invalid redaction path (${path70})`);
7088
+ if (path71.includes("..")) {
7089
+ throw new Error(`Invalid redaction path (${path71})`);
7064
7090
  }
7065
- if (path70.includes(",")) {
7066
- throw new Error(`Invalid redaction path (${path70})`);
7091
+ if (path71.includes(",")) {
7092
+ throw new Error(`Invalid redaction path (${path71})`);
7067
7093
  }
7068
7094
  let bracketCount = 0;
7069
7095
  let inQuotes = false;
7070
7096
  let quoteChar = "";
7071
- for (let i = 0; i < path70.length; i++) {
7072
- const char = path70[i];
7097
+ for (let i = 0; i < path71.length; i++) {
7098
+ const char = path71[i];
7073
7099
  if ((char === '"' || char === "'") && bracketCount > 0) {
7074
7100
  if (!inQuotes) {
7075
7101
  inQuotes = true;
@@ -7083,20 +7109,20 @@ var require_redact = __commonJS({
7083
7109
  } else if (char === "]" && !inQuotes) {
7084
7110
  bracketCount--;
7085
7111
  if (bracketCount < 0) {
7086
- throw new Error(`Invalid redaction path (${path70})`);
7112
+ throw new Error(`Invalid redaction path (${path71})`);
7087
7113
  }
7088
7114
  }
7089
7115
  }
7090
7116
  if (bracketCount !== 0) {
7091
- throw new Error(`Invalid redaction path (${path70})`);
7117
+ throw new Error(`Invalid redaction path (${path71})`);
7092
7118
  }
7093
7119
  }
7094
7120
  function validatePaths(paths) {
7095
7121
  if (!Array.isArray(paths)) {
7096
7122
  throw new TypeError("paths must be an array");
7097
7123
  }
7098
- for (const path70 of paths) {
7099
- validatePath(path70);
7124
+ for (const path71 of paths) {
7125
+ validatePath(path71);
7100
7126
  }
7101
7127
  }
7102
7128
  function slowRedact(options = {}) {
@@ -7264,8 +7290,8 @@ var require_redaction = __commonJS({
7264
7290
  if (shape[k2] === null) {
7265
7291
  o[k2] = (value) => topCensor(value, [k2]);
7266
7292
  } else {
7267
- const wrappedCensor = typeof censor === "function" ? (value, path70) => {
7268
- return censor(value, [k2, ...path70]);
7293
+ const wrappedCensor = typeof censor === "function" ? (value, path71) => {
7294
+ return censor(value, [k2, ...path71]);
7269
7295
  } : censor;
7270
7296
  o[k2] = Redact({
7271
7297
  paths: shape[k2],
@@ -7483,10 +7509,10 @@ var require_atomic_sleep = __commonJS({
7483
7509
  var require_sonic_boom = __commonJS({
7484
7510
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
7485
7511
  "use strict";
7486
- var fs64 = require("fs");
7512
+ var fs65 = require("fs");
7487
7513
  var EventEmitter3 = require("events");
7488
7514
  var inherits = require("util").inherits;
7489
- var path70 = require("path");
7515
+ var path71 = require("path");
7490
7516
  var sleep2 = require_atomic_sleep();
7491
7517
  var assert = require("assert");
7492
7518
  var BUSY_WRITE_TIMEOUT = 100;
@@ -7540,20 +7566,20 @@ var require_sonic_boom = __commonJS({
7540
7566
  const mode = sonic.mode;
7541
7567
  if (sonic.sync) {
7542
7568
  try {
7543
- if (sonic.mkdir) fs64.mkdirSync(path70.dirname(file), { recursive: true });
7544
- const fd = fs64.openSync(file, flags, mode);
7569
+ if (sonic.mkdir) fs65.mkdirSync(path71.dirname(file), { recursive: true });
7570
+ const fd = fs65.openSync(file, flags, mode);
7545
7571
  fileOpened(null, fd);
7546
7572
  } catch (err) {
7547
7573
  fileOpened(err);
7548
7574
  throw err;
7549
7575
  }
7550
7576
  } else if (sonic.mkdir) {
7551
- fs64.mkdir(path70.dirname(file), { recursive: true }, (err) => {
7577
+ fs65.mkdir(path71.dirname(file), { recursive: true }, (err) => {
7552
7578
  if (err) return fileOpened(err);
7553
- fs64.open(file, flags, mode, fileOpened);
7579
+ fs65.open(file, flags, mode, fileOpened);
7554
7580
  });
7555
7581
  } else {
7556
- fs64.open(file, flags, mode, fileOpened);
7582
+ fs65.open(file, flags, mode, fileOpened);
7557
7583
  }
7558
7584
  }
7559
7585
  function SonicBoom(opts) {
@@ -7594,8 +7620,8 @@ var require_sonic_boom = __commonJS({
7594
7620
  this.flush = flushBuffer;
7595
7621
  this.flushSync = flushBufferSync;
7596
7622
  this._actualWrite = actualWriteBuffer;
7597
- fsWriteSync = () => fs64.writeSync(this.fd, this._writingBuf);
7598
- fsWrite = () => fs64.write(this.fd, this._writingBuf, this.release);
7623
+ fsWriteSync = () => fs65.writeSync(this.fd, this._writingBuf);
7624
+ fsWrite = () => fs65.write(this.fd, this._writingBuf, this.release);
7599
7625
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
7600
7626
  this._writingBuf = "";
7601
7627
  this.write = write;
@@ -7604,15 +7630,15 @@ var require_sonic_boom = __commonJS({
7604
7630
  this._actualWrite = actualWrite;
7605
7631
  fsWriteSync = () => {
7606
7632
  if (Buffer.isBuffer(this._writingBuf)) {
7607
- return fs64.writeSync(this.fd, this._writingBuf);
7633
+ return fs65.writeSync(this.fd, this._writingBuf);
7608
7634
  }
7609
- return fs64.writeSync(this.fd, this._writingBuf, "utf8");
7635
+ return fs65.writeSync(this.fd, this._writingBuf, "utf8");
7610
7636
  };
7611
7637
  fsWrite = () => {
7612
7638
  if (Buffer.isBuffer(this._writingBuf)) {
7613
- return fs64.write(this.fd, this._writingBuf, this.release);
7639
+ return fs65.write(this.fd, this._writingBuf, this.release);
7614
7640
  }
7615
- return fs64.write(this.fd, this._writingBuf, "utf8", this.release);
7641
+ return fs65.write(this.fd, this._writingBuf, "utf8", this.release);
7616
7642
  };
7617
7643
  } else {
7618
7644
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -7669,7 +7695,7 @@ var require_sonic_boom = __commonJS({
7669
7695
  }
7670
7696
  }
7671
7697
  if (this._fsync) {
7672
- fs64.fsyncSync(this.fd);
7698
+ fs65.fsyncSync(this.fd);
7673
7699
  }
7674
7700
  const len = this._len;
7675
7701
  if (this._reopening) {
@@ -7783,7 +7809,7 @@ var require_sonic_boom = __commonJS({
7783
7809
  const onDrain = () => {
7784
7810
  if (!this._fsync) {
7785
7811
  try {
7786
- fs64.fsync(this.fd, (err) => {
7812
+ fs65.fsync(this.fd, (err) => {
7787
7813
  this._flushPending = false;
7788
7814
  cb(err);
7789
7815
  });
@@ -7885,7 +7911,7 @@ var require_sonic_boom = __commonJS({
7885
7911
  const fd = this.fd;
7886
7912
  this.once("ready", () => {
7887
7913
  if (fd !== this.fd) {
7888
- fs64.close(fd, (err) => {
7914
+ fs65.close(fd, (err) => {
7889
7915
  if (err) {
7890
7916
  return this.emit("error", err);
7891
7917
  }
@@ -7934,7 +7960,7 @@ var require_sonic_boom = __commonJS({
7934
7960
  buf = this._bufs[0];
7935
7961
  }
7936
7962
  try {
7937
- const n = Buffer.isBuffer(buf) ? fs64.writeSync(this.fd, buf) : fs64.writeSync(this.fd, buf, "utf8");
7963
+ const n = Buffer.isBuffer(buf) ? fs65.writeSync(this.fd, buf) : fs65.writeSync(this.fd, buf, "utf8");
7938
7964
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
7939
7965
  buf = releasedBufObj.writingBuf;
7940
7966
  this._len = releasedBufObj.len;
@@ -7950,7 +7976,7 @@ var require_sonic_boom = __commonJS({
7950
7976
  }
7951
7977
  }
7952
7978
  try {
7953
- fs64.fsyncSync(this.fd);
7979
+ fs65.fsyncSync(this.fd);
7954
7980
  } catch {
7955
7981
  }
7956
7982
  }
@@ -7971,7 +7997,7 @@ var require_sonic_boom = __commonJS({
7971
7997
  buf = mergeBuf(this._bufs[0], this._lens[0]);
7972
7998
  }
7973
7999
  try {
7974
- const n = fs64.writeSync(this.fd, buf);
8000
+ const n = fs65.writeSync(this.fd, buf);
7975
8001
  buf = buf.subarray(n);
7976
8002
  this._len = Math.max(this._len - n, 0);
7977
8003
  if (buf.length <= 0) {
@@ -7999,13 +8025,13 @@ var require_sonic_boom = __commonJS({
7999
8025
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
8000
8026
  if (this.sync) {
8001
8027
  try {
8002
- const written = Buffer.isBuffer(this._writingBuf) ? fs64.writeSync(this.fd, this._writingBuf) : fs64.writeSync(this.fd, this._writingBuf, "utf8");
8028
+ const written = Buffer.isBuffer(this._writingBuf) ? fs65.writeSync(this.fd, this._writingBuf) : fs65.writeSync(this.fd, this._writingBuf, "utf8");
8003
8029
  release(null, written);
8004
8030
  } catch (err) {
8005
8031
  release(err);
8006
8032
  }
8007
8033
  } else {
8008
- fs64.write(this.fd, this._writingBuf, release);
8034
+ fs65.write(this.fd, this._writingBuf, release);
8009
8035
  }
8010
8036
  }
8011
8037
  function actualWriteBuffer() {
@@ -8014,7 +8040,7 @@ var require_sonic_boom = __commonJS({
8014
8040
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
8015
8041
  if (this.sync) {
8016
8042
  try {
8017
- const written = fs64.writeSync(this.fd, this._writingBuf);
8043
+ const written = fs65.writeSync(this.fd, this._writingBuf);
8018
8044
  release(null, written);
8019
8045
  } catch (err) {
8020
8046
  release(err);
@@ -8023,7 +8049,7 @@ var require_sonic_boom = __commonJS({
8023
8049
  if (kCopyBuffer) {
8024
8050
  this._writingBuf = Buffer.from(this._writingBuf);
8025
8051
  }
8026
- fs64.write(this.fd, this._writingBuf, release);
8052
+ fs65.write(this.fd, this._writingBuf, release);
8027
8053
  }
8028
8054
  }
8029
8055
  function actualClose(sonic) {
@@ -8039,12 +8065,12 @@ var require_sonic_boom = __commonJS({
8039
8065
  sonic._lens = [];
8040
8066
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
8041
8067
  try {
8042
- fs64.fsync(sonic.fd, closeWrapped);
8068
+ fs65.fsync(sonic.fd, closeWrapped);
8043
8069
  } catch {
8044
8070
  }
8045
8071
  function closeWrapped() {
8046
8072
  if (sonic.fd !== 1 && sonic.fd !== 2) {
8047
- fs64.close(sonic.fd, done);
8073
+ fs65.close(sonic.fd, done);
8048
8074
  } else {
8049
8075
  done();
8050
8076
  }
@@ -11179,11 +11205,11 @@ var init_lib = __esm({
11179
11205
  }
11180
11206
  }
11181
11207
  },
11182
- addToPath: function addToPath(path70, added, removed, oldPosInc, options) {
11183
- var last = path70.lastComponent;
11208
+ addToPath: function addToPath(path71, added, removed, oldPosInc, options) {
11209
+ var last = path71.lastComponent;
11184
11210
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
11185
11211
  return {
11186
- oldPos: path70.oldPos + oldPosInc,
11212
+ oldPos: path71.oldPos + oldPosInc,
11187
11213
  lastComponent: {
11188
11214
  count: last.count + 1,
11189
11215
  added,
@@ -11193,7 +11219,7 @@ var init_lib = __esm({
11193
11219
  };
11194
11220
  } else {
11195
11221
  return {
11196
- oldPos: path70.oldPos + oldPosInc,
11222
+ oldPos: path71.oldPos + oldPosInc,
11197
11223
  lastComponent: {
11198
11224
  count: 1,
11199
11225
  added,
@@ -11702,10 +11728,10 @@ function attachmentToHistoryMessage(o, ts) {
11702
11728
  const memories = raw.map((m2) => {
11703
11729
  if (!m2 || typeof m2 !== "object") return null;
11704
11730
  const rec3 = m2;
11705
- const path70 = typeof rec3.path === "string" ? rec3.path : null;
11731
+ const path71 = typeof rec3.path === "string" ? rec3.path : null;
11706
11732
  const content = typeof rec3.content === "string" ? rec3.content : null;
11707
- if (!path70 || content == null) return null;
11708
- const entry = { path: path70, content };
11733
+ if (!path71 || content == null) return null;
11734
+ const entry = { path: path71, content };
11709
11735
  if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
11710
11736
  return entry;
11711
11737
  }).filter((m2) => m2 !== null);
@@ -12508,10 +12534,10 @@ function parseAttachment(obj) {
12508
12534
  const memories = raw.map((m2) => {
12509
12535
  if (!m2 || typeof m2 !== "object") return null;
12510
12536
  const rec3 = m2;
12511
- const path70 = typeof rec3.path === "string" ? rec3.path : null;
12537
+ const path71 = typeof rec3.path === "string" ? rec3.path : null;
12512
12538
  const content = typeof rec3.content === "string" ? rec3.content : null;
12513
- if (!path70 || content == null) return null;
12514
- const out = { path: path70, content };
12539
+ if (!path71 || content == null) return null;
12540
+ const out = { path: path71, content };
12515
12541
  if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
12516
12542
  return out;
12517
12543
  }).filter((m2) => m2 !== null);
@@ -33480,8 +33506,8 @@ var require_utils = __commonJS({
33480
33506
  var result = transform[inputType][outputType](input);
33481
33507
  return result;
33482
33508
  };
33483
- exports2.resolve = function(path70) {
33484
- var parts = path70.split("/");
33509
+ exports2.resolve = function(path71) {
33510
+ var parts = path71.split("/");
33485
33511
  var result = [];
33486
33512
  for (var index = 0; index < parts.length; index++) {
33487
33513
  var part = parts[index];
@@ -39334,18 +39360,18 @@ var require_object = __commonJS({
39334
39360
  var object = new ZipObject(name, zipObjectContent, o);
39335
39361
  this.files[name] = object;
39336
39362
  };
39337
- var parentFolder = function(path70) {
39338
- if (path70.slice(-1) === "/") {
39339
- path70 = path70.substring(0, path70.length - 1);
39363
+ var parentFolder = function(path71) {
39364
+ if (path71.slice(-1) === "/") {
39365
+ path71 = path71.substring(0, path71.length - 1);
39340
39366
  }
39341
- var lastSlash = path70.lastIndexOf("/");
39342
- return lastSlash > 0 ? path70.substring(0, lastSlash) : "";
39367
+ var lastSlash = path71.lastIndexOf("/");
39368
+ return lastSlash > 0 ? path71.substring(0, lastSlash) : "";
39343
39369
  };
39344
- var forceTrailingSlash = function(path70) {
39345
- if (path70.slice(-1) !== "/") {
39346
- path70 += "/";
39370
+ var forceTrailingSlash = function(path71) {
39371
+ if (path71.slice(-1) !== "/") {
39372
+ path71 += "/";
39347
39373
  }
39348
- return path70;
39374
+ return path71;
39349
39375
  };
39350
39376
  var folderAdd = function(name, createFolders) {
39351
39377
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -40347,7 +40373,7 @@ var require_lib3 = __commonJS({
40347
40373
  // src/run-case/recorder.ts
40348
40374
  function startRunCaseRecorder(opts) {
40349
40375
  const now = opts.now ?? Date.now;
40350
- const dir = import_node_path58.default.dirname(opts.recordPath);
40376
+ const dir = import_node_path59.default.dirname(opts.recordPath);
40351
40377
  let stream = null;
40352
40378
  let closing = false;
40353
40379
  let closedSettled = false;
@@ -40387,12 +40413,12 @@ function startRunCaseRecorder(opts) {
40387
40413
  };
40388
40414
  return { tap, close, closed };
40389
40415
  }
40390
- var import_node_fs46, import_node_path58;
40416
+ var import_node_fs46, import_node_path59;
40391
40417
  var init_recorder = __esm({
40392
40418
  "src/run-case/recorder.ts"() {
40393
40419
  "use strict";
40394
40420
  import_node_fs46 = __toESM(require("fs"), 1);
40395
- import_node_path58 = __toESM(require("path"), 1);
40421
+ import_node_path59 = __toESM(require("path"), 1);
40396
40422
  }
40397
40423
  });
40398
40424
 
@@ -40435,7 +40461,7 @@ var init_wire = __esm({
40435
40461
  // src/run-case/controller.ts
40436
40462
  async function runController(opts) {
40437
40463
  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-"));
40464
+ const cwd = opts.cwd ?? (0, import_node_fs47.mkdtempSync)(import_node_path60.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
40439
40465
  const ownsCwd = opts.cwd === void 0;
40440
40466
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
40441
40467
  const spawnCtx = { cwd };
@@ -40602,13 +40628,13 @@ async function runController(opts) {
40602
40628
  }
40603
40629
  return exitCode ?? 0;
40604
40630
  }
40605
- var import_node_fs47, import_node_os23, import_node_path59;
40631
+ var import_node_fs47, import_node_os23, import_node_path60;
40606
40632
  var init_controller = __esm({
40607
40633
  "src/run-case/controller.ts"() {
40608
40634
  "use strict";
40609
40635
  import_node_fs47 = require("fs");
40610
40636
  import_node_os23 = __toESM(require("os"), 1);
40611
- import_node_path59 = __toESM(require("path"), 1);
40637
+ import_node_path60 = __toESM(require("path"), 1);
40612
40638
  init_claude();
40613
40639
  init_stdout_splitter();
40614
40640
  init_permission_stdio();
@@ -40870,7 +40896,7 @@ Env (advanced):
40870
40896
  `;
40871
40897
 
40872
40898
  // src/index.ts
40873
- var import_node_path57 = __toESM(require("path"), 1);
40899
+ var import_node_path58 = __toESM(require("path"), 1);
40874
40900
  var import_node_fs45 = __toESM(require("fs"), 1);
40875
40901
  var import_node_os22 = __toESM(require("os"), 1);
40876
40902
 
@@ -41735,6 +41761,28 @@ function dispatchShiftEnd(info, settle, killImpl) {
41735
41761
  throw new Error(`dispatchShiftEnd: unhandled kind ${JSON.stringify(_exhaustive)}`);
41736
41762
  }
41737
41763
 
41764
+ // src/dispatch/delivery.ts
41765
+ function selectPendingForDelivery(records, sourceSessionId) {
41766
+ return records.filter(
41767
+ (r) => r.sourceSessionId === sourceSessionId && (r.status === "completed" || r.status === "failed") && !r.deliveredAt
41768
+ ).slice().sort((a, b2) => a.createdAt < b2.createdAt ? -1 : a.createdAt > b2.createdAt ? 1 : 0);
41769
+ }
41770
+ function formatDeliveryText(records) {
41771
+ const blocks = records.map((r) => {
41772
+ const head = `[dispatch ${r.dispatchId} \u2192 ${r.targetPersonaId}]`;
41773
+ if (r.outcome?.kind === "success") {
41774
+ const files = r.outcome.filePaths && r.outcome.filePaths.length > 0 ? `
41775
+ Related files:
41776
+ ${r.outcome.filePaths.map((p2) => `- ${p2}`).join("\n")}` : "";
41777
+ return `${head} \u5B8C\u6210\uFF1A
41778
+ ${r.outcome.text}${files}`;
41779
+ }
41780
+ const reason = r.outcome?.kind === "failure" ? r.outcome.reason : "unknown failure";
41781
+ return `${head} \u5931\u8D25\uFF1A${reason}`;
41782
+ });
41783
+ return ["\u4F60\u4E4B\u524D\u59D4\u6D3E\u51FA\u53BB\u7684\u4EFB\u52A1\u6709\u4E86\u7ED3\u679C\uFF1A", "", blocks.join("\n\n")].join("\n");
41784
+ }
41785
+
41738
41786
  // src/session/runner.ts
41739
41787
  var import_node_os4 = __toESM(require("os"), 1);
41740
41788
  var import_node_path7 = __toESM(require("path"), 1);
@@ -41862,7 +41910,7 @@ var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A perso
41862
41910
  - \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
41863
41911
  - \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
41864
41912
 
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
41913
+ 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
41914
 
41867
41915
  - **\u4E0D\u8981**\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF08\u4F60\u4E0D\u662F\u90A3\u4E2A persona\uFF09
41868
41916
  - **\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 +41923,7 @@ tool \u4F1A\u963B\u585E\u6302\u8D77\u7B49\u5BF9\u65B9\u4EBA\u683C\u5E72\u5B8C\uF
41875
41923
 
41876
41924
  - \`targetDeviceId = <token \u7B2C\u4E8C\u6BB5\u7684 deviceId\uFF0C\u539F\u6837\u586B>\`
41877
41925
 
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
41926
+ 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
41927
 
41880
41928
  ## \u88AB dispatch \u63A5\u5230\u4EFB\u52A1
41881
41929
 
@@ -43725,6 +43773,13 @@ var SessionManager = class {
43725
43773
  }
43726
43774
  }
43727
43775
  }
43776
+ if (compressed.type === "session:status" && this.deps.dispatchStore) {
43777
+ const s = compressed;
43778
+ if (s.sessionId && s.status !== "running") {
43779
+ const sid = s.sessionId;
43780
+ setTimeout(() => this.deliverPending(sid), 0);
43781
+ }
43782
+ }
43728
43783
  if (this.currentCollector) {
43729
43784
  this.currentCollector.push({ frame: compressed, target });
43730
43785
  return;
@@ -44051,6 +44106,67 @@ var SessionManager = class {
44051
44106
  });
44052
44107
  return { response: { ok: true }, broadcast };
44053
44108
  }
44109
+ /**
44110
+ * Dispatch 结果投递(spec 2026-07-20 §5):查台账里该 source session 名下已完成
44111
+ * 且未投递的行,合并成一段 plain text 结果包注入回 source session。
44112
+ *
44113
+ * 触发点两个:complete 钩子(PersonaDispatchManager.onCompleted)+ source turn-end
44114
+ * 兜底 sweep(routeFromRunner 的 session:status 钩子)。幂等:投递成功盖 deliveredAt,
44115
+ * 再次调用查无未投递行直接返回。
44116
+ *
44117
+ * 判定口径:source 当前 running(含 reducer spawning,压缩后同 running)→ 不打扰,
44118
+ * 结果躺台账等下次 sweep。send 抛错(session 已删等)→ 记 log 不盖 deliveredAt,
44119
+ * 下次 sweep 自然重试。注入直接走 runner.input(无 collector),frames 经
44120
+ * routeFromRunner 正常广播上 wire。
44121
+ */
44122
+ deliverPending(sourceSessionId) {
44123
+ const store = this.deps.dispatchStore;
44124
+ if (!store) return;
44125
+ const pending = selectPendingForDelivery(store.list({ sourceSessionId }), sourceSessionId);
44126
+ if (pending.length === 0) return;
44127
+ const state = this.tryGetState(sourceSessionId);
44128
+ if (state && compressStatus(state.status) === "running") return;
44129
+ if (!this.deps.ownerPrincipalId) {
44130
+ this.deps.logger?.warn("dispatch.deliver.no-owner-principal", { sourceSessionId });
44131
+ return;
44132
+ }
44133
+ const sender = principalToSender(
44134
+ makeOwnerPrincipal(
44135
+ this.deps.ownerPrincipalId,
44136
+ this.deps.ownerDisplayName ?? "Owner",
44137
+ this.deps.ownerFeishuUnionId
44138
+ )
44139
+ );
44140
+ try {
44141
+ const file = this.findOwnedSession(sourceSessionId);
44142
+ if (!file) {
44143
+ this.deps.logger?.info("dispatch.deliver.source-gone", { sourceSessionId });
44144
+ return;
44145
+ }
44146
+ const runner = this.ensureRunnerForScope(file, this.scopeForFile(file));
44147
+ runner.input({
44148
+ kind: "command",
44149
+ command: {
44150
+ kind: "send",
44151
+ text: formatDeliveryText(pending),
44152
+ senderPrincipal: sender
44153
+ }
44154
+ });
44155
+ } catch (err) {
44156
+ this.deps.logger?.warn("dispatch.deliver.send-failed", {
44157
+ sourceSessionId,
44158
+ reason: err instanceof Error ? err.message : String(err)
44159
+ });
44160
+ return;
44161
+ }
44162
+ const nowIso3 = new Date(this.deps.now?.() ?? Date.now()).toISOString();
44163
+ for (const r of pending) store.update(r.dispatchId, { deliveredAt: nowIso3 });
44164
+ this.deps.logger?.info("dispatch.deliver.ok", {
44165
+ sourceSessionId,
44166
+ count: pending.length,
44167
+ dispatchIds: pending.map((r) => r.dispatchId)
44168
+ });
44169
+ }
44054
44170
  /**
44055
44171
  * 只读拿 SessionState;session 不存在返 null(不 throw)。
44056
44172
  * handlers/session.ts:currentTurnSender 用(loopback HTTP RPC 绝对不能因不存在的 sid 崩)。
@@ -46657,8 +46773,8 @@ function turnStartInput(text) {
46657
46773
  const items = [];
46658
46774
  let leftover = text;
46659
46775
  for (const m2 of text.matchAll(SKILL_RE)) {
46660
- const [marker, name, path70] = m2;
46661
- items.push({ type: "skill", name, path: path70 });
46776
+ const [marker, name, path71] = m2;
46777
+ items.push({ type: "skill", name, path: path71 });
46662
46778
  leftover = leftover.replace(marker, "");
46663
46779
  }
46664
46780
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -48157,35 +48273,60 @@ var PersonaDispatchManager = class {
48157
48273
  dispatchId,
48158
48274
  sourceSessionId: args.sourceSessionId,
48159
48275
  targetPersona: args.targetPersona,
48160
- waiters: [],
48161
- outcome: null
48276
+ waiters: []
48277
+ });
48278
+ this.deps.store.add({
48279
+ dispatchId,
48280
+ sourceSessionId: args.sourceSessionId,
48281
+ ...args.sourcePersonaId ? { sourcePersonaId: args.sourcePersonaId } : {},
48282
+ targetPersonaId: args.targetPersona,
48283
+ taskText: args.taskText
48162
48284
  });
48163
48285
  return { dispatchId };
48164
48286
  }
48165
48287
  get(dispatchId) {
48166
48288
  return this.map.get(dispatchId);
48167
48289
  }
48168
- async wait(dispatchId) {
48290
+ complete(dispatchId, outcome) {
48291
+ const state = this.map.get(dispatchId);
48292
+ const status = outcome.kind === "success" ? "completed" : "failed";
48293
+ const updated = this.deps.store.update(dispatchId, {
48294
+ status,
48295
+ outcome,
48296
+ completedAt: new Date(this.deps.now()).toISOString()
48297
+ });
48298
+ if (state) {
48299
+ const waiters = state.waiters;
48300
+ state.waiters = [];
48301
+ for (const w2 of waiters) w2.resolve(outcome);
48302
+ this.map.delete(dispatchId);
48303
+ }
48304
+ const sourceSessionId = updated?.sourceSessionId ?? state?.sourceSessionId;
48305
+ if (sourceSessionId) this.deps.onCompleted?.(sourceSessionId);
48306
+ }
48307
+ /**
48308
+ * mesh B 角色 hold 专用(跨设备 dispatch 的 peer 侧):guest B-role handler 用它
48309
+ * 挂住 /rpc HTTP 响应直到 complete,把 outcome 回传给 A 侧 daemon 的 forwardToPeer
48310
+ * (A 侧后台 await,A 的 tool call 不受影响照样秒回)。
48311
+ * 本地 dispatch 链路**不用**这个——本地 outcome 只走台账 + deliverPending。
48312
+ */
48313
+ async waitForOutcome(dispatchId) {
48169
48314
  const state = this.map.get(dispatchId);
48170
- if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
48171
- if (state.outcome) return state.outcome;
48315
+ if (!state) {
48316
+ const rec3 = this.deps.store.get(dispatchId);
48317
+ if (rec3?.outcome) return rec3.outcome;
48318
+ throw new Error(`unknown dispatchId: ${dispatchId}`);
48319
+ }
48172
48320
  const d = defer();
48173
48321
  state.waiters.push(d);
48174
48322
  return d.promise;
48175
48323
  }
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
48324
  /** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
48185
48325
  registerBSession(dispatchId, bSessionId) {
48186
48326
  const state = this.map.get(dispatchId);
48187
48327
  if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
48188
48328
  state.bSessionId = bSessionId;
48329
+ this.deps.store.update(dispatchId, { workerSessionId: bSessionId });
48189
48330
  }
48190
48331
  /** reducer buildSpawnContext 调,按 B 的 sessionId 反查 dispatchId(用于注 CLAWD_DISPATCH_ID env) */
48191
48332
  lookupDispatchByBSessionId(bSessionId) {
@@ -48196,11 +48337,112 @@ var PersonaDispatchManager = class {
48196
48337
  }
48197
48338
  };
48198
48339
 
48340
+ // src/dispatch/store.ts
48341
+ var import_promises = __toESM(require("fs/promises"), 1);
48342
+ var import_node_path16 = __toESM(require("path"), 1);
48343
+
48344
+ // src/shift/constants.ts
48345
+ var MAX_RUNS_PER_SHIFT = 30;
48346
+ var DEFAULT_TIMEOUT_MS = 30 * 6e4;
48347
+ var CONSECUTIVE_ERROR_THRESHOLD = 5;
48348
+ var TICK_INTERVAL_MS = 1e4;
48349
+ var STORE_FLUSH_DEBOUNCE_MS = 500;
48350
+ var CLOCK_JUMP_THRESHOLD_MS = 5 * 6e4;
48351
+
48352
+ // src/dispatch/store.ts
48353
+ var TASK_TEXT_MAX = 500;
48354
+ function createDispatchStore(deps) {
48355
+ let records = [];
48356
+ let flushTimer = null;
48357
+ async function load() {
48358
+ let raw;
48359
+ try {
48360
+ raw = await import_promises.default.readFile(deps.filePath, "utf8");
48361
+ } catch (e) {
48362
+ if (e.code === "ENOENT") {
48363
+ records = [];
48364
+ return;
48365
+ }
48366
+ throw e;
48367
+ }
48368
+ const parsed = JSON.parse(raw);
48369
+ if (parsed.version !== 1) {
48370
+ throw new Error(`dispatch.json: unsupported version ${parsed.version}`);
48371
+ }
48372
+ records = parsed.records ?? [];
48373
+ }
48374
+ async function flushNow() {
48375
+ if (flushTimer) {
48376
+ clearTimeout(flushTimer);
48377
+ flushTimer = null;
48378
+ }
48379
+ const content = { version: 1, records };
48380
+ await import_promises.default.mkdir(import_node_path16.default.dirname(deps.filePath), { recursive: true });
48381
+ const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
48382
+ await import_promises.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
48383
+ await import_promises.default.rename(tmp, deps.filePath);
48384
+ }
48385
+ function scheduleFlush() {
48386
+ if (flushTimer) return;
48387
+ flushTimer = setTimeout(() => {
48388
+ flushTimer = null;
48389
+ flushNow().catch((err) => {
48390
+ deps.onFlushError?.(err);
48391
+ });
48392
+ }, STORE_FLUSH_DEBOUNCE_MS);
48393
+ }
48394
+ function get(dispatchId) {
48395
+ return records.find((r) => r.dispatchId === dispatchId);
48396
+ }
48397
+ function add(input) {
48398
+ const rec3 = {
48399
+ dispatchId: input.dispatchId,
48400
+ sourceSessionId: input.sourceSessionId,
48401
+ ...input.sourcePersonaId ? { sourcePersonaId: input.sourcePersonaId } : {},
48402
+ targetPersonaId: input.targetPersonaId,
48403
+ taskText: input.taskText.slice(0, TASK_TEXT_MAX),
48404
+ status: "running",
48405
+ ...input.meta ? { meta: input.meta } : {},
48406
+ createdAt: new Date(deps.now()).toISOString()
48407
+ };
48408
+ records.push(rec3);
48409
+ scheduleFlush();
48410
+ return rec3;
48411
+ }
48412
+ function update(dispatchId, patch) {
48413
+ const idx = records.findIndex((r) => r.dispatchId === dispatchId);
48414
+ if (idx < 0) return void 0;
48415
+ const merged = { ...records[idx], ...patch };
48416
+ records[idx] = merged;
48417
+ scheduleFlush();
48418
+ return merged;
48419
+ }
48420
+ function list(filter) {
48421
+ 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);
48422
+ }
48423
+ function markInterruptedAsFailed(nowIso3) {
48424
+ let touched = false;
48425
+ for (const r of records) {
48426
+ if (r.status === "running") {
48427
+ r.status = "failed";
48428
+ r.outcome = {
48429
+ kind: "failure",
48430
+ reason: "daemon restarted while dispatch in flight"
48431
+ };
48432
+ r.completedAt = nowIso3;
48433
+ touched = true;
48434
+ }
48435
+ }
48436
+ if (touched) scheduleFlush();
48437
+ }
48438
+ return { load, flushNow, add, update, list, get, markInterruptedAsFailed };
48439
+ }
48440
+
48199
48441
  // src/dispatch/mcp-config.ts
48200
48442
  var import_node_fs19 = __toESM(require("fs"), 1);
48201
- var import_node_path16 = __toESM(require("path"), 1);
48443
+ var import_node_path17 = __toESM(require("path"), 1);
48202
48444
  function dispatchMcpConfigPath(dataDir) {
48203
- return import_node_path16.default.join(dataDir, "dispatch.mcp.json");
48445
+ return import_node_path17.default.join(dataDir, "dispatch.mcp.json");
48204
48446
  }
48205
48447
  function writeDispatchMcpConfig(args) {
48206
48448
  const cfgPath = dispatchMcpConfigPath(args.dataDir);
@@ -48222,9 +48464,9 @@ function writeDispatchMcpConfig(args) {
48222
48464
 
48223
48465
  // src/ticket/mcp-config.ts
48224
48466
  var import_node_fs20 = __toESM(require("fs"), 1);
48225
- var import_node_path17 = __toESM(require("path"), 1);
48467
+ var import_node_path18 = __toESM(require("path"), 1);
48226
48468
  function ticketMcpConfigPath(dataDir) {
48227
- return import_node_path17.default.join(dataDir, "ticket.mcp.json");
48469
+ return import_node_path18.default.join(dataDir, "ticket.mcp.json");
48228
48470
  }
48229
48471
  function writeTicketMcpConfig(args) {
48230
48472
  const cfgPath = ticketMcpConfigPath(args.dataDir);
@@ -48251,9 +48493,9 @@ function writeTicketMcpConfig(args) {
48251
48493
 
48252
48494
  // src/shift/mcp-config.ts
48253
48495
  var import_node_fs21 = __toESM(require("fs"), 1);
48254
- var import_node_path18 = __toESM(require("path"), 1);
48496
+ var import_node_path19 = __toESM(require("path"), 1);
48255
48497
  function shiftMcpConfigPath(dataDir) {
48256
- return import_node_path18.default.join(dataDir, "shift.mcp.json");
48498
+ return import_node_path19.default.join(dataDir, "shift.mcp.json");
48257
48499
  }
48258
48500
  async function writeShiftMcpConfig(args) {
48259
48501
  const cfgPath = shiftMcpConfigPath(args.dataDir);
@@ -48275,9 +48517,9 @@ async function writeShiftMcpConfig(args) {
48275
48517
 
48276
48518
  // src/inbox/mcp-config.ts
48277
48519
  var import_node_fs22 = __toESM(require("fs"), 1);
48278
- var import_node_path19 = __toESM(require("path"), 1);
48520
+ var import_node_path20 = __toESM(require("path"), 1);
48279
48521
  function inboxMcpConfigPath(dataDir) {
48280
- return import_node_path19.default.join(dataDir, "inbox.mcp.json");
48522
+ return import_node_path20.default.join(dataDir, "inbox.mcp.json");
48281
48523
  }
48282
48524
  async function writeInboxMcpConfig(args) {
48283
48525
  const cfgPath = inboxMcpConfigPath(args.dataDir);
@@ -48299,9 +48541,9 @@ async function writeInboxMcpConfig(args) {
48299
48541
 
48300
48542
  // src/peer-ops/mcp-config.ts
48301
48543
  var import_node_fs23 = __toESM(require("fs"), 1);
48302
- var import_node_path20 = __toESM(require("path"), 1);
48544
+ var import_node_path21 = __toESM(require("path"), 1);
48303
48545
  function peerOpsMcpConfigPath(dataDir) {
48304
- return import_node_path20.default.join(dataDir, "peer-ops.mcp.json");
48546
+ return import_node_path21.default.join(dataDir, "peer-ops.mcp.json");
48305
48547
  }
48306
48548
  function writePeerOpsMcpConfig(args) {
48307
48549
  const cfgPath = peerOpsMcpConfigPath(args.dataDir);
@@ -48320,18 +48562,10 @@ function writePeerOpsMcpConfig(args) {
48320
48562
  }
48321
48563
 
48322
48564
  // src/shift/store.ts
48323
- var import_promises = __toESM(require("fs/promises"), 1);
48324
- var import_node_path21 = __toESM(require("path"), 1);
48565
+ var import_promises2 = __toESM(require("fs/promises"), 1);
48566
+ var import_node_path22 = __toESM(require("path"), 1);
48325
48567
  var import_node_crypto6 = require("crypto");
48326
48568
 
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
48569
  // src/shift/schedule.ts
48336
48570
  var import_cron_parser = __toESM(require_dist(), 1);
48337
48571
  function computeNextRunAtMs(schedule, fromMs) {
@@ -48376,7 +48610,7 @@ function createShiftStore(deps) {
48376
48610
  async function load() {
48377
48611
  let raw;
48378
48612
  try {
48379
- raw = await import_promises.default.readFile(deps.filePath, "utf8");
48613
+ raw = await import_promises2.default.readFile(deps.filePath, "utf8");
48380
48614
  } catch (e) {
48381
48615
  if (e.code === "ENOENT") {
48382
48616
  shifts = [];
@@ -48404,10 +48638,10 @@ function createShiftStore(deps) {
48404
48638
  flushTimer = null;
48405
48639
  }
48406
48640
  const content = { version: 1, shifts };
48407
- await import_promises.default.mkdir(import_node_path21.default.dirname(deps.filePath), { recursive: true });
48641
+ await import_promises2.default.mkdir(import_node_path22.default.dirname(deps.filePath), { recursive: true });
48408
48642
  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);
48643
+ await import_promises2.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
48644
+ await import_promises2.default.rename(tmp, deps.filePath);
48411
48645
  }
48412
48646
  function scheduleFlush() {
48413
48647
  if (flushTimer) return;
@@ -48842,18 +49076,33 @@ function buildPersonaDispatchHandlers(deps) {
48842
49076
  if (!deps.forwardToPeer) {
48843
49077
  throw new Error("cross-device dispatch not wired (forwardToPeer missing)");
48844
49078
  }
49079
+ if (!sourceSessionId) {
49080
+ throw new Error(
49081
+ "personaDispatch:run requires sessionId (caller must pass x-clawd-session-id header)"
49082
+ );
49083
+ }
49084
+ const { dispatchId: dispatchId2 } = mgr.start({
49085
+ sourceSessionId,
49086
+ targetPersona: args.targetPersona,
49087
+ taskText: args.prompt
49088
+ });
48845
49089
  logger?.info("dispatch.run.forward", {
49090
+ dispatchId: dispatchId2,
48846
49091
  targetDeviceId: args.targetDeviceId,
48847
49092
  targetPersona: args.targetPersona
48848
49093
  });
48849
- const outcome2 = await deps.forwardToPeer({
49094
+ void deps.forwardToPeer({
48850
49095
  targetDeviceId: args.targetDeviceId,
48851
49096
  targetPersona: args.targetPersona,
48852
49097
  prompt: args.prompt,
48853
49098
  ...args.model ? { model: args.model } : {}
49099
+ }).then((outcome) => mgr.complete(dispatchId2, outcome)).catch((err) => {
49100
+ const reason = err instanceof Error ? err.message : String(err);
49101
+ logger?.warn("dispatch.forward.failed", { dispatchId: dispatchId2, reason });
49102
+ mgr.complete(dispatchId2, { kind: "failure", reason });
48854
49103
  });
48855
49104
  return {
48856
- response: { type: "personaDispatch:run:ok", outcome: outcome2 }
49105
+ response: { type: "personaDispatch:run:ok", dispatchId: dispatchId2 }
48857
49106
  };
48858
49107
  }
48859
49108
  if (ctx?.principal.kind === "guest") {
@@ -48866,7 +49115,8 @@ function buildPersonaDispatchHandlers(deps) {
48866
49115
  }
48867
49116
  const { dispatchId: dispatchId2 } = mgr.start({
48868
49117
  sourceSessionId: ctx.principal.id,
48869
- targetPersona: args.targetPersona
49118
+ targetPersona: args.targetPersona,
49119
+ taskText: args.prompt
48870
49120
  });
48871
49121
  logger?.info("dispatch.run.received.guest", {
48872
49122
  dispatchId: dispatchId2,
@@ -48892,9 +49142,9 @@ function buildPersonaDispatchHandlers(deps) {
48892
49142
  reason: `failed to spawn B: ${reason}`
48893
49143
  });
48894
49144
  });
48895
- const outcome2 = await mgr.wait(dispatchId2);
49145
+ const outcome = await mgr.waitForOutcome(dispatchId2);
48896
49146
  return {
48897
- response: { type: "personaDispatch:run:ok", outcome: outcome2 }
49147
+ response: { type: "personaDispatch:run:ok", outcome }
48898
49148
  };
48899
49149
  }
48900
49150
  if (!sourceSessionId) {
@@ -48904,7 +49154,8 @@ function buildPersonaDispatchHandlers(deps) {
48904
49154
  }
48905
49155
  const { dispatchId } = mgr.start({
48906
49156
  sourceSessionId,
48907
- targetPersona: args.targetPersona
49157
+ targetPersona: args.targetPersona,
49158
+ taskText: args.prompt
48908
49159
  });
48909
49160
  logger?.info("dispatch.run.received", {
48910
49161
  dispatchId,
@@ -48928,14 +49179,8 @@ function buildPersonaDispatchHandlers(deps) {
48928
49179
  reason: `failed to spawn B: ${reason}`
48929
49180
  });
48930
49181
  });
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
49182
  return {
48938
- response: { type: "personaDispatch:run:ok", outcome }
49183
+ response: { type: "personaDispatch:run:ok", dispatchId }
48939
49184
  };
48940
49185
  };
48941
49186
  const complete = async (frame) => {
@@ -48950,9 +49195,20 @@ function buildPersonaDispatchHandlers(deps) {
48950
49195
  response: { type: "personaDispatch:complete:ok" }
48951
49196
  };
48952
49197
  };
49198
+ const list = async (frame) => {
49199
+ const { type: _t, requestId: _r, ...rest } = frame;
49200
+ const args = DispatchListArgsSchema.parse(rest);
49201
+ const records = deps.store.list(
49202
+ args.sourceSessionId ? { sourceSessionId: args.sourceSessionId } : void 0
49203
+ );
49204
+ return {
49205
+ response: { type: "personaDispatch:list:ok", records }
49206
+ };
49207
+ };
48953
49208
  return {
48954
49209
  "personaDispatch:run": run,
48955
- "personaDispatch:complete": complete
49210
+ "personaDispatch:complete": complete,
49211
+ "personaDispatch:list": list
48956
49212
  };
48957
49213
  }
48958
49214
 
@@ -49258,13 +49514,13 @@ function mapSkillsListResponse(res) {
49258
49514
  const r = s ?? {};
49259
49515
  const name = str3(r.name);
49260
49516
  if (!name) continue;
49261
- const path70 = str3(r.path);
49517
+ const path71 = str3(r.path);
49262
49518
  const description = str3(r.description);
49263
49519
  const isPlugin = name.includes(":");
49264
49520
  out.push({
49265
49521
  name,
49266
49522
  source: isPlugin ? "plugin" : "project",
49267
- ...path70 ? { path: path70 } : {},
49523
+ ...path71 ? { path: path71 } : {},
49268
49524
  ...description ? { description } : {},
49269
49525
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
49270
49526
  });
@@ -49305,14 +49561,14 @@ async function listCodexSkills(cwd, deps = {}) {
49305
49561
  // src/workspace/browser.ts
49306
49562
  var import_node_fs24 = __toESM(require("fs"), 1);
49307
49563
  var import_node_os8 = __toESM(require("os"), 1);
49308
- var import_node_path22 = __toESM(require("path"), 1);
49564
+ var import_node_path23 = __toESM(require("path"), 1);
49309
49565
  init_protocol();
49310
49566
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
49311
49567
  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)) {
49568
+ const absCwd = import_node_path23.default.resolve(cwd);
49569
+ const joined = import_node_path23.default.resolve(absCwd, subpath ?? ".");
49570
+ const rel = import_node_path23.default.relative(absCwd, joined);
49571
+ if (rel.startsWith("..") || import_node_path23.default.isAbsolute(rel)) {
49316
49572
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
49317
49573
  }
49318
49574
  return joined;
@@ -49343,7 +49599,7 @@ var WorkspaceBrowser = class {
49343
49599
  mtime: ""
49344
49600
  };
49345
49601
  try {
49346
- const st = import_node_fs24.default.statSync(import_node_path22.default.join(full, d.name));
49602
+ const st = import_node_fs24.default.statSync(import_node_path23.default.join(full, d.name));
49347
49603
  entry.mtime = new Date(st.mtimeMs).toISOString();
49348
49604
  if (d.isFile()) entry.size = st.size;
49349
49605
  } catch {
@@ -49390,7 +49646,7 @@ var WorkspaceBrowser = class {
49390
49646
  // src/skills/agents-scanner.ts
49391
49647
  var import_node_fs25 = __toESM(require("fs"), 1);
49392
49648
  var import_node_os9 = __toESM(require("os"), 1);
49393
- var import_node_path23 = __toESM(require("path"), 1);
49649
+ var import_node_path24 = __toESM(require("path"), 1);
49394
49650
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
49395
49651
  function isDirLikeSync2(p2) {
49396
49652
  try {
@@ -49428,10 +49684,10 @@ function scanAgentsDir(dir, source, seen, out) {
49428
49684
  }
49429
49685
  for (const ent of entries) {
49430
49686
  if (!ent.name.endsWith(".md")) continue;
49431
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path23.default.join(dir, ent.name)))) {
49687
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path24.default.join(dir, ent.name)))) {
49432
49688
  continue;
49433
49689
  }
49434
- const filePath = import_node_path23.default.join(dir, ent.name);
49690
+ const filePath = import_node_path24.default.join(dir, ent.name);
49435
49691
  const baseName = ent.name.replace(/\.md$/, "");
49436
49692
  if (seen.has(baseName)) continue;
49437
49693
  seen.add(baseName);
@@ -49454,7 +49710,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
49454
49710
  return;
49455
49711
  }
49456
49712
  for (const ent of entries) {
49457
- const childPath = import_node_path23.default.join(dir, ent.name);
49713
+ const childPath = import_node_path24.default.join(dir, ent.name);
49458
49714
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
49459
49715
  walk2(childPath, [...namespaces, ent.name]);
49460
49716
  continue;
@@ -49479,9 +49735,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
49479
49735
  walk2(root, []);
49480
49736
  }
49481
49737
  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");
49738
+ const pluginsDir = import_node_path24.default.join(home, ".claude", "plugins");
49739
+ const v2 = import_node_path24.default.join(pluginsDir, "installed_plugins_v2.json");
49740
+ const v1 = import_node_path24.default.join(pluginsDir, "installed_plugins.json");
49485
49741
  let raw = null;
49486
49742
  for (const candidate of [v2, v1]) {
49487
49743
  try {
@@ -49510,19 +49766,19 @@ function readInstalledPlugins2(home) {
49510
49766
  return out;
49511
49767
  }
49512
49768
  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;
49769
+ let cur = import_node_path24.default.resolve(startCwd);
49770
+ const fsRoot = import_node_path24.default.parse(cur).root;
49515
49771
  while (true) {
49516
- scanAgentsDir(import_node_path23.default.join(cur, ".claude", "agents"), "project", seen, out);
49772
+ scanAgentsDir(import_node_path24.default.join(cur, ".claude", "agents"), "project", seen, out);
49517
49773
  let hasGit = false;
49518
49774
  try {
49519
- hasGit = import_node_fs25.default.existsSync(import_node_path23.default.join(cur, ".git"));
49775
+ hasGit = import_node_fs25.default.existsSync(import_node_path24.default.join(cur, ".git"));
49520
49776
  } catch {
49521
49777
  }
49522
49778
  if (hasGit) return;
49523
49779
  if (cur === home) return;
49524
49780
  if (cur === fsRoot) return;
49525
- const parent = import_node_path23.default.dirname(cur);
49781
+ const parent = import_node_path24.default.dirname(cur);
49526
49782
  if (parent === cur) return;
49527
49783
  cur = parent;
49528
49784
  }
@@ -49557,7 +49813,7 @@ var AgentsScanner = class {
49557
49813
  }
49558
49814
  const fsBlock = [];
49559
49815
  scanAgentsDir(
49560
- import_node_path23.default.join(this.home, ".claude", "agents"),
49816
+ import_node_path24.default.join(this.home, ".claude", "agents"),
49561
49817
  "global",
49562
49818
  seen,
49563
49819
  fsBlock
@@ -49571,7 +49827,7 @@ var AgentsScanner = class {
49571
49827
  ...this.extraPluginRoots
49572
49828
  ];
49573
49829
  for (const { name, root } of plugins) {
49574
- const agentsRoot = import_node_path23.default.join(root, "agents");
49830
+ const agentsRoot = import_node_path24.default.join(root, "agents");
49575
49831
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
49576
49832
  }
49577
49833
  return [...builtinBlock, ...fsBlock];
@@ -49581,13 +49837,13 @@ var AgentsScanner = class {
49581
49837
  // src/observer/session-observer.ts
49582
49838
  var import_node_fs27 = __toESM(require("fs"), 1);
49583
49839
  var import_node_os11 = __toESM(require("os"), 1);
49584
- var import_node_path25 = __toESM(require("path"), 1);
49840
+ var import_node_path26 = __toESM(require("path"), 1);
49585
49841
  init_claude_history();
49586
49842
 
49587
49843
  // src/observer/subagent-meta-observer.ts
49588
49844
  var import_node_fs26 = __toESM(require("fs"), 1);
49589
49845
  var import_node_os10 = __toESM(require("os"), 1);
49590
- var import_node_path24 = __toESM(require("path"), 1);
49846
+ var import_node_path25 = __toESM(require("path"), 1);
49591
49847
  init_claude_history();
49592
49848
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
49593
49849
  var SubagentMetaObserver = class {
@@ -49600,7 +49856,7 @@ var SubagentMetaObserver = class {
49600
49856
  watches = /* @__PURE__ */ new Map();
49601
49857
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
49602
49858
  resolveSubagentDir(cwd, toolSessionId) {
49603
- return import_node_path24.default.join(
49859
+ return import_node_path25.default.join(
49604
49860
  this.home,
49605
49861
  ".claude",
49606
49862
  "projects",
@@ -49656,7 +49912,7 @@ var SubagentMetaObserver = class {
49656
49912
  if (!m2) return;
49657
49913
  const agentId = m2[1];
49658
49914
  if (w2.emitted.has(agentId)) return;
49659
- const file = import_node_path24.default.join(w2.dirPath, name);
49915
+ const file = import_node_path25.default.join(w2.dirPath, name);
49660
49916
  let raw;
49661
49917
  try {
49662
49918
  raw = import_node_fs26.default.readFileSync(file, "utf8");
@@ -49716,7 +49972,7 @@ var SessionObserver = class {
49716
49972
  metaObserver;
49717
49973
  resolveJsonlPath(cwd, toolSessionId, override) {
49718
49974
  if (override) return override;
49719
- return import_node_path25.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
49975
+ return import_node_path26.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
49720
49976
  }
49721
49977
  start(args) {
49722
49978
  this.stop(args.sessionId);
@@ -49742,10 +49998,10 @@ var SessionObserver = class {
49742
49998
  lastDeriveMs: 0
49743
49999
  };
49744
50000
  try {
49745
- import_node_fs27.default.mkdirSync(import_node_path25.default.dirname(filePath), { recursive: true });
50001
+ import_node_fs27.default.mkdirSync(import_node_path26.default.dirname(filePath), { recursive: true });
49746
50002
  } catch {
49747
50003
  }
49748
- w2.watcher = import_node_fs27.default.watch(import_node_path25.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
50004
+ w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
49749
50005
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
49750
50006
  this.poll(w2);
49751
50007
  });
@@ -49842,7 +50098,7 @@ var SessionObserver = class {
49842
50098
  const now = Date.now();
49843
50099
  if (now - w2.lastRelocateScanMs < 1e3) return;
49844
50100
  w2.lastRelocateScanMs = now;
49845
- const projectsRoot = import_node_path25.default.join(this.home, ".claude", "projects");
50101
+ const projectsRoot = import_node_path26.default.join(this.home, ".claude", "projects");
49846
50102
  const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
49847
50103
  if (!found || found === w2.filePath) return;
49848
50104
  try {
@@ -49851,7 +50107,7 @@ var SessionObserver = class {
49851
50107
  }
49852
50108
  w2.filePath = found;
49853
50109
  try {
49854
- w2.watcher = import_node_fs27.default.watch(import_node_path25.default.dirname(found), { persistent: false }, (_event, changedName) => {
50110
+ w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(found), { persistent: false }, (_event, changedName) => {
49855
50111
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
49856
50112
  this.poll(w2);
49857
50113
  });
@@ -50435,13 +50691,13 @@ var EXPOSED_RPC_METHODS = [
50435
50691
  // dataclaw-builder:persona 建页时取建页人身份(含 union_id)写进生成 app 的配置。
50436
50692
  // 路由到 handlers['auth:getIdentity'],只返 identity、绝不带 ttcToken(见 handlers/feishu-auth.ts)。
50437
50693
  "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。
50694
+ // Persona dispatch(异步,spec 2026-07-20):A 端 dispatch MCP server 调 run(秒回 dispatchId);
50695
+ // B 端调 complete(带 outcome 台账 + 投递);发起方调 list 查台账。详见 protocol/src/dispatch.ts。
50441
50696
  "personaDispatch.run",
50442
50697
  // 跨设备 exec(spec 2026-07-16):A 侧本地 cc 经 /api/rpc 调,带 peerDeviceId → daemon forward。
50443
50698
  "peerExec.run",
50444
50699
  "personaDispatch.complete",
50700
+ "personaDispatch.list",
50445
50701
  // clawd-shift v1 (spec 2026-06-24-clawd-shift):cc 子进程内的 shift MCP server 调
50446
50702
  // 这 5 个 method 管理 owner 的 shift(fire-and-forget 排班)。鉴权靠 body.personaId
50447
50703
  // (mcp-server 从 process.env.CLAWD_PERSONA_ID 读,源 = SessionFile.ownerPersonaId)。
@@ -50706,14 +50962,14 @@ async function authenticate(token, deps) {
50706
50962
  }
50707
50963
 
50708
50964
  // src/permission/capability-store.ts
50709
- var fs31 = __toESM(require("fs"), 1);
50710
- var path30 = __toESM(require("path"), 1);
50965
+ var fs32 = __toESM(require("fs"), 1);
50966
+ var path31 = __toESM(require("path"), 1);
50711
50967
  var CAPABILITIES_FILE_NAME = "capabilities.json";
50712
50968
  var FILE_VERSION = 1;
50713
50969
  var CapabilityStore = class {
50714
50970
  constructor(dataDir) {
50715
50971
  this.dataDir = dataDir;
50716
- fs31.mkdirSync(dataDir, { recursive: true });
50972
+ fs32.mkdirSync(dataDir, { recursive: true });
50717
50973
  this.cache = this.readFromDisk();
50718
50974
  }
50719
50975
  dataDir;
@@ -50737,13 +50993,13 @@ var CapabilityStore = class {
50737
50993
  this.flush();
50738
50994
  }
50739
50995
  filePath() {
50740
- return path30.join(this.dataDir, CAPABILITIES_FILE_NAME);
50996
+ return path31.join(this.dataDir, CAPABILITIES_FILE_NAME);
50741
50997
  }
50742
50998
  readFromDisk() {
50743
50999
  const file = this.filePath();
50744
51000
  let raw;
50745
51001
  try {
50746
- raw = fs31.readFileSync(file, "utf8");
51002
+ raw = fs32.readFileSync(file, "utf8");
50747
51003
  } catch (err) {
50748
51004
  if (err?.code === "ENOENT") return [];
50749
51005
  return [];
@@ -50771,10 +51027,10 @@ var CapabilityStore = class {
50771
51027
  }
50772
51028
  atomicWrite(file, content) {
50773
51029
  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);
51030
+ fs32.writeFileSync(tmp, content, { mode: 384 });
51031
+ fs32.renameSync(tmp, file);
50776
51032
  try {
50777
- fs31.chmodSync(file, 384);
51033
+ fs32.chmodSync(file, 384);
50778
51034
  } catch {
50779
51035
  }
50780
51036
  }
@@ -50867,14 +51123,14 @@ var CapabilityManager = class {
50867
51123
  };
50868
51124
 
50869
51125
  // src/permission/cleanup.ts
50870
- var fs32 = __toESM(require("fs"), 1);
51126
+ var fs33 = __toESM(require("fs"), 1);
50871
51127
  function cleanupGuestSessionsForCapability(cap, factory) {
50872
51128
  const removed = [];
50873
51129
  for (const g2 of cap.grants) {
50874
51130
  if (g2.resource.type !== "persona") continue;
50875
51131
  const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
50876
51132
  try {
50877
- fs32.rmSync(dir, { recursive: true, force: true });
51133
+ fs33.rmSync(dir, { recursive: true, force: true });
50878
51134
  removed.push(dir);
50879
51135
  } catch {
50880
51136
  }
@@ -50883,13 +51139,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
50883
51139
  }
50884
51140
 
50885
51141
  // src/inbox/inbox-store.ts
50886
- var fs33 = __toESM(require("fs"), 1);
50887
- var path31 = __toESM(require("path"), 1);
51142
+ var fs34 = __toESM(require("fs"), 1);
51143
+ var path32 = __toESM(require("path"), 1);
50888
51144
  var INBOX_SUBDIR = "inbox";
50889
51145
  var InboxStore = class {
50890
51146
  constructor(dataDir) {
50891
51147
  this.dataDir = dataDir;
50892
- fs33.mkdirSync(this.dirPath(), { recursive: true });
51148
+ fs34.mkdirSync(this.dirPath(), { recursive: true });
50893
51149
  }
50894
51150
  dataDir;
50895
51151
  /**
@@ -50901,7 +51157,7 @@ var InboxStore = class {
50901
51157
  const file = this.filePath(peerDeviceId);
50902
51158
  let raw;
50903
51159
  try {
50904
- raw = fs33.readFileSync(file, "utf8");
51160
+ raw = fs34.readFileSync(file, "utf8");
50905
51161
  } catch (err) {
50906
51162
  if (err?.code === "ENOENT") return [];
50907
51163
  return [];
@@ -50917,7 +51173,7 @@ var InboxStore = class {
50917
51173
  const dir = this.dirPath();
50918
51174
  let entries;
50919
51175
  try {
50920
- entries = fs33.readdirSync(dir);
51176
+ entries = fs34.readdirSync(dir);
50921
51177
  } catch (err) {
50922
51178
  if (err?.code === "ENOENT") return [];
50923
51179
  return [];
@@ -50933,9 +51189,9 @@ var InboxStore = class {
50933
51189
  if (existing.some((m2) => m2.id === message.id)) return;
50934
51190
  const file = this.filePath(message.peerDeviceId);
50935
51191
  const line = JSON.stringify(message) + "\n";
50936
- fs33.appendFileSync(file, line, { mode: 384 });
51192
+ fs34.appendFileSync(file, line, { mode: 384 });
50937
51193
  try {
50938
- fs33.chmodSync(file, 384);
51194
+ fs34.chmodSync(file, 384);
50939
51195
  } catch {
50940
51196
  }
50941
51197
  }
@@ -50965,7 +51221,7 @@ var InboxStore = class {
50965
51221
  removeByPeerDeviceId(peerDeviceId) {
50966
51222
  const file = this.filePath(peerDeviceId);
50967
51223
  try {
50968
- fs33.unlinkSync(file);
51224
+ fs34.unlinkSync(file);
50969
51225
  } catch (err) {
50970
51226
  if (err?.code === "ENOENT") return;
50971
51227
  }
@@ -50974,18 +51230,18 @@ var InboxStore = class {
50974
51230
  const file = this.filePath(peerDeviceId);
50975
51231
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
50976
51232
  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);
51233
+ fs34.writeFileSync(tmp, content, { mode: 384 });
51234
+ fs34.renameSync(tmp, file);
50979
51235
  try {
50980
- fs33.chmodSync(file, 384);
51236
+ fs34.chmodSync(file, 384);
50981
51237
  } catch {
50982
51238
  }
50983
51239
  }
50984
51240
  dirPath() {
50985
- return path31.join(this.dataDir, INBOX_SUBDIR);
51241
+ return path32.join(this.dataDir, INBOX_SUBDIR);
50986
51242
  }
50987
51243
  filePath(peerDeviceId) {
50988
- return path31.join(this.dirPath(), `${peerDeviceId}.jsonl`);
51244
+ return path32.join(this.dirPath(), `${peerDeviceId}.jsonl`);
50989
51245
  }
50990
51246
  };
50991
51247
  function parseAllLines(raw) {
@@ -51073,8 +51329,8 @@ var InboxManager = class {
51073
51329
  };
51074
51330
 
51075
51331
  // src/state/contact-store.ts
51076
- var fs34 = __toESM(require("fs"), 1);
51077
- var path32 = __toESM(require("path"), 1);
51332
+ var fs35 = __toESM(require("fs"), 1);
51333
+ var path33 = __toESM(require("path"), 1);
51078
51334
  var FILE_NAME = "contacts.json";
51079
51335
  var ContactStore = class {
51080
51336
  constructor(dataDir) {
@@ -51084,10 +51340,10 @@ var ContactStore = class {
51084
51340
  contacts = /* @__PURE__ */ new Map();
51085
51341
  load() {
51086
51342
  this.contacts.clear();
51087
- const file = path32.join(this.dataDir, FILE_NAME);
51343
+ const file = path33.join(this.dataDir, FILE_NAME);
51088
51344
  let raw;
51089
51345
  try {
51090
- raw = fs34.readFileSync(file, "utf8");
51346
+ raw = fs35.readFileSync(file, "utf8");
51091
51347
  } catch (err) {
51092
51348
  if (err?.code !== "ENOENT") this.renameBak(file);
51093
51349
  return;
@@ -51156,20 +51412,20 @@ var ContactStore = class {
51156
51412
  return true;
51157
51413
  }
51158
51414
  flush() {
51159
- const file = path32.join(this.dataDir, FILE_NAME);
51415
+ const file = path33.join(this.dataDir, FILE_NAME);
51160
51416
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
51161
51417
  const content = JSON.stringify(
51162
51418
  { contacts: Array.from(this.contacts.values()) },
51163
51419
  null,
51164
51420
  2
51165
51421
  );
51166
- fs34.mkdirSync(this.dataDir, { recursive: true });
51167
- fs34.writeFileSync(tmp, content, { mode: 384 });
51168
- fs34.renameSync(tmp, file);
51422
+ fs35.mkdirSync(this.dataDir, { recursive: true });
51423
+ fs35.writeFileSync(tmp, content, { mode: 384 });
51424
+ fs35.renameSync(tmp, file);
51169
51425
  }
51170
51426
  renameBak(file) {
51171
51427
  try {
51172
- fs34.renameSync(file, `${file}.bak`);
51428
+ fs35.renameSync(file, `${file}.bak`);
51173
51429
  } catch {
51174
51430
  }
51175
51431
  }
@@ -51322,61 +51578,61 @@ async function autoReverseContact(args) {
51322
51578
  }
51323
51579
 
51324
51580
  // src/migrations/2026-05-20-flatten-sessions.ts
51325
- var fs35 = __toESM(require("fs"), 1);
51326
- var path33 = __toESM(require("path"), 1);
51581
+ var fs36 = __toESM(require("fs"), 1);
51582
+ var path34 = __toESM(require("path"), 1);
51327
51583
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
51328
51584
  function migrateFlattenSessions(opts) {
51329
51585
  const dataDir = opts.dataDir;
51330
51586
  const now = opts.now ?? Date.now;
51331
- const sessionsDir = path33.join(dataDir, "sessions");
51332
- const flagPath = path33.join(sessionsDir, MIGRATION_FLAG_NAME);
51587
+ const sessionsDir = path34.join(dataDir, "sessions");
51588
+ const flagPath = path34.join(sessionsDir, MIGRATION_FLAG_NAME);
51333
51589
  if (existsSync3(flagPath)) {
51334
51590
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
51335
51591
  }
51336
51592
  let movedBare = 0;
51337
51593
  let movedVmOwner = 0;
51338
51594
  let archivedListener = 0;
51339
- const defaultDir = path33.join(sessionsDir, "default");
51595
+ const defaultDir = path34.join(sessionsDir, "default");
51340
51596
  if (existsSync3(defaultDir)) {
51341
51597
  for (const entry of readdirSafe(defaultDir)) {
51342
51598
  if (!entry.endsWith(".json")) continue;
51343
- const src = path33.join(defaultDir, entry);
51344
- const dst = path33.join(sessionsDir, entry);
51345
- fs35.renameSync(src, dst);
51599
+ const src = path34.join(defaultDir, entry);
51600
+ const dst = path34.join(sessionsDir, entry);
51601
+ fs36.renameSync(src, dst);
51346
51602
  movedBare += 1;
51347
51603
  }
51348
51604
  rmdirIfEmpty(defaultDir);
51349
51605
  }
51350
51606
  for (const pid of readdirSafe(sessionsDir)) {
51351
- const personaDir = path33.join(sessionsDir, pid);
51607
+ const personaDir = path34.join(sessionsDir, pid);
51352
51608
  if (!isDir(personaDir)) continue;
51353
51609
  if (pid === "default") continue;
51354
- const ownerSrc = path33.join(personaDir, "owner");
51610
+ const ownerSrc = path34.join(personaDir, "owner");
51355
51611
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
51356
- const ownerDst = path33.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
51357
- fs35.mkdirSync(ownerDst, { recursive: true });
51612
+ const ownerDst = path34.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
51613
+ fs36.mkdirSync(ownerDst, { recursive: true });
51358
51614
  for (const file of readdirSafe(ownerSrc)) {
51359
51615
  if (!file.endsWith(".json")) continue;
51360
- fs35.renameSync(path33.join(ownerSrc, file), path33.join(ownerDst, file));
51616
+ fs36.renameSync(path34.join(ownerSrc, file), path34.join(ownerDst, file));
51361
51617
  movedVmOwner += 1;
51362
51618
  }
51363
51619
  rmdirIfEmpty(ownerSrc);
51364
51620
  }
51365
- const listenerSrc = path33.join(personaDir, "listener");
51621
+ const listenerSrc = path34.join(personaDir, "listener");
51366
51622
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
51367
- const archiveDst = path33.join(dataDir, ".legacy", `listener-${pid}`);
51368
- fs35.mkdirSync(archiveDst, { recursive: true });
51623
+ const archiveDst = path34.join(dataDir, ".legacy", `listener-${pid}`);
51624
+ fs36.mkdirSync(archiveDst, { recursive: true });
51369
51625
  for (const file of readdirSafe(listenerSrc)) {
51370
51626
  if (!file.endsWith(".json")) continue;
51371
- fs35.renameSync(path33.join(listenerSrc, file), path33.join(archiveDst, file));
51627
+ fs36.renameSync(path34.join(listenerSrc, file), path34.join(archiveDst, file));
51372
51628
  archivedListener += 1;
51373
51629
  }
51374
51630
  rmdirIfEmpty(listenerSrc);
51375
51631
  }
51376
51632
  rmdirIfEmpty(personaDir);
51377
51633
  }
51378
- fs35.mkdirSync(sessionsDir, { recursive: true });
51379
- fs35.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
51634
+ fs36.mkdirSync(sessionsDir, { recursive: true });
51635
+ fs36.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
51380
51636
  return {
51381
51637
  skipped: false,
51382
51638
  flagWritten: true,
@@ -51387,7 +51643,7 @@ function migrateFlattenSessions(opts) {
51387
51643
  }
51388
51644
  function existsSync3(p2) {
51389
51645
  try {
51390
- fs35.statSync(p2);
51646
+ fs36.statSync(p2);
51391
51647
  return true;
51392
51648
  } catch {
51393
51649
  return false;
@@ -51395,31 +51651,31 @@ function existsSync3(p2) {
51395
51651
  }
51396
51652
  function isDir(p2) {
51397
51653
  try {
51398
- return fs35.statSync(p2).isDirectory();
51654
+ return fs36.statSync(p2).isDirectory();
51399
51655
  } catch {
51400
51656
  return false;
51401
51657
  }
51402
51658
  }
51403
51659
  function readdirSafe(p2) {
51404
51660
  try {
51405
- return fs35.readdirSync(p2);
51661
+ return fs36.readdirSync(p2);
51406
51662
  } catch {
51407
51663
  return [];
51408
51664
  }
51409
51665
  }
51410
51666
  function rmdirIfEmpty(p2) {
51411
51667
  try {
51412
- fs35.rmdirSync(p2);
51668
+ fs36.rmdirSync(p2);
51413
51669
  } catch {
51414
51670
  }
51415
51671
  }
51416
51672
 
51417
51673
  // src/transport/http-router.ts
51418
51674
  var import_node_fs29 = __toESM(require("fs"), 1);
51419
- var import_node_path29 = __toESM(require("path"), 1);
51675
+ var import_node_path30 = __toESM(require("path"), 1);
51420
51676
 
51421
51677
  // src/attachment/mime.ts
51422
- var import_node_path26 = __toESM(require("path"), 1);
51678
+ var import_node_path27 = __toESM(require("path"), 1);
51423
51679
  var TEXT_PLAIN = "text/plain; charset=utf-8";
51424
51680
  var EXT_TO_NATIVE_MIME = {
51425
51681
  // 图片
@@ -51526,7 +51782,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
51526
51782
  ".mk"
51527
51783
  ]);
51528
51784
  function lookupMime(filePathOrName) {
51529
- const ext = import_node_path26.default.extname(filePathOrName).toLowerCase();
51785
+ const ext = import_node_path27.default.extname(filePathOrName).toLowerCase();
51530
51786
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
51531
51787
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
51532
51788
  return "application/octet-stream";
@@ -51596,9 +51852,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
51596
51852
 
51597
51853
  // src/attachment/upload.ts
51598
51854
  var import_node_fs28 = __toESM(require("fs"), 1);
51599
- var import_node_path27 = __toESM(require("path"), 1);
51855
+ var import_node_path28 = __toESM(require("path"), 1);
51600
51856
  var import_node_crypto8 = __toESM(require("crypto"), 1);
51601
- var import_promises2 = require("stream/promises");
51857
+ var import_promises3 = require("stream/promises");
51602
51858
  var UploadError = class extends Error {
51603
51859
  constructor(code, message) {
51604
51860
  super(message);
@@ -51608,14 +51864,14 @@ var UploadError = class extends Error {
51608
51864
  code;
51609
51865
  };
51610
51866
  function assertValidFileName(fileName) {
51611
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path27.default.basename(fileName)) {
51867
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path28.default.basename(fileName)) {
51612
51868
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
51613
51869
  }
51614
51870
  }
51615
51871
  var HASH_PREFIX_LEN = 16;
51616
51872
  async function writeUploadedAttachment(args) {
51617
51873
  assertValidFileName(args.fileName);
51618
- const attachmentsRoot = import_node_path27.default.join(args.sessionDir, ".attachments");
51874
+ const attachmentsRoot = import_node_path28.default.join(args.sessionDir, ".attachments");
51619
51875
  try {
51620
51876
  import_node_fs28.default.mkdirSync(attachmentsRoot, { recursive: true });
51621
51877
  } catch (err) {
@@ -51623,12 +51879,12 @@ async function writeUploadedAttachment(args) {
51623
51879
  }
51624
51880
  const hasher = import_node_crypto8.default.createHash("sha256");
51625
51881
  let actualSize = 0;
51626
- const tmpPath = import_node_path27.default.join(
51882
+ const tmpPath = import_node_path28.default.join(
51627
51883
  attachmentsRoot,
51628
51884
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
51629
51885
  );
51630
51886
  try {
51631
- await (0, import_promises2.pipeline)(
51887
+ await (0, import_promises3.pipeline)(
51632
51888
  args.body,
51633
51889
  async function* (source) {
51634
51890
  for await (const chunk of source) {
@@ -51658,7 +51914,7 @@ async function writeUploadedAttachment(args) {
51658
51914
  );
51659
51915
  }
51660
51916
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
51661
- const hashDir = import_node_path27.default.join(attachmentsRoot, attachmentId);
51917
+ const hashDir = import_node_path28.default.join(attachmentsRoot, attachmentId);
51662
51918
  let finalFileName;
51663
51919
  let hashDirExists = false;
51664
51920
  try {
@@ -51676,7 +51932,7 @@ async function writeUploadedAttachment(args) {
51676
51932
  try {
51677
51933
  import_node_fs28.default.mkdirSync(hashDir, { recursive: true });
51678
51934
  finalFileName = args.fileName;
51679
- import_node_fs28.default.renameSync(tmpPath, import_node_path27.default.join(hashDir, finalFileName));
51935
+ import_node_fs28.default.renameSync(tmpPath, import_node_path28.default.join(hashDir, finalFileName));
51680
51936
  } catch (err) {
51681
51937
  try {
51682
51938
  import_node_fs28.default.unlinkSync(tmpPath);
@@ -51685,8 +51941,8 @@ async function writeUploadedAttachment(args) {
51685
51941
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
51686
51942
  }
51687
51943
  }
51688
- const absPath = import_node_path27.default.join(hashDir, finalFileName);
51689
- const relPath = import_node_path27.default.relative(args.sessionDir, absPath);
51944
+ const absPath = import_node_path28.default.join(hashDir, finalFileName);
51945
+ const relPath = import_node_path28.default.relative(args.sessionDir, absPath);
51690
51946
  args.groupFileStore.upsert(args.scope, args.sessionId, {
51691
51947
  relPath: absPath,
51692
51948
  // 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
@@ -51699,8 +51955,8 @@ async function writeUploadedAttachment(args) {
51699
51955
  }
51700
51956
 
51701
51957
  // src/extension/import.ts
51702
- var import_promises3 = __toESM(require("fs/promises"), 1);
51703
- var import_node_path28 = __toESM(require("path"), 1);
51958
+ var import_promises4 = __toESM(require("fs/promises"), 1);
51959
+ var import_node_path29 = __toESM(require("path"), 1);
51704
51960
  var import_node_os12 = __toESM(require("os"), 1);
51705
51961
  var import_jszip = __toESM(require_lib3(), 1);
51706
51962
  var ImportError = class extends Error {
@@ -51718,7 +51974,7 @@ async function importZip(buf, root) {
51718
51974
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
51719
51975
  }
51720
51976
  for (const name of Object.keys(zip.files)) {
51721
- if (name.includes("..") || name.startsWith("/") || import_node_path28.default.isAbsolute(name)) {
51977
+ if (name.includes("..") || name.startsWith("/") || import_node_path29.default.isAbsolute(name)) {
51722
51978
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
51723
51979
  }
51724
51980
  }
@@ -51751,33 +52007,33 @@ async function importZip(buf, root) {
51751
52007
  );
51752
52008
  }
51753
52009
  }
51754
- const destDir = import_node_path28.default.join(root, manifest.id);
52010
+ const destDir = import_node_path29.default.join(root, manifest.id);
51755
52011
  let destExists = false;
51756
52012
  try {
51757
- await import_promises3.default.access(destDir);
52013
+ await import_promises4.default.access(destDir);
51758
52014
  destExists = true;
51759
52015
  } catch {
51760
52016
  }
51761
52017
  if (destExists) {
51762
52018
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
51763
52019
  }
51764
- const stage = await import_promises3.default.mkdtemp(import_node_path28.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
52020
+ const stage = await import_promises4.default.mkdtemp(import_node_path29.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
51765
52021
  try {
51766
52022
  for (const [name, entry] of Object.entries(zip.files)) {
51767
- const dest = import_node_path28.default.join(stage, name);
52023
+ const dest = import_node_path29.default.join(stage, name);
51768
52024
  if (entry.dir) {
51769
- await import_promises3.default.mkdir(dest, { recursive: true });
52025
+ await import_promises4.default.mkdir(dest, { recursive: true });
51770
52026
  continue;
51771
52027
  }
51772
- await import_promises3.default.mkdir(import_node_path28.default.dirname(dest), { recursive: true });
52028
+ await import_promises4.default.mkdir(import_node_path29.default.dirname(dest), { recursive: true });
51773
52029
  const content = await entry.async("nodebuffer");
51774
- await import_promises3.default.writeFile(dest, content);
52030
+ await import_promises4.default.writeFile(dest, content);
51775
52031
  }
51776
- await import_promises3.default.mkdir(root, { recursive: true });
51777
- await import_promises3.default.rename(stage, destDir);
52032
+ await import_promises4.default.mkdir(root, { recursive: true });
52033
+ await import_promises4.default.rename(stage, destDir);
51778
52034
  return { extId: manifest.id };
51779
52035
  } catch (e) {
51780
- await import_promises3.default.rm(stage, { recursive: true, force: true }).catch(() => {
52036
+ await import_promises4.default.rm(stage, { recursive: true, force: true }).catch(() => {
51781
52037
  });
51782
52038
  throw e;
51783
52039
  }
@@ -51800,7 +52056,7 @@ var SHARE_UI_ASSET_MIME = {
51800
52056
  ".wasm": "application/wasm"
51801
52057
  };
51802
52058
  function shareUiAssetMime(filePath) {
51803
- const ext = import_node_path29.default.extname(filePath).toLowerCase();
52059
+ const ext = import_node_path30.default.extname(filePath).toLowerCase();
51804
52060
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
51805
52061
  }
51806
52062
  var DISPATCH_HEARTBEAT_MS = 25e3;
@@ -51887,7 +52143,7 @@ function isValidUploadFileName(fileName) {
51887
52143
  if (fileName === "." || fileName === "..") return false;
51888
52144
  if (fileName.startsWith(".")) return false;
51889
52145
  if (fileName.includes("/") || fileName.includes("\\")) return false;
51890
- return fileName === import_node_path29.default.basename(fileName);
52146
+ return fileName === import_node_path30.default.basename(fileName);
51891
52147
  }
51892
52148
  function createHttpRouter(deps) {
51893
52149
  return async (req, res) => {
@@ -52183,7 +52439,7 @@ function createHttpRouter(deps) {
52183
52439
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
52184
52440
  return true;
52185
52441
  }
52186
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path29.default.basename(r.absPath)));
52442
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path30.default.basename(r.absPath)));
52187
52443
  return true;
52188
52444
  }
52189
52445
  const ctx = deps.authResolver.resolveFromHeader(
@@ -52304,7 +52560,7 @@ function createHttpRouter(deps) {
52304
52560
  return true;
52305
52561
  }
52306
52562
  let absPath;
52307
- if (import_node_path29.default.isAbsolute(pathParam)) {
52563
+ if (import_node_path30.default.isAbsolute(pathParam)) {
52308
52564
  absPath = pathParam;
52309
52565
  } else if (deps.sessionStore) {
52310
52566
  const file = deps.sessionStore.read(sid);
@@ -52312,7 +52568,7 @@ function createHttpRouter(deps) {
52312
52568
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
52313
52569
  return true;
52314
52570
  }
52315
- absPath = import_node_path29.default.join(file.cwd, pathParam);
52571
+ absPath = import_node_path30.default.join(file.cwd, pathParam);
52316
52572
  } else {
52317
52573
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
52318
52574
  return true;
@@ -52414,7 +52670,7 @@ function streamFile(res, absPath, logger) {
52414
52670
  return;
52415
52671
  }
52416
52672
  const mime = lookupMime(absPath);
52417
- const basename = import_node_path29.default.basename(absPath);
52673
+ const basename = import_node_path30.default.basename(absPath);
52418
52674
  res.writeHead(200, {
52419
52675
  "Content-Type": mime,
52420
52676
  "Content-Length": String(stat.size),
@@ -52432,7 +52688,7 @@ function streamFile(res, absPath, logger) {
52432
52688
 
52433
52689
  // src/attachment/gc.ts
52434
52690
  var import_node_fs30 = __toESM(require("fs"), 1);
52435
- var import_node_path30 = __toESM(require("path"), 1);
52691
+ var import_node_path31 = __toESM(require("path"), 1);
52436
52692
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
52437
52693
  function runAttachmentGc(args) {
52438
52694
  const now = (args.now ?? Date.now)();
@@ -52441,17 +52697,17 @@ function runAttachmentGc(args) {
52441
52697
  for (const { scope, sessionId } of args.sessionScopes) {
52442
52698
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
52443
52699
  if (entry.stale) continue;
52444
- if (import_node_path30.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
52700
+ if (import_node_path31.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
52445
52701
  }
52446
52702
  }
52447
52703
  for (const { scope, sessionId } of args.sessionScopes) {
52448
- const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path30.default.join(
52704
+ const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path31.default.join(
52449
52705
  args.dataDir,
52450
52706
  "sessions",
52451
52707
  ...scopeSubPath(scope).map(safeFileName),
52452
52708
  safeFileName(sessionId)
52453
52709
  );
52454
- const attRoot = import_node_path30.default.join(sessionDir, ".attachments");
52710
+ const attRoot = import_node_path31.default.join(sessionDir, ".attachments");
52455
52711
  let hashDirs;
52456
52712
  try {
52457
52713
  hashDirs = import_node_fs30.default.readdirSync(attRoot);
@@ -52461,7 +52717,7 @@ function runAttachmentGc(args) {
52461
52717
  continue;
52462
52718
  }
52463
52719
  for (const hashDir of hashDirs) {
52464
- const hashDirAbs = import_node_path30.default.join(attRoot, hashDir);
52720
+ const hashDirAbs = import_node_path31.default.join(attRoot, hashDir);
52465
52721
  let files;
52466
52722
  try {
52467
52723
  files = import_node_fs30.default.readdirSync(hashDirAbs);
@@ -52469,7 +52725,7 @@ function runAttachmentGc(args) {
52469
52725
  continue;
52470
52726
  }
52471
52727
  for (const name of files) {
52472
- const file = import_node_path30.default.join(hashDirAbs, name);
52728
+ const file = import_node_path31.default.join(hashDirAbs, name);
52473
52729
  let stat;
52474
52730
  try {
52475
52731
  stat = import_node_fs30.default.statSync(file);
@@ -52500,7 +52756,7 @@ function runAttachmentGc(args) {
52500
52756
 
52501
52757
  // src/attachment/group.ts
52502
52758
  var import_node_fs31 = __toESM(require("fs"), 1);
52503
- var import_node_path31 = __toESM(require("path"), 1);
52759
+ var import_node_path32 = __toESM(require("path"), 1);
52504
52760
  var import_node_crypto9 = __toESM(require("crypto"), 1);
52505
52761
  init_protocol();
52506
52762
  var GroupFileStore = class {
@@ -52512,11 +52768,11 @@ var GroupFileStore = class {
52512
52768
  this.logger = opts.logger;
52513
52769
  }
52514
52770
  rootForScope(scope) {
52515
- return import_node_path31.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
52771
+ return import_node_path32.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
52516
52772
  }
52517
52773
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
52518
52774
  filePath(scope, sessionId) {
52519
- return import_node_path31.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
52775
+ return import_node_path32.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
52520
52776
  }
52521
52777
  cacheKey(scope, sessionId) {
52522
52778
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -52551,7 +52807,7 @@ var GroupFileStore = class {
52551
52807
  }
52552
52808
  writeFile(scope, sessionId, entries) {
52553
52809
  const file = this.filePath(scope, sessionId);
52554
- import_node_fs31.default.mkdirSync(import_node_path31.default.dirname(file), { recursive: true });
52810
+ import_node_fs31.default.mkdirSync(import_node_path32.default.dirname(file), { recursive: true });
52555
52811
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
52556
52812
  import_node_fs31.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
52557
52813
  import_node_fs31.default.renameSync(tmp, file);
@@ -52641,9 +52897,9 @@ var GroupFileStore = class {
52641
52897
 
52642
52898
  // src/discovery/state-file.ts
52643
52899
  var import_node_fs32 = __toESM(require("fs"), 1);
52644
- var import_node_path32 = __toESM(require("path"), 1);
52900
+ var import_node_path33 = __toESM(require("path"), 1);
52645
52901
  function defaultStateFilePath(dataDir) {
52646
- return import_node_path32.default.join(dataDir, "state.json");
52902
+ return import_node_path33.default.join(dataDir, "state.json");
52647
52903
  }
52648
52904
  function isPidAlive(pid) {
52649
52905
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -52679,7 +52935,7 @@ var StateFileManager = class {
52679
52935
  return { status: "stale", existing };
52680
52936
  }
52681
52937
  write(state) {
52682
- import_node_fs32.default.mkdirSync(import_node_path32.default.dirname(this.file), { recursive: true });
52938
+ import_node_fs32.default.mkdirSync(import_node_path33.default.dirname(this.file), { recursive: true });
52683
52939
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
52684
52940
  import_node_fs32.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
52685
52941
  import_node_fs32.default.renameSync(tmp, this.file);
@@ -52707,13 +52963,13 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
52707
52963
 
52708
52964
  // src/tunnel/tunnel-manager.ts
52709
52965
  var import_node_fs36 = __toESM(require("fs"), 1);
52710
- var import_node_path36 = __toESM(require("path"), 1);
52966
+ var import_node_path37 = __toESM(require("path"), 1);
52711
52967
  var import_node_crypto10 = __toESM(require("crypto"), 1);
52712
52968
  var import_node_child_process9 = require("child_process");
52713
52969
 
52714
52970
  // src/tunnel/tunnel-store.ts
52715
52971
  var import_node_fs33 = __toESM(require("fs"), 1);
52716
- var import_node_path33 = __toESM(require("path"), 1);
52972
+ var import_node_path34 = __toESM(require("path"), 1);
52717
52973
  var TunnelStore = class {
52718
52974
  constructor(filePath) {
52719
52975
  this.filePath = filePath;
@@ -52732,7 +52988,7 @@ var TunnelStore = class {
52732
52988
  }
52733
52989
  }
52734
52990
  async set(v2) {
52735
- const dir = import_node_path33.default.dirname(this.filePath);
52991
+ const dir = import_node_path34.default.dirname(this.filePath);
52736
52992
  await import_node_fs33.default.promises.mkdir(dir, { recursive: true });
52737
52993
  const data = JSON.stringify(v2, null, 2);
52738
52994
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
@@ -52844,10 +53100,10 @@ function escape(v2) {
52844
53100
  // src/tunnel/frpc-binary.ts
52845
53101
  var import_node_fs34 = __toESM(require("fs"), 1);
52846
53102
  var import_node_os13 = __toESM(require("os"), 1);
52847
- var import_node_path34 = __toESM(require("path"), 1);
53103
+ var import_node_path35 = __toESM(require("path"), 1);
52848
53104
  var import_node_child_process7 = require("child_process");
52849
53105
  var import_node_stream3 = require("stream");
52850
- var import_promises4 = require("stream/promises");
53106
+ var import_promises5 = require("stream/promises");
52851
53107
  var FRPC_VERSION = "0.68.0";
52852
53108
  var UnsupportedPlatformError = class extends Error {
52853
53109
  constructor(platform, arch) {
@@ -52883,13 +53139,13 @@ async function ensureFrpcBinary(opts) {
52883
53139
  }
52884
53140
  const version2 = opts.version ?? FRPC_VERSION;
52885
53141
  const platform = opts.platform ?? detectPlatform();
52886
- const binDir = import_node_path34.default.join(opts.dataDir, "bin");
53142
+ const binDir = import_node_path35.default.join(opts.dataDir, "bin");
52887
53143
  import_node_fs34.default.mkdirSync(binDir, { recursive: true });
52888
53144
  cleanupStaleArtifacts(binDir);
52889
- const stableBin = import_node_path34.default.join(binDir, "frpc");
53145
+ const stableBin = import_node_path35.default.join(binDir, "frpc");
52890
53146
  if (import_node_fs34.default.existsSync(stableBin)) return stableBin;
52891
53147
  const partialBin = `${stableBin}.partial`;
52892
- const tarballPath = import_node_path34.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
53148
+ const tarballPath = import_node_path35.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
52893
53149
  try {
52894
53150
  const url = frpcDownloadUrl(version2, platform);
52895
53151
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -52915,7 +53171,7 @@ function cleanupStaleArtifacts(binDir) {
52915
53171
  }
52916
53172
  for (const name of entries) {
52917
53173
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
52918
- const full = import_node_path34.default.join(binDir, name);
53174
+ const full = import_node_path35.default.join(binDir, name);
52919
53175
  try {
52920
53176
  import_node_fs34.default.rmSync(full, { recursive: true, force: true });
52921
53177
  } catch {
@@ -52938,10 +53194,10 @@ async function downloadToFile(url, dest, fetchImpl) {
52938
53194
  }
52939
53195
  const out = import_node_fs34.default.createWriteStream(dest);
52940
53196
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
52941
- await (0, import_promises4.pipeline)(nodeStream, out);
53197
+ await (0, import_promises5.pipeline)(nodeStream, out);
52942
53198
  }
52943
53199
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
52944
- const work = import_node_path34.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
53200
+ const work = import_node_path35.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
52945
53201
  import_node_fs34.default.mkdirSync(work, { recursive: true });
52946
53202
  try {
52947
53203
  await new Promise((resolve6, reject) => {
@@ -52950,7 +53206,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
52950
53206
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
52951
53207
  });
52952
53208
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
52953
- const src = import_node_path34.default.join(work, dirName, "frpc");
53209
+ const src = import_node_path35.default.join(work, dirName, "frpc");
52954
53210
  if (!import_node_fs34.default.existsSync(src)) {
52955
53211
  throw new Error(`frpc not found inside tarball at ${src}`);
52956
53212
  }
@@ -52962,10 +53218,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
52962
53218
 
52963
53219
  // src/tunnel/frpc-process.ts
52964
53220
  var import_node_fs35 = __toESM(require("fs"), 1);
52965
- var import_node_path35 = __toESM(require("path"), 1);
53221
+ var import_node_path36 = __toESM(require("path"), 1);
52966
53222
  var import_node_child_process8 = require("child_process");
52967
53223
  function frpcPidFilePath(dataDir) {
52968
- return import_node_path35.default.join(dataDir, "frpc.pid");
53224
+ return import_node_path36.default.join(dataDir, "frpc.pid");
52969
53225
  }
52970
53226
  function writeFrpcPid(dataDir, pid) {
52971
53227
  try {
@@ -53007,7 +53263,7 @@ function defaultSleep(ms) {
53007
53263
  }
53008
53264
  async function killStaleFrpc(deps) {
53009
53265
  const pidFile = frpcPidFilePath(deps.dataDir);
53010
- const tomlPath = import_node_path35.default.join(deps.dataDir, "frpc.toml");
53266
+ const tomlPath = import_node_path36.default.join(deps.dataDir, "frpc.toml");
53011
53267
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
53012
53268
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
53013
53269
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -53079,7 +53335,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
53079
53335
  var TunnelManager = class {
53080
53336
  constructor(deps) {
53081
53337
  this.deps = deps;
53082
- this.store = deps.store ?? new TunnelStore(import_node_path36.default.join(deps.dataDir, "tunnel.json"));
53338
+ this.store = deps.store ?? new TunnelStore(import_node_path37.default.join(deps.dataDir, "tunnel.json"));
53083
53339
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
53084
53340
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
53085
53341
  }
@@ -53206,7 +53462,7 @@ var TunnelManager = class {
53206
53462
  dataDir: this.deps.dataDir,
53207
53463
  override: this.deps.frpcBinaryOverride ?? void 0
53208
53464
  });
53209
- const tomlPath = import_node_path36.default.join(this.deps.dataDir, "frpc.toml");
53465
+ const tomlPath = import_node_path37.default.join(this.deps.dataDir, "frpc.toml");
53210
53466
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
53211
53467
  const toml = buildFrpcToml({
53212
53468
  serverAddr: t.frpsHost,
@@ -53221,9 +53477,9 @@ var TunnelManager = class {
53221
53477
  const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
53222
53478
  stdio: ["ignore", "pipe", "pipe"]
53223
53479
  });
53224
- const logDir = import_node_path36.default.join(this.deps.dataDir, "log");
53480
+ const logDir = import_node_path37.default.join(this.deps.dataDir, "log");
53225
53481
  import_node_fs36.default.mkdirSync(logDir, { recursive: true });
53226
- const logFilePath = import_node_path36.default.join(logDir, "frpc.log");
53482
+ const logFilePath = import_node_path37.default.join(logDir, "frpc.log");
53227
53483
  const logStream = import_node_fs36.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
53228
53484
  logStream.on("error", () => {
53229
53485
  });
@@ -53307,15 +53563,15 @@ async function waitForFrpcReady(proc, timeoutMs) {
53307
53563
 
53308
53564
  // src/tunnel/device-key.ts
53309
53565
  var import_node_os14 = __toESM(require("os"), 1);
53310
- var import_node_path37 = __toESM(require("path"), 1);
53566
+ var import_node_path38 = __toESM(require("path"), 1);
53311
53567
  var import_node_crypto11 = __toESM(require("crypto"), 1);
53312
53568
  var DERIVE_SALT = "clawd-tunnel-device-v1";
53313
53569
  function deriveStableDeviceKey(opts = {}) {
53314
53570
  const hostname = opts.hostname ?? import_node_os14.default.hostname();
53315
53571
  const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
53316
53572
  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;
53573
+ const defaultDataDir = import_node_path38.default.resolve(import_node_path38.default.join(home, ".clawd"));
53574
+ const normalizedDataDir = opts.dataDir ? import_node_path38.default.resolve(opts.dataDir) : null;
53319
53575
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
53320
53576
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
53321
53577
  return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
@@ -53323,11 +53579,11 @@ function deriveStableDeviceKey(opts = {}) {
53323
53579
 
53324
53580
  // src/auth-store.ts
53325
53581
  var import_node_fs37 = __toESM(require("fs"), 1);
53326
- var import_node_path38 = __toESM(require("path"), 1);
53582
+ var import_node_path39 = __toESM(require("path"), 1);
53327
53583
  var import_node_crypto12 = __toESM(require("crypto"), 1);
53328
53584
  var AUTH_FILE_NAME = "auth.json";
53329
53585
  function authFilePath(dataDir) {
53330
- return import_node_path38.default.join(dataDir, AUTH_FILE_NAME);
53586
+ return import_node_path39.default.join(dataDir, AUTH_FILE_NAME);
53331
53587
  }
53332
53588
  function loadOrCreateAuthFile(opts) {
53333
53589
  const file = authFilePath(opts.dataDir);
@@ -53383,7 +53639,7 @@ function readAuthFile(file) {
53383
53639
  }
53384
53640
  }
53385
53641
  function writeAuthFile(file, content) {
53386
- import_node_fs37.default.mkdirSync(import_node_path38.default.dirname(file), { recursive: true });
53642
+ import_node_fs37.default.mkdirSync(import_node_path39.default.dirname(file), { recursive: true });
53387
53643
  import_node_fs37.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
53388
53644
  try {
53389
53645
  import_node_fs37.default.chmodSync(file, 384);
@@ -53394,11 +53650,11 @@ function writeAuthFile(file, content) {
53394
53650
  // src/owner-profile.ts
53395
53651
  var import_node_fs38 = __toESM(require("fs"), 1);
53396
53652
  var import_node_os15 = __toESM(require("os"), 1);
53397
- var import_node_path39 = __toESM(require("path"), 1);
53653
+ var import_node_path40 = __toESM(require("path"), 1);
53398
53654
  var PROFILE_FILENAME = "profile.json";
53399
53655
  function loadOwnerDisplayName(dataDir) {
53400
53656
  const fallback = import_node_os15.default.userInfo().username;
53401
- const profilePath = import_node_path39.default.join(dataDir, PROFILE_FILENAME);
53657
+ const profilePath = import_node_path40.default.join(dataDir, PROFILE_FILENAME);
53402
53658
  let raw;
53403
53659
  try {
53404
53660
  raw = import_node_fs38.default.readFileSync(profilePath, "utf8");
@@ -53425,12 +53681,12 @@ function loadOwnerDisplayName(dataDir) {
53425
53681
 
53426
53682
  // src/feishu-auth/owner-identity-store.ts
53427
53683
  var import_node_fs39 = __toESM(require("fs"), 1);
53428
- var import_node_path40 = __toESM(require("path"), 1);
53684
+ var import_node_path41 = __toESM(require("path"), 1);
53429
53685
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
53430
53686
  var OwnerIdentityStore = class {
53431
53687
  file;
53432
53688
  constructor(dataDir) {
53433
- this.file = import_node_path40.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
53689
+ this.file = import_node_path41.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
53434
53690
  }
53435
53691
  read() {
53436
53692
  let raw;
@@ -53463,7 +53719,7 @@ var OwnerIdentityStore = class {
53463
53719
  };
53464
53720
  }
53465
53721
  write(record) {
53466
- import_node_fs39.default.mkdirSync(import_node_path40.default.dirname(this.file), { recursive: true });
53722
+ import_node_fs39.default.mkdirSync(import_node_path41.default.dirname(this.file), { recursive: true });
53467
53723
  import_node_fs39.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
53468
53724
  try {
53469
53725
  import_node_fs39.default.chmodSync(this.file, 384);
@@ -53609,9 +53865,9 @@ var CentralClientError = class extends Error {
53609
53865
  code;
53610
53866
  cause;
53611
53867
  };
53612
- async function centralRequest(opts, path70, init) {
53868
+ async function centralRequest(opts, path71, init) {
53613
53869
  const f = opts.fetchImpl ?? globalThis.fetch;
53614
- const url = `${opts.api.replace(/\/+$/, "")}${path70}`;
53870
+ const url = `${opts.api.replace(/\/+$/, "")}${path71}`;
53615
53871
  const ctrl = new AbortController();
53616
53872
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
53617
53873
  let res;
@@ -53805,8 +54061,8 @@ function verifyConnectToken(args) {
53805
54061
  }
53806
54062
 
53807
54063
  // src/feishu-auth/server-key.ts
53808
- var fs49 = __toESM(require("fs"), 1);
53809
- var path49 = __toESM(require("path"), 1);
54064
+ var fs50 = __toESM(require("fs"), 1);
54065
+ var path50 = __toESM(require("path"), 1);
53810
54066
  var FILE_NAME2 = "server-signing-key.json";
53811
54067
  var ServerKeyStore = class {
53812
54068
  constructor(dataDir) {
@@ -53814,12 +54070,12 @@ var ServerKeyStore = class {
53814
54070
  }
53815
54071
  dataDir;
53816
54072
  filePath() {
53817
- return path49.join(this.dataDir, FILE_NAME2);
54073
+ return path50.join(this.dataDir, FILE_NAME2);
53818
54074
  }
53819
54075
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
53820
54076
  read() {
53821
54077
  try {
53822
- const raw = fs49.readFileSync(this.filePath(), "utf8");
54078
+ const raw = fs50.readFileSync(this.filePath(), "utf8");
53823
54079
  const parsed = JSON.parse(raw);
53824
54080
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
53825
54081
  return parsed.publicKeyPem;
@@ -53834,12 +54090,12 @@ var ServerKeyStore = class {
53834
54090
  publicKeyPem,
53835
54091
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
53836
54092
  };
53837
- fs49.mkdirSync(this.dataDir, { recursive: true });
53838
- fs49.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
54093
+ fs50.mkdirSync(this.dataDir, { recursive: true });
54094
+ fs50.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
53839
54095
  }
53840
54096
  clear() {
53841
54097
  try {
53842
- fs49.unlinkSync(this.filePath());
54098
+ fs50.unlinkSync(this.filePath());
53843
54099
  } catch {
53844
54100
  }
53845
54101
  }
@@ -53854,7 +54110,7 @@ init_protocol();
53854
54110
  // src/session/fork.ts
53855
54111
  var import_node_fs40 = __toESM(require("fs"), 1);
53856
54112
  var import_node_os16 = __toESM(require("os"), 1);
53857
- var import_node_path41 = __toESM(require("path"), 1);
54113
+ var import_node_path42 = __toESM(require("path"), 1);
53858
54114
  init_claude_history();
53859
54115
  function readJsonlEntries(file) {
53860
54116
  const raw = import_node_fs40.default.readFileSync(file, "utf8");
@@ -53870,19 +54126,19 @@ function readJsonlEntries(file) {
53870
54126
  return out;
53871
54127
  }
53872
54128
  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`);
54129
+ const baseDir = input.baseDir ?? import_node_path42.default.join(import_node_os16.default.homedir(), ".claude");
54130
+ let projectDir = import_node_path42.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
54131
+ let sourceFile = import_node_path42.default.join(projectDir, `${input.toolSessionId}.jsonl`);
53876
54132
  if (!import_node_fs40.default.existsSync(sourceFile)) {
53877
54133
  const found = findTranscriptByToolSessionId(
53878
- import_node_path41.default.join(baseDir, "projects"),
54134
+ import_node_path42.default.join(baseDir, "projects"),
53879
54135
  input.toolSessionId
53880
54136
  );
53881
54137
  if (!found) {
53882
54138
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
53883
54139
  }
53884
54140
  sourceFile = found;
53885
- projectDir = import_node_path41.default.dirname(found);
54141
+ projectDir = import_node_path42.default.dirname(found);
53886
54142
  }
53887
54143
  const entries = readJsonlEntries(sourceFile);
53888
54144
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -53911,7 +54167,7 @@ function forkSession(input) {
53911
54167
  }
53912
54168
  forkedLines.push(JSON.stringify(forked));
53913
54169
  }
53914
- const forkedFilePath = import_node_path41.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
54170
+ const forkedFilePath = import_node_path42.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
53915
54171
  import_node_fs40.default.mkdirSync(projectDir, { recursive: true });
53916
54172
  import_node_fs40.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
53917
54173
  return { forkedToolSessionId, forkedFilePath };
@@ -54311,7 +54567,7 @@ function buildPermissionHandlers(deps) {
54311
54567
  }
54312
54568
 
54313
54569
  // src/handlers/history.ts
54314
- var path52 = __toESM(require("path"), 1);
54570
+ var path53 = __toESM(require("path"), 1);
54315
54571
  init_protocol();
54316
54572
 
54317
54573
  // src/session/recent-dirs.ts
@@ -54329,7 +54585,7 @@ function listRecentDirs(store, limit = 50) {
54329
54585
  }
54330
54586
 
54331
54587
  // src/permission/persona-paths.ts
54332
- var path51 = __toESM(require("path"), 1);
54588
+ var path52 = __toESM(require("path"), 1);
54333
54589
  function getAllowedPersonaIds(grants, action) {
54334
54590
  const ids = /* @__PURE__ */ new Set();
54335
54591
  for (const g2 of grants) {
@@ -54342,42 +54598,42 @@ function getAllowedPersonaIds(grants, action) {
54342
54598
  return ids;
54343
54599
  }
54344
54600
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
54345
- const target = path51.resolve(absPath);
54601
+ const target = path52.resolve(absPath);
54346
54602
  if (userWorkDir) {
54347
- const u = path51.resolve(userWorkDir);
54348
- const usep = u.endsWith(path51.sep) ? "" : path51.sep;
54603
+ const u = path52.resolve(userWorkDir);
54604
+ const usep = u.endsWith(path52.sep) ? "" : path52.sep;
54349
54605
  if (target === u || target.startsWith(u + usep)) return true;
54350
54606
  }
54351
- const root = path51.resolve(personaRoot);
54352
- const sep3 = root.endsWith(path51.sep) ? "" : path51.sep;
54607
+ const root = path52.resolve(personaRoot);
54608
+ const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
54353
54609
  if (!target.startsWith(root + sep3)) return false;
54354
- const rel = path51.relative(root, target);
54610
+ const rel = path52.relative(root, target);
54355
54611
  if (!rel || rel.startsWith("..")) return false;
54356
- const personaId = rel.split(path51.sep)[0];
54612
+ const personaId = rel.split(path52.sep)[0];
54357
54613
  if (!personaId) return false;
54358
54614
  const allowed = getAllowedPersonaIds(grants, action);
54359
54615
  if (allowed === "*") return true;
54360
54616
  return allowed.has(personaId);
54361
54617
  }
54362
54618
  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;
54619
+ const root = path52.resolve(personaRoot);
54620
+ const target = path52.resolve(absPath);
54621
+ const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
54366
54622
  if (!target.startsWith(root + sep3)) return null;
54367
- const rel = path51.relative(root, target);
54623
+ const rel = path52.relative(root, target);
54368
54624
  if (!rel || rel.startsWith("..")) return null;
54369
- const id = rel.split(path51.sep)[0];
54625
+ const id = rel.split(path52.sep)[0];
54370
54626
  return id || null;
54371
54627
  }
54372
54628
  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;
54629
+ const d = path52.resolve(dir);
54630
+ const t = path52.resolve(absPath);
54631
+ const sep3 = d.endsWith(path52.sep) ? "" : path52.sep;
54376
54632
  return t === d || t.startsWith(d + sep3);
54377
54633
  }
54378
54634
  function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
54379
54635
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
54380
- return personaIdFromPath(path51.resolve(absPath), personaRoot) === personaId;
54636
+ return personaIdFromPath(path52.resolve(absPath), personaRoot) === personaId;
54381
54637
  }
54382
54638
 
54383
54639
  // src/handlers/history.ts
@@ -54429,7 +54685,7 @@ function buildHistoryHandlers(deps) {
54429
54685
  if (!pid) return false;
54430
54686
  return isGuestPathAllowed(
54431
54687
  ctx.grants,
54432
- path52.join(personaRoot, pid),
54688
+ path53.join(personaRoot, pid),
54433
54689
  personaRoot,
54434
54690
  "read",
54435
54691
  userWorkDir
@@ -54441,7 +54697,7 @@ function buildHistoryHandlers(deps) {
54441
54697
  };
54442
54698
  const list = async (frame, _client, ctx) => {
54443
54699
  const args = HistoryListArgs.parse(frame);
54444
- assertGuestPath(ctx, path52.resolve(args.projectPath), personaRoot, "history:list");
54700
+ assertGuestPath(ctx, path53.resolve(args.projectPath), personaRoot, "history:list");
54445
54701
  const sessions = await history.listSessions(args);
54446
54702
  return { response: { type: "history:list", sessions } };
54447
54703
  };
@@ -54474,13 +54730,13 @@ function buildHistoryHandlers(deps) {
54474
54730
  };
54475
54731
  const subagents = async (frame, _client, ctx) => {
54476
54732
  const args = HistorySubagentsArgs.parse(frame);
54477
- assertGuestPath(ctx, path52.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
54733
+ assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
54478
54734
  const subs = await history.listSubagents(args);
54479
54735
  return { response: { type: "history:subagents", subagents: subs } };
54480
54736
  };
54481
54737
  const subagentRead = async (frame, _client, ctx) => {
54482
54738
  const args = HistorySubagentReadArgs.parse(frame);
54483
- assertGuestPath(ctx, path52.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
54739
+ assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
54484
54740
  const res = await history.readSubagent(args);
54485
54741
  return { response: { type: "history:subagent-read", ...res } };
54486
54742
  };
@@ -54489,7 +54745,7 @@ function buildHistoryHandlers(deps) {
54489
54745
  if (ctx?.principal.kind === "guest" && personaRoot) {
54490
54746
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
54491
54747
  const filtered = dirs.filter(
54492
- (d) => isGuestPathAllowed(ctx.grants, path52.resolve(d.cwd), personaRoot, "read", userWorkDir)
54748
+ (d) => isGuestPathAllowed(ctx.grants, path53.resolve(d.cwd), personaRoot, "read", userWorkDir)
54493
54749
  );
54494
54750
  return { response: { type: "history:recentDirs", dirs: filtered } };
54495
54751
  }
@@ -54506,7 +54762,7 @@ function buildHistoryHandlers(deps) {
54506
54762
  }
54507
54763
 
54508
54764
  // src/handlers/workspace.ts
54509
- var path53 = __toESM(require("path"), 1);
54765
+ var path54 = __toESM(require("path"), 1);
54510
54766
  var os16 = __toESM(require("os"), 1);
54511
54767
  init_protocol();
54512
54768
  init_protocol();
@@ -54548,22 +54804,22 @@ function buildWorkspaceHandlers(deps) {
54548
54804
  const args = WorkspaceListArgs.parse(frame);
54549
54805
  const isGuest = ctx?.principal.kind === "guest";
54550
54806
  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;
54807
+ const resolvedCwd = path54.resolve(args.cwd ?? fallbackCwd);
54808
+ const target = args.path ? path54.resolve(resolvedCwd, args.path) : resolvedCwd;
54553
54809
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
54554
54810
  const res = workspace.list({ ...args, cwd: resolvedCwd });
54555
54811
  return { response: { type: "workspace:list", ...res } };
54556
54812
  };
54557
54813
  const read = async (frame, _client, ctx) => {
54558
54814
  const args = WorkspaceReadArgs.parse(frame);
54559
- const target = path53.isAbsolute(args.path) ? path53.resolve(args.path) : path53.resolve(args.cwd, args.path);
54815
+ const target = path54.isAbsolute(args.path) ? path54.resolve(args.path) : path54.resolve(args.cwd, args.path);
54560
54816
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
54561
54817
  const res = workspace.read(args);
54562
54818
  return { response: { type: "workspace:read", ...res } };
54563
54819
  };
54564
54820
  const skillsList = async (frame, _client, ctx) => {
54565
54821
  const args = SkillsListArgs.parse(frame);
54566
- const cwdAbs = path53.resolve(args.cwd);
54822
+ const cwdAbs = path54.resolve(args.cwd);
54567
54823
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
54568
54824
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
54569
54825
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -54575,7 +54831,7 @@ function buildWorkspaceHandlers(deps) {
54575
54831
  };
54576
54832
  const agentsList = async (frame, _client, ctx) => {
54577
54833
  const args = AgentsListArgs.parse(frame);
54578
- const cwdAbs = path53.resolve(args.cwd);
54834
+ const cwdAbs = path54.resolve(args.cwd);
54579
54835
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
54580
54836
  if (args.tool === "codex") {
54581
54837
  return { response: { type: "agents:list", agents: [] } };
@@ -54597,18 +54853,18 @@ function buildWorkspaceHandlers(deps) {
54597
54853
  }
54598
54854
 
54599
54855
  // src/handlers/git.ts
54600
- var path55 = __toESM(require("path"), 1);
54856
+ var path56 = __toESM(require("path"), 1);
54601
54857
  init_protocol();
54602
54858
  init_protocol();
54603
54859
 
54604
54860
  // src/workspace/git.ts
54605
54861
  var import_node_child_process10 = require("child_process");
54606
54862
  var import_node_fs41 = __toESM(require("fs"), 1);
54607
- var import_node_path42 = __toESM(require("path"), 1);
54863
+ var import_node_path43 = __toESM(require("path"), 1);
54608
54864
  var import_node_util = require("util");
54609
54865
  var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
54610
54866
  function normalizePath(p2) {
54611
- const resolved = import_node_path42.default.resolve(p2);
54867
+ const resolved = import_node_path43.default.resolve(p2);
54612
54868
  try {
54613
54869
  return import_node_fs41.default.realpathSync(resolved);
54614
54870
  } catch {
@@ -54684,7 +54940,7 @@ async function listGitBranches(cwd) {
54684
54940
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
54685
54941
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
54686
54942
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
54687
- if (!isGuestPathAllowed(ctx.grants, path55.resolve(cwd), personaRoot, "read", userWorkDir)) {
54943
+ if (!isGuestPathAllowed(ctx.grants, path56.resolve(cwd), personaRoot, "read", userWorkDir)) {
54688
54944
  throw new ClawdError(
54689
54945
  ERROR_CODES.UNAUTHORIZED,
54690
54946
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -55370,7 +55626,7 @@ function buildPersonaHandlers(deps) {
55370
55626
  }
55371
55627
 
55372
55628
  // src/handlers/attachment.ts
55373
- var import_node_path43 = __toESM(require("path"), 1);
55629
+ var import_node_path44 = __toESM(require("path"), 1);
55374
55630
  init_protocol();
55375
55631
  init_protocol();
55376
55632
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -55450,12 +55706,12 @@ function buildAttachmentHandlers(deps) {
55450
55706
  `session ${args.sessionId} scope unresolved`
55451
55707
  );
55452
55708
  }
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);
55709
+ const cwdAbs = import_node_path44.default.resolve(sessionFile.cwd);
55710
+ 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
55711
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
55456
55712
  const entries = deps.groupFileStore.list(scope, args.sessionId);
55457
55713
  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);
55714
+ 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
55715
  return storedAbs === candidateAbs && !e.stale;
55460
55716
  });
55461
55717
  if (!entry) {
@@ -55480,7 +55736,7 @@ function buildAttachmentHandlers(deps) {
55480
55736
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
55481
55737
  const f = deps.sessionStore.read(sessionId);
55482
55738
  if (!f) return;
55483
- assertGuestAttachmentPath(ctx, import_node_path43.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
55739
+ assertGuestAttachmentPath(ctx, import_node_path44.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
55484
55740
  }
55485
55741
  const groupAdd = async (frame, _client, ctx) => {
55486
55742
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -55495,8 +55751,8 @@ function buildAttachmentHandlers(deps) {
55495
55751
  if (!scope) {
55496
55752
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
55497
55753
  }
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);
55754
+ const cwdAbs = import_node_path44.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
55755
+ 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
55756
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
55501
55757
  const from = ctx?.principal.kind === "owner" ? "owner" : "agent";
55502
55758
  const size = 0;
@@ -55554,21 +55810,21 @@ function buildAttachmentHandlers(deps) {
55554
55810
  }
55555
55811
 
55556
55812
  // src/handlers/extension.ts
55557
- var import_promises8 = __toESM(require("fs/promises"), 1);
55558
- var import_node_path48 = __toESM(require("path"), 1);
55813
+ var import_promises9 = __toESM(require("fs/promises"), 1);
55814
+ var import_node_path49 = __toESM(require("path"), 1);
55559
55815
  init_protocol();
55560
55816
 
55561
55817
  // src/extension/bundle-zip.ts
55562
- var import_promises5 = __toESM(require("fs/promises"), 1);
55563
- var import_node_path44 = __toESM(require("path"), 1);
55818
+ var import_promises6 = __toESM(require("fs/promises"), 1);
55819
+ var import_node_path45 = __toESM(require("path"), 1);
55564
55820
  var import_node_crypto14 = __toESM(require("crypto"), 1);
55565
55821
  var import_jszip2 = __toESM(require_lib3(), 1);
55566
55822
  async function bundleExtensionDir(dir) {
55567
55823
  const entries = await listFilesSorted(dir);
55568
55824
  const zip = new import_jszip2.default();
55569
55825
  for (const rel of entries) {
55570
- const abs = import_node_path44.default.join(dir, rel);
55571
- const content = await import_promises5.default.readFile(abs);
55826
+ const abs = import_node_path45.default.join(dir, rel);
55827
+ const content = await import_promises6.default.readFile(abs);
55572
55828
  zip.file(rel, content, { date: FIXED_DATE });
55573
55829
  }
55574
55830
  const buffer = await zip.generateAsync({
@@ -55588,8 +55844,8 @@ async function listFilesSorted(rootDir) {
55588
55844
  return out;
55589
55845
  }
55590
55846
  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 });
55847
+ const dirAbs = import_node_path45.default.join(absRoot, relPrefix);
55848
+ const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
55593
55849
  for (const e of entries) {
55594
55850
  if (IGNORE_BASENAMES.has(e.name)) continue;
55595
55851
  const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
@@ -55641,26 +55897,26 @@ function computePublishCheck(args) {
55641
55897
  }
55642
55898
 
55643
55899
  // src/extension/install-flow.ts
55644
- var import_promises6 = __toESM(require("fs/promises"), 1);
55645
- var import_node_path46 = __toESM(require("path"), 1);
55900
+ var import_promises7 = __toESM(require("fs/promises"), 1);
55901
+ var import_node_path47 = __toESM(require("path"), 1);
55646
55902
  var import_node_os19 = __toESM(require("os"), 1);
55647
55903
  var import_node_crypto15 = __toESM(require("crypto"), 1);
55648
55904
  var import_jszip3 = __toESM(require_lib3(), 1);
55649
55905
 
55650
55906
  // src/extension/paths.ts
55651
55907
  var import_node_os18 = __toESM(require("os"), 1);
55652
- var import_node_path45 = __toESM(require("path"), 1);
55908
+ var import_node_path46 = __toESM(require("path"), 1);
55653
55909
  function clawdHomeRoot(override) {
55654
- return override ?? process.env.CLAWD_HOME ?? import_node_path45.default.join(import_node_os18.default.homedir(), ".clawd");
55910
+ return override ?? process.env.CLAWD_HOME ?? import_node_path46.default.join(import_node_os18.default.homedir(), ".clawd");
55655
55911
  }
55656
55912
  function extensionsRoot(override) {
55657
- return import_node_path45.default.join(clawdHomeRoot(override), "extensions");
55913
+ return import_node_path46.default.join(clawdHomeRoot(override), "extensions");
55658
55914
  }
55659
55915
  function publishedChannelsFile(override) {
55660
- return import_node_path45.default.join(clawdHomeRoot(override), "extensions-published.json");
55916
+ return import_node_path46.default.join(clawdHomeRoot(override), "extensions-published.json");
55661
55917
  }
55662
55918
  function bundleCacheRoot(override) {
55663
- return import_node_path45.default.join(clawdHomeRoot(override), "extension-bundles");
55919
+ return import_node_path46.default.join(clawdHomeRoot(override), "extension-bundles");
55664
55920
  }
55665
55921
 
55666
55922
  // src/extension/install-flow.ts
@@ -55687,7 +55943,7 @@ async function installFromChannel(args, deps) {
55687
55943
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
55688
55944
  }
55689
55945
  for (const name of Object.keys(zip.files)) {
55690
- if (name.includes("..") || name.startsWith("/") || import_node_path46.default.isAbsolute(name)) {
55946
+ if (name.includes("..") || name.startsWith("/") || import_node_path47.default.isAbsolute(name)) {
55691
55947
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
55692
55948
  }
55693
55949
  }
@@ -55719,10 +55975,10 @@ async function installFromChannel(args, deps) {
55719
55975
  );
55720
55976
  }
55721
55977
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
55722
- const destDir = import_node_path46.default.join(deps.extensionsRoot, localExtId);
55978
+ const destDir = import_node_path47.default.join(deps.extensionsRoot, localExtId);
55723
55979
  let destExists = false;
55724
55980
  try {
55725
- await import_promises6.default.access(destDir);
55981
+ await import_promises7.default.access(destDir);
55726
55982
  destExists = true;
55727
55983
  } catch {
55728
55984
  }
@@ -55732,28 +55988,28 @@ async function installFromChannel(args, deps) {
55732
55988
  `extension ${localExtId} already installed locally (from owner ${channelRef.ownerPrincipalId})`
55733
55989
  );
55734
55990
  }
55735
- const stage = await import_promises6.default.mkdtemp(
55736
- import_node_path46.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
55991
+ const stage = await import_promises7.default.mkdtemp(
55992
+ import_node_path47.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
55737
55993
  );
55738
55994
  try {
55739
55995
  for (const [name, entry] of Object.entries(zip.files)) {
55740
- const dest = import_node_path46.default.join(stage, name);
55996
+ const dest = import_node_path47.default.join(stage, name);
55741
55997
  if (entry.dir) {
55742
- await import_promises6.default.mkdir(dest, { recursive: true });
55998
+ await import_promises7.default.mkdir(dest, { recursive: true });
55743
55999
  continue;
55744
56000
  }
55745
- await import_promises6.default.mkdir(import_node_path46.default.dirname(dest), { recursive: true });
56001
+ await import_promises7.default.mkdir(import_node_path47.default.dirname(dest), { recursive: true });
55746
56002
  if (name === "manifest.json") {
55747
56003
  const rewritten = { ...parsed.data, id: localExtId };
55748
- await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
56004
+ await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
55749
56005
  } else {
55750
- await import_promises6.default.writeFile(dest, await entry.async("nodebuffer"));
56006
+ await import_promises7.default.writeFile(dest, await entry.async("nodebuffer"));
55751
56007
  }
55752
56008
  }
55753
- await import_promises6.default.mkdir(deps.extensionsRoot, { recursive: true });
55754
- await import_promises6.default.rename(stage, destDir);
56009
+ await import_promises7.default.mkdir(deps.extensionsRoot, { recursive: true });
56010
+ await import_promises7.default.rename(stage, destDir);
55755
56011
  } catch (e) {
55756
- await import_promises6.default.rm(stage, { recursive: true, force: true }).catch(() => {
56012
+ await import_promises7.default.rm(stage, { recursive: true, force: true }).catch(() => {
55757
56013
  });
55758
56014
  throw e;
55759
56015
  }
@@ -55762,8 +56018,8 @@ async function installFromChannel(args, deps) {
55762
56018
  }
55763
56019
 
55764
56020
  // src/extension/update-flow.ts
55765
- var import_promises7 = __toESM(require("fs/promises"), 1);
55766
- var import_node_path47 = __toESM(require("path"), 1);
56021
+ var import_promises8 = __toESM(require("fs/promises"), 1);
56022
+ var import_node_path48 = __toESM(require("path"), 1);
55767
56023
  var import_node_os20 = __toESM(require("os"), 1);
55768
56024
  var import_node_crypto16 = __toESM(require("crypto"), 1);
55769
56025
  var import_jszip4 = __toESM(require_lib3(), 1);
@@ -55780,11 +56036,11 @@ async function updateFromChannel(args, deps) {
55780
56036
  channelRef.extId,
55781
56037
  channelRef.ownerPrincipalId
55782
56038
  );
55783
- const liveDir = import_node_path47.default.join(deps.extensionsRoot, localExtId);
56039
+ const liveDir = import_node_path48.default.join(deps.extensionsRoot, localExtId);
55784
56040
  const prevDir = `${liveDir}.prev`;
55785
56041
  let existingVersion;
55786
56042
  try {
55787
- const raw = await import_promises7.default.readFile(import_node_path47.default.join(liveDir, "manifest.json"), "utf8");
56043
+ const raw = await import_promises8.default.readFile(import_node_path48.default.join(liveDir, "manifest.json"), "utf8");
55788
56044
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
55789
56045
  if (!parsed2.success) {
55790
56046
  throw new UpdateError(
@@ -55817,7 +56073,7 @@ async function updateFromChannel(args, deps) {
55817
56073
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
55818
56074
  }
55819
56075
  for (const name of Object.keys(zip.files)) {
55820
- if (name.includes("..") || name.startsWith("/") || import_node_path47.default.isAbsolute(name)) {
56076
+ if (name.includes("..") || name.startsWith("/") || import_node_path48.default.isAbsolute(name)) {
55821
56077
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
55822
56078
  }
55823
56079
  }
@@ -55849,31 +56105,31 @@ async function updateFromChannel(args, deps) {
55849
56105
  );
55850
56106
  }
55851
56107
  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}-`)
56108
+ await import_promises8.default.rm(prevDir, { recursive: true, force: true });
56109
+ await import_promises8.default.rename(liveDir, prevDir);
56110
+ const stage = await import_promises8.default.mkdtemp(
56111
+ import_node_path48.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
55856
56112
  );
55857
56113
  try {
55858
56114
  for (const [name, entry] of Object.entries(zip.files)) {
55859
- const dest = import_node_path47.default.join(stage, name);
56115
+ const dest = import_node_path48.default.join(stage, name);
55860
56116
  if (entry.dir) {
55861
- await import_promises7.default.mkdir(dest, { recursive: true });
56117
+ await import_promises8.default.mkdir(dest, { recursive: true });
55862
56118
  continue;
55863
56119
  }
55864
- await import_promises7.default.mkdir(import_node_path47.default.dirname(dest), { recursive: true });
56120
+ await import_promises8.default.mkdir(import_node_path48.default.dirname(dest), { recursive: true });
55865
56121
  if (name === "manifest.json") {
55866
56122
  const rewritten = { ...parsed.data, id: localExtId };
55867
- await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
56123
+ await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
55868
56124
  } else {
55869
- await import_promises7.default.writeFile(dest, await entry.async("nodebuffer"));
56125
+ await import_promises8.default.writeFile(dest, await entry.async("nodebuffer"));
55870
56126
  }
55871
56127
  }
55872
- await import_promises7.default.rename(stage, liveDir);
56128
+ await import_promises8.default.rename(stage, liveDir);
55873
56129
  } catch (e) {
55874
- await import_promises7.default.rm(stage, { recursive: true, force: true }).catch(() => {
56130
+ await import_promises8.default.rm(stage, { recursive: true, force: true }).catch(() => {
55875
56131
  });
55876
- await import_promises7.default.rename(prevDir, liveDir).catch(() => {
56132
+ await import_promises8.default.rename(prevDir, liveDir).catch(() => {
55877
56133
  });
55878
56134
  await deps.runtime.open(localExtId).catch(() => {
55879
56135
  });
@@ -55895,7 +56151,7 @@ async function updateFromChannel(args, deps) {
55895
56151
  reason: e.message
55896
56152
  };
55897
56153
  }
55898
- await import_promises7.default.rm(prevDir, { recursive: true, force: true });
56154
+ await import_promises8.default.rm(prevDir, { recursive: true, force: true });
55899
56155
  return {
55900
56156
  kind: "updated",
55901
56157
  extId: localExtId,
@@ -55903,9 +56159,9 @@ async function updateFromChannel(args, deps) {
55903
56159
  };
55904
56160
  }
55905
56161
  async function rollback(deps, localExtId, liveDir, prevDir) {
55906
- await import_promises7.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
56162
+ await import_promises8.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
55907
56163
  });
55908
- await import_promises7.default.rename(prevDir, liveDir).catch(() => {
56164
+ await import_promises8.default.rename(prevDir, liveDir).catch(() => {
55909
56165
  });
55910
56166
  await deps.runtime.open(localExtId).catch(() => {
55911
56167
  });
@@ -55954,18 +56210,18 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
55954
56210
  );
55955
56211
  }
55956
56212
  }
55957
- const manifestPath = import_node_path48.default.join(root, extId, "manifest.json");
56213
+ const manifestPath = import_node_path49.default.join(root, extId, "manifest.json");
55958
56214
  const manifest = await readManifest(root, extId);
55959
56215
  const next = { ...manifest, version: newVersion };
55960
56216
  const tmp = `${manifestPath}.tmp`;
55961
- await import_promises8.default.writeFile(tmp, JSON.stringify(next, null, 2));
55962
- await import_promises8.default.rename(tmp, manifestPath);
56217
+ await import_promises9.default.writeFile(tmp, JSON.stringify(next, null, 2));
56218
+ await import_promises9.default.rename(tmp, manifestPath);
55963
56219
  }
55964
56220
  async function readManifest(root, extId) {
55965
- const file = import_node_path48.default.join(root, extId, "manifest.json");
56221
+ const file = import_node_path49.default.join(root, extId, "manifest.json");
55966
56222
  let raw;
55967
56223
  try {
55968
- raw = await import_promises8.default.readFile(file, "utf8");
56224
+ raw = await import_promises9.default.readFile(file, "utf8");
55969
56225
  } catch (e) {
55970
56226
  if (e.code === "ENOENT") {
55971
56227
  throw new ClawdError(ERROR_CODES.INVALID_PARAM, `extension ${extId} not installed`);
@@ -56053,7 +56309,7 @@ function buildExtensionHandlers(deps) {
56053
56309
  };
56054
56310
  async function buildSnapshotMeta(extId) {
56055
56311
  const manifest = await readManifest(deps.root, extId);
56056
- const { sha256, buffer } = await bundleExtensionDir(import_node_path48.default.join(deps.root, extId));
56312
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path49.default.join(deps.root, extId));
56057
56313
  return { manifest, contentHash: sha256, buffer };
56058
56314
  }
56059
56315
  const publish = async (frame, _client, ctx) => {
@@ -56236,7 +56492,7 @@ function buildExtensionHandlers(deps) {
56236
56492
  // src/app-builder/project-store.ts
56237
56493
  var import_node_fs42 = require("fs");
56238
56494
  var import_node_child_process11 = require("child_process");
56239
- var import_node_path49 = require("path");
56495
+ var import_node_path50 = require("path");
56240
56496
  init_protocol();
56241
56497
  var PROJECTS_DIR = "projects";
56242
56498
  var META_FILE = ".clawd-project.json";
@@ -56250,14 +56506,14 @@ var ProjectStore = class {
56250
56506
  root;
56251
56507
  /** projects/<name>/.clawd-project.json 路径 */
56252
56508
  metaPath(name) {
56253
- return (0, import_node_path49.join)(this.projectsRoot(), name, META_FILE);
56509
+ return (0, import_node_path50.join)(this.projectsRoot(), name, META_FILE);
56254
56510
  }
56255
56511
  /** projects/<name>/ 目录路径(cwd 用) */
56256
56512
  projectDir(name) {
56257
- return (0, import_node_path49.join)(this.projectsRoot(), name);
56513
+ return (0, import_node_path50.join)(this.projectsRoot(), name);
56258
56514
  }
56259
56515
  projectsRoot() {
56260
- return (0, import_node_path49.join)(this.root, PROJECTS_DIR);
56516
+ return (0, import_node_path50.join)(this.root, PROJECTS_DIR);
56261
56517
  }
56262
56518
  async list() {
56263
56519
  let entries;
@@ -56560,7 +56816,7 @@ var PublishJobRegistry = class {
56560
56816
  // src/app-builder/publish-job-runner.ts
56561
56817
  var import_node_child_process13 = require("child_process");
56562
56818
  var import_node_fs43 = require("fs");
56563
- var import_node_path50 = require("path");
56819
+ var import_node_path51 = require("path");
56564
56820
 
56565
56821
  // src/app-builder/publish-stage-parser.ts
56566
56822
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -56592,7 +56848,7 @@ async function startPublishJob(deps, args) {
56592
56848
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
56593
56849
  }
56594
56850
  const projDir = projectDir(args.name);
56595
- const logPath = (0, import_node_path50.join)(projDir, ".publish.log");
56851
+ const logPath = (0, import_node_path51.join)(projDir, ".publish.log");
56596
56852
  let logStream = null;
56597
56853
  try {
56598
56854
  logStream = (0, import_node_fs43.createWriteStream)(logPath, { flags: "w" });
@@ -56852,7 +57108,7 @@ async function recoverInterruptedJobs(deps) {
56852
57108
 
56853
57109
  // src/handlers/app-builder.ts
56854
57110
  init_protocol();
56855
- var import_node_path51 = require("path");
57111
+ var import_node_path52 = require("path");
56856
57112
  var import_node_fs44 = require("fs");
56857
57113
  var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
56858
57114
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
@@ -57010,8 +57266,8 @@ function buildAppBuilderHandlers(deps) {
57010
57266
  const project = await userStore.create(f.name, reservedPorts);
57011
57267
  try {
57012
57268
  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");
57269
+ const templateSrcDir = (0, import_node_path52.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
57270
+ const scaffoldScript = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
57015
57271
  const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
57016
57272
  deps.logger?.info("app-builder.scaffold.done", {
57017
57273
  name: project.name,
@@ -57232,7 +57488,7 @@ function buildAppBuilderHandlers(deps) {
57232
57488
  await userStore.clearPublishJob(args.name);
57233
57489
  }
57234
57490
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
57235
- const scriptPath = (0, import_node_path51.join)(deps.deployKitRoot, "scripts", "publish.sh");
57491
+ const scriptPath = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "publish.sh");
57236
57492
  deps.logger?.info("app-builder.publish.start", {
57237
57493
  name: args.name,
57238
57494
  sessionId: boundSession.sessionId,
@@ -57407,12 +57663,12 @@ function buildVisitorHandlers(deps) {
57407
57663
  }
57408
57664
 
57409
57665
  // src/extension/registry.ts
57410
- var import_promises9 = __toESM(require("fs/promises"), 1);
57411
- var import_node_path52 = __toESM(require("path"), 1);
57666
+ var import_promises10 = __toESM(require("fs/promises"), 1);
57667
+ var import_node_path53 = __toESM(require("path"), 1);
57412
57668
  async function loadAll(root) {
57413
57669
  let entries;
57414
57670
  try {
57415
- entries = await import_promises9.default.readdir(root, { withFileTypes: true });
57671
+ entries = await import_promises10.default.readdir(root, { withFileTypes: true });
57416
57672
  } catch (e) {
57417
57673
  if (e.code === "ENOENT") return [];
57418
57674
  throw e;
@@ -57421,16 +57677,16 @@ async function loadAll(root) {
57421
57677
  for (const ent of entries) {
57422
57678
  if (!ent.isDirectory()) continue;
57423
57679
  if (ent.name.startsWith(".")) continue;
57424
- records.push(await loadOne(import_node_path52.default.join(root, ent.name), ent.name));
57680
+ records.push(await loadOne(import_node_path53.default.join(root, ent.name), ent.name));
57425
57681
  }
57426
57682
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
57427
57683
  return records;
57428
57684
  }
57429
57685
  async function loadOne(dir, dirName) {
57430
- const manifestPath = import_node_path52.default.join(dir, "manifest.json");
57686
+ const manifestPath = import_node_path53.default.join(dir, "manifest.json");
57431
57687
  let raw;
57432
57688
  try {
57433
- raw = await import_promises9.default.readFile(manifestPath, "utf8");
57689
+ raw = await import_promises10.default.readFile(manifestPath, "utf8");
57434
57690
  } catch {
57435
57691
  return {
57436
57692
  extId: dirName,
@@ -57471,8 +57727,8 @@ async function loadOne(dir, dirName) {
57471
57727
  }
57472
57728
 
57473
57729
  // src/extension/uninstall.ts
57474
- var import_promises10 = __toESM(require("fs/promises"), 1);
57475
- var import_node_path53 = __toESM(require("path"), 1);
57730
+ var import_promises11 = __toESM(require("fs/promises"), 1);
57731
+ var import_node_path54 = __toESM(require("path"), 1);
57476
57732
  var UninstallError = class extends Error {
57477
57733
  constructor(code, message) {
57478
57734
  super(message);
@@ -57481,14 +57737,14 @@ var UninstallError = class extends Error {
57481
57737
  code;
57482
57738
  };
57483
57739
  async function uninstall(deps) {
57484
- const dir = import_node_path53.default.join(deps.root, deps.extId);
57740
+ const dir = import_node_path54.default.join(deps.root, deps.extId);
57485
57741
  try {
57486
- await import_promises10.default.access(dir);
57742
+ await import_promises11.default.access(dir);
57487
57743
  } catch {
57488
57744
  throw new UninstallError("NOT_FOUND", `extension ${deps.extId} not installed`);
57489
57745
  }
57490
57746
  await deps.runtime.close(deps.extId);
57491
- await import_promises10.default.rm(dir, { recursive: true, force: true });
57747
+ await import_promises11.default.rm(dir, { recursive: true, force: true });
57492
57748
  }
57493
57749
 
57494
57750
  // src/handlers/index.ts
@@ -58201,8 +58457,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
58201
58457
 
58202
58458
  // src/extension/runtime.ts
58203
58459
  var import_node_child_process16 = require("child_process");
58204
- var import_node_path54 = __toESM(require("path"), 1);
58205
- var import_promises11 = require("timers/promises");
58460
+ var import_node_path55 = __toESM(require("path"), 1);
58461
+ var import_promises12 = require("timers/promises");
58206
58462
 
58207
58463
  // src/extension/port-allocator.ts
58208
58464
  var import_node_net2 = __toESM(require("net"), 1);
@@ -58302,7 +58558,7 @@ var Runtime = class {
58302
58558
  /\$CLAWOS_EXT_PORT/g,
58303
58559
  String(port)
58304
58560
  );
58305
- const dir = import_node_path54.default.join(this.root, extId);
58561
+ const dir = import_node_path55.default.join(this.root, extId);
58306
58562
  const env = {
58307
58563
  ...process.env,
58308
58564
  CLAWOS_EXT_PORT: String(port),
@@ -58378,7 +58634,7 @@ ${handle.stderrTail}`
58378
58634
  if (res.ok) return;
58379
58635
  } catch {
58380
58636
  }
58381
- await (0, import_promises11.setTimeout)(this.healthzIntervalMs);
58637
+ await (0, import_promises12.setTimeout)(this.healthzIntervalMs);
58382
58638
  }
58383
58639
  throw new RuntimeError(
58384
58640
  "HEALTHZ_FAILED",
@@ -58403,7 +58659,7 @@ ${handle.stderrTail}`
58403
58659
  };
58404
58660
  killGroup("SIGTERM");
58405
58661
  const exited = new Promise((resolve6) => child.once("exit", () => resolve6()));
58406
- const timed = (0, import_promises11.setTimeout)(5e3).then(() => "timeout");
58662
+ const timed = (0, import_promises12.setTimeout)(5e3).then(() => "timeout");
58407
58663
  const winner = await Promise.race([exited.then(() => "exited"), timed]);
58408
58664
  if (winner === "timeout" && child.exitCode === null) {
58409
58665
  killGroup("SIGKILL");
@@ -58413,8 +58669,8 @@ ${handle.stderrTail}`
58413
58669
  };
58414
58670
 
58415
58671
  // src/extension/published-channels.ts
58416
- var import_promises12 = __toESM(require("fs/promises"), 1);
58417
- var import_node_path55 = __toESM(require("path"), 1);
58672
+ var import_promises13 = __toESM(require("fs/promises"), 1);
58673
+ var import_node_path56 = __toESM(require("path"), 1);
58418
58674
  init_zod();
58419
58675
  var PublishedChannelsError = class extends Error {
58420
58676
  constructor(code, message) {
@@ -58444,7 +58700,7 @@ var PublishedChannelStore = class {
58444
58700
  this.channels.clear();
58445
58701
  let raw;
58446
58702
  try {
58447
- raw = await import_promises12.default.readFile(this.filePath, "utf8");
58703
+ raw = await import_promises13.default.readFile(this.filePath, "utf8");
58448
58704
  } catch (e) {
58449
58705
  if (e.code === "ENOENT") {
58450
58706
  this.loaded = true;
@@ -58513,15 +58769,15 @@ var PublishedChannelStore = class {
58513
58769
  )
58514
58770
  };
58515
58771
  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);
58772
+ await import_promises13.default.mkdir(import_node_path56.default.dirname(this.filePath), { recursive: true });
58773
+ await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
58774
+ await import_promises13.default.rename(tmp, this.filePath);
58519
58775
  }
58520
58776
  };
58521
58777
 
58522
58778
  // src/extension/bundle-cache.ts
58523
- var import_promises13 = __toESM(require("fs/promises"), 1);
58524
- var import_node_path56 = __toESM(require("path"), 1);
58779
+ var import_promises14 = __toESM(require("fs/promises"), 1);
58780
+ var import_node_path57 = __toESM(require("path"), 1);
58525
58781
  var BundleCache = class {
58526
58782
  constructor(rootDir) {
58527
58783
  this.rootDir = rootDir;
@@ -58529,17 +58785,17 @@ var BundleCache = class {
58529
58785
  rootDir;
58530
58786
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
58531
58787
  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`);
58788
+ await import_promises14.default.mkdir(this.rootDir, { recursive: true });
58789
+ const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
58534
58790
  const tmp = `${file}.tmp`;
58535
- await import_promises13.default.writeFile(tmp, buffer, { mode: 384 });
58536
- await import_promises13.default.rename(tmp, file);
58791
+ await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
58792
+ await import_promises14.default.rename(tmp, file);
58537
58793
  }
58538
58794
  /** Returns the bundle bytes, or null when the file doesn't exist. */
58539
58795
  async read(snapshotHash) {
58540
- const file = import_node_path56.default.join(this.rootDir, `${snapshotHash}.zip`);
58796
+ const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
58541
58797
  try {
58542
- return await import_promises13.default.readFile(file);
58798
+ return await import_promises14.default.readFile(file);
58543
58799
  } catch (e) {
58544
58800
  if (e.code === "ENOENT") return null;
58545
58801
  throw e;
@@ -58547,8 +58803,8 @@ var BundleCache = class {
58547
58803
  }
58548
58804
  /** Idempotent — missing file is not an error. */
58549
58805
  async delete(snapshotHash) {
58550
- const file = import_node_path56.default.join(this.rootDir, `${snapshotHash}.zip`);
58551
- await import_promises13.default.rm(file, { force: true });
58806
+ const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
58807
+ await import_promises14.default.rm(file, { force: true });
58552
58808
  }
58553
58809
  };
58554
58810
 
@@ -58570,24 +58826,24 @@ async function startDaemon(config) {
58570
58826
  sampling: logShippingCfg.sampling,
58571
58827
  homeDir: import_node_os22.default.homedir()
58572
58828
  });
58573
- const logDir = import_node_path57.default.join(config.dataDir, "log");
58829
+ const logDir = import_node_path58.default.join(config.dataDir, "log");
58574
58830
  import_node_fs45.default.mkdirSync(logDir, { recursive: true });
58575
58831
  const logger = createLogger({
58576
58832
  level: config.logLevel,
58577
- file: import_node_path57.default.join(logDir, "clawd.log"),
58833
+ file: import_node_path58.default.join(logDir, "clawd.log"),
58578
58834
  logClient
58579
58835
  });
58580
58836
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
58581
58837
  const screenIdleProbeLogger = createFileOnlyLogger({
58582
- file: import_node_path57.default.join(logDir, "screen-idle-probe.log"),
58838
+ file: import_node_path58.default.join(logDir, "screen-idle-probe.log"),
58583
58839
  level: "debug"
58584
58840
  });
58585
58841
  logger.info("screen-idle probe logger enabled", {
58586
- file: import_node_path57.default.join(logDir, "screen-idle-probe.log")
58842
+ file: import_node_path58.default.join(logDir, "screen-idle-probe.log")
58587
58843
  });
58588
58844
  const CAP_TARGETS = [
58589
- import_node_path57.default.join(logDir, "clawd.log"),
58590
- import_node_path57.default.join(logDir, "screen-idle-probe.log")
58845
+ import_node_path58.default.join(logDir, "clawd.log"),
58846
+ import_node_path58.default.join(logDir, "screen-idle-probe.log")
58591
58847
  ];
58592
58848
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
58593
58849
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -58741,8 +58997,8 @@ async function startDaemon(config) {
58741
58997
  const agents = new AgentsScanner();
58742
58998
  const history = new ClaudeHistoryReader();
58743
58999
  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");
59000
+ const personaStore = new PersonaStore(import_node_path58.default.join(config.dataDir, "personas"));
59001
+ const usersRoot = import_node_path58.default.join(config.dataDir, "users");
58746
59002
  const defaultsRoot = findDefaultsRoot(logger);
58747
59003
  if (defaultsRoot) {
58748
59004
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -58761,18 +59017,33 @@ async function startDaemon(config) {
58761
59017
  migrateAgentsMirror({ store: personaStore, logger });
58762
59018
  migrateCodexSandbox({ store: personaStore, logger });
58763
59019
  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));
59020
+ const dispatchStore = createDispatchStore({
59021
+ filePath: import_node_path58.default.join(config.dataDir, "dispatch.json"),
59022
+ now: () => Date.now(),
59023
+ onFlushError: (err) => logger.error("dispatch store flush failed", {
59024
+ reason: err instanceof Error ? err.message : String(err)
59025
+ })
59026
+ });
59027
+ await dispatchStore.load();
59028
+ dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
59029
+ let deliverPendingRef;
59030
+ const personaDispatchManager = new PersonaDispatchManager({
59031
+ genId: () => v4_default(),
59032
+ store: dispatchStore,
59033
+ now: () => Date.now(),
59034
+ onCompleted: (sid) => deliverPendingRef?.(sid)
59035
+ });
59036
+ const here = typeof __dirname === "string" ? __dirname : import_node_path58.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
58766
59037
  const mcpConfigs = [];
58767
59038
  const dispatchServerCandidates = [
58768
- import_node_path57.default.join(here, "dispatch", "mcp-server.cjs"),
59039
+ import_node_path58.default.join(here, "dispatch", "mcp-server.cjs"),
58769
59040
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
58770
- import_node_path57.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
59041
+ import_node_path58.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
58771
59042
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
58772
59043
  ];
58773
59044
  const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
58774
59045
  if (dispatchServerScriptPath) {
58775
- const dispatchLogPath = import_node_path57.default.join(logDir, "dispatch-mcp-server.log");
59046
+ const dispatchLogPath = import_node_path58.default.join(logDir, "dispatch-mcp-server.log");
58776
59047
  const dispatchCfgPath = writeDispatchMcpConfig({
58777
59048
  dataDir: config.dataDir,
58778
59049
  serverScriptPath: dispatchServerScriptPath,
@@ -58790,12 +59061,12 @@ async function startDaemon(config) {
58790
59061
  });
58791
59062
  }
58792
59063
  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")
59064
+ import_node_path58.default.join(here, "ticket", "mcp-server.cjs"),
59065
+ import_node_path58.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
58795
59066
  ];
58796
59067
  const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
58797
59068
  if (ticketServerScriptPath) {
58798
- const ticketLogPath = import_node_path57.default.join(logDir, "ticket-mcp-server.log");
59069
+ const ticketLogPath = import_node_path58.default.join(logDir, "ticket-mcp-server.log");
58799
59070
  const ticketCfgPath = writeTicketMcpConfig({
58800
59071
  dataDir: config.dataDir,
58801
59072
  serverScriptPath: ticketServerScriptPath,
@@ -58815,12 +59086,12 @@ async function startDaemon(config) {
58815
59086
  });
58816
59087
  }
58817
59088
  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")
59089
+ import_node_path58.default.join(here, "shift", "mcp-server.cjs"),
59090
+ import_node_path58.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
58820
59091
  ];
58821
59092
  const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
58822
59093
  if (shiftServerScriptPath) {
58823
- const shiftLogPath = import_node_path57.default.join(logDir, "shift-mcp-server.log");
59094
+ const shiftLogPath = import_node_path58.default.join(logDir, "shift-mcp-server.log");
58824
59095
  const shiftCfgPath = await writeShiftMcpConfig({
58825
59096
  dataDir: config.dataDir,
58826
59097
  serverScriptPath: shiftServerScriptPath,
@@ -58839,12 +59110,12 @@ async function startDaemon(config) {
58839
59110
  );
58840
59111
  }
58841
59112
  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")
59113
+ import_node_path58.default.join(here, "inbox", "mcp-server.cjs"),
59114
+ import_node_path58.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
58844
59115
  ];
58845
59116
  const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
58846
59117
  if (inboxServerScriptPath) {
58847
- const inboxLogPath = import_node_path57.default.join(logDir, "inbox-mcp-server.log");
59118
+ const inboxLogPath = import_node_path58.default.join(logDir, "inbox-mcp-server.log");
58848
59119
  const inboxCfgPath = await writeInboxMcpConfig({
58849
59120
  dataDir: config.dataDir,
58850
59121
  serverScriptPath: inboxServerScriptPath,
@@ -58863,8 +59134,8 @@ async function startDaemon(config) {
58863
59134
  );
58864
59135
  }
58865
59136
  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")
59137
+ import_node_path58.default.join(here, "peer-ops", "mcp-server.cjs"),
59138
+ import_node_path58.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
58868
59139
  ];
58869
59140
  const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
58870
59141
  if (peerOpsServerScriptPath) {
@@ -58884,7 +59155,7 @@ async function startDaemon(config) {
58884
59155
  );
58885
59156
  }
58886
59157
  const shiftStore = createShiftStore({
58887
- filePath: import_node_path57.default.join(config.dataDir, "shift.json"),
59158
+ filePath: import_node_path58.default.join(config.dataDir, "shift.json"),
58888
59159
  ownerIdProvider: () => ownerPrincipalId,
58889
59160
  now: () => Date.now()
58890
59161
  });
@@ -58906,7 +59177,7 @@ async function startDaemon(config) {
58906
59177
  getAdapter,
58907
59178
  historyReader: history,
58908
59179
  dataDir: config.dataDir,
58909
- personaRoot: import_node_path57.default.join(config.dataDir, "personas"),
59180
+ personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
58910
59181
  usersRoot,
58911
59182
  personaStore,
58912
59183
  ownerDisplayName,
@@ -58922,6 +59193,8 @@ async function startDaemon(config) {
58922
59193
  // Persona dispatch (Task 8): manager.createDispatchedSession 用 personaDispatchManager
58923
59194
  // registerBSession;reducer 通过闭包反查 dispatchId 注 CLAWD_DISPATCH_ID env。
58924
59195
  personaDispatchManager,
59196
+ // Dispatch 结果投递:deliverPending 查台账 + turn-end sweep(spec 2026-07-20 §5)。
59197
+ dispatchStore,
58925
59198
  // daemon 级 MCP server 登记表(dispatch / ticket / shift / inbox / ...,上方各 writer
58926
59199
  // 块写盘成功即登记);reducer 透传到 SpawnContext.mcpConfigs,cc spawn 逐项 --mcp-config。
58927
59200
  mcpConfigs,
@@ -58944,7 +59217,7 @@ async function startDaemon(config) {
58944
59217
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
58945
59218
  attachmentGroup: {
58946
59219
  onFileEdit: (input) => {
58947
- const absPath = import_node_path57.default.isAbsolute(input.relPath) ? input.relPath : import_node_path57.default.join(input.cwd, input.relPath);
59220
+ const absPath = import_node_path58.default.isAbsolute(input.relPath) ? input.relPath : import_node_path58.default.join(input.cwd, input.relPath);
58948
59221
  let size = 0;
58949
59222
  try {
58950
59223
  size = import_node_fs45.default.statSync(absPath).size;
@@ -59010,6 +59283,7 @@ async function startDaemon(config) {
59010
59283
  }
59011
59284
  });
59012
59285
  manager.attachObserver(observer);
59286
+ deliverPendingRef = (sid) => manager.deliverPending(sid);
59013
59287
  const claudeAdapter = config.mode === "tui" ? new ClaudeTuiAdapter({
59014
59288
  logger,
59015
59289
  historyReader: new ClaudeHistoryReader(),
@@ -59176,11 +59450,11 @@ async function startDaemon(config) {
59176
59450
  // 'persona/<pid>/owner',default 走 'default'。
59177
59451
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
59178
59452
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
59179
- personaRoot: import_node_path57.default.join(config.dataDir, "personas"),
59453
+ personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
59180
59454
  usersRoot
59181
59455
  },
59182
59456
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
59183
- personaRoot: import_node_path57.default.join(config.dataDir, "personas"),
59457
+ personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
59184
59458
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
59185
59459
  usersRoot,
59186
59460
  // capability:list / delete handler 依赖
@@ -59291,11 +59565,11 @@ async function startDaemon(config) {
59291
59565
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
59292
59566
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
59293
59567
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
59294
- appBuilderPersonaRoot: import_node_path57.default.join(config.dataDir, "personas", "persona-app-builder"),
59568
+ appBuilderPersonaRoot: import_node_path58.default.join(config.dataDir, "personas", "persona-app-builder"),
59295
59569
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
59296
- deployKitRoot: import_node_path57.default.join(config.dataDir, "deploy-kit"),
59570
+ deployKitRoot: import_node_path58.default.join(config.dataDir, "deploy-kit"),
59297
59571
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
59298
- resolvePersonaRoot: (personaId) => import_node_path57.default.join(config.dataDir, "personas", personaId),
59572
+ resolvePersonaRoot: (personaId) => import_node_path58.default.join(config.dataDir, "personas", personaId),
59299
59573
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
59300
59574
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
59301
59575
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -59325,6 +59599,7 @@ async function startDaemon(config) {
59325
59599
  let handlers = makeHandlers();
59326
59600
  const dispatchHandlers = buildPersonaDispatchHandlers({
59327
59601
  personaDispatchManager,
59602
+ store: dispatchStore,
59328
59603
  logger,
59329
59604
  spawnB: async (args) => {
59330
59605
  logger.info("dispatch.spawnB.start", {
@@ -59338,7 +59613,7 @@ async function startDaemon(config) {
59338
59613
  }
59339
59614
  let sourceJsonlPath = "(no transcript yet \u2014 operate from the task description alone)";
59340
59615
  if (sourceFile && sourceFile.toolSessionId) {
59341
- sourceJsonlPath = import_node_path57.default.join(
59616
+ sourceJsonlPath = import_node_path58.default.join(
59342
59617
  import_node_os22.default.homedir(),
59343
59618
  ".claude",
59344
59619
  "projects",
@@ -59656,8 +59931,8 @@ async function startDaemon(config) {
59656
59931
  const lines = [
59657
59932
  `Tunnel: ${r.url}`,
59658
59933
  ...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")}`
59934
+ `Frpc config: ${import_node_path58.default.join(config.dataDir, "frpc.toml")}`,
59935
+ `Frpc log: ${import_node_path58.default.join(logDir, "frpc.log")}`
59661
59936
  ];
59662
59937
  const width = Math.max(...lines.map((l) => l.length));
59663
59938
  const bar = "\u2550".repeat(width + 4);
@@ -59670,7 +59945,7 @@ ${bar}
59670
59945
 
59671
59946
  `);
59672
59947
  try {
59673
- const connectPath = import_node_path57.default.join(config.dataDir, "connect.txt");
59948
+ const connectPath = import_node_path58.default.join(config.dataDir, "connect.txt");
59674
59949
  import_node_fs45.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
59675
59950
  } catch {
59676
59951
  }
@@ -59743,7 +60018,7 @@ ${bar}
59743
60018
  };
59744
60019
  }
59745
60020
  function migrateDropPersonsDir(dataDir) {
59746
- const dir = import_node_path57.default.join(dataDir, "persons");
60021
+ const dir = import_node_path58.default.join(dataDir, "persons");
59747
60022
  try {
59748
60023
  import_node_fs45.default.rmSync(dir, { recursive: true, force: true });
59749
60024
  } catch {