@clawos-dev/clawd 0.2.249 → 0.2.251

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: path71, errorMaps, issueData } = params;
755
- const fullPath = [...path71, ...issueData.path || []];
754
+ const { data, path: path74, errorMaps, issueData } = params;
755
+ const fullPath = [...path74, ...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, path71, key) {
1066
+ constructor(parent, value, path74, key) {
1067
1067
  this._cachedPath = [];
1068
1068
  this.parent = parent;
1069
1069
  this.data = value;
1070
- this._path = path71;
1070
+ this._path = path74;
1071
1071
  this._key = key;
1072
1072
  }
1073
1073
  get path() {
@@ -6213,7 +6213,12 @@ var init_dispatch = __esm({
6213
6213
  })
6214
6214
  ]);
6215
6215
  DispatchRunArgsSchema = external_exports.object({
6216
- targetPersona: external_exports.string().min(1),
6216
+ // 新开必填;续派(dispatchId 非空)时可省略——targetPersonaId 从台账行取。
6217
+ targetPersona: external_exports.string().min(1).optional(),
6218
+ // 续派(spec 2026-07-21,单 dispatchId 语义:一件事一行一 id):非空 = 把 prompt
6219
+ // 作为新 turn 打进该 dispatch 的原 worker session 接着干(台账行复位 running)。
6220
+ // 省略 = 新开一件事,daemon 铸新 id。
6221
+ dispatchId: external_exports.string().min(1).optional(),
6217
6222
  prompt: external_exports.string(),
6218
6223
  // 跨设备 dispatch:非空 = A 角色,转发到该 contact deviceId 的 peer daemon;
6219
6224
  // 省略 = 本地 dispatch / B 角色本地执行。A 转发给 B 时 body 不带此字段。
@@ -6223,6 +6228,10 @@ var init_dispatch = __esm({
6223
6228
  // tools/claude.ts CLAUDE_MODEL_IDS);handler 层做二次校验,非法值 fail-fast。
6224
6229
  // protocol 层保持 string 便于未来跨 tool 扩展(届时 union 收合法字面量)。
6225
6230
  model: external_exports.string().min(1).optional()
6231
+ }).refine((v2) => v2.targetPersona !== void 0 || v2.dispatchId !== void 0, {
6232
+ message: "either targetPersona (new dispatch) or dispatchId (follow-up) is required"
6233
+ }).refine((v2) => !(v2.dispatchId !== void 0 && v2.targetDeviceId !== void 0), {
6234
+ message: "cross-device dispatch cannot be continued (dispatchId + targetDeviceId are mutually exclusive)"
6226
6235
  });
6227
6236
  DispatchCompleteArgsSchema = external_exports.object({
6228
6237
  dispatchId: external_exports.string().min(1),
@@ -6606,8 +6615,8 @@ var require_req = __commonJS({
6606
6615
  if (req.originalUrl) {
6607
6616
  _req.url = req.originalUrl;
6608
6617
  } else {
6609
- const path71 = req.path;
6610
- _req.url = typeof path71 === "string" ? path71 : req.url ? req.url.path || req.url : void 0;
6618
+ const path74 = req.path;
6619
+ _req.url = typeof path74 === "string" ? path74 : req.url ? req.url.path || req.url : void 0;
6611
6620
  }
6612
6621
  if (req.query) {
6613
6622
  _req.query = req.query;
@@ -6772,14 +6781,14 @@ var require_redact = __commonJS({
6772
6781
  }
6773
6782
  return obj;
6774
6783
  }
6775
- function parsePath(path71) {
6784
+ function parsePath(path74) {
6776
6785
  const parts = [];
6777
6786
  let current = "";
6778
6787
  let inBrackets = false;
6779
6788
  let inQuotes = false;
6780
6789
  let quoteChar = "";
6781
- for (let i = 0; i < path71.length; i++) {
6782
- const char = path71[i];
6790
+ for (let i = 0; i < path74.length; i++) {
6791
+ const char = path74[i];
6783
6792
  if (!inBrackets && char === ".") {
6784
6793
  if (current) {
6785
6794
  parts.push(current);
@@ -6910,10 +6919,10 @@ var require_redact = __commonJS({
6910
6919
  return current;
6911
6920
  }
6912
6921
  function redactPaths(obj, paths, censor, remove = false) {
6913
- for (const path71 of paths) {
6914
- const parts = parsePath(path71);
6922
+ for (const path74 of paths) {
6923
+ const parts = parsePath(path74);
6915
6924
  if (parts.includes("*")) {
6916
- redactWildcardPath(obj, parts, censor, path71, remove);
6925
+ redactWildcardPath(obj, parts, censor, path74, remove);
6917
6926
  } else {
6918
6927
  if (remove) {
6919
6928
  removeKey(obj, parts);
@@ -6998,8 +7007,8 @@ var require_redact = __commonJS({
6998
7007
  }
6999
7008
  } else {
7000
7009
  if (afterWildcard.includes("*")) {
7001
- const wrappedCensor = typeof censor === "function" ? (value, path71) => {
7002
- const fullPath = [...pathArray.slice(0, pathLength), ...path71];
7010
+ const wrappedCensor = typeof censor === "function" ? (value, path74) => {
7011
+ const fullPath = [...pathArray.slice(0, pathLength), ...path74];
7003
7012
  return censor(value, fullPath);
7004
7013
  } : censor;
7005
7014
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -7034,8 +7043,8 @@ var require_redact = __commonJS({
7034
7043
  return null;
7035
7044
  }
7036
7045
  const pathStructure = /* @__PURE__ */ new Map();
7037
- for (const path71 of pathsToClone) {
7038
- const parts = parsePath(path71);
7046
+ for (const path74 of pathsToClone) {
7047
+ const parts = parsePath(path74);
7039
7048
  let current = pathStructure;
7040
7049
  for (let i = 0; i < parts.length; i++) {
7041
7050
  const part = parts[i];
@@ -7087,24 +7096,24 @@ var require_redact = __commonJS({
7087
7096
  }
7088
7097
  return cloneSelectively(obj, pathStructure);
7089
7098
  }
7090
- function validatePath(path71) {
7091
- if (typeof path71 !== "string") {
7099
+ function validatePath(path74) {
7100
+ if (typeof path74 !== "string") {
7092
7101
  throw new Error("Paths must be (non-empty) strings");
7093
7102
  }
7094
- if (path71 === "") {
7103
+ if (path74 === "") {
7095
7104
  throw new Error("Invalid redaction path ()");
7096
7105
  }
7097
- if (path71.includes("..")) {
7098
- throw new Error(`Invalid redaction path (${path71})`);
7106
+ if (path74.includes("..")) {
7107
+ throw new Error(`Invalid redaction path (${path74})`);
7099
7108
  }
7100
- if (path71.includes(",")) {
7101
- throw new Error(`Invalid redaction path (${path71})`);
7109
+ if (path74.includes(",")) {
7110
+ throw new Error(`Invalid redaction path (${path74})`);
7102
7111
  }
7103
7112
  let bracketCount = 0;
7104
7113
  let inQuotes = false;
7105
7114
  let quoteChar = "";
7106
- for (let i = 0; i < path71.length; i++) {
7107
- const char = path71[i];
7115
+ for (let i = 0; i < path74.length; i++) {
7116
+ const char = path74[i];
7108
7117
  if ((char === '"' || char === "'") && bracketCount > 0) {
7109
7118
  if (!inQuotes) {
7110
7119
  inQuotes = true;
@@ -7118,20 +7127,20 @@ var require_redact = __commonJS({
7118
7127
  } else if (char === "]" && !inQuotes) {
7119
7128
  bracketCount--;
7120
7129
  if (bracketCount < 0) {
7121
- throw new Error(`Invalid redaction path (${path71})`);
7130
+ throw new Error(`Invalid redaction path (${path74})`);
7122
7131
  }
7123
7132
  }
7124
7133
  }
7125
7134
  if (bracketCount !== 0) {
7126
- throw new Error(`Invalid redaction path (${path71})`);
7135
+ throw new Error(`Invalid redaction path (${path74})`);
7127
7136
  }
7128
7137
  }
7129
7138
  function validatePaths(paths) {
7130
7139
  if (!Array.isArray(paths)) {
7131
7140
  throw new TypeError("paths must be an array");
7132
7141
  }
7133
- for (const path71 of paths) {
7134
- validatePath(path71);
7142
+ for (const path74 of paths) {
7143
+ validatePath(path74);
7135
7144
  }
7136
7145
  }
7137
7146
  function slowRedact(options = {}) {
@@ -7299,8 +7308,8 @@ var require_redaction = __commonJS({
7299
7308
  if (shape[k2] === null) {
7300
7309
  o[k2] = (value) => topCensor(value, [k2]);
7301
7310
  } else {
7302
- const wrappedCensor = typeof censor === "function" ? (value, path71) => {
7303
- return censor(value, [k2, ...path71]);
7311
+ const wrappedCensor = typeof censor === "function" ? (value, path74) => {
7312
+ return censor(value, [k2, ...path74]);
7304
7313
  } : censor;
7305
7314
  o[k2] = Redact({
7306
7315
  paths: shape[k2],
@@ -7518,10 +7527,10 @@ var require_atomic_sleep = __commonJS({
7518
7527
  var require_sonic_boom = __commonJS({
7519
7528
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
7520
7529
  "use strict";
7521
- var fs65 = require("fs");
7530
+ var fs66 = require("fs");
7522
7531
  var EventEmitter3 = require("events");
7523
7532
  var inherits = require("util").inherits;
7524
- var path71 = require("path");
7533
+ var path74 = require("path");
7525
7534
  var sleep2 = require_atomic_sleep();
7526
7535
  var assert = require("assert");
7527
7536
  var BUSY_WRITE_TIMEOUT = 100;
@@ -7575,20 +7584,20 @@ var require_sonic_boom = __commonJS({
7575
7584
  const mode = sonic.mode;
7576
7585
  if (sonic.sync) {
7577
7586
  try {
7578
- if (sonic.mkdir) fs65.mkdirSync(path71.dirname(file), { recursive: true });
7579
- const fd = fs65.openSync(file, flags, mode);
7587
+ if (sonic.mkdir) fs66.mkdirSync(path74.dirname(file), { recursive: true });
7588
+ const fd = fs66.openSync(file, flags, mode);
7580
7589
  fileOpened(null, fd);
7581
7590
  } catch (err) {
7582
7591
  fileOpened(err);
7583
7592
  throw err;
7584
7593
  }
7585
7594
  } else if (sonic.mkdir) {
7586
- fs65.mkdir(path71.dirname(file), { recursive: true }, (err) => {
7595
+ fs66.mkdir(path74.dirname(file), { recursive: true }, (err) => {
7587
7596
  if (err) return fileOpened(err);
7588
- fs65.open(file, flags, mode, fileOpened);
7597
+ fs66.open(file, flags, mode, fileOpened);
7589
7598
  });
7590
7599
  } else {
7591
- fs65.open(file, flags, mode, fileOpened);
7600
+ fs66.open(file, flags, mode, fileOpened);
7592
7601
  }
7593
7602
  }
7594
7603
  function SonicBoom(opts) {
@@ -7629,8 +7638,8 @@ var require_sonic_boom = __commonJS({
7629
7638
  this.flush = flushBuffer;
7630
7639
  this.flushSync = flushBufferSync;
7631
7640
  this._actualWrite = actualWriteBuffer;
7632
- fsWriteSync = () => fs65.writeSync(this.fd, this._writingBuf);
7633
- fsWrite = () => fs65.write(this.fd, this._writingBuf, this.release);
7641
+ fsWriteSync = () => fs66.writeSync(this.fd, this._writingBuf);
7642
+ fsWrite = () => fs66.write(this.fd, this._writingBuf, this.release);
7634
7643
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
7635
7644
  this._writingBuf = "";
7636
7645
  this.write = write;
@@ -7639,15 +7648,15 @@ var require_sonic_boom = __commonJS({
7639
7648
  this._actualWrite = actualWrite;
7640
7649
  fsWriteSync = () => {
7641
7650
  if (Buffer.isBuffer(this._writingBuf)) {
7642
- return fs65.writeSync(this.fd, this._writingBuf);
7651
+ return fs66.writeSync(this.fd, this._writingBuf);
7643
7652
  }
7644
- return fs65.writeSync(this.fd, this._writingBuf, "utf8");
7653
+ return fs66.writeSync(this.fd, this._writingBuf, "utf8");
7645
7654
  };
7646
7655
  fsWrite = () => {
7647
7656
  if (Buffer.isBuffer(this._writingBuf)) {
7648
- return fs65.write(this.fd, this._writingBuf, this.release);
7657
+ return fs66.write(this.fd, this._writingBuf, this.release);
7649
7658
  }
7650
- return fs65.write(this.fd, this._writingBuf, "utf8", this.release);
7659
+ return fs66.write(this.fd, this._writingBuf, "utf8", this.release);
7651
7660
  };
7652
7661
  } else {
7653
7662
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -7704,7 +7713,7 @@ var require_sonic_boom = __commonJS({
7704
7713
  }
7705
7714
  }
7706
7715
  if (this._fsync) {
7707
- fs65.fsyncSync(this.fd);
7716
+ fs66.fsyncSync(this.fd);
7708
7717
  }
7709
7718
  const len = this._len;
7710
7719
  if (this._reopening) {
@@ -7818,7 +7827,7 @@ var require_sonic_boom = __commonJS({
7818
7827
  const onDrain = () => {
7819
7828
  if (!this._fsync) {
7820
7829
  try {
7821
- fs65.fsync(this.fd, (err) => {
7830
+ fs66.fsync(this.fd, (err) => {
7822
7831
  this._flushPending = false;
7823
7832
  cb(err);
7824
7833
  });
@@ -7920,7 +7929,7 @@ var require_sonic_boom = __commonJS({
7920
7929
  const fd = this.fd;
7921
7930
  this.once("ready", () => {
7922
7931
  if (fd !== this.fd) {
7923
- fs65.close(fd, (err) => {
7932
+ fs66.close(fd, (err) => {
7924
7933
  if (err) {
7925
7934
  return this.emit("error", err);
7926
7935
  }
@@ -7969,7 +7978,7 @@ var require_sonic_boom = __commonJS({
7969
7978
  buf = this._bufs[0];
7970
7979
  }
7971
7980
  try {
7972
- const n = Buffer.isBuffer(buf) ? fs65.writeSync(this.fd, buf) : fs65.writeSync(this.fd, buf, "utf8");
7981
+ const n = Buffer.isBuffer(buf) ? fs66.writeSync(this.fd, buf) : fs66.writeSync(this.fd, buf, "utf8");
7973
7982
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
7974
7983
  buf = releasedBufObj.writingBuf;
7975
7984
  this._len = releasedBufObj.len;
@@ -7985,7 +7994,7 @@ var require_sonic_boom = __commonJS({
7985
7994
  }
7986
7995
  }
7987
7996
  try {
7988
- fs65.fsyncSync(this.fd);
7997
+ fs66.fsyncSync(this.fd);
7989
7998
  } catch {
7990
7999
  }
7991
8000
  }
@@ -8006,7 +8015,7 @@ var require_sonic_boom = __commonJS({
8006
8015
  buf = mergeBuf(this._bufs[0], this._lens[0]);
8007
8016
  }
8008
8017
  try {
8009
- const n = fs65.writeSync(this.fd, buf);
8018
+ const n = fs66.writeSync(this.fd, buf);
8010
8019
  buf = buf.subarray(n);
8011
8020
  this._len = Math.max(this._len - n, 0);
8012
8021
  if (buf.length <= 0) {
@@ -8034,13 +8043,13 @@ var require_sonic_boom = __commonJS({
8034
8043
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
8035
8044
  if (this.sync) {
8036
8045
  try {
8037
- const written = Buffer.isBuffer(this._writingBuf) ? fs65.writeSync(this.fd, this._writingBuf) : fs65.writeSync(this.fd, this._writingBuf, "utf8");
8046
+ const written = Buffer.isBuffer(this._writingBuf) ? fs66.writeSync(this.fd, this._writingBuf) : fs66.writeSync(this.fd, this._writingBuf, "utf8");
8038
8047
  release(null, written);
8039
8048
  } catch (err) {
8040
8049
  release(err);
8041
8050
  }
8042
8051
  } else {
8043
- fs65.write(this.fd, this._writingBuf, release);
8052
+ fs66.write(this.fd, this._writingBuf, release);
8044
8053
  }
8045
8054
  }
8046
8055
  function actualWriteBuffer() {
@@ -8049,7 +8058,7 @@ var require_sonic_boom = __commonJS({
8049
8058
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
8050
8059
  if (this.sync) {
8051
8060
  try {
8052
- const written = fs65.writeSync(this.fd, this._writingBuf);
8061
+ const written = fs66.writeSync(this.fd, this._writingBuf);
8053
8062
  release(null, written);
8054
8063
  } catch (err) {
8055
8064
  release(err);
@@ -8058,7 +8067,7 @@ var require_sonic_boom = __commonJS({
8058
8067
  if (kCopyBuffer) {
8059
8068
  this._writingBuf = Buffer.from(this._writingBuf);
8060
8069
  }
8061
- fs65.write(this.fd, this._writingBuf, release);
8070
+ fs66.write(this.fd, this._writingBuf, release);
8062
8071
  }
8063
8072
  }
8064
8073
  function actualClose(sonic) {
@@ -8074,12 +8083,12 @@ var require_sonic_boom = __commonJS({
8074
8083
  sonic._lens = [];
8075
8084
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
8076
8085
  try {
8077
- fs65.fsync(sonic.fd, closeWrapped);
8086
+ fs66.fsync(sonic.fd, closeWrapped);
8078
8087
  } catch {
8079
8088
  }
8080
8089
  function closeWrapped() {
8081
8090
  if (sonic.fd !== 1 && sonic.fd !== 2) {
8082
- fs65.close(sonic.fd, done);
8091
+ fs66.close(sonic.fd, done);
8083
8092
  } else {
8084
8093
  done();
8085
8094
  }
@@ -11214,11 +11223,11 @@ var init_lib = __esm({
11214
11223
  }
11215
11224
  }
11216
11225
  },
11217
- addToPath: function addToPath(path71, added, removed, oldPosInc, options) {
11218
- var last = path71.lastComponent;
11226
+ addToPath: function addToPath(path74, added, removed, oldPosInc, options) {
11227
+ var last = path74.lastComponent;
11219
11228
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
11220
11229
  return {
11221
- oldPos: path71.oldPos + oldPosInc,
11230
+ oldPos: path74.oldPos + oldPosInc,
11222
11231
  lastComponent: {
11223
11232
  count: last.count + 1,
11224
11233
  added,
@@ -11228,7 +11237,7 @@ var init_lib = __esm({
11228
11237
  };
11229
11238
  } else {
11230
11239
  return {
11231
- oldPos: path71.oldPos + oldPosInc,
11240
+ oldPos: path74.oldPos + oldPosInc,
11232
11241
  lastComponent: {
11233
11242
  count: 1,
11234
11243
  added,
@@ -11737,10 +11746,10 @@ function attachmentToHistoryMessage(o, ts) {
11737
11746
  const memories = raw.map((m2) => {
11738
11747
  if (!m2 || typeof m2 !== "object") return null;
11739
11748
  const rec3 = m2;
11740
- const path71 = typeof rec3.path === "string" ? rec3.path : null;
11749
+ const path74 = typeof rec3.path === "string" ? rec3.path : null;
11741
11750
  const content = typeof rec3.content === "string" ? rec3.content : null;
11742
- if (!path71 || content == null) return null;
11743
- const entry = { path: path71, content };
11751
+ if (!path74 || content == null) return null;
11752
+ const entry = { path: path74, content };
11744
11753
  if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
11745
11754
  return entry;
11746
11755
  }).filter((m2) => m2 !== null);
@@ -12543,10 +12552,10 @@ function parseAttachment(obj) {
12543
12552
  const memories = raw.map((m2) => {
12544
12553
  if (!m2 || typeof m2 !== "object") return null;
12545
12554
  const rec3 = m2;
12546
- const path71 = typeof rec3.path === "string" ? rec3.path : null;
12555
+ const path74 = typeof rec3.path === "string" ? rec3.path : null;
12547
12556
  const content = typeof rec3.content === "string" ? rec3.content : null;
12548
- if (!path71 || content == null) return null;
12549
- const out = { path: path71, content };
12557
+ if (!path74 || content == null) return null;
12558
+ const out = { path: path74, content };
12550
12559
  if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
12551
12560
  return out;
12552
12561
  }).filter((m2) => m2 !== null);
@@ -33515,8 +33524,8 @@ var require_utils = __commonJS({
33515
33524
  var result = transform[inputType][outputType](input);
33516
33525
  return result;
33517
33526
  };
33518
- exports2.resolve = function(path71) {
33519
- var parts = path71.split("/");
33527
+ exports2.resolve = function(path74) {
33528
+ var parts = path74.split("/");
33520
33529
  var result = [];
33521
33530
  for (var index = 0; index < parts.length; index++) {
33522
33531
  var part = parts[index];
@@ -39369,18 +39378,18 @@ var require_object = __commonJS({
39369
39378
  var object = new ZipObject(name, zipObjectContent, o);
39370
39379
  this.files[name] = object;
39371
39380
  };
39372
- var parentFolder = function(path71) {
39373
- if (path71.slice(-1) === "/") {
39374
- path71 = path71.substring(0, path71.length - 1);
39381
+ var parentFolder = function(path74) {
39382
+ if (path74.slice(-1) === "/") {
39383
+ path74 = path74.substring(0, path74.length - 1);
39375
39384
  }
39376
- var lastSlash = path71.lastIndexOf("/");
39377
- return lastSlash > 0 ? path71.substring(0, lastSlash) : "";
39385
+ var lastSlash = path74.lastIndexOf("/");
39386
+ return lastSlash > 0 ? path74.substring(0, lastSlash) : "";
39378
39387
  };
39379
- var forceTrailingSlash = function(path71) {
39380
- if (path71.slice(-1) !== "/") {
39381
- path71 += "/";
39388
+ var forceTrailingSlash = function(path74) {
39389
+ if (path74.slice(-1) !== "/") {
39390
+ path74 += "/";
39382
39391
  }
39383
- return path71;
39392
+ return path74;
39384
39393
  };
39385
39394
  var folderAdd = function(name, createFolders) {
39386
39395
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -40382,7 +40391,7 @@ var require_lib3 = __commonJS({
40382
40391
  // src/run-case/recorder.ts
40383
40392
  function startRunCaseRecorder(opts) {
40384
40393
  const now = opts.now ?? Date.now;
40385
- const dir = import_node_path59.default.dirname(opts.recordPath);
40394
+ const dir = import_node_path62.default.dirname(opts.recordPath);
40386
40395
  let stream = null;
40387
40396
  let closing = false;
40388
40397
  let closedSettled = false;
@@ -40396,8 +40405,8 @@ function startRunCaseRecorder(opts) {
40396
40405
  });
40397
40406
  const ensureStream = () => {
40398
40407
  if (stream) return stream;
40399
- import_node_fs46.default.mkdirSync(dir, { recursive: true });
40400
- stream = import_node_fs46.default.createWriteStream(opts.recordPath, { flags: "a" });
40408
+ import_node_fs47.default.mkdirSync(dir, { recursive: true });
40409
+ stream = import_node_fs47.default.createWriteStream(opts.recordPath, { flags: "a" });
40401
40410
  stream.on("close", () => closedResolve());
40402
40411
  return stream;
40403
40412
  };
@@ -40422,12 +40431,12 @@ function startRunCaseRecorder(opts) {
40422
40431
  };
40423
40432
  return { tap, close, closed };
40424
40433
  }
40425
- var import_node_fs46, import_node_path59;
40434
+ var import_node_fs47, import_node_path62;
40426
40435
  var init_recorder = __esm({
40427
40436
  "src/run-case/recorder.ts"() {
40428
40437
  "use strict";
40429
- import_node_fs46 = __toESM(require("fs"), 1);
40430
- import_node_path59 = __toESM(require("path"), 1);
40438
+ import_node_fs47 = __toESM(require("fs"), 1);
40439
+ import_node_path62 = __toESM(require("path"), 1);
40431
40440
  }
40432
40441
  });
40433
40442
 
@@ -40470,7 +40479,7 @@ var init_wire = __esm({
40470
40479
  // src/run-case/controller.ts
40471
40480
  async function runController(opts) {
40472
40481
  const now = opts.now ?? Date.now;
40473
- const cwd = opts.cwd ?? (0, import_node_fs47.mkdtempSync)(import_node_path60.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
40482
+ const cwd = opts.cwd ?? (0, import_node_fs48.mkdtempSync)(import_node_path63.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
40474
40483
  const ownsCwd = opts.cwd === void 0;
40475
40484
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
40476
40485
  const spawnCtx = { cwd };
@@ -40631,19 +40640,19 @@ async function runController(opts) {
40631
40640
  if (sigintHandler) process.off("SIGINT", sigintHandler);
40632
40641
  if (ownsCwd) {
40633
40642
  try {
40634
- (0, import_node_fs47.rmSync)(cwd, { recursive: true, force: true });
40643
+ (0, import_node_fs48.rmSync)(cwd, { recursive: true, force: true });
40635
40644
  } catch {
40636
40645
  }
40637
40646
  }
40638
40647
  return exitCode ?? 0;
40639
40648
  }
40640
- var import_node_fs47, import_node_os23, import_node_path60;
40649
+ var import_node_fs48, import_node_os23, import_node_path63;
40641
40650
  var init_controller = __esm({
40642
40651
  "src/run-case/controller.ts"() {
40643
40652
  "use strict";
40644
- import_node_fs47 = require("fs");
40653
+ import_node_fs48 = require("fs");
40645
40654
  import_node_os23 = __toESM(require("os"), 1);
40646
- import_node_path60 = __toESM(require("path"), 1);
40655
+ import_node_path63 = __toESM(require("path"), 1);
40647
40656
  init_claude();
40648
40657
  init_stdout_splitter();
40649
40658
  init_permission_stdio();
@@ -40905,8 +40914,8 @@ Env (advanced):
40905
40914
  `;
40906
40915
 
40907
40916
  // src/index.ts
40908
- var import_node_path58 = __toESM(require("path"), 1);
40909
- var import_node_fs45 = __toESM(require("fs"), 1);
40917
+ var import_node_path61 = __toESM(require("path"), 1);
40918
+ var import_node_fs46 = __toESM(require("fs"), 1);
40910
40919
  var import_node_os22 = __toESM(require("os"), 1);
40911
40920
 
40912
40921
  // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
@@ -41909,23 +41918,27 @@ var ATTACHMENT_SHARING_HINT = `## \u628A\u4EA7\u51FA\u6587\u4EF6\u5206\u4EAB\u7E
41909
41918
 
41910
41919
  - \`relPath\` \u5FC5\u987B\u4F20**\u7EDD\u5BF9\u8DEF\u5F84**\uFF08\u4F60\u4EA7\u51FA\u6587\u4EF6\u7684\u771F\u5B9E\u8DEF\u5F84\uFF09\uFF0C\u4E0D\u8981\u4F20\u76F8\u5BF9\u8DEF\u5F84\u3002
41911
41920
  - \u53EA\u80FD\u5206\u4EAB\u4F60\u81EA\u5DF1\u5DE5\u4F5C\u76EE\u5F55\u5185\u7684\u6587\u4EF6\uFF0C\u8D8A\u754C\u4F1A\u88AB\u62D2\u3002
41912
- - \u88AB dispatch \u63A5\u5230\u4EFB\u52A1\u3001\u8981\u56DE\u4F20\u4EA7\u7269\u65F6\uFF1A\u628A\u7B7E\u540D URL \u5199\u8FDB \`personaDispatchComplete\` \u7684 \`text\` \u91CC\uFF08\`filePaths\` \u53EA\u662F\u4F60\u672C\u673A\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u8DE8\u8BBE\u5907\u5BF9\u65B9\u6253\u4E0D\u5F00\uFF0CURL \u624D\u80FD\u6253\u5F00\uFF09\u3002`;
41921
+ - \u88AB dispatch \u63A5\u5230\u4EFB\u52A1\u3001\u8981\u56DE\u4F20\u4EA7\u7269\u65F6\uFF1A\u628A\u7B7E\u540D URL \u5199\u8FDB \`personaDispatchComplete\` tool\uFF08\`clawd-dispatch\` MCP\uFF09\u7684 \`text\` \u91CC\uFF08\`filePaths\` \u53EA\u662F\u4F60\u672C\u673A\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u8DE8\u8BBE\u5907\u5BF9\u65B9\u6253\u4E0D\u5F00\uFF0CURL \u624D\u80FD\u6253\u5F00\uFF09\u3002`;
41913
41922
 
41914
41923
  // src/dispatch/system-prompt.ts
41915
41924
  var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A persona\uFF08dispatch\uFF09
41916
41925
 
41917
- \u5F53\u7528\u6237\u6D88\u606F\u91CC\u542B \`@persona/<id>\`\uFF08\u5982 \`@persona/persona-app-builder\`\uFF09\u65F6\uFF0C**\u4F60\u5FC5\u987B**\u7ACB\u5373\u8C03 MCP tool \`mcp__clawd-dispatch__personaDispatch\` \u59D4\u6D3E\uFF0C\u4E0D\u8981\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF1A
41926
+ \u5F53\u7528\u6237\u6D88\u606F\u91CC\u542B \`@persona/<id>\`\uFF08\u5982 \`@persona/persona-app-builder\`\uFF09\u65F6\uFF0C**\u4F60\u5FC5\u987B**\u7ACB\u5373\u8C03 \`clawd-dispatch\` MCP server \u7684 \`personaDispatch\` tool \u59D4\u6D3E\uFF08\u5404 agent \u5BF9 MCP tool \u7684\u5C55\u793A\u540D\u4E0D\u540C\uFF0C\u5982 claude \u663E\u793A\u4E3A \`mcp__clawd-dispatch__personaDispatch\`\uFF1B\u6309\u4F60\u73AF\u5883\u91CC\u5B9E\u9645\u5217\u51FA\u7684\u540D\u5B57\u8C03\u7528\uFF09\uFF0C\u4E0D\u8981\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF1A
41918
41927
 
41919
41928
  - \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
41920
41929
  - \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
41921
41930
 
41922
- tool \u4F1A**\u7ACB\u5373\u8FD4\u56DE** dispatchId\uFF08\u5F02\u6B65\u59D4\u6D3E\uFF09\uFF0C\u5BF9\u65B9\u4EBA\u683C\u5728\u540E\u53F0\u5E72\u6D3B\u3002\u4F60\u544A\u8BC9\u7528\u6237"\u4EFB\u52A1\u5DF2\u4EA4\u529E"\u5373\u53EF\u7ED3\u675F\u672C\u8F6E\u2014\u2014**\u4E0D\u8981\u7B49\u5F85\u3001\u4E0D\u8981\u8F6E\u8BE2**\u3002\u5BF9\u65B9\u5E72\u5B8C\u540E\uFF0C\u7ED3\u679C\u4F1A\u4F5C\u4E3A\u4E00\u6761\u65B0\u6D88\u606F\u81EA\u52A8\u6CE8\u5165\u56DE\u4F60\u7684 session\uFF0C\u4F60\u5C4A\u65F6\u518D\u7EFC\u5408\u8F6C\u8FBE\u7ED9\u7528\u6237\u3002\u60F3\u67E5\u8FDB\u5C55\u65F6\uFF08\u7528\u6237\u95EE\u8D77\uFF09\u8C03 \`mcp__clawd-dispatch__personaDispatchList\`\u3002
41931
+ 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\u540C\u4E00 MCP \u7684 \`personaDispatchList\`\u3002
41923
41932
 
41924
41933
  - **\u4E0D\u8981**\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF08\u4F60\u4E0D\u662F\u90A3\u4E2A persona\uFF09
41925
41934
  - **\u4E0D\u8981** in-place \u6A21\u4EFF\u5BF9\u65B9\u4EBA\u683C \u2014\u2014 dispatch \u662F\u771F\u5207\u5230\u53E6\u4E00\u4E2A\u72EC\u7ACB session
41926
41935
  - \u4E00\u53E5\u8BDD\u91CC\u591A\u4E2A \`@persona/<id>\` \u65F6\u9009\u7B2C\u4E00\u4E2A\uFF08tool \u4E00\u6B21\u53EA\u5904\u7406\u4E00\u4E2A target\uFF09
41927
41936
  - \u59D4\u6D3E\u5931\u8D25\uFF08tool_result.is_error=true\uFF09\u65F6\u5982\u5B9E\u544A\u8BC9\u7528\u6237\u539F\u56E0\uFF0C**\u4E0D\u8981\u91CD\u8BD5**
41928
41937
 
41938
+ ### \u7EED\u6D3E\uFF08\u540C\u4E00\u4EF6\u4E8B\u7684\u540E\u7EED\u6307\u4EE4\uFF09
41939
+
41940
+ \u7528\u6237\u5BF9\u4E00\u4EF6**\u5DF2\u59D4\u6D3E**\u7684\u4E8B\u4E0B\u540E\u7EED\u6307\u4EE4\u65F6\uFF0C\u8C03 \`personaDispatch({ dispatchId: <\u8BE5\u4E8B\u7684 dispatchId>, prompt: <\u65B0\u6307\u4EE4> })\`\uFF08targetPersona \u53EF\u7701\u7565\uFF09\u2014\u2014\u65B0\u6307\u4EE4\u4F1A\u8FDB\u5165\u539F worker session \u63A5\u7740\u5E72\uFF0C\u4E0A\u4E0B\u6587\u4E0D\u4E22\u3002dispatchId \u7528\u4F60\u9996\u6B21\u59D4\u6D3E\u65F6\u62FF\u5230\u7684\u90A3\u4E2A\uFF1B\u4E0D\u786E\u5B9A\u662F\u54EA\u4EF6\u4E8B\u5C31\u5148\u8C03 \`personaDispatchList\` \u67E5\u3002
41941
+
41929
41942
  ### \u8DE8\u8BBE\u5907\u59D4\u6D3E\uFF08remote persona\uFF09
41930
41943
 
41931
41944
  \u5F53 @ token \u5F62\u5982 \`@persona/<id>@<deviceId>\`\uFF08\u7B2C\u4E8C\u6BB5\u662F\u8054\u7CFB\u4EBA**\u8BBE\u5907\u7684 deviceId**\uFF0CUI \u9009\u8054\u7CFB\u4EBA\u65F6\u5DF2\u89E3\u6790\u597D\u586B\u5165\uFF09\u65F6\uFF0C\u662F\u628A\u4EFB\u52A1\u59D4\u6D3E\u7ED9\u90A3\u53F0\u8BBE\u5907\u4E0A\u7684 persona\u3002\u9664 targetPersona / prompt \u5916\u518D\u5E26\u4E00\u4E2A\u53C2\u6570\uFF1A
@@ -41940,7 +41953,7 @@ deviceId \u76F4\u63A5\u53D6\u81EA token\uFF0C\u4E0D\u8981\u6539\u5199\u6216\u731
41940
41953
 
41941
41954
  - \u4EFB\u52A1\u5728 \`Task:\` \u6BB5
41942
41955
  - \u539F\u4F1A\u8BDD\u7684\u5BF9\u8BDD\u5386\u53F2\u5728 \`Source conversation\` \u6BB5\u7ED9\u7684 jsonl \u8DEF\u5F84\u4E0B\uFF1B\u6309\u9700 Read \u5B83\u4E86\u89E3\u4E0A\u4E0B\u6587\uFF08\u4E0D\u5FC5\u8BFB\u5B8C\uFF09
41943
- - \u5E72\u5B8C\u540E**\u5FC5\u987B**\u8C03 \`mcp__clawd-dispatch__personaDispatchComplete\` \u62A5\u544A\u7ED3\u679C\uFF1A
41956
+ - \u5E72\u5B8C\u540E**\u5FC5\u987B**\u8C03 \`clawd-dispatch\` MCP \u7684 \`personaDispatchComplete\` tool \u62A5\u544A\u7ED3\u679C\uFF1A
41944
41957
  - \u6210\u529F\uFF1A\`{ text: "\u603B\u7ED3/\u7ED3\u8BBA", filePaths?: ["\u4F60\u4EA7\u51FA/\u6539\u7684\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84"] }\`
41945
41958
  - \u5931\u8D25\uFF1A\`{ isFailure: true, reason: "..." }\`
41946
41959
  - \u62A5\u544A\u5B8C\u540E\u4F60\u7684 session \u5C31\u7ED3\u675F\u4E86\uFF0C\u4E0D\u8981\u7EE7\u7EED\u8F93\u51FA`;
@@ -43340,7 +43353,8 @@ Source conversation (jsonl, CC stream-json format, one message per line):
43340
43353
  ${args.sourceJsonlPath}
43341
43354
  You may read this file with your Read tool to understand context. You do not have to read it all.
43342
43355
 
43343
- When done, call the MCP tool \`mcp__clawd-dispatch__personaDispatchComplete\` with your result:
43356
+ When done, call the \`personaDispatchComplete\` tool from the \`clawd-dispatch\` MCP server with your result
43357
+ (tool display name varies by agent, e.g. \`mcp__clawd-dispatch__personaDispatchComplete\` in claude):
43344
43358
  - Success: { text: "...", filePaths?: ["abs/path", ...] }
43345
43359
  - Failure: { isFailure: true, reason: "..." }
43346
43360
 
@@ -43645,18 +43659,20 @@ var SessionManager = class {
43645
43659
  `newRunner: guest session ${file.sessionId} \u7F3A personaRoot/userWorkDir\uFF0C\u65E0\u6CD5\u7269\u5316 OS \u6C99\u7BB1\uFF08\u62D2\u7EDD\u521B\u5EFA\u65E0\u6C99\u7BB1 guest\uFF09`
43646
43660
  );
43647
43661
  }
43648
- const base = this.deps.personaStore?.readSandboxSettings(scope.personaId) ?? null;
43649
- const sandboxSettings = composeGuestSandbox(base, subSessionMeta.userWorkDir, file.cwd);
43650
- const ownerCreds = readOwnerCredentials(import_node_os5.default.homedir(), this.deps.logger);
43651
- const merged = mergeOwnerCredentials(sandboxSettings, ownerCreds);
43652
- if (ownerCreds) {
43653
- this.deps.logger?.info("owner credentials injected into guest spawn", {
43654
- sessionId: file.sessionId,
43655
- envKeys: ownerCreds.env ? Object.keys(ownerCreds.env) : [],
43656
- apiKeyHelper: ownerCreds.apiKeyHelper ? "present" : "absent"
43657
- });
43662
+ if ((file.tool ?? "claude") === "claude") {
43663
+ const base = this.deps.personaStore?.readSandboxSettings(scope.personaId) ?? null;
43664
+ const sandboxSettings = composeGuestSandbox(base, subSessionMeta.userWorkDir, file.cwd);
43665
+ const ownerCreds = readOwnerCredentials(import_node_os5.default.homedir(), this.deps.logger);
43666
+ const merged = mergeOwnerCredentials(sandboxSettings, ownerCreds);
43667
+ if (ownerCreds) {
43668
+ this.deps.logger?.info("owner credentials injected into guest spawn", {
43669
+ sessionId: file.sessionId,
43670
+ envKeys: ownerCreds.env ? Object.keys(ownerCreds.env) : [],
43671
+ apiKeyHelper: ownerCreds.apiKeyHelper ? "present" : "absent"
43672
+ });
43673
+ }
43674
+ subSessionMeta.extraSettings = JSON.stringify(merged);
43658
43675
  }
43659
- subSessionMeta.extraSettings = JSON.stringify(merged);
43660
43676
  const home = import_node_os5.default.homedir();
43661
43677
  const expand = (p2) => p2 === "~" ? home : p2.startsWith("~/") ? import_node_path9.default.join(home, p2.slice(2)) : p2;
43662
43678
  const codexCfg = this.deps.personaStore?.readCodexSandboxSettings(scope.personaId) ?? null;
@@ -44135,9 +44151,25 @@ var SessionManager = class {
44135
44151
  if (pending.length === 0) return;
44136
44152
  const state = this.tryGetState(sourceSessionId);
44137
44153
  if (state && compressStatus(state.status) === "running") return;
44154
+ if (!this.injectIntoSession(sourceSessionId, formatDeliveryText(pending))) return;
44155
+ const nowIso3 = new Date(this.deps.now?.() ?? Date.now()).toISOString();
44156
+ for (const r of pending) store.update(r.dispatchId, { deliveredAt: nowIso3 });
44157
+ this.deps.logger?.info("dispatch.deliver.ok", {
44158
+ sourceSessionId,
44159
+ count: pending.length,
44160
+ dispatchIds: pending.map((r) => r.dispatchId)
44161
+ });
44162
+ }
44163
+ /**
44164
+ * 把一段 plain text 以 owner sender 注入指定 session 当新 turn——dispatch 结果投递
44165
+ * (deliverPending)与续派任务包(handlers/persona-dispatch 经 sendFollowUp 闭包)共用。
44166
+ * session 文件不存在或 send 抛错 → false(记 log,不 throw)。直接 runner.input
44167
+ * (无 collector),frames 经 routeFromRunner 正常广播上 wire。
44168
+ */
44169
+ injectIntoSession(sessionId, text) {
44138
44170
  if (!this.deps.ownerPrincipalId) {
44139
- this.deps.logger?.warn("dispatch.deliver.no-owner-principal", { sourceSessionId });
44140
- return;
44171
+ this.deps.logger?.warn("dispatch.inject.no-owner-principal", { sessionId });
44172
+ return false;
44141
44173
  }
44142
44174
  const sender = principalToSender(
44143
44175
  makeOwnerPrincipal(
@@ -44147,34 +44179,24 @@ var SessionManager = class {
44147
44179
  )
44148
44180
  );
44149
44181
  try {
44150
- const file = this.findOwnedSession(sourceSessionId);
44182
+ const file = this.findOwnedSession(sessionId);
44151
44183
  if (!file) {
44152
- this.deps.logger?.info("dispatch.deliver.source-gone", { sourceSessionId });
44153
- return;
44184
+ this.deps.logger?.info("dispatch.inject.session-gone", { sessionId });
44185
+ return false;
44154
44186
  }
44155
44187
  const runner = this.ensureRunnerForScope(file, this.scopeForFile(file));
44156
44188
  runner.input({
44157
44189
  kind: "command",
44158
- command: {
44159
- kind: "send",
44160
- text: formatDeliveryText(pending),
44161
- senderPrincipal: sender
44162
- }
44190
+ command: { kind: "send", text, senderPrincipal: sender }
44163
44191
  });
44192
+ return true;
44164
44193
  } catch (err) {
44165
- this.deps.logger?.warn("dispatch.deliver.send-failed", {
44166
- sourceSessionId,
44194
+ this.deps.logger?.warn("dispatch.inject.send-failed", {
44195
+ sessionId,
44167
44196
  reason: err instanceof Error ? err.message : String(err)
44168
44197
  });
44169
- return;
44198
+ return false;
44170
44199
  }
44171
- const nowIso3 = new Date(this.deps.now?.() ?? Date.now()).toISOString();
44172
- for (const r of pending) store.update(r.dispatchId, { deliveredAt: nowIso3 });
44173
- this.deps.logger?.info("dispatch.deliver.ok", {
44174
- sourceSessionId,
44175
- count: pending.length,
44176
- dispatchIds: pending.map((r) => r.dispatchId)
44177
- });
44178
44200
  }
44179
44201
  /**
44180
44202
  * 只读拿 SessionState;session 不存在返 null(不 throw)。
@@ -44700,7 +44722,9 @@ var SessionManager = class {
44700
44722
  const file = {
44701
44723
  sessionId,
44702
44724
  cwd,
44703
- tool: "claude",
44725
+ // dispatch B session 跟随 persona 绑定的 tool(codex persona 用 codex spawn),
44726
+ // 与 UI 手建路径(handlers/session.ts create 的 persona.tool 优先)同语义
44727
+ tool: this.deps.getPersonaTool?.(args.targetPersona) ?? "claude",
44704
44728
  ownerPersonaId: args.targetPersona,
44705
44729
  dispatchedFromSessionId: args.sourceSessionId,
44706
44730
  // 跨设备显示关键(spec §8):creatorPrincipalId = A 的 deviceId,让 A 的
@@ -44790,7 +44814,8 @@ var SessionManager = class {
44790
44814
  const file = {
44791
44815
  sessionId,
44792
44816
  cwd,
44793
- tool: "claude",
44817
+ // shift 定时 spawn 同样跟随 persona 绑定 tool(对齐 dispatch B session)
44818
+ tool: this.deps.getPersonaTool?.(args.targetPersona) ?? "claude",
44794
44819
  ownerPersonaId: args.targetPersona,
44795
44820
  ...args.sourceSessionId ? { shiftFiredFromSessionId: args.sourceSessionId } : {},
44796
44821
  createdAt: now,
@@ -46166,6 +46191,9 @@ function refreshDaemonManagedDirs(args) {
46166
46191
  const dstPath = path14.join(personaDir, relPath);
46167
46192
  try {
46168
46193
  fs12.cpSync(srcPath, dstPath, { recursive: true, force: true, dereference: true, filter: skipNodeModulesUnder(srcPath) });
46194
+ if (relPath === "CLAUDE.md") {
46195
+ fs12.cpSync(srcPath, path14.join(personaDir, "AGENTS.md"), { force: true, dereference: true });
46196
+ }
46169
46197
  args.logger.info("persona.refresh.synced", {
46170
46198
  personaId: entry.personaId,
46171
46199
  path: relPath
@@ -46533,11 +46561,12 @@ function createVisitorStore(opts) {
46533
46561
  init_claude();
46534
46562
 
46535
46563
  // src/tools/codex.ts
46536
- var import_node_child_process4 = require("child_process");
46537
- var import_node_fs17 = __toESM(require("fs"), 1);
46564
+ var import_node_child_process5 = require("child_process");
46565
+ var import_node_fs18 = __toESM(require("fs"), 1);
46538
46566
 
46539
46567
  // src/tools/codex-session.ts
46540
- var import_node_child_process3 = require("child_process");
46568
+ var import_node_child_process4 = require("child_process");
46569
+ var import_node_path16 = __toESM(require("path"), 1);
46541
46570
 
46542
46571
  // src/tools/codex-app-server-client.ts
46543
46572
  var import_node_readline = require("readline");
@@ -46720,7 +46749,7 @@ function resolveApprovalPolicy(ctx) {
46720
46749
  if (m2 === "untrusted" || m2 === "on-failure" || m2 === "on-request" || m2 === "never") return m2;
46721
46750
  return "on-request";
46722
46751
  }
46723
- function buildCodexGuestConfig(cs) {
46752
+ function buildCodexGuestConfig(cs, opts = {}) {
46724
46753
  const filesystem = {};
46725
46754
  for (const w2 of cs.writableRoots ?? []) filesystem[w2] = "write";
46726
46755
  const deny = cs.denyRead ?? [];
@@ -46735,7 +46764,7 @@ function buildCodexGuestConfig(cs) {
46735
46764
  clawos_guest: {
46736
46765
  extends: ":workspace",
46737
46766
  filesystem,
46738
- network: cs.network ? { enabled: true, domains: { "*": "allow" } } : { enabled: false }
46767
+ network: cs.network ? { enabled: true, domains: { "*": "allow" } } : opts.loopbackDaemonAccess ? { enabled: true, allowed_domains: [], allow_local_binding: true } : { enabled: false }
46739
46768
  }
46740
46769
  }
46741
46770
  };
@@ -46749,15 +46778,32 @@ function tomlValue(v2) {
46749
46778
  }
46750
46779
  return JSON.stringify(v2);
46751
46780
  }
46752
- function codexGuestCliArgs(cs) {
46753
- const cfg = buildCodexGuestConfig(cs);
46781
+ function codexGuestCliArgs(cs, opts = {}) {
46782
+ const cfg = buildCodexGuestConfig(cs, opts);
46754
46783
  const profile = cfg.permissions.clawos_guest;
46755
- return [
46784
+ const args = [
46756
46785
  "-c",
46757
46786
  `default_permissions=${tomlValue("clawos_guest")}`,
46758
46787
  "-c",
46759
46788
  `permissions.clawos_guest=${tomlValue(profile)}`
46760
46789
  ];
46790
+ if (!cs.network && opts.loopbackDaemonAccess) {
46791
+ args.push("-c", "features.network_proxy=true");
46792
+ }
46793
+ return args;
46794
+ }
46795
+ function codexMcpCliArgs(defs) {
46796
+ const out = [];
46797
+ for (const d of defs) {
46798
+ const cfg = {
46799
+ command: d.command,
46800
+ ...d.args && d.args.length > 0 ? { args: d.args } : {},
46801
+ ...d.env && Object.keys(d.env).length > 0 ? { env: d.env } : {}
46802
+ };
46803
+ const key = /^[A-Za-z0-9_-]+$/.test(d.name) ? d.name : JSON.stringify(d.name);
46804
+ out.push("-c", `mcp_servers.${key}=${tomlValue(cfg)}`);
46805
+ }
46806
+ return out;
46761
46807
  }
46762
46808
  function threadStartParams(ctx) {
46763
46809
  const params = {
@@ -46782,8 +46828,8 @@ function turnStartInput(text) {
46782
46828
  const items = [];
46783
46829
  let leftover = text;
46784
46830
  for (const m2 of text.matchAll(SKILL_RE)) {
46785
- const [marker, name, path71] = m2;
46786
- items.push({ type: "skill", name, path: path71 });
46831
+ const [marker, name, path74] = m2;
46832
+ items.push({ type: "skill", name, path: path74 });
46787
46833
  leftover = leftover.replace(marker, "");
46788
46834
  }
46789
46835
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -46798,15 +46844,122 @@ function turnStartInput(text) {
46798
46844
  return items;
46799
46845
  }
46800
46846
 
46847
+ // src/tools/codex-mcp-config.ts
46848
+ var import_node_fs17 = __toESM(require("fs"), 1);
46849
+ var import_node_path15 = __toESM(require("path"), 1);
46850
+ function loadCodexMcpServerDefs(args) {
46851
+ const out = [];
46852
+ const seen = /* @__PURE__ */ new Set();
46853
+ const sources = [...args.mcpConfigPaths, import_node_path15.default.join(args.cwd, ".mcp.json")];
46854
+ for (const file of sources) {
46855
+ let parsed;
46856
+ try {
46857
+ parsed = JSON.parse(import_node_fs17.default.readFileSync(file, "utf8"));
46858
+ } catch (e) {
46859
+ const code = e.code;
46860
+ if (code !== "ENOENT") {
46861
+ args.logger?.warn("codex mcp config unreadable, skipped", { file, code: code ?? "parse-error" });
46862
+ }
46863
+ continue;
46864
+ }
46865
+ const servers = parsed?.mcpServers;
46866
+ if (!servers || typeof servers !== "object") continue;
46867
+ for (const [name, raw] of Object.entries(servers)) {
46868
+ const def = raw ?? {};
46869
+ const type = typeof def.type === "string" ? def.type : "stdio";
46870
+ if (type !== "stdio") {
46871
+ args.logger?.warn("codex mcp server type unsupported, skipped", { file, name, type });
46872
+ continue;
46873
+ }
46874
+ if (typeof def.command !== "string" || !def.command) {
46875
+ args.logger?.warn("codex mcp server missing command, skipped", { file, name });
46876
+ continue;
46877
+ }
46878
+ if (seen.has(name)) {
46879
+ args.logger?.warn("codex mcp server name collision, first-wins", { file, name });
46880
+ continue;
46881
+ }
46882
+ seen.add(name);
46883
+ const fileEnv = def.env && typeof def.env === "object" ? Object.fromEntries(
46884
+ Object.entries(def.env).filter(
46885
+ (kv) => typeof kv[1] === "string"
46886
+ )
46887
+ ) : {};
46888
+ const env = { ...args.baseEnv ?? {}, ...fileEnv };
46889
+ out.push({
46890
+ name,
46891
+ command: def.command,
46892
+ ...Array.isArray(def.args) && def.args.every((a) => typeof a === "string") ? { args: def.args } : {},
46893
+ ...Object.keys(env).length > 0 ? { env } : {}
46894
+ });
46895
+ }
46896
+ }
46897
+ return out;
46898
+ }
46899
+
46900
+ // src/tools/codex-features.ts
46901
+ var import_node_child_process3 = require("child_process");
46902
+ var cachedNetworkProxy;
46903
+ function hasNetworkProxyFeature(deps = {}) {
46904
+ if (cachedNetworkProxy !== void 0) return cachedNetworkProxy;
46905
+ try {
46906
+ const out = deps.execOverride ? deps.execOverride() : (0, import_node_child_process3.execFileSync)(process.env.CODEX_BIN ?? "codex", ["features", "list"], {
46907
+ encoding: "utf8",
46908
+ timeout: 3e3
46909
+ });
46910
+ const m2 = /^network_proxy\s+(.+?)\s+(?:true|false)\s*$/m.exec(out);
46911
+ cachedNetworkProxy = m2 !== null && m2[1].trim() !== "removed";
46912
+ } catch {
46913
+ cachedNetworkProxy = false;
46914
+ }
46915
+ return cachedNetworkProxy;
46916
+ }
46917
+ var warming = false;
46918
+ function warmCodexFeatureCache() {
46919
+ if (cachedNetworkProxy !== void 0 || warming) return;
46920
+ warming = true;
46921
+ (0, import_node_child_process3.execFile)(
46922
+ process.env.CODEX_BIN ?? "codex",
46923
+ ["features", "list"],
46924
+ { encoding: "utf8", timeout: 3e3 },
46925
+ (err, stdout) => {
46926
+ warming = false;
46927
+ if (cachedNetworkProxy !== void 0) return;
46928
+ if (err) {
46929
+ cachedNetworkProxy = false;
46930
+ return;
46931
+ }
46932
+ const m2 = /^network_proxy\s+(.+?)\s+(?:true|false)\s*$/m.exec(stdout);
46933
+ cachedNetworkProxy = m2 !== null && m2[1].trim() !== "removed";
46934
+ }
46935
+ );
46936
+ }
46937
+
46801
46938
  // src/tools/codex-session.ts
46802
46939
  function createCodexSession(ctx, sink, deps = {}) {
46803
46940
  const cmd = process.env.CODEX_BIN ?? "codex";
46804
46941
  const args = ["app-server", "--listen", "stdio://"];
46805
46942
  if (ctx.personaMode === "guest" && ctx.codexSandbox) {
46806
- args.push(...codexGuestCliArgs(ctx.codexSandbox));
46943
+ const loopbackDaemonAccess = deps.hasNetworkProxyOverride ? deps.hasNetworkProxyOverride() : hasNetworkProxyFeature();
46944
+ args.push(...codexGuestCliArgs(ctx.codexSandbox, { loopbackDaemonAccess }));
46807
46945
  }
46946
+ const clawdEnv = Object.fromEntries(
46947
+ Object.entries(ctx.env ?? {}).filter(
46948
+ (kv) => kv[0].startsWith("CLAWD_") && typeof kv[1] === "string"
46949
+ )
46950
+ );
46951
+ args.push(
46952
+ ...codexMcpCliArgs(
46953
+ loadCodexMcpServerDefs({
46954
+ mcpConfigPaths: (ctx.mcpConfigs ?? []).map((m2) => m2.path),
46955
+ cwd: ctx.cwd,
46956
+ baseEnv: clawdEnv,
46957
+ logger: deps.logger
46958
+ })
46959
+ )
46960
+ );
46808
46961
  const env = { ...process.env, ...ctx.env };
46809
- const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, ctx.cwd, env) : (0, import_node_child_process3.spawn)(cmd, args, { cwd: ctx.cwd, env, stdio: ["pipe", "pipe", "pipe"] });
46962
+ const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, ctx.cwd, env) : (0, import_node_child_process4.spawn)(cmd, args, { cwd: ctx.cwd, env, stdio: ["pipe", "pipe", "pipe"] });
46810
46963
  let threadId = ctx.toolSessionId;
46811
46964
  let turnId;
46812
46965
  const approvalIds = /* @__PURE__ */ new Map();
@@ -46863,6 +47016,7 @@ function createCodexSession(ctx, sink, deps = {}) {
46863
47016
  capabilities: null
46864
47017
  });
46865
47018
  client.notify("initialized", {});
47019
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path16.default.join(ctx.cwd, ".claude", "skills")] }).catch((e) => deps.logger?.warn("codex skills/extraRoots/set failed", { message: e.message }));
46866
47020
  if (threadId) {
46867
47021
  await client.request("thread/resume", { threadId, ...threadStartParams(ctx) });
46868
47022
  } else {
@@ -46909,6 +47063,7 @@ function createCodexSession(ctx, sink, deps = {}) {
46909
47063
  }
46910
47064
 
46911
47065
  // src/tools/codex.ts
47066
+ var CODEX_MODEL_IDS = ["gpt-5.5", "gpt-5.4", "gpt-5.4-mini"];
46912
47067
  var CODEX_MODELS = [
46913
47068
  { id: "", label: "Default", description: "codex config.toml \u9ED8\u8BA4", contextWindowSize: 258400, default: true },
46914
47069
  { id: "gpt-5.5", label: "GPT-5.5", description: "Frontier model for complex coding", contextWindowSize: 258400 },
@@ -46967,10 +47122,10 @@ function sanitizeCodexModel(model) {
46967
47122
  return CODEX_MODELS.some((m2) => m2.id === model) ? model : void 0;
46968
47123
  }
46969
47124
  async function probeCodex(env = process.env) {
46970
- if (env.CODEX_BIN && import_node_fs17.default.existsSync(env.CODEX_BIN)) return { available: true, path: env.CODEX_BIN };
47125
+ if (env.CODEX_BIN && import_node_fs18.default.existsSync(env.CODEX_BIN)) return { available: true, path: env.CODEX_BIN };
46971
47126
  try {
46972
- const out = (0, import_node_child_process4.execFileSync)("which", ["codex"], { encoding: "utf8" }).trim();
46973
- if (out && import_node_fs17.default.existsSync(out)) return { available: true, path: out };
47127
+ const out = (0, import_node_child_process5.execFileSync)("which", ["codex"], { encoding: "utf8" }).trim();
47128
+ if (out && import_node_fs18.default.existsSync(out)) return { available: true, path: out };
46974
47129
  } catch {
46975
47130
  }
46976
47131
  return { available: false };
@@ -47016,9 +47171,9 @@ var CodexAdapter = class {
47016
47171
 
47017
47172
  // src/tools/claude-tui.ts
47018
47173
  var import_node_crypto5 = require("crypto");
47019
- var import_node_fs18 = __toESM(require("fs"), 1);
47174
+ var import_node_fs19 = __toESM(require("fs"), 1);
47020
47175
  var import_node_os7 = __toESM(require("os"), 1);
47021
- var import_node_path15 = __toESM(require("path"), 1);
47176
+ var import_node_path17 = __toESM(require("path"), 1);
47022
47177
  var import_headless = __toESM(require_xterm_headless(), 1);
47023
47178
 
47024
47179
  // ../node_modules/.pnpm/@xterm+addon-serialize@0.14.0/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs
@@ -48251,9 +48406,9 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
48251
48406
  function jsonlExistsForCtx(ctx) {
48252
48407
  if (!ctx.toolSessionId) return false;
48253
48408
  const home = import_node_os7.default.homedir();
48254
- const file = import_node_path15.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
48409
+ const file = import_node_path17.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
48255
48410
  try {
48256
- return import_node_fs18.default.statSync(file).isFile();
48411
+ return import_node_fs19.default.statSync(file).isFile();
48257
48412
  } catch {
48258
48413
  return false;
48259
48414
  }
@@ -48330,6 +48485,21 @@ var PersonaDispatchManager = class {
48330
48485
  state.waiters.push(d);
48331
48486
  return d.promise;
48332
48487
  }
48488
+ /**
48489
+ * 续派(spec 2026-07-21):complete 已清掉 map 条目,续派前重建——bSessionId 映射
48490
+ * 保证 worker 进程死后 respawn 时 reducer lookupDispatchByBSessionId 仍注回同一
48491
+ * CLAWD_DISPATCH_ID env。台账行的复位由 handler 直接走 store(本方法只管内存态)。
48492
+ */
48493
+ reopen(dispatchId, args) {
48494
+ const existing = this.map.get(dispatchId);
48495
+ this.map.set(dispatchId, {
48496
+ dispatchId,
48497
+ sourceSessionId: args.sourceSessionId,
48498
+ targetPersona: args.targetPersona,
48499
+ bSessionId: args.workerSessionId,
48500
+ waiters: existing?.waiters ?? []
48501
+ });
48502
+ }
48333
48503
  /** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
48334
48504
  registerBSession(dispatchId, bSessionId) {
48335
48505
  const state = this.map.get(dispatchId);
@@ -48348,7 +48518,7 @@ var PersonaDispatchManager = class {
48348
48518
 
48349
48519
  // src/dispatch/store.ts
48350
48520
  var import_promises = __toESM(require("fs/promises"), 1);
48351
- var import_node_path16 = __toESM(require("path"), 1);
48521
+ var import_node_path18 = __toESM(require("path"), 1);
48352
48522
 
48353
48523
  // src/shift/constants.ts
48354
48524
  var MAX_RUNS_PER_SHIFT = 30;
@@ -48386,7 +48556,7 @@ function createDispatchStore(deps) {
48386
48556
  flushTimer = null;
48387
48557
  }
48388
48558
  const content = { version: 1, records };
48389
- await import_promises.default.mkdir(import_node_path16.default.dirname(deps.filePath), { recursive: true });
48559
+ await import_promises.default.mkdir(import_node_path18.default.dirname(deps.filePath), { recursive: true });
48390
48560
  const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
48391
48561
  await import_promises.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
48392
48562
  await import_promises.default.rename(tmp, deps.filePath);
@@ -48448,10 +48618,10 @@ function createDispatchStore(deps) {
48448
48618
  }
48449
48619
 
48450
48620
  // src/dispatch/mcp-config.ts
48451
- var import_node_fs19 = __toESM(require("fs"), 1);
48452
- var import_node_path17 = __toESM(require("path"), 1);
48621
+ var import_node_fs20 = __toESM(require("fs"), 1);
48622
+ var import_node_path19 = __toESM(require("path"), 1);
48453
48623
  function dispatchMcpConfigPath(dataDir) {
48454
- return import_node_path17.default.join(dataDir, "dispatch.mcp.json");
48624
+ return import_node_path19.default.join(dataDir, "dispatch.mcp.json");
48455
48625
  }
48456
48626
  function writeDispatchMcpConfig(args) {
48457
48627
  const cfgPath = dispatchMcpConfigPath(args.dataDir);
@@ -48466,16 +48636,16 @@ function writeDispatchMcpConfig(args) {
48466
48636
  }
48467
48637
  }
48468
48638
  };
48469
- import_node_fs19.default.mkdirSync(args.dataDir, { recursive: true });
48470
- import_node_fs19.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
48639
+ import_node_fs20.default.mkdirSync(args.dataDir, { recursive: true });
48640
+ import_node_fs20.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
48471
48641
  return cfgPath;
48472
48642
  }
48473
48643
 
48474
48644
  // src/ticket/mcp-config.ts
48475
- var import_node_fs20 = __toESM(require("fs"), 1);
48476
- var import_node_path18 = __toESM(require("path"), 1);
48645
+ var import_node_fs21 = __toESM(require("fs"), 1);
48646
+ var import_node_path20 = __toESM(require("path"), 1);
48477
48647
  function ticketMcpConfigPath(dataDir) {
48478
- return import_node_path18.default.join(dataDir, "ticket.mcp.json");
48648
+ return import_node_path20.default.join(dataDir, "ticket.mcp.json");
48479
48649
  }
48480
48650
  function writeTicketMcpConfig(args) {
48481
48651
  const cfgPath = ticketMcpConfigPath(args.dataDir);
@@ -48495,16 +48665,16 @@ function writeTicketMcpConfig(args) {
48495
48665
  }
48496
48666
  }
48497
48667
  };
48498
- import_node_fs20.default.mkdirSync(args.dataDir, { recursive: true });
48499
- import_node_fs20.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
48668
+ import_node_fs21.default.mkdirSync(args.dataDir, { recursive: true });
48669
+ import_node_fs21.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
48500
48670
  return cfgPath;
48501
48671
  }
48502
48672
 
48503
48673
  // src/shift/mcp-config.ts
48504
- var import_node_fs21 = __toESM(require("fs"), 1);
48505
- var import_node_path19 = __toESM(require("path"), 1);
48674
+ var import_node_fs22 = __toESM(require("fs"), 1);
48675
+ var import_node_path21 = __toESM(require("path"), 1);
48506
48676
  function shiftMcpConfigPath(dataDir) {
48507
- return import_node_path19.default.join(dataDir, "shift.mcp.json");
48677
+ return import_node_path21.default.join(dataDir, "shift.mcp.json");
48508
48678
  }
48509
48679
  async function writeShiftMcpConfig(args) {
48510
48680
  const cfgPath = shiftMcpConfigPath(args.dataDir);
@@ -48519,16 +48689,16 @@ async function writeShiftMcpConfig(args) {
48519
48689
  }
48520
48690
  }
48521
48691
  };
48522
- await import_node_fs21.default.promises.mkdir(args.dataDir, { recursive: true });
48523
- await import_node_fs21.default.promises.writeFile(cfgPath, JSON.stringify(content, null, 2), "utf8");
48692
+ await import_node_fs22.default.promises.mkdir(args.dataDir, { recursive: true });
48693
+ await import_node_fs22.default.promises.writeFile(cfgPath, JSON.stringify(content, null, 2), "utf8");
48524
48694
  return cfgPath;
48525
48695
  }
48526
48696
 
48527
48697
  // src/inbox/mcp-config.ts
48528
- var import_node_fs22 = __toESM(require("fs"), 1);
48529
- var import_node_path20 = __toESM(require("path"), 1);
48698
+ var import_node_fs23 = __toESM(require("fs"), 1);
48699
+ var import_node_path22 = __toESM(require("path"), 1);
48530
48700
  function inboxMcpConfigPath(dataDir) {
48531
- return import_node_path20.default.join(dataDir, "inbox.mcp.json");
48701
+ return import_node_path22.default.join(dataDir, "inbox.mcp.json");
48532
48702
  }
48533
48703
  async function writeInboxMcpConfig(args) {
48534
48704
  const cfgPath = inboxMcpConfigPath(args.dataDir);
@@ -48543,16 +48713,16 @@ async function writeInboxMcpConfig(args) {
48543
48713
  }
48544
48714
  }
48545
48715
  };
48546
- await import_node_fs22.default.promises.mkdir(args.dataDir, { recursive: true });
48547
- await import_node_fs22.default.promises.writeFile(cfgPath, JSON.stringify(content, null, 2), "utf8");
48716
+ await import_node_fs23.default.promises.mkdir(args.dataDir, { recursive: true });
48717
+ await import_node_fs23.default.promises.writeFile(cfgPath, JSON.stringify(content, null, 2), "utf8");
48548
48718
  return cfgPath;
48549
48719
  }
48550
48720
 
48551
48721
  // src/peer-ops/mcp-config.ts
48552
- var import_node_fs23 = __toESM(require("fs"), 1);
48553
- var import_node_path21 = __toESM(require("path"), 1);
48722
+ var import_node_fs24 = __toESM(require("fs"), 1);
48723
+ var import_node_path23 = __toESM(require("path"), 1);
48554
48724
  function peerOpsMcpConfigPath(dataDir) {
48555
- return import_node_path21.default.join(dataDir, "peer-ops.mcp.json");
48725
+ return import_node_path23.default.join(dataDir, "peer-ops.mcp.json");
48556
48726
  }
48557
48727
  function writePeerOpsMcpConfig(args) {
48558
48728
  const cfgPath = peerOpsMcpConfigPath(args.dataDir);
@@ -48565,14 +48735,14 @@ function writePeerOpsMcpConfig(args) {
48565
48735
  }
48566
48736
  }
48567
48737
  };
48568
- import_node_fs23.default.mkdirSync(args.dataDir, { recursive: true });
48569
- import_node_fs23.default.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
48738
+ import_node_fs24.default.mkdirSync(args.dataDir, { recursive: true });
48739
+ import_node_fs24.default.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
48570
48740
  return cfgPath;
48571
48741
  }
48572
48742
 
48573
48743
  // src/shift/store.ts
48574
48744
  var import_promises2 = __toESM(require("fs/promises"), 1);
48575
- var import_node_path22 = __toESM(require("path"), 1);
48745
+ var import_node_path24 = __toESM(require("path"), 1);
48576
48746
  var import_node_crypto6 = require("crypto");
48577
48747
 
48578
48748
  // src/shift/schedule.ts
@@ -48647,7 +48817,7 @@ function createShiftStore(deps) {
48647
48817
  flushTimer = null;
48648
48818
  }
48649
48819
  const content = { version: 1, shifts };
48650
- await import_promises2.default.mkdir(import_node_path22.default.dirname(deps.filePath), { recursive: true });
48820
+ await import_promises2.default.mkdir(import_node_path24.default.dirname(deps.filePath), { recursive: true });
48651
48821
  const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
48652
48822
  await import_promises2.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
48653
48823
  await import_promises2.default.rename(tmp, deps.filePath);
@@ -49063,17 +49233,103 @@ function canAccessPersona(grants, personaId, action) {
49063
49233
 
49064
49234
  // src/handlers/persona-dispatch.ts
49065
49235
  init_claude();
49236
+ function buildFollowUpTaskPack(dispatchId, prompt) {
49237
+ return [
49238
+ `[Follow-up instruction for dispatch ${dispatchId}]`,
49239
+ "",
49240
+ `Task: ${prompt}`,
49241
+ "",
49242
+ `This is a follow-up turn in the same dispatched task (dispatchId=${dispatchId}).`,
49243
+ "When you finish this round, report back by calling personaDispatchComplete again,",
49244
+ "exactly as you did before."
49245
+ ].join("\n");
49246
+ }
49066
49247
  function buildPersonaDispatchHandlers(deps) {
49067
49248
  const { personaDispatchManager: mgr, spawnB, logger } = deps;
49068
49249
  const run = async (frame, _client, ctx) => {
49069
49250
  const { type: _t, requestId: _r, ...rest } = frame;
49070
49251
  const sourceSessionId = typeof rest.sessionId === "string" ? rest.sessionId : void 0;
49071
49252
  const args = DispatchRunArgsSchema.parse(rest);
49072
- if (args.model !== void 0 && !CLAUDE_MODEL_IDS.includes(args.model)) {
49073
- throw new ClawdError(
49074
- ERROR_CODES.INVALID_PARAM,
49075
- `model '${args.model}' not supported; allowed: ${CLAUDE_MODEL_IDS.join(", ")}`
49253
+ if (args.model !== void 0) {
49254
+ const targetPersona2 = args.targetPersona ?? (args.dispatchId ? deps.store.get(args.dispatchId)?.targetPersonaId : void 0);
49255
+ const targetTool = (targetPersona2 ? deps.getPersonaTool?.(targetPersona2) : void 0) ?? "claude";
49256
+ const allowed = targetTool === "codex" ? CODEX_MODEL_IDS : CLAUDE_MODEL_IDS;
49257
+ if (!allowed.includes(args.model)) {
49258
+ throw new ClawdError(
49259
+ ERROR_CODES.INVALID_PARAM,
49260
+ `model '${args.model}' not supported for tool '${targetTool}'; allowed: ${allowed.join(", ")}`
49261
+ );
49262
+ }
49263
+ }
49264
+ if (args.dispatchId) {
49265
+ if (ctx?.principal.kind === "guest") {
49266
+ throw new ClawdError(
49267
+ ERROR_CODES.UNAUTHORIZED,
49268
+ "follow-up dispatch cannot be initiated by a guest"
49269
+ );
49270
+ }
49271
+ if (!sourceSessionId) {
49272
+ throw new Error(
49273
+ "personaDispatch:run requires sessionId (caller must pass x-clawd-session-id header)"
49274
+ );
49275
+ }
49276
+ const rec3 = deps.store.get(args.dispatchId);
49277
+ if (!rec3) {
49278
+ throw new ClawdError(ERROR_CODES.INVALID_PARAM, `dispatch not found: ${args.dispatchId}`);
49279
+ }
49280
+ if (!rec3.workerSessionId) {
49281
+ throw new ClawdError(
49282
+ ERROR_CODES.INVALID_PARAM,
49283
+ `dispatch ${args.dispatchId} has no worker session and cannot be continued (cross-device or spawn incomplete)`
49284
+ );
49285
+ }
49286
+ if (args.targetPersona && args.targetPersona !== rec3.targetPersonaId) {
49287
+ throw new ClawdError(
49288
+ ERROR_CODES.INVALID_PARAM,
49289
+ `targetPersona mismatch: dispatch ${args.dispatchId} belongs to ${rec3.targetPersonaId}`
49290
+ );
49291
+ }
49292
+ if (!deps.sendFollowUp) {
49293
+ throw new Error("follow-up dispatch not wired (sendFollowUp missing)");
49294
+ }
49295
+ deps.store.update(args.dispatchId, {
49296
+ status: "running",
49297
+ outcome: void 0,
49298
+ completedAt: void 0,
49299
+ deliveredAt: void 0,
49300
+ taskText: args.prompt.slice(0, TASK_TEXT_MAX)
49301
+ });
49302
+ mgr.reopen(args.dispatchId, {
49303
+ sourceSessionId,
49304
+ targetPersona: rec3.targetPersonaId,
49305
+ workerSessionId: rec3.workerSessionId
49306
+ });
49307
+ logger?.info("dispatch.run.follow-up", {
49308
+ dispatchId: args.dispatchId,
49309
+ workerSessionId: rec3.workerSessionId,
49310
+ promptLen: args.prompt.length
49311
+ });
49312
+ const ok = deps.sendFollowUp(
49313
+ rec3.workerSessionId,
49314
+ buildFollowUpTaskPack(args.dispatchId, args.prompt)
49076
49315
  );
49316
+ if (!ok) {
49317
+ mgr.complete(args.dispatchId, {
49318
+ kind: "failure",
49319
+ reason: "worker session unavailable for follow-up"
49320
+ });
49321
+ throw new ClawdError(
49322
+ ERROR_CODES.SESSION_NOT_FOUND,
49323
+ `worker session unavailable; follow-up failed for dispatch ${args.dispatchId}`
49324
+ );
49325
+ }
49326
+ return {
49327
+ response: { type: "personaDispatch:run:ok", dispatchId: args.dispatchId }
49328
+ };
49329
+ }
49330
+ const targetPersona = args.targetPersona;
49331
+ if (!targetPersona) {
49332
+ throw new ClawdError(ERROR_CODES.INVALID_PARAM, "targetPersona is required for a new dispatch");
49077
49333
  }
49078
49334
  if (args.targetDeviceId) {
49079
49335
  if (ctx?.principal.kind === "guest") {
@@ -49092,17 +49348,17 @@ function buildPersonaDispatchHandlers(deps) {
49092
49348
  }
49093
49349
  const { dispatchId: dispatchId2 } = mgr.start({
49094
49350
  sourceSessionId,
49095
- targetPersona: args.targetPersona,
49351
+ targetPersona,
49096
49352
  taskText: args.prompt
49097
49353
  });
49098
49354
  logger?.info("dispatch.run.forward", {
49099
49355
  dispatchId: dispatchId2,
49100
49356
  targetDeviceId: args.targetDeviceId,
49101
- targetPersona: args.targetPersona
49357
+ targetPersona
49102
49358
  });
49103
49359
  void deps.forwardToPeer({
49104
49360
  targetDeviceId: args.targetDeviceId,
49105
- targetPersona: args.targetPersona,
49361
+ targetPersona,
49106
49362
  prompt: args.prompt,
49107
49363
  ...args.model ? { model: args.model } : {}
49108
49364
  }).then((outcome) => mgr.complete(dispatchId2, outcome)).catch((err) => {
@@ -49115,28 +49371,28 @@ function buildPersonaDispatchHandlers(deps) {
49115
49371
  };
49116
49372
  }
49117
49373
  if (ctx?.principal.kind === "guest") {
49118
- const isPublic = deps.getPersonaPublic?.(args.targetPersona) ?? false;
49119
- if (!isPublic || !canAccessPersona(ctx.grants, args.targetPersona, "send")) {
49374
+ const isPublic = deps.getPersonaPublic?.(targetPersona) ?? false;
49375
+ if (!isPublic || !canAccessPersona(ctx.grants, targetPersona, "send")) {
49120
49376
  throw new ClawdError(
49121
49377
  ERROR_CODES.UNAUTHORIZED,
49122
- `persona not dispatchable: ${args.targetPersona}`
49378
+ `persona not dispatchable: ${targetPersona}`
49123
49379
  );
49124
49380
  }
49125
49381
  const { dispatchId: dispatchId2 } = mgr.start({
49126
49382
  sourceSessionId: ctx.principal.id,
49127
- targetPersona: args.targetPersona,
49383
+ targetPersona,
49128
49384
  taskText: args.prompt
49129
49385
  });
49130
49386
  logger?.info("dispatch.run.received.guest", {
49131
49387
  dispatchId: dispatchId2,
49132
49388
  sourcePrincipal: ctx.principal.id,
49133
- targetPersona: args.targetPersona,
49389
+ targetPersona,
49134
49390
  promptLen: args.prompt.length
49135
49391
  });
49136
49392
  void spawnB({
49137
49393
  dispatchId: dispatchId2,
49138
49394
  sourceSessionId: ctx.principal.id,
49139
- targetPersona: args.targetPersona,
49395
+ targetPersona,
49140
49396
  prompt: args.prompt,
49141
49397
  guestPrincipalId: ctx.principal.id,
49142
49398
  guestDisplayName: ctx.principal.displayName,
@@ -49163,19 +49419,19 @@ function buildPersonaDispatchHandlers(deps) {
49163
49419
  }
49164
49420
  const { dispatchId } = mgr.start({
49165
49421
  sourceSessionId,
49166
- targetPersona: args.targetPersona,
49422
+ targetPersona,
49167
49423
  taskText: args.prompt
49168
49424
  });
49169
49425
  logger?.info("dispatch.run.received", {
49170
49426
  dispatchId,
49171
49427
  sourceSessionId,
49172
- targetPersona: args.targetPersona,
49428
+ targetPersona,
49173
49429
  promptLen: args.prompt.length
49174
49430
  });
49175
49431
  void spawnB({
49176
49432
  dispatchId,
49177
49433
  sourceSessionId,
49178
- targetPersona: args.targetPersona,
49434
+ targetPersona,
49179
49435
  prompt: args.prompt,
49180
49436
  ...args.model ? { model: args.model } : {}
49181
49437
  }).then(() => {
@@ -49338,7 +49594,7 @@ async function forwardPeerExecToPeer(args) {
49338
49594
  }
49339
49595
 
49340
49596
  // src/tools/codex-history.ts
49341
- var import_node_child_process5 = require("child_process");
49597
+ var import_node_child_process6 = require("child_process");
49342
49598
  var DEFAULT_TIMEOUT_MS2 = 8e3;
49343
49599
  function rec2(v2) {
49344
49600
  return v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
@@ -49401,7 +49657,7 @@ function threadItemToHistoryMessages(item) {
49401
49657
  async function queryCodexAppServer(cwd, method, params, deps) {
49402
49658
  const cmd = process.env.CODEX_BIN ?? "codex";
49403
49659
  const args = ["app-server", "--listen", "stdio://"];
49404
- const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, cwd) : (0, import_node_child_process5.spawn)(cmd, args, { cwd, env: process.env, stdio: ["pipe", "pipe", "pipe"] });
49660
+ const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, cwd) : (0, import_node_child_process6.spawn)(cmd, args, { cwd, env: process.env, stdio: ["pipe", "pipe", "pipe"] });
49405
49661
  const client = new CodexAppServerClient(proc, {});
49406
49662
  const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
49407
49663
  let timer;
@@ -49507,7 +49763,8 @@ var CodexHistoryReader = class {
49507
49763
  };
49508
49764
 
49509
49765
  // src/tools/codex-skills.ts
49510
- var import_node_child_process6 = require("child_process");
49766
+ var import_node_child_process7 = require("child_process");
49767
+ var import_node_path25 = __toESM(require("path"), 1);
49511
49768
  var DEFAULT_TIMEOUT_MS3 = 8e3;
49512
49769
  function str3(v2) {
49513
49770
  return typeof v2 === "string" ? v2 : void 0;
@@ -49523,13 +49780,13 @@ function mapSkillsListResponse(res) {
49523
49780
  const r = s ?? {};
49524
49781
  const name = str3(r.name);
49525
49782
  if (!name) continue;
49526
- const path71 = str3(r.path);
49783
+ const path74 = str3(r.path);
49527
49784
  const description = str3(r.description);
49528
49785
  const isPlugin = name.includes(":");
49529
49786
  out.push({
49530
49787
  name,
49531
49788
  source: isPlugin ? "plugin" : "project",
49532
- ...path71 ? { path: path71 } : {},
49789
+ ...path74 ? { path: path74 } : {},
49533
49790
  ...description ? { description } : {},
49534
49791
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
49535
49792
  });
@@ -49540,7 +49797,7 @@ function mapSkillsListResponse(res) {
49540
49797
  async function listCodexSkills(cwd, deps = {}) {
49541
49798
  const cmd = process.env.CODEX_BIN ?? "codex";
49542
49799
  const args = ["app-server", "--listen", "stdio://"];
49543
- const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, cwd) : (0, import_node_child_process6.spawn)(cmd, args, { cwd, env: process.env, stdio: ["pipe", "pipe", "pipe"] });
49800
+ const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, cwd) : (0, import_node_child_process7.spawn)(cmd, args, { cwd, env: process.env, stdio: ["pipe", "pipe", "pipe"] });
49544
49801
  const client = new CodexAppServerClient(proc, {});
49545
49802
  const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
49546
49803
  let timer;
@@ -49559,6 +49816,7 @@ async function listCodexSkills(cwd, deps = {}) {
49559
49816
  })(),
49560
49817
  timeout
49561
49818
  ]);
49819
+ void client.request("skills/extraRoots/set", { extraRoots: [import_node_path25.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
49562
49820
  const res = await Promise.race([client.request("skills/list", { cwds: [cwd] }), timeout]);
49563
49821
  return mapSkillsListResponse(res);
49564
49822
  } finally {
@@ -49568,23 +49826,23 @@ async function listCodexSkills(cwd, deps = {}) {
49568
49826
  }
49569
49827
 
49570
49828
  // src/workspace/browser.ts
49571
- var import_node_fs24 = __toESM(require("fs"), 1);
49829
+ var import_node_fs25 = __toESM(require("fs"), 1);
49572
49830
  var import_node_os8 = __toESM(require("os"), 1);
49573
- var import_node_path23 = __toESM(require("path"), 1);
49831
+ var import_node_path26 = __toESM(require("path"), 1);
49574
49832
  init_protocol();
49575
49833
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
49576
49834
  function resolveInsideCwd(cwd, subpath) {
49577
- const absCwd = import_node_path23.default.resolve(cwd);
49578
- const joined = import_node_path23.default.resolve(absCwd, subpath ?? ".");
49579
- const rel = import_node_path23.default.relative(absCwd, joined);
49580
- if (rel.startsWith("..") || import_node_path23.default.isAbsolute(rel)) {
49835
+ const absCwd = import_node_path26.default.resolve(cwd);
49836
+ const joined = import_node_path26.default.resolve(absCwd, subpath ?? ".");
49837
+ const rel = import_node_path26.default.relative(absCwd, joined);
49838
+ if (rel.startsWith("..") || import_node_path26.default.isAbsolute(rel)) {
49581
49839
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
49582
49840
  }
49583
49841
  return joined;
49584
49842
  }
49585
49843
  function ensureCwd(cwd) {
49586
49844
  try {
49587
- const stat = import_node_fs24.default.statSync(cwd);
49845
+ const stat = import_node_fs25.default.statSync(cwd);
49588
49846
  if (!stat.isDirectory()) {
49589
49847
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
49590
49848
  }
@@ -49598,7 +49856,7 @@ var WorkspaceBrowser = class {
49598
49856
  const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os8.default.homedir();
49599
49857
  ensureCwd(cwd);
49600
49858
  const full = resolveInsideCwd(cwd, args.path);
49601
- const dirents = import_node_fs24.default.readdirSync(full, { withFileTypes: true });
49859
+ const dirents = import_node_fs25.default.readdirSync(full, { withFileTypes: true });
49602
49860
  const entries = [];
49603
49861
  for (const d of dirents) {
49604
49862
  if (!args.showHidden && d.name.startsWith(".")) continue;
@@ -49608,7 +49866,7 @@ var WorkspaceBrowser = class {
49608
49866
  mtime: ""
49609
49867
  };
49610
49868
  try {
49611
- const st = import_node_fs24.default.statSync(import_node_path23.default.join(full, d.name));
49869
+ const st = import_node_fs25.default.statSync(import_node_path26.default.join(full, d.name));
49612
49870
  entry.mtime = new Date(st.mtimeMs).toISOString();
49613
49871
  if (d.isFile()) entry.size = st.size;
49614
49872
  } catch {
@@ -49624,14 +49882,14 @@ var WorkspaceBrowser = class {
49624
49882
  read(args) {
49625
49883
  ensureCwd(args.cwd);
49626
49884
  const full = resolveInsideCwd(args.cwd, args.path);
49627
- const st = import_node_fs24.default.statSync(full);
49885
+ const st = import_node_fs25.default.statSync(full);
49628
49886
  if (!st.isFile()) {
49629
49887
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
49630
49888
  }
49631
49889
  if (st.size > MAX_FILE_BYTES) {
49632
49890
  throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
49633
49891
  }
49634
- const buf = import_node_fs24.default.readFileSync(full);
49892
+ const buf = import_node_fs25.default.readFileSync(full);
49635
49893
  const isBinary = buf.includes(0);
49636
49894
  if (isBinary) {
49637
49895
  return {
@@ -49653,20 +49911,20 @@ var WorkspaceBrowser = class {
49653
49911
  };
49654
49912
 
49655
49913
  // src/skills/agents-scanner.ts
49656
- var import_node_fs25 = __toESM(require("fs"), 1);
49914
+ var import_node_fs26 = __toESM(require("fs"), 1);
49657
49915
  var import_node_os9 = __toESM(require("os"), 1);
49658
- var import_node_path24 = __toESM(require("path"), 1);
49916
+ var import_node_path27 = __toESM(require("path"), 1);
49659
49917
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
49660
49918
  function isDirLikeSync2(p2) {
49661
49919
  try {
49662
- return import_node_fs25.default.statSync(p2).isDirectory();
49920
+ return import_node_fs26.default.statSync(p2).isDirectory();
49663
49921
  } catch {
49664
49922
  return false;
49665
49923
  }
49666
49924
  }
49667
49925
  function fileExistsSync(p2) {
49668
49926
  try {
49669
- return import_node_fs25.default.statSync(p2).isFile();
49927
+ return import_node_fs26.default.statSync(p2).isFile();
49670
49928
  } catch {
49671
49929
  return false;
49672
49930
  }
@@ -49674,7 +49932,7 @@ function fileExistsSync(p2) {
49674
49932
  function parseAgentFile(filePath) {
49675
49933
  let content;
49676
49934
  try {
49677
- content = import_node_fs25.default.readFileSync(filePath, "utf8");
49935
+ content = import_node_fs26.default.readFileSync(filePath, "utf8");
49678
49936
  } catch {
49679
49937
  return {};
49680
49938
  }
@@ -49687,16 +49945,16 @@ function parseAgentFile(filePath) {
49687
49945
  function scanAgentsDir(dir, source, seen, out) {
49688
49946
  let entries;
49689
49947
  try {
49690
- entries = import_node_fs25.default.readdirSync(dir, { withFileTypes: true });
49948
+ entries = import_node_fs26.default.readdirSync(dir, { withFileTypes: true });
49691
49949
  } catch {
49692
49950
  return;
49693
49951
  }
49694
49952
  for (const ent of entries) {
49695
49953
  if (!ent.name.endsWith(".md")) continue;
49696
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path24.default.join(dir, ent.name)))) {
49954
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path27.default.join(dir, ent.name)))) {
49697
49955
  continue;
49698
49956
  }
49699
- const filePath = import_node_path24.default.join(dir, ent.name);
49957
+ const filePath = import_node_path27.default.join(dir, ent.name);
49700
49958
  const baseName = ent.name.replace(/\.md$/, "");
49701
49959
  if (seen.has(baseName)) continue;
49702
49960
  seen.add(baseName);
@@ -49714,12 +49972,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
49714
49972
  function walk2(dir, namespaces) {
49715
49973
  let entries;
49716
49974
  try {
49717
- entries = import_node_fs25.default.readdirSync(dir, { withFileTypes: true });
49975
+ entries = import_node_fs26.default.readdirSync(dir, { withFileTypes: true });
49718
49976
  } catch {
49719
49977
  return;
49720
49978
  }
49721
49979
  for (const ent of entries) {
49722
- const childPath = import_node_path24.default.join(dir, ent.name);
49980
+ const childPath = import_node_path27.default.join(dir, ent.name);
49723
49981
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
49724
49982
  walk2(childPath, [...namespaces, ent.name]);
49725
49983
  continue;
@@ -49744,13 +50002,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
49744
50002
  walk2(root, []);
49745
50003
  }
49746
50004
  function readInstalledPlugins2(home) {
49747
- const pluginsDir = import_node_path24.default.join(home, ".claude", "plugins");
49748
- const v2 = import_node_path24.default.join(pluginsDir, "installed_plugins_v2.json");
49749
- const v1 = import_node_path24.default.join(pluginsDir, "installed_plugins.json");
50005
+ const pluginsDir = import_node_path27.default.join(home, ".claude", "plugins");
50006
+ const v2 = import_node_path27.default.join(pluginsDir, "installed_plugins_v2.json");
50007
+ const v1 = import_node_path27.default.join(pluginsDir, "installed_plugins.json");
49750
50008
  let raw = null;
49751
50009
  for (const candidate of [v2, v1]) {
49752
50010
  try {
49753
- raw = import_node_fs25.default.readFileSync(candidate, "utf8");
50011
+ raw = import_node_fs26.default.readFileSync(candidate, "utf8");
49754
50012
  break;
49755
50013
  } catch {
49756
50014
  }
@@ -49775,19 +50033,19 @@ function readInstalledPlugins2(home) {
49775
50033
  return out;
49776
50034
  }
49777
50035
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
49778
- let cur = import_node_path24.default.resolve(startCwd);
49779
- const fsRoot = import_node_path24.default.parse(cur).root;
50036
+ let cur = import_node_path27.default.resolve(startCwd);
50037
+ const fsRoot = import_node_path27.default.parse(cur).root;
49780
50038
  while (true) {
49781
- scanAgentsDir(import_node_path24.default.join(cur, ".claude", "agents"), "project", seen, out);
50039
+ scanAgentsDir(import_node_path27.default.join(cur, ".claude", "agents"), "project", seen, out);
49782
50040
  let hasGit = false;
49783
50041
  try {
49784
- hasGit = import_node_fs25.default.existsSync(import_node_path24.default.join(cur, ".git"));
50042
+ hasGit = import_node_fs26.default.existsSync(import_node_path27.default.join(cur, ".git"));
49785
50043
  } catch {
49786
50044
  }
49787
50045
  if (hasGit) return;
49788
50046
  if (cur === home) return;
49789
50047
  if (cur === fsRoot) return;
49790
- const parent = import_node_path24.default.dirname(cur);
50048
+ const parent = import_node_path27.default.dirname(cur);
49791
50049
  if (parent === cur) return;
49792
50050
  cur = parent;
49793
50051
  }
@@ -49822,7 +50080,7 @@ var AgentsScanner = class {
49822
50080
  }
49823
50081
  const fsBlock = [];
49824
50082
  scanAgentsDir(
49825
- import_node_path24.default.join(this.home, ".claude", "agents"),
50083
+ import_node_path27.default.join(this.home, ".claude", "agents"),
49826
50084
  "global",
49827
50085
  seen,
49828
50086
  fsBlock
@@ -49836,7 +50094,7 @@ var AgentsScanner = class {
49836
50094
  ...this.extraPluginRoots
49837
50095
  ];
49838
50096
  for (const { name, root } of plugins) {
49839
- const agentsRoot = import_node_path24.default.join(root, "agents");
50097
+ const agentsRoot = import_node_path27.default.join(root, "agents");
49840
50098
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
49841
50099
  }
49842
50100
  return [...builtinBlock, ...fsBlock];
@@ -49844,15 +50102,15 @@ var AgentsScanner = class {
49844
50102
  };
49845
50103
 
49846
50104
  // src/observer/session-observer.ts
49847
- var import_node_fs27 = __toESM(require("fs"), 1);
50105
+ var import_node_fs28 = __toESM(require("fs"), 1);
49848
50106
  var import_node_os11 = __toESM(require("os"), 1);
49849
- var import_node_path26 = __toESM(require("path"), 1);
50107
+ var import_node_path29 = __toESM(require("path"), 1);
49850
50108
  init_claude_history();
49851
50109
 
49852
50110
  // src/observer/subagent-meta-observer.ts
49853
- var import_node_fs26 = __toESM(require("fs"), 1);
50111
+ var import_node_fs27 = __toESM(require("fs"), 1);
49854
50112
  var import_node_os10 = __toESM(require("os"), 1);
49855
- var import_node_path25 = __toESM(require("path"), 1);
50113
+ var import_node_path28 = __toESM(require("path"), 1);
49856
50114
  init_claude_history();
49857
50115
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
49858
50116
  var SubagentMetaObserver = class {
@@ -49865,7 +50123,7 @@ var SubagentMetaObserver = class {
49865
50123
  watches = /* @__PURE__ */ new Map();
49866
50124
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
49867
50125
  resolveSubagentDir(cwd, toolSessionId) {
49868
- return import_node_path25.default.join(
50126
+ return import_node_path28.default.join(
49869
50127
  this.home,
49870
50128
  ".claude",
49871
50129
  "projects",
@@ -49895,7 +50153,7 @@ var SubagentMetaObserver = class {
49895
50153
  attachWatcher(w2) {
49896
50154
  if (w2.watcher) return;
49897
50155
  try {
49898
- w2.watcher = import_node_fs26.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
50156
+ w2.watcher = import_node_fs27.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
49899
50157
  if (!name) return;
49900
50158
  const m2 = META_RE.exec(String(name));
49901
50159
  if (!m2) return;
@@ -49907,7 +50165,7 @@ var SubagentMetaObserver = class {
49907
50165
  scan(w2) {
49908
50166
  let entries;
49909
50167
  try {
49910
- entries = import_node_fs26.default.readdirSync(w2.dirPath);
50168
+ entries = import_node_fs27.default.readdirSync(w2.dirPath);
49911
50169
  } catch {
49912
50170
  return;
49913
50171
  }
@@ -49921,10 +50179,10 @@ var SubagentMetaObserver = class {
49921
50179
  if (!m2) return;
49922
50180
  const agentId = m2[1];
49923
50181
  if (w2.emitted.has(agentId)) return;
49924
- const file = import_node_path25.default.join(w2.dirPath, name);
50182
+ const file = import_node_path28.default.join(w2.dirPath, name);
49925
50183
  let raw;
49926
50184
  try {
49927
- raw = import_node_fs26.default.readFileSync(file, "utf8");
50185
+ raw = import_node_fs27.default.readFileSync(file, "utf8");
49928
50186
  } catch {
49929
50187
  return;
49930
50188
  }
@@ -49981,14 +50239,14 @@ var SessionObserver = class {
49981
50239
  metaObserver;
49982
50240
  resolveJsonlPath(cwd, toolSessionId, override) {
49983
50241
  if (override) return override;
49984
- return import_node_path26.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
50242
+ return import_node_path29.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
49985
50243
  }
49986
50244
  start(args) {
49987
50245
  this.stop(args.sessionId);
49988
50246
  const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
49989
50247
  let size = 0;
49990
50248
  try {
49991
- size = import_node_fs27.default.statSync(filePath).size;
50249
+ size = import_node_fs28.default.statSync(filePath).size;
49992
50250
  } catch {
49993
50251
  }
49994
50252
  const w2 = {
@@ -50001,16 +50259,16 @@ var SessionObserver = class {
50001
50259
  adapter: args.adapter,
50002
50260
  prevIsRejectSentinel: false,
50003
50261
  toolSessionId: args.toolSessionId,
50004
- sawFile: import_node_fs27.default.existsSync(filePath),
50262
+ sawFile: import_node_fs28.default.existsSync(filePath),
50005
50263
  lastRelocateScanMs: 0,
50006
50264
  pendingCwdDerive: false,
50007
50265
  lastDeriveMs: 0
50008
50266
  };
50009
50267
  try {
50010
- import_node_fs27.default.mkdirSync(import_node_path26.default.dirname(filePath), { recursive: true });
50268
+ import_node_fs28.default.mkdirSync(import_node_path29.default.dirname(filePath), { recursive: true });
50011
50269
  } catch {
50012
50270
  }
50013
- w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
50271
+ w2.watcher = import_node_fs28.default.watch(import_node_path29.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
50014
50272
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
50015
50273
  this.poll(w2);
50016
50274
  });
@@ -50033,7 +50291,7 @@ var SessionObserver = class {
50033
50291
  // 异常静默吞,不阻塞 watcher 启动
50034
50292
  hydrateMetaTail(w2, maxLines = 200) {
50035
50293
  try {
50036
- const raw = import_node_fs27.default.readFileSync(w2.filePath, "utf8");
50294
+ const raw = import_node_fs28.default.readFileSync(w2.filePath, "utf8");
50037
50295
  if (!raw) return;
50038
50296
  const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
50039
50297
  if (allLines.length === 0) return;
@@ -50057,7 +50315,7 @@ var SessionObserver = class {
50057
50315
  poll(w2) {
50058
50316
  let size = 0;
50059
50317
  try {
50060
- size = import_node_fs27.default.statSync(w2.filePath).size;
50318
+ size = import_node_fs28.default.statSync(w2.filePath).size;
50061
50319
  } catch {
50062
50320
  if (w2.sawFile) this.maybeRelocate(w2);
50063
50321
  return;
@@ -50068,11 +50326,11 @@ var SessionObserver = class {
50068
50326
  w2.buf = "";
50069
50327
  }
50070
50328
  if (size === w2.lastSize) return;
50071
- const fd = import_node_fs27.default.openSync(w2.filePath, "r");
50329
+ const fd = import_node_fs28.default.openSync(w2.filePath, "r");
50072
50330
  try {
50073
50331
  const len = size - w2.lastSize;
50074
50332
  const buf = Buffer.alloc(len);
50075
- import_node_fs27.default.readSync(fd, buf, 0, len, w2.lastSize);
50333
+ import_node_fs28.default.readSync(fd, buf, 0, len, w2.lastSize);
50076
50334
  w2.lastSize = size;
50077
50335
  w2.buf += buf.toString("utf8");
50078
50336
  let newlineIndex;
@@ -50095,7 +50353,7 @@ var SessionObserver = class {
50095
50353
  }
50096
50354
  }
50097
50355
  } finally {
50098
- import_node_fs27.default.closeSync(fd);
50356
+ import_node_fs28.default.closeSync(fd);
50099
50357
  }
50100
50358
  if (w2.pendingCwdDerive) this.maybeDeriveCwd(w2);
50101
50359
  }
@@ -50107,7 +50365,7 @@ var SessionObserver = class {
50107
50365
  const now = Date.now();
50108
50366
  if (now - w2.lastRelocateScanMs < 1e3) return;
50109
50367
  w2.lastRelocateScanMs = now;
50110
- const projectsRoot = import_node_path26.default.join(this.home, ".claude", "projects");
50368
+ const projectsRoot = import_node_path29.default.join(this.home, ".claude", "projects");
50111
50369
  const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
50112
50370
  if (!found || found === w2.filePath) return;
50113
50371
  try {
@@ -50116,7 +50374,7 @@ var SessionObserver = class {
50116
50374
  }
50117
50375
  w2.filePath = found;
50118
50376
  try {
50119
- w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(found), { persistent: false }, (_event, changedName) => {
50377
+ w2.watcher = import_node_fs28.default.watch(import_node_path29.default.dirname(found), { persistent: false }, (_event, changedName) => {
50120
50378
  if (!changedName || !w2.filePath.endsWith(changedName)) return;
50121
50379
  this.poll(w2);
50122
50380
  });
@@ -50707,6 +50965,9 @@ var EXPOSED_RPC_METHODS = [
50707
50965
  "peerExec.run",
50708
50966
  "personaDispatch.complete",
50709
50967
  "personaDispatch.list",
50968
+ // persona 清单(spec 2026-07-21):两级路由第一级——发起方 cc(loopback owner 语义)
50969
+ // 用 curl 拿全量 personaId+label 紧凑清单,再按需读候选 CLAUDE.md 首段做终选。
50970
+ "persona.list",
50710
50971
  // clawd-shift v1 (spec 2026-06-24-clawd-shift):cc 子进程内的 shift MCP server 调
50711
50972
  // 这 5 个 method 管理 owner 的 shift(fire-and-forget 排班)。鉴权靠 body.personaId
50712
50973
  // (mcp-server 从 process.env.CLAWD_PERSONA_ID 读,源 = SessionFile.ownerPersonaId)。
@@ -50971,14 +51232,14 @@ async function authenticate(token, deps) {
50971
51232
  }
50972
51233
 
50973
51234
  // src/permission/capability-store.ts
50974
- var fs32 = __toESM(require("fs"), 1);
50975
- var path31 = __toESM(require("path"), 1);
51235
+ var fs33 = __toESM(require("fs"), 1);
51236
+ var path34 = __toESM(require("path"), 1);
50976
51237
  var CAPABILITIES_FILE_NAME = "capabilities.json";
50977
51238
  var FILE_VERSION = 1;
50978
51239
  var CapabilityStore = class {
50979
51240
  constructor(dataDir) {
50980
51241
  this.dataDir = dataDir;
50981
- fs32.mkdirSync(dataDir, { recursive: true });
51242
+ fs33.mkdirSync(dataDir, { recursive: true });
50982
51243
  this.cache = this.readFromDisk();
50983
51244
  }
50984
51245
  dataDir;
@@ -51002,13 +51263,13 @@ var CapabilityStore = class {
51002
51263
  this.flush();
51003
51264
  }
51004
51265
  filePath() {
51005
- return path31.join(this.dataDir, CAPABILITIES_FILE_NAME);
51266
+ return path34.join(this.dataDir, CAPABILITIES_FILE_NAME);
51006
51267
  }
51007
51268
  readFromDisk() {
51008
51269
  const file = this.filePath();
51009
51270
  let raw;
51010
51271
  try {
51011
- raw = fs32.readFileSync(file, "utf8");
51272
+ raw = fs33.readFileSync(file, "utf8");
51012
51273
  } catch (err) {
51013
51274
  if (err?.code === "ENOENT") return [];
51014
51275
  return [];
@@ -51036,10 +51297,10 @@ var CapabilityStore = class {
51036
51297
  }
51037
51298
  atomicWrite(file, content) {
51038
51299
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
51039
- fs32.writeFileSync(tmp, content, { mode: 384 });
51040
- fs32.renameSync(tmp, file);
51300
+ fs33.writeFileSync(tmp, content, { mode: 384 });
51301
+ fs33.renameSync(tmp, file);
51041
51302
  try {
51042
- fs32.chmodSync(file, 384);
51303
+ fs33.chmodSync(file, 384);
51043
51304
  } catch {
51044
51305
  }
51045
51306
  }
@@ -51132,14 +51393,14 @@ var CapabilityManager = class {
51132
51393
  };
51133
51394
 
51134
51395
  // src/permission/cleanup.ts
51135
- var fs33 = __toESM(require("fs"), 1);
51396
+ var fs34 = __toESM(require("fs"), 1);
51136
51397
  function cleanupGuestSessionsForCapability(cap, factory) {
51137
51398
  const removed = [];
51138
51399
  for (const g2 of cap.grants) {
51139
51400
  if (g2.resource.type !== "persona") continue;
51140
51401
  const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
51141
51402
  try {
51142
- fs33.rmSync(dir, { recursive: true, force: true });
51403
+ fs34.rmSync(dir, { recursive: true, force: true });
51143
51404
  removed.push(dir);
51144
51405
  } catch {
51145
51406
  }
@@ -51148,13 +51409,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
51148
51409
  }
51149
51410
 
51150
51411
  // src/inbox/inbox-store.ts
51151
- var fs34 = __toESM(require("fs"), 1);
51152
- var path32 = __toESM(require("path"), 1);
51412
+ var fs35 = __toESM(require("fs"), 1);
51413
+ var path35 = __toESM(require("path"), 1);
51153
51414
  var INBOX_SUBDIR = "inbox";
51154
51415
  var InboxStore = class {
51155
51416
  constructor(dataDir) {
51156
51417
  this.dataDir = dataDir;
51157
- fs34.mkdirSync(this.dirPath(), { recursive: true });
51418
+ fs35.mkdirSync(this.dirPath(), { recursive: true });
51158
51419
  }
51159
51420
  dataDir;
51160
51421
  /**
@@ -51166,7 +51427,7 @@ var InboxStore = class {
51166
51427
  const file = this.filePath(peerDeviceId);
51167
51428
  let raw;
51168
51429
  try {
51169
- raw = fs34.readFileSync(file, "utf8");
51430
+ raw = fs35.readFileSync(file, "utf8");
51170
51431
  } catch (err) {
51171
51432
  if (err?.code === "ENOENT") return [];
51172
51433
  return [];
@@ -51182,7 +51443,7 @@ var InboxStore = class {
51182
51443
  const dir = this.dirPath();
51183
51444
  let entries;
51184
51445
  try {
51185
- entries = fs34.readdirSync(dir);
51446
+ entries = fs35.readdirSync(dir);
51186
51447
  } catch (err) {
51187
51448
  if (err?.code === "ENOENT") return [];
51188
51449
  return [];
@@ -51198,9 +51459,9 @@ var InboxStore = class {
51198
51459
  if (existing.some((m2) => m2.id === message.id)) return;
51199
51460
  const file = this.filePath(message.peerDeviceId);
51200
51461
  const line = JSON.stringify(message) + "\n";
51201
- fs34.appendFileSync(file, line, { mode: 384 });
51462
+ fs35.appendFileSync(file, line, { mode: 384 });
51202
51463
  try {
51203
- fs34.chmodSync(file, 384);
51464
+ fs35.chmodSync(file, 384);
51204
51465
  } catch {
51205
51466
  }
51206
51467
  }
@@ -51230,7 +51491,7 @@ var InboxStore = class {
51230
51491
  removeByPeerDeviceId(peerDeviceId) {
51231
51492
  const file = this.filePath(peerDeviceId);
51232
51493
  try {
51233
- fs34.unlinkSync(file);
51494
+ fs35.unlinkSync(file);
51234
51495
  } catch (err) {
51235
51496
  if (err?.code === "ENOENT") return;
51236
51497
  }
@@ -51239,18 +51500,18 @@ var InboxStore = class {
51239
51500
  const file = this.filePath(peerDeviceId);
51240
51501
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
51241
51502
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
51242
- fs34.writeFileSync(tmp, content, { mode: 384 });
51243
- fs34.renameSync(tmp, file);
51503
+ fs35.writeFileSync(tmp, content, { mode: 384 });
51504
+ fs35.renameSync(tmp, file);
51244
51505
  try {
51245
- fs34.chmodSync(file, 384);
51506
+ fs35.chmodSync(file, 384);
51246
51507
  } catch {
51247
51508
  }
51248
51509
  }
51249
51510
  dirPath() {
51250
- return path32.join(this.dataDir, INBOX_SUBDIR);
51511
+ return path35.join(this.dataDir, INBOX_SUBDIR);
51251
51512
  }
51252
51513
  filePath(peerDeviceId) {
51253
- return path32.join(this.dirPath(), `${peerDeviceId}.jsonl`);
51514
+ return path35.join(this.dirPath(), `${peerDeviceId}.jsonl`);
51254
51515
  }
51255
51516
  };
51256
51517
  function parseAllLines(raw) {
@@ -51338,8 +51599,8 @@ var InboxManager = class {
51338
51599
  };
51339
51600
 
51340
51601
  // src/state/contact-store.ts
51341
- var fs35 = __toESM(require("fs"), 1);
51342
- var path33 = __toESM(require("path"), 1);
51602
+ var fs36 = __toESM(require("fs"), 1);
51603
+ var path36 = __toESM(require("path"), 1);
51343
51604
  var FILE_NAME = "contacts.json";
51344
51605
  var ContactStore = class {
51345
51606
  constructor(dataDir) {
@@ -51349,10 +51610,10 @@ var ContactStore = class {
51349
51610
  contacts = /* @__PURE__ */ new Map();
51350
51611
  load() {
51351
51612
  this.contacts.clear();
51352
- const file = path33.join(this.dataDir, FILE_NAME);
51613
+ const file = path36.join(this.dataDir, FILE_NAME);
51353
51614
  let raw;
51354
51615
  try {
51355
- raw = fs35.readFileSync(file, "utf8");
51616
+ raw = fs36.readFileSync(file, "utf8");
51356
51617
  } catch (err) {
51357
51618
  if (err?.code !== "ENOENT") this.renameBak(file);
51358
51619
  return;
@@ -51421,20 +51682,20 @@ var ContactStore = class {
51421
51682
  return true;
51422
51683
  }
51423
51684
  flush() {
51424
- const file = path33.join(this.dataDir, FILE_NAME);
51685
+ const file = path36.join(this.dataDir, FILE_NAME);
51425
51686
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
51426
51687
  const content = JSON.stringify(
51427
51688
  { contacts: Array.from(this.contacts.values()) },
51428
51689
  null,
51429
51690
  2
51430
51691
  );
51431
- fs35.mkdirSync(this.dataDir, { recursive: true });
51432
- fs35.writeFileSync(tmp, content, { mode: 384 });
51433
- fs35.renameSync(tmp, file);
51692
+ fs36.mkdirSync(this.dataDir, { recursive: true });
51693
+ fs36.writeFileSync(tmp, content, { mode: 384 });
51694
+ fs36.renameSync(tmp, file);
51434
51695
  }
51435
51696
  renameBak(file) {
51436
51697
  try {
51437
- fs35.renameSync(file, `${file}.bak`);
51698
+ fs36.renameSync(file, `${file}.bak`);
51438
51699
  } catch {
51439
51700
  }
51440
51701
  }
@@ -51587,61 +51848,61 @@ async function autoReverseContact(args) {
51587
51848
  }
51588
51849
 
51589
51850
  // src/migrations/2026-05-20-flatten-sessions.ts
51590
- var fs36 = __toESM(require("fs"), 1);
51591
- var path34 = __toESM(require("path"), 1);
51851
+ var fs37 = __toESM(require("fs"), 1);
51852
+ var path37 = __toESM(require("path"), 1);
51592
51853
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
51593
51854
  function migrateFlattenSessions(opts) {
51594
51855
  const dataDir = opts.dataDir;
51595
51856
  const now = opts.now ?? Date.now;
51596
- const sessionsDir = path34.join(dataDir, "sessions");
51597
- const flagPath = path34.join(sessionsDir, MIGRATION_FLAG_NAME);
51857
+ const sessionsDir = path37.join(dataDir, "sessions");
51858
+ const flagPath = path37.join(sessionsDir, MIGRATION_FLAG_NAME);
51598
51859
  if (existsSync3(flagPath)) {
51599
51860
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
51600
51861
  }
51601
51862
  let movedBare = 0;
51602
51863
  let movedVmOwner = 0;
51603
51864
  let archivedListener = 0;
51604
- const defaultDir = path34.join(sessionsDir, "default");
51865
+ const defaultDir = path37.join(sessionsDir, "default");
51605
51866
  if (existsSync3(defaultDir)) {
51606
51867
  for (const entry of readdirSafe(defaultDir)) {
51607
51868
  if (!entry.endsWith(".json")) continue;
51608
- const src = path34.join(defaultDir, entry);
51609
- const dst = path34.join(sessionsDir, entry);
51610
- fs36.renameSync(src, dst);
51869
+ const src = path37.join(defaultDir, entry);
51870
+ const dst = path37.join(sessionsDir, entry);
51871
+ fs37.renameSync(src, dst);
51611
51872
  movedBare += 1;
51612
51873
  }
51613
51874
  rmdirIfEmpty(defaultDir);
51614
51875
  }
51615
51876
  for (const pid of readdirSafe(sessionsDir)) {
51616
- const personaDir = path34.join(sessionsDir, pid);
51877
+ const personaDir = path37.join(sessionsDir, pid);
51617
51878
  if (!isDir(personaDir)) continue;
51618
51879
  if (pid === "default") continue;
51619
- const ownerSrc = path34.join(personaDir, "owner");
51880
+ const ownerSrc = path37.join(personaDir, "owner");
51620
51881
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
51621
- const ownerDst = path34.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
51622
- fs36.mkdirSync(ownerDst, { recursive: true });
51882
+ const ownerDst = path37.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
51883
+ fs37.mkdirSync(ownerDst, { recursive: true });
51623
51884
  for (const file of readdirSafe(ownerSrc)) {
51624
51885
  if (!file.endsWith(".json")) continue;
51625
- fs36.renameSync(path34.join(ownerSrc, file), path34.join(ownerDst, file));
51886
+ fs37.renameSync(path37.join(ownerSrc, file), path37.join(ownerDst, file));
51626
51887
  movedVmOwner += 1;
51627
51888
  }
51628
51889
  rmdirIfEmpty(ownerSrc);
51629
51890
  }
51630
- const listenerSrc = path34.join(personaDir, "listener");
51891
+ const listenerSrc = path37.join(personaDir, "listener");
51631
51892
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
51632
- const archiveDst = path34.join(dataDir, ".legacy", `listener-${pid}`);
51633
- fs36.mkdirSync(archiveDst, { recursive: true });
51893
+ const archiveDst = path37.join(dataDir, ".legacy", `listener-${pid}`);
51894
+ fs37.mkdirSync(archiveDst, { recursive: true });
51634
51895
  for (const file of readdirSafe(listenerSrc)) {
51635
51896
  if (!file.endsWith(".json")) continue;
51636
- fs36.renameSync(path34.join(listenerSrc, file), path34.join(archiveDst, file));
51897
+ fs37.renameSync(path37.join(listenerSrc, file), path37.join(archiveDst, file));
51637
51898
  archivedListener += 1;
51638
51899
  }
51639
51900
  rmdirIfEmpty(listenerSrc);
51640
51901
  }
51641
51902
  rmdirIfEmpty(personaDir);
51642
51903
  }
51643
- fs36.mkdirSync(sessionsDir, { recursive: true });
51644
- fs36.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
51904
+ fs37.mkdirSync(sessionsDir, { recursive: true });
51905
+ fs37.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
51645
51906
  return {
51646
51907
  skipped: false,
51647
51908
  flagWritten: true,
@@ -51652,7 +51913,7 @@ function migrateFlattenSessions(opts) {
51652
51913
  }
51653
51914
  function existsSync3(p2) {
51654
51915
  try {
51655
- fs36.statSync(p2);
51916
+ fs37.statSync(p2);
51656
51917
  return true;
51657
51918
  } catch {
51658
51919
  return false;
@@ -51660,31 +51921,31 @@ function existsSync3(p2) {
51660
51921
  }
51661
51922
  function isDir(p2) {
51662
51923
  try {
51663
- return fs36.statSync(p2).isDirectory();
51924
+ return fs37.statSync(p2).isDirectory();
51664
51925
  } catch {
51665
51926
  return false;
51666
51927
  }
51667
51928
  }
51668
51929
  function readdirSafe(p2) {
51669
51930
  try {
51670
- return fs36.readdirSync(p2);
51931
+ return fs37.readdirSync(p2);
51671
51932
  } catch {
51672
51933
  return [];
51673
51934
  }
51674
51935
  }
51675
51936
  function rmdirIfEmpty(p2) {
51676
51937
  try {
51677
- fs36.rmdirSync(p2);
51938
+ fs37.rmdirSync(p2);
51678
51939
  } catch {
51679
51940
  }
51680
51941
  }
51681
51942
 
51682
51943
  // src/transport/http-router.ts
51683
- var import_node_fs29 = __toESM(require("fs"), 1);
51684
- var import_node_path30 = __toESM(require("path"), 1);
51944
+ var import_node_fs30 = __toESM(require("fs"), 1);
51945
+ var import_node_path33 = __toESM(require("path"), 1);
51685
51946
 
51686
51947
  // src/attachment/mime.ts
51687
- var import_node_path27 = __toESM(require("path"), 1);
51948
+ var import_node_path30 = __toESM(require("path"), 1);
51688
51949
  var TEXT_PLAIN = "text/plain; charset=utf-8";
51689
51950
  var EXT_TO_NATIVE_MIME = {
51690
51951
  // 图片
@@ -51791,7 +52052,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
51791
52052
  ".mk"
51792
52053
  ]);
51793
52054
  function lookupMime(filePathOrName) {
51794
- const ext = import_node_path27.default.extname(filePathOrName).toLowerCase();
52055
+ const ext = import_node_path30.default.extname(filePathOrName).toLowerCase();
51795
52056
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
51796
52057
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
51797
52058
  return "application/octet-stream";
@@ -51860,8 +52121,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
51860
52121
  }
51861
52122
 
51862
52123
  // src/attachment/upload.ts
51863
- var import_node_fs28 = __toESM(require("fs"), 1);
51864
- var import_node_path28 = __toESM(require("path"), 1);
52124
+ var import_node_fs29 = __toESM(require("fs"), 1);
52125
+ var import_node_path31 = __toESM(require("path"), 1);
51865
52126
  var import_node_crypto8 = __toESM(require("crypto"), 1);
51866
52127
  var import_promises3 = require("stream/promises");
51867
52128
  var UploadError = class extends Error {
@@ -51873,22 +52134,22 @@ var UploadError = class extends Error {
51873
52134
  code;
51874
52135
  };
51875
52136
  function assertValidFileName(fileName) {
51876
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path28.default.basename(fileName)) {
52137
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path31.default.basename(fileName)) {
51877
52138
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
51878
52139
  }
51879
52140
  }
51880
52141
  var HASH_PREFIX_LEN = 16;
51881
52142
  async function writeUploadedAttachment(args) {
51882
52143
  assertValidFileName(args.fileName);
51883
- const attachmentsRoot = import_node_path28.default.join(args.sessionDir, ".attachments");
52144
+ const attachmentsRoot = import_node_path31.default.join(args.sessionDir, ".attachments");
51884
52145
  try {
51885
- import_node_fs28.default.mkdirSync(attachmentsRoot, { recursive: true });
52146
+ import_node_fs29.default.mkdirSync(attachmentsRoot, { recursive: true });
51886
52147
  } catch (err) {
51887
52148
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
51888
52149
  }
51889
52150
  const hasher = import_node_crypto8.default.createHash("sha256");
51890
52151
  let actualSize = 0;
51891
- const tmpPath = import_node_path28.default.join(
52152
+ const tmpPath = import_node_path31.default.join(
51892
52153
  attachmentsRoot,
51893
52154
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
51894
52155
  );
@@ -51903,18 +52164,18 @@ async function writeUploadedAttachment(args) {
51903
52164
  yield buf;
51904
52165
  }
51905
52166
  },
51906
- import_node_fs28.default.createWriteStream(tmpPath, { mode: 384 })
52167
+ import_node_fs29.default.createWriteStream(tmpPath, { mode: 384 })
51907
52168
  );
51908
52169
  } catch (err) {
51909
52170
  try {
51910
- import_node_fs28.default.unlinkSync(tmpPath);
52171
+ import_node_fs29.default.unlinkSync(tmpPath);
51911
52172
  } catch {
51912
52173
  }
51913
52174
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
51914
52175
  }
51915
52176
  if (actualSize !== args.contentLength) {
51916
52177
  try {
51917
- import_node_fs28.default.unlinkSync(tmpPath);
52178
+ import_node_fs29.default.unlinkSync(tmpPath);
51918
52179
  } catch {
51919
52180
  }
51920
52181
  throw new UploadError(
@@ -51923,35 +52184,35 @@ async function writeUploadedAttachment(args) {
51923
52184
  );
51924
52185
  }
51925
52186
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
51926
- const hashDir = import_node_path28.default.join(attachmentsRoot, attachmentId);
52187
+ const hashDir = import_node_path31.default.join(attachmentsRoot, attachmentId);
51927
52188
  let finalFileName;
51928
52189
  let hashDirExists = false;
51929
52190
  try {
51930
- hashDirExists = import_node_fs28.default.statSync(hashDir).isDirectory();
52191
+ hashDirExists = import_node_fs29.default.statSync(hashDir).isDirectory();
51931
52192
  } catch {
51932
52193
  }
51933
52194
  if (hashDirExists) {
51934
- const existing = import_node_fs28.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
52195
+ const existing = import_node_fs29.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
51935
52196
  finalFileName = existing[0] ?? args.fileName;
51936
52197
  try {
51937
- import_node_fs28.default.unlinkSync(tmpPath);
52198
+ import_node_fs29.default.unlinkSync(tmpPath);
51938
52199
  } catch {
51939
52200
  }
51940
52201
  } else {
51941
52202
  try {
51942
- import_node_fs28.default.mkdirSync(hashDir, { recursive: true });
52203
+ import_node_fs29.default.mkdirSync(hashDir, { recursive: true });
51943
52204
  finalFileName = args.fileName;
51944
- import_node_fs28.default.renameSync(tmpPath, import_node_path28.default.join(hashDir, finalFileName));
52205
+ import_node_fs29.default.renameSync(tmpPath, import_node_path31.default.join(hashDir, finalFileName));
51945
52206
  } catch (err) {
51946
52207
  try {
51947
- import_node_fs28.default.unlinkSync(tmpPath);
52208
+ import_node_fs29.default.unlinkSync(tmpPath);
51948
52209
  } catch {
51949
52210
  }
51950
52211
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
51951
52212
  }
51952
52213
  }
51953
- const absPath = import_node_path28.default.join(hashDir, finalFileName);
51954
- const relPath = import_node_path28.default.relative(args.sessionDir, absPath);
52214
+ const absPath = import_node_path31.default.join(hashDir, finalFileName);
52215
+ const relPath = import_node_path31.default.relative(args.sessionDir, absPath);
51955
52216
  args.groupFileStore.upsert(args.scope, args.sessionId, {
51956
52217
  relPath: absPath,
51957
52218
  // 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
@@ -51965,7 +52226,7 @@ async function writeUploadedAttachment(args) {
51965
52226
 
51966
52227
  // src/extension/import.ts
51967
52228
  var import_promises4 = __toESM(require("fs/promises"), 1);
51968
- var import_node_path29 = __toESM(require("path"), 1);
52229
+ var import_node_path32 = __toESM(require("path"), 1);
51969
52230
  var import_node_os12 = __toESM(require("os"), 1);
51970
52231
  var import_jszip = __toESM(require_lib3(), 1);
51971
52232
  var ImportError = class extends Error {
@@ -51983,7 +52244,7 @@ async function importZip(buf, root) {
51983
52244
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
51984
52245
  }
51985
52246
  for (const name of Object.keys(zip.files)) {
51986
- if (name.includes("..") || name.startsWith("/") || import_node_path29.default.isAbsolute(name)) {
52247
+ if (name.includes("..") || name.startsWith("/") || import_node_path32.default.isAbsolute(name)) {
51987
52248
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
51988
52249
  }
51989
52250
  }
@@ -52016,7 +52277,7 @@ async function importZip(buf, root) {
52016
52277
  );
52017
52278
  }
52018
52279
  }
52019
- const destDir = import_node_path29.default.join(root, manifest.id);
52280
+ const destDir = import_node_path32.default.join(root, manifest.id);
52020
52281
  let destExists = false;
52021
52282
  try {
52022
52283
  await import_promises4.default.access(destDir);
@@ -52026,15 +52287,15 @@ async function importZip(buf, root) {
52026
52287
  if (destExists) {
52027
52288
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
52028
52289
  }
52029
- const stage = await import_promises4.default.mkdtemp(import_node_path29.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
52290
+ const stage = await import_promises4.default.mkdtemp(import_node_path32.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
52030
52291
  try {
52031
52292
  for (const [name, entry] of Object.entries(zip.files)) {
52032
- const dest = import_node_path29.default.join(stage, name);
52293
+ const dest = import_node_path32.default.join(stage, name);
52033
52294
  if (entry.dir) {
52034
52295
  await import_promises4.default.mkdir(dest, { recursive: true });
52035
52296
  continue;
52036
52297
  }
52037
- await import_promises4.default.mkdir(import_node_path29.default.dirname(dest), { recursive: true });
52298
+ await import_promises4.default.mkdir(import_node_path32.default.dirname(dest), { recursive: true });
52038
52299
  const content = await entry.async("nodebuffer");
52039
52300
  await import_promises4.default.writeFile(dest, content);
52040
52301
  }
@@ -52065,7 +52326,7 @@ var SHARE_UI_ASSET_MIME = {
52065
52326
  ".wasm": "application/wasm"
52066
52327
  };
52067
52328
  function shareUiAssetMime(filePath) {
52068
- const ext = import_node_path30.default.extname(filePath).toLowerCase();
52329
+ const ext = import_node_path33.default.extname(filePath).toLowerCase();
52069
52330
  return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
52070
52331
  }
52071
52332
  var DISPATCH_HEARTBEAT_MS = 25e3;
@@ -52152,7 +52413,7 @@ function isValidUploadFileName(fileName) {
52152
52413
  if (fileName === "." || fileName === "..") return false;
52153
52414
  if (fileName.startsWith(".")) return false;
52154
52415
  if (fileName.includes("/") || fileName.includes("\\")) return false;
52155
- return fileName === import_node_path30.default.basename(fileName);
52416
+ return fileName === import_node_path33.default.basename(fileName);
52156
52417
  }
52157
52418
  function createHttpRouter(deps) {
52158
52419
  return async (req, res) => {
@@ -52224,7 +52485,7 @@ function createHttpRouter(deps) {
52224
52485
  }
52225
52486
  let buf;
52226
52487
  try {
52227
- buf = await import_node_fs29.default.promises.readFile(abs);
52488
+ buf = await import_node_fs30.default.promises.readFile(abs);
52228
52489
  } catch {
52229
52490
  sendJson(res, 404, { code: "NOT_FOUND", message: "asset not found" });
52230
52491
  return true;
@@ -52448,7 +52709,7 @@ function createHttpRouter(deps) {
52448
52709
  sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
52449
52710
  return true;
52450
52711
  }
52451
- sendHtml(res, 200, loader.renderViewerHtml(import_node_path30.default.basename(r.absPath)));
52712
+ sendHtml(res, 200, loader.renderViewerHtml(import_node_path33.default.basename(r.absPath)));
52452
52713
  return true;
52453
52714
  }
52454
52715
  const ctx = deps.authResolver.resolveFromHeader(
@@ -52569,7 +52830,7 @@ function createHttpRouter(deps) {
52569
52830
  return true;
52570
52831
  }
52571
52832
  let absPath;
52572
- if (import_node_path30.default.isAbsolute(pathParam)) {
52833
+ if (import_node_path33.default.isAbsolute(pathParam)) {
52573
52834
  absPath = pathParam;
52574
52835
  } else if (deps.sessionStore) {
52575
52836
  const file = deps.sessionStore.read(sid);
@@ -52577,7 +52838,7 @@ function createHttpRouter(deps) {
52577
52838
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
52578
52839
  return true;
52579
52840
  }
52580
- absPath = import_node_path30.default.join(file.cwd, pathParam);
52841
+ absPath = import_node_path33.default.join(file.cwd, pathParam);
52581
52842
  } else {
52582
52843
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
52583
52844
  return true;
@@ -52664,7 +52925,7 @@ function withCtx(ctx, body) {
52664
52925
  function streamFile(res, absPath, logger) {
52665
52926
  let stat;
52666
52927
  try {
52667
- stat = import_node_fs29.default.statSync(absPath);
52928
+ stat = import_node_fs30.default.statSync(absPath);
52668
52929
  } catch (err) {
52669
52930
  const code = err?.code;
52670
52931
  if (code === "ENOENT") {
@@ -52679,7 +52940,7 @@ function streamFile(res, absPath, logger) {
52679
52940
  return;
52680
52941
  }
52681
52942
  const mime = lookupMime(absPath);
52682
- const basename = import_node_path30.default.basename(absPath);
52943
+ const basename = import_node_path33.default.basename(absPath);
52683
52944
  res.writeHead(200, {
52684
52945
  "Content-Type": mime,
52685
52946
  "Content-Length": String(stat.size),
@@ -52687,7 +52948,7 @@ function streamFile(res, absPath, logger) {
52687
52948
  // 防止浏览器把任意 mime 当 html 渲染
52688
52949
  "X-Content-Type-Options": "nosniff"
52689
52950
  });
52690
- const stream = import_node_fs29.default.createReadStream(absPath);
52951
+ const stream = import_node_fs30.default.createReadStream(absPath);
52691
52952
  stream.on("error", (err) => {
52692
52953
  logger?.warn("streamFile read error", { absPath, err: err.message });
52693
52954
  res.destroy();
@@ -52696,8 +52957,8 @@ function streamFile(res, absPath, logger) {
52696
52957
  }
52697
52958
 
52698
52959
  // src/attachment/gc.ts
52699
- var import_node_fs30 = __toESM(require("fs"), 1);
52700
- var import_node_path31 = __toESM(require("path"), 1);
52960
+ var import_node_fs31 = __toESM(require("fs"), 1);
52961
+ var import_node_path34 = __toESM(require("path"), 1);
52701
52962
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
52702
52963
  function runAttachmentGc(args) {
52703
52964
  const now = (args.now ?? Date.now)();
@@ -52706,38 +52967,38 @@ function runAttachmentGc(args) {
52706
52967
  for (const { scope, sessionId } of args.sessionScopes) {
52707
52968
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
52708
52969
  if (entry.stale) continue;
52709
- if (import_node_path31.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
52970
+ if (import_node_path34.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
52710
52971
  }
52711
52972
  }
52712
52973
  for (const { scope, sessionId } of args.sessionScopes) {
52713
- const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path31.default.join(
52974
+ const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path34.default.join(
52714
52975
  args.dataDir,
52715
52976
  "sessions",
52716
52977
  ...scopeSubPath(scope).map(safeFileName),
52717
52978
  safeFileName(sessionId)
52718
52979
  );
52719
- const attRoot = import_node_path31.default.join(sessionDir, ".attachments");
52980
+ const attRoot = import_node_path34.default.join(sessionDir, ".attachments");
52720
52981
  let hashDirs;
52721
52982
  try {
52722
- hashDirs = import_node_fs30.default.readdirSync(attRoot);
52983
+ hashDirs = import_node_fs31.default.readdirSync(attRoot);
52723
52984
  } catch (err) {
52724
52985
  if (err.code === "ENOENT") continue;
52725
52986
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
52726
52987
  continue;
52727
52988
  }
52728
52989
  for (const hashDir of hashDirs) {
52729
- const hashDirAbs = import_node_path31.default.join(attRoot, hashDir);
52990
+ const hashDirAbs = import_node_path34.default.join(attRoot, hashDir);
52730
52991
  let files;
52731
52992
  try {
52732
- files = import_node_fs30.default.readdirSync(hashDirAbs);
52993
+ files = import_node_fs31.default.readdirSync(hashDirAbs);
52733
52994
  } catch {
52734
52995
  continue;
52735
52996
  }
52736
52997
  for (const name of files) {
52737
- const file = import_node_path31.default.join(hashDirAbs, name);
52998
+ const file = import_node_path34.default.join(hashDirAbs, name);
52738
52999
  let stat;
52739
53000
  try {
52740
- stat = import_node_fs30.default.statSync(file);
53001
+ stat = import_node_fs31.default.statSync(file);
52741
53002
  } catch {
52742
53003
  continue;
52743
53004
  }
@@ -52746,26 +53007,26 @@ function runAttachmentGc(args) {
52746
53007
  if (age < ttlMs) continue;
52747
53008
  if (liveAbs.has(file)) continue;
52748
53009
  try {
52749
- import_node_fs30.default.unlinkSync(file);
53010
+ import_node_fs31.default.unlinkSync(file);
52750
53011
  } catch (err) {
52751
53012
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
52752
53013
  }
52753
53014
  }
52754
53015
  try {
52755
- if (import_node_fs30.default.readdirSync(hashDirAbs).length === 0) import_node_fs30.default.rmdirSync(hashDirAbs);
53016
+ if (import_node_fs31.default.readdirSync(hashDirAbs).length === 0) import_node_fs31.default.rmdirSync(hashDirAbs);
52756
53017
  } catch {
52757
53018
  }
52758
53019
  }
52759
53020
  try {
52760
- if (import_node_fs30.default.readdirSync(attRoot).length === 0) import_node_fs30.default.rmdirSync(attRoot);
53021
+ if (import_node_fs31.default.readdirSync(attRoot).length === 0) import_node_fs31.default.rmdirSync(attRoot);
52761
53022
  } catch {
52762
53023
  }
52763
53024
  }
52764
53025
  }
52765
53026
 
52766
53027
  // src/attachment/group.ts
52767
- var import_node_fs31 = __toESM(require("fs"), 1);
52768
- var import_node_path32 = __toESM(require("path"), 1);
53028
+ var import_node_fs32 = __toESM(require("fs"), 1);
53029
+ var import_node_path35 = __toESM(require("path"), 1);
52769
53030
  var import_node_crypto9 = __toESM(require("crypto"), 1);
52770
53031
  init_protocol();
52771
53032
  var GroupFileStore = class {
@@ -52777,11 +53038,11 @@ var GroupFileStore = class {
52777
53038
  this.logger = opts.logger;
52778
53039
  }
52779
53040
  rootForScope(scope) {
52780
- return import_node_path32.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
53041
+ return import_node_path35.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
52781
53042
  }
52782
53043
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
52783
53044
  filePath(scope, sessionId) {
52784
- return import_node_path32.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
53045
+ return import_node_path35.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
52785
53046
  }
52786
53047
  cacheKey(scope, sessionId) {
52787
53048
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -52790,7 +53051,7 @@ var GroupFileStore = class {
52790
53051
  readFile(scope, sessionId) {
52791
53052
  const file = this.filePath(scope, sessionId);
52792
53053
  try {
52793
- const raw = import_node_fs31.default.readFileSync(file, "utf8");
53054
+ const raw = import_node_fs32.default.readFileSync(file, "utf8");
52794
53055
  const parsed = JSON.parse(raw);
52795
53056
  if (!Array.isArray(parsed)) {
52796
53057
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -52816,10 +53077,10 @@ var GroupFileStore = class {
52816
53077
  }
52817
53078
  writeFile(scope, sessionId, entries) {
52818
53079
  const file = this.filePath(scope, sessionId);
52819
- import_node_fs31.default.mkdirSync(import_node_path32.default.dirname(file), { recursive: true });
53080
+ import_node_fs32.default.mkdirSync(import_node_path35.default.dirname(file), { recursive: true });
52820
53081
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
52821
- import_node_fs31.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
52822
- import_node_fs31.default.renameSync(tmp, file);
53082
+ import_node_fs32.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
53083
+ import_node_fs32.default.renameSync(tmp, file);
52823
53084
  }
52824
53085
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
52825
53086
  list(scope, sessionId) {
@@ -52905,10 +53166,10 @@ var GroupFileStore = class {
52905
53166
  };
52906
53167
 
52907
53168
  // src/discovery/state-file.ts
52908
- var import_node_fs32 = __toESM(require("fs"), 1);
52909
- var import_node_path33 = __toESM(require("path"), 1);
53169
+ var import_node_fs33 = __toESM(require("fs"), 1);
53170
+ var import_node_path36 = __toESM(require("path"), 1);
52910
53171
  function defaultStateFilePath(dataDir) {
52911
- return import_node_path33.default.join(dataDir, "state.json");
53172
+ return import_node_path36.default.join(dataDir, "state.json");
52912
53173
  }
52913
53174
  function isPidAlive(pid) {
52914
53175
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -52930,7 +53191,7 @@ var StateFileManager = class {
52930
53191
  }
52931
53192
  read() {
52932
53193
  try {
52933
- const raw = import_node_fs32.default.readFileSync(this.file, "utf8");
53194
+ const raw = import_node_fs33.default.readFileSync(this.file, "utf8");
52934
53195
  const parsed = JSON.parse(raw);
52935
53196
  return parsed;
52936
53197
  } catch {
@@ -52944,20 +53205,20 @@ var StateFileManager = class {
52944
53205
  return { status: "stale", existing };
52945
53206
  }
52946
53207
  write(state) {
52947
- import_node_fs32.default.mkdirSync(import_node_path33.default.dirname(this.file), { recursive: true });
53208
+ import_node_fs33.default.mkdirSync(import_node_path36.default.dirname(this.file), { recursive: true });
52948
53209
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
52949
- import_node_fs32.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
52950
- import_node_fs32.default.renameSync(tmp, this.file);
53210
+ import_node_fs33.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
53211
+ import_node_fs33.default.renameSync(tmp, this.file);
52951
53212
  if (process.platform !== "win32") {
52952
53213
  try {
52953
- import_node_fs32.default.chmodSync(this.file, 384);
53214
+ import_node_fs33.default.chmodSync(this.file, 384);
52954
53215
  } catch {
52955
53216
  }
52956
53217
  }
52957
53218
  }
52958
53219
  delete() {
52959
53220
  try {
52960
- import_node_fs32.default.unlinkSync(this.file);
53221
+ import_node_fs33.default.unlinkSync(this.file);
52961
53222
  } catch {
52962
53223
  }
52963
53224
  }
@@ -52971,14 +53232,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
52971
53232
  }
52972
53233
 
52973
53234
  // src/tunnel/tunnel-manager.ts
52974
- var import_node_fs36 = __toESM(require("fs"), 1);
52975
- var import_node_path37 = __toESM(require("path"), 1);
53235
+ var import_node_fs37 = __toESM(require("fs"), 1);
53236
+ var import_node_path40 = __toESM(require("path"), 1);
52976
53237
  var import_node_crypto10 = __toESM(require("crypto"), 1);
52977
- var import_node_child_process9 = require("child_process");
53238
+ var import_node_child_process10 = require("child_process");
52978
53239
 
52979
53240
  // src/tunnel/tunnel-store.ts
52980
- var import_node_fs33 = __toESM(require("fs"), 1);
52981
- var import_node_path34 = __toESM(require("path"), 1);
53241
+ var import_node_fs34 = __toESM(require("fs"), 1);
53242
+ var import_node_path37 = __toESM(require("path"), 1);
52982
53243
  var TunnelStore = class {
52983
53244
  constructor(filePath) {
52984
53245
  this.filePath = filePath;
@@ -52986,7 +53247,7 @@ var TunnelStore = class {
52986
53247
  filePath;
52987
53248
  async get() {
52988
53249
  try {
52989
- const raw = await import_node_fs33.default.promises.readFile(this.filePath, "utf8");
53250
+ const raw = await import_node_fs34.default.promises.readFile(this.filePath, "utf8");
52990
53251
  const obj = JSON.parse(raw);
52991
53252
  if (!isPersistedTunnel(obj)) return null;
52992
53253
  return obj;
@@ -52997,22 +53258,22 @@ var TunnelStore = class {
52997
53258
  }
52998
53259
  }
52999
53260
  async set(v2) {
53000
- const dir = import_node_path34.default.dirname(this.filePath);
53001
- await import_node_fs33.default.promises.mkdir(dir, { recursive: true });
53261
+ const dir = import_node_path37.default.dirname(this.filePath);
53262
+ await import_node_fs34.default.promises.mkdir(dir, { recursive: true });
53002
53263
  const data = JSON.stringify(v2, null, 2);
53003
53264
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
53004
- await import_node_fs33.default.promises.writeFile(tmp, data, { mode: 384 });
53265
+ await import_node_fs34.default.promises.writeFile(tmp, data, { mode: 384 });
53005
53266
  if (process.platform !== "win32") {
53006
53267
  try {
53007
- await import_node_fs33.default.promises.chmod(tmp, 384);
53268
+ await import_node_fs34.default.promises.chmod(tmp, 384);
53008
53269
  } catch {
53009
53270
  }
53010
53271
  }
53011
- await import_node_fs33.default.promises.rename(tmp, this.filePath);
53272
+ await import_node_fs34.default.promises.rename(tmp, this.filePath);
53012
53273
  }
53013
53274
  async clear() {
53014
53275
  try {
53015
- await import_node_fs33.default.promises.unlink(this.filePath);
53276
+ await import_node_fs34.default.promises.unlink(this.filePath);
53016
53277
  } catch (err) {
53017
53278
  const code = err?.code;
53018
53279
  if (code !== "ENOENT") throw err;
@@ -53107,10 +53368,10 @@ function escape(v2) {
53107
53368
  }
53108
53369
 
53109
53370
  // src/tunnel/frpc-binary.ts
53110
- var import_node_fs34 = __toESM(require("fs"), 1);
53371
+ var import_node_fs35 = __toESM(require("fs"), 1);
53111
53372
  var import_node_os13 = __toESM(require("os"), 1);
53112
- var import_node_path35 = __toESM(require("path"), 1);
53113
- var import_node_child_process7 = require("child_process");
53373
+ var import_node_path38 = __toESM(require("path"), 1);
53374
+ var import_node_child_process8 = require("child_process");
53114
53375
  var import_node_stream3 = require("stream");
53115
53376
  var import_promises5 = require("stream/promises");
53116
53377
  var FRPC_VERSION = "0.68.0";
@@ -53141,20 +53402,20 @@ function frpcDownloadUrl(version2, p2) {
53141
53402
  }
53142
53403
  async function ensureFrpcBinary(opts) {
53143
53404
  if (opts.override) {
53144
- if (!import_node_fs34.default.existsSync(opts.override)) {
53405
+ if (!import_node_fs35.default.existsSync(opts.override)) {
53145
53406
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
53146
53407
  }
53147
53408
  return opts.override;
53148
53409
  }
53149
53410
  const version2 = opts.version ?? FRPC_VERSION;
53150
53411
  const platform = opts.platform ?? detectPlatform();
53151
- const binDir = import_node_path35.default.join(opts.dataDir, "bin");
53152
- import_node_fs34.default.mkdirSync(binDir, { recursive: true });
53412
+ const binDir = import_node_path38.default.join(opts.dataDir, "bin");
53413
+ import_node_fs35.default.mkdirSync(binDir, { recursive: true });
53153
53414
  cleanupStaleArtifacts(binDir);
53154
- const stableBin = import_node_path35.default.join(binDir, "frpc");
53155
- if (import_node_fs34.default.existsSync(stableBin)) return stableBin;
53415
+ const stableBin = import_node_path38.default.join(binDir, "frpc");
53416
+ if (import_node_fs35.default.existsSync(stableBin)) return stableBin;
53156
53417
  const partialBin = `${stableBin}.partial`;
53157
- const tarballPath = import_node_path35.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
53418
+ const tarballPath = import_node_path38.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
53158
53419
  try {
53159
53420
  const url = frpcDownloadUrl(version2, platform);
53160
53421
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -53163,8 +53424,8 @@ async function ensureFrpcBinary(opts) {
53163
53424
  } else {
53164
53425
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
53165
53426
  }
53166
- import_node_fs34.default.chmodSync(partialBin, 493);
53167
- import_node_fs34.default.renameSync(partialBin, stableBin);
53427
+ import_node_fs35.default.chmodSync(partialBin, 493);
53428
+ import_node_fs35.default.renameSync(partialBin, stableBin);
53168
53429
  } finally {
53169
53430
  safeUnlink(tarballPath);
53170
53431
  safeUnlink(partialBin);
@@ -53174,15 +53435,15 @@ async function ensureFrpcBinary(opts) {
53174
53435
  function cleanupStaleArtifacts(binDir) {
53175
53436
  let entries;
53176
53437
  try {
53177
- entries = import_node_fs34.default.readdirSync(binDir);
53438
+ entries = import_node_fs35.default.readdirSync(binDir);
53178
53439
  } catch {
53179
53440
  return;
53180
53441
  }
53181
53442
  for (const name of entries) {
53182
53443
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
53183
- const full = import_node_path35.default.join(binDir, name);
53444
+ const full = import_node_path38.default.join(binDir, name);
53184
53445
  try {
53185
- import_node_fs34.default.rmSync(full, { recursive: true, force: true });
53446
+ import_node_fs35.default.rmSync(full, { recursive: true, force: true });
53186
53447
  } catch {
53187
53448
  }
53188
53449
  }
@@ -53190,7 +53451,7 @@ function cleanupStaleArtifacts(binDir) {
53190
53451
  }
53191
53452
  function safeUnlink(p2) {
53192
53453
  try {
53193
- import_node_fs34.default.unlinkSync(p2);
53454
+ import_node_fs35.default.unlinkSync(p2);
53194
53455
  } catch {
53195
53456
  }
53196
53457
  }
@@ -53201,46 +53462,46 @@ async function downloadToFile(url, dest, fetchImpl) {
53201
53462
  if (!res.ok || !res.body) {
53202
53463
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
53203
53464
  }
53204
- const out = import_node_fs34.default.createWriteStream(dest);
53465
+ const out = import_node_fs35.default.createWriteStream(dest);
53205
53466
  const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
53206
53467
  await (0, import_promises5.pipeline)(nodeStream, out);
53207
53468
  }
53208
53469
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
53209
- const work = import_node_path35.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
53210
- import_node_fs34.default.mkdirSync(work, { recursive: true });
53470
+ const work = import_node_path38.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
53471
+ import_node_fs35.default.mkdirSync(work, { recursive: true });
53211
53472
  try {
53212
53473
  await new Promise((resolve6, reject) => {
53213
- const proc = (0, import_node_child_process7.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
53474
+ const proc = (0, import_node_child_process8.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
53214
53475
  proc.on("error", reject);
53215
53476
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
53216
53477
  });
53217
53478
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
53218
- const src = import_node_path35.default.join(work, dirName, "frpc");
53219
- if (!import_node_fs34.default.existsSync(src)) {
53479
+ const src = import_node_path38.default.join(work, dirName, "frpc");
53480
+ if (!import_node_fs35.default.existsSync(src)) {
53220
53481
  throw new Error(`frpc not found inside tarball at ${src}`);
53221
53482
  }
53222
- import_node_fs34.default.copyFileSync(src, destBin);
53483
+ import_node_fs35.default.copyFileSync(src, destBin);
53223
53484
  } finally {
53224
- import_node_fs34.default.rmSync(work, { recursive: true, force: true });
53485
+ import_node_fs35.default.rmSync(work, { recursive: true, force: true });
53225
53486
  }
53226
53487
  }
53227
53488
 
53228
53489
  // src/tunnel/frpc-process.ts
53229
- var import_node_fs35 = __toESM(require("fs"), 1);
53230
- var import_node_path36 = __toESM(require("path"), 1);
53231
- var import_node_child_process8 = require("child_process");
53490
+ var import_node_fs36 = __toESM(require("fs"), 1);
53491
+ var import_node_path39 = __toESM(require("path"), 1);
53492
+ var import_node_child_process9 = require("child_process");
53232
53493
  function frpcPidFilePath(dataDir) {
53233
- return import_node_path36.default.join(dataDir, "frpc.pid");
53494
+ return import_node_path39.default.join(dataDir, "frpc.pid");
53234
53495
  }
53235
53496
  function writeFrpcPid(dataDir, pid) {
53236
53497
  try {
53237
- import_node_fs35.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
53498
+ import_node_fs36.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
53238
53499
  } catch {
53239
53500
  }
53240
53501
  }
53241
53502
  function clearFrpcPid(dataDir) {
53242
53503
  try {
53243
- import_node_fs35.default.unlinkSync(frpcPidFilePath(dataDir));
53504
+ import_node_fs36.default.unlinkSync(frpcPidFilePath(dataDir));
53244
53505
  } catch {
53245
53506
  }
53246
53507
  }
@@ -53256,7 +53517,7 @@ function defaultIsPidAlive(pid) {
53256
53517
  }
53257
53518
  function defaultReadPidFile(file) {
53258
53519
  try {
53259
- return import_node_fs35.default.readFileSync(file, "utf8");
53520
+ return import_node_fs36.default.readFileSync(file, "utf8");
53260
53521
  } catch {
53261
53522
  return null;
53262
53523
  }
@@ -53272,7 +53533,7 @@ function defaultSleep(ms) {
53272
53533
  }
53273
53534
  async function killStaleFrpc(deps) {
53274
53535
  const pidFile = frpcPidFilePath(deps.dataDir);
53275
- const tomlPath = import_node_path36.default.join(deps.dataDir, "frpc.toml");
53536
+ const tomlPath = import_node_path39.default.join(deps.dataDir, "frpc.toml");
53276
53537
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
53277
53538
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
53278
53539
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -53296,7 +53557,7 @@ async function killStaleFrpc(deps) {
53296
53557
  }
53297
53558
  if (victims.size === 0) {
53298
53559
  try {
53299
- import_node_fs35.default.unlinkSync(pidFile);
53560
+ import_node_fs36.default.unlinkSync(pidFile);
53300
53561
  } catch {
53301
53562
  }
53302
53563
  return;
@@ -53307,14 +53568,14 @@ async function killStaleFrpc(deps) {
53307
53568
  }
53308
53569
  await sleep2(deps.reapWaitMs ?? 300);
53309
53570
  try {
53310
- import_node_fs35.default.unlinkSync(pidFile);
53571
+ import_node_fs36.default.unlinkSync(pidFile);
53311
53572
  } catch {
53312
53573
  }
53313
53574
  }
53314
53575
  async function defaultScanFrpcPidsByCmdline(tomlPath, logger) {
53315
53576
  if (process.platform === "win32") return [];
53316
53577
  return new Promise((resolve6) => {
53317
- const ps = (0, import_node_child_process8.spawn)("ps", ["-axo", "pid=,command="], { stdio: ["ignore", "pipe", "ignore"] });
53578
+ const ps = (0, import_node_child_process9.spawn)("ps", ["-axo", "pid=,command="], { stdio: ["ignore", "pipe", "ignore"] });
53318
53579
  let buf = "";
53319
53580
  ps.stdout.on("data", (c) => {
53320
53581
  buf += c.toString();
@@ -53344,7 +53605,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
53344
53605
  var TunnelManager = class {
53345
53606
  constructor(deps) {
53346
53607
  this.deps = deps;
53347
- this.store = deps.store ?? new TunnelStore(import_node_path37.default.join(deps.dataDir, "tunnel.json"));
53608
+ this.store = deps.store ?? new TunnelStore(import_node_path40.default.join(deps.dataDir, "tunnel.json"));
53348
53609
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
53349
53610
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
53350
53611
  }
@@ -53471,7 +53732,7 @@ var TunnelManager = class {
53471
53732
  dataDir: this.deps.dataDir,
53472
53733
  override: this.deps.frpcBinaryOverride ?? void 0
53473
53734
  });
53474
- const tomlPath = import_node_path37.default.join(this.deps.dataDir, "frpc.toml");
53735
+ const tomlPath = import_node_path40.default.join(this.deps.dataDir, "frpc.toml");
53475
53736
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
53476
53737
  const toml = buildFrpcToml({
53477
53738
  serverAddr: t.frpsHost,
@@ -53482,14 +53743,14 @@ var TunnelManager = class {
53482
53743
  localPort,
53483
53744
  logLevel: "info"
53484
53745
  });
53485
- await import_node_fs36.default.promises.writeFile(tomlPath, toml, { mode: 384 });
53486
- const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
53746
+ await import_node_fs37.default.promises.writeFile(tomlPath, toml, { mode: 384 });
53747
+ const proc = (this.deps.spawnImpl ?? import_node_child_process10.spawn)(frpcBin, ["-c", tomlPath], {
53487
53748
  stdio: ["ignore", "pipe", "pipe"]
53488
53749
  });
53489
- const logDir = import_node_path37.default.join(this.deps.dataDir, "log");
53490
- import_node_fs36.default.mkdirSync(logDir, { recursive: true });
53491
- const logFilePath = import_node_path37.default.join(logDir, "frpc.log");
53492
- const logStream = import_node_fs36.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
53750
+ const logDir = import_node_path40.default.join(this.deps.dataDir, "log");
53751
+ import_node_fs37.default.mkdirSync(logDir, { recursive: true });
53752
+ const logFilePath = import_node_path40.default.join(logDir, "frpc.log");
53753
+ const logStream = import_node_fs37.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
53493
53754
  logStream.on("error", () => {
53494
53755
  });
53495
53756
  const tee = (chunk) => {
@@ -53572,27 +53833,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
53572
53833
 
53573
53834
  // src/tunnel/device-key.ts
53574
53835
  var import_node_os14 = __toESM(require("os"), 1);
53575
- var import_node_path38 = __toESM(require("path"), 1);
53836
+ var import_node_path41 = __toESM(require("path"), 1);
53576
53837
  var import_node_crypto11 = __toESM(require("crypto"), 1);
53577
53838
  var DERIVE_SALT = "clawd-tunnel-device-v1";
53578
53839
  function deriveStableDeviceKey(opts = {}) {
53579
53840
  const hostname = opts.hostname ?? import_node_os14.default.hostname();
53580
53841
  const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
53581
53842
  const home = opts.home ?? import_node_os14.default.homedir();
53582
- const defaultDataDir = import_node_path38.default.resolve(import_node_path38.default.join(home, ".clawd"));
53583
- const normalizedDataDir = opts.dataDir ? import_node_path38.default.resolve(opts.dataDir) : null;
53843
+ const defaultDataDir = import_node_path41.default.resolve(import_node_path41.default.join(home, ".clawd"));
53844
+ const normalizedDataDir = opts.dataDir ? import_node_path41.default.resolve(opts.dataDir) : null;
53584
53845
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
53585
53846
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
53586
53847
  return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
53587
53848
  }
53588
53849
 
53589
53850
  // src/auth-store.ts
53590
- var import_node_fs37 = __toESM(require("fs"), 1);
53591
- var import_node_path39 = __toESM(require("path"), 1);
53851
+ var import_node_fs38 = __toESM(require("fs"), 1);
53852
+ var import_node_path42 = __toESM(require("path"), 1);
53592
53853
  var import_node_crypto12 = __toESM(require("crypto"), 1);
53593
53854
  var AUTH_FILE_NAME = "auth.json";
53594
53855
  function authFilePath(dataDir) {
53595
- return import_node_path39.default.join(dataDir, AUTH_FILE_NAME);
53856
+ return import_node_path42.default.join(dataDir, AUTH_FILE_NAME);
53596
53857
  }
53597
53858
  function loadOrCreateAuthFile(opts) {
53598
53859
  const file = authFilePath(opts.dataDir);
@@ -53628,7 +53889,7 @@ function defaultGenerateOwnerPrincipalId() {
53628
53889
  }
53629
53890
  function readAuthFile(file) {
53630
53891
  try {
53631
- const raw = import_node_fs37.default.readFileSync(file, "utf8");
53892
+ const raw = import_node_fs38.default.readFileSync(file, "utf8");
53632
53893
  const parsed = JSON.parse(raw);
53633
53894
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
53634
53895
  return null;
@@ -53648,25 +53909,25 @@ function readAuthFile(file) {
53648
53909
  }
53649
53910
  }
53650
53911
  function writeAuthFile(file, content) {
53651
- import_node_fs37.default.mkdirSync(import_node_path39.default.dirname(file), { recursive: true });
53652
- import_node_fs37.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
53912
+ import_node_fs38.default.mkdirSync(import_node_path42.default.dirname(file), { recursive: true });
53913
+ import_node_fs38.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
53653
53914
  try {
53654
- import_node_fs37.default.chmodSync(file, 384);
53915
+ import_node_fs38.default.chmodSync(file, 384);
53655
53916
  } catch {
53656
53917
  }
53657
53918
  }
53658
53919
 
53659
53920
  // src/owner-profile.ts
53660
- var import_node_fs38 = __toESM(require("fs"), 1);
53921
+ var import_node_fs39 = __toESM(require("fs"), 1);
53661
53922
  var import_node_os15 = __toESM(require("os"), 1);
53662
- var import_node_path40 = __toESM(require("path"), 1);
53923
+ var import_node_path43 = __toESM(require("path"), 1);
53663
53924
  var PROFILE_FILENAME = "profile.json";
53664
53925
  function loadOwnerDisplayName(dataDir) {
53665
53926
  const fallback = import_node_os15.default.userInfo().username;
53666
- const profilePath = import_node_path40.default.join(dataDir, PROFILE_FILENAME);
53927
+ const profilePath = import_node_path43.default.join(dataDir, PROFILE_FILENAME);
53667
53928
  let raw;
53668
53929
  try {
53669
- raw = import_node_fs38.default.readFileSync(profilePath, "utf8");
53930
+ raw = import_node_fs39.default.readFileSync(profilePath, "utf8");
53670
53931
  } catch {
53671
53932
  return fallback;
53672
53933
  }
@@ -53689,18 +53950,18 @@ function loadOwnerDisplayName(dataDir) {
53689
53950
  }
53690
53951
 
53691
53952
  // src/feishu-auth/owner-identity-store.ts
53692
- var import_node_fs39 = __toESM(require("fs"), 1);
53693
- var import_node_path41 = __toESM(require("path"), 1);
53953
+ var import_node_fs40 = __toESM(require("fs"), 1);
53954
+ var import_node_path44 = __toESM(require("path"), 1);
53694
53955
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
53695
53956
  var OwnerIdentityStore = class {
53696
53957
  file;
53697
53958
  constructor(dataDir) {
53698
- this.file = import_node_path41.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
53959
+ this.file = import_node_path44.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
53699
53960
  }
53700
53961
  read() {
53701
53962
  let raw;
53702
53963
  try {
53703
- raw = import_node_fs39.default.readFileSync(this.file, "utf8");
53964
+ raw = import_node_fs40.default.readFileSync(this.file, "utf8");
53704
53965
  } catch {
53705
53966
  return null;
53706
53967
  }
@@ -53728,16 +53989,16 @@ var OwnerIdentityStore = class {
53728
53989
  };
53729
53990
  }
53730
53991
  write(record) {
53731
- import_node_fs39.default.mkdirSync(import_node_path41.default.dirname(this.file), { recursive: true });
53732
- import_node_fs39.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
53992
+ import_node_fs40.default.mkdirSync(import_node_path44.default.dirname(this.file), { recursive: true });
53993
+ import_node_fs40.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
53733
53994
  try {
53734
- import_node_fs39.default.chmodSync(this.file, 384);
53995
+ import_node_fs40.default.chmodSync(this.file, 384);
53735
53996
  } catch {
53736
53997
  }
53737
53998
  }
53738
53999
  clear() {
53739
54000
  try {
53740
- import_node_fs39.default.unlinkSync(this.file);
54001
+ import_node_fs40.default.unlinkSync(this.file);
53741
54002
  } catch (err) {
53742
54003
  const code = err?.code;
53743
54004
  if (code !== "ENOENT") throw err;
@@ -53874,9 +54135,9 @@ var CentralClientError = class extends Error {
53874
54135
  code;
53875
54136
  cause;
53876
54137
  };
53877
- async function centralRequest(opts, path71, init) {
54138
+ async function centralRequest(opts, path74, init) {
53878
54139
  const f = opts.fetchImpl ?? globalThis.fetch;
53879
- const url = `${opts.api.replace(/\/+$/, "")}${path71}`;
54140
+ const url = `${opts.api.replace(/\/+$/, "")}${path74}`;
53880
54141
  const ctrl = new AbortController();
53881
54142
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
53882
54143
  let res;
@@ -54070,8 +54331,8 @@ function verifyConnectToken(args) {
54070
54331
  }
54071
54332
 
54072
54333
  // src/feishu-auth/server-key.ts
54073
- var fs50 = __toESM(require("fs"), 1);
54074
- var path50 = __toESM(require("path"), 1);
54334
+ var fs51 = __toESM(require("fs"), 1);
54335
+ var path53 = __toESM(require("path"), 1);
54075
54336
  var FILE_NAME2 = "server-signing-key.json";
54076
54337
  var ServerKeyStore = class {
54077
54338
  constructor(dataDir) {
@@ -54079,12 +54340,12 @@ var ServerKeyStore = class {
54079
54340
  }
54080
54341
  dataDir;
54081
54342
  filePath() {
54082
- return path50.join(this.dataDir, FILE_NAME2);
54343
+ return path53.join(this.dataDir, FILE_NAME2);
54083
54344
  }
54084
54345
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
54085
54346
  read() {
54086
54347
  try {
54087
- const raw = fs50.readFileSync(this.filePath(), "utf8");
54348
+ const raw = fs51.readFileSync(this.filePath(), "utf8");
54088
54349
  const parsed = JSON.parse(raw);
54089
54350
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
54090
54351
  return parsed.publicKeyPem;
@@ -54099,12 +54360,12 @@ var ServerKeyStore = class {
54099
54360
  publicKeyPem,
54100
54361
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
54101
54362
  };
54102
- fs50.mkdirSync(this.dataDir, { recursive: true });
54103
- fs50.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
54363
+ fs51.mkdirSync(this.dataDir, { recursive: true });
54364
+ fs51.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
54104
54365
  }
54105
54366
  clear() {
54106
54367
  try {
54107
- fs50.unlinkSync(this.filePath());
54368
+ fs51.unlinkSync(this.filePath());
54108
54369
  } catch {
54109
54370
  }
54110
54371
  }
@@ -54117,12 +54378,12 @@ init_protocol();
54117
54378
  init_protocol();
54118
54379
 
54119
54380
  // src/session/fork.ts
54120
- var import_node_fs40 = __toESM(require("fs"), 1);
54381
+ var import_node_fs41 = __toESM(require("fs"), 1);
54121
54382
  var import_node_os16 = __toESM(require("os"), 1);
54122
- var import_node_path42 = __toESM(require("path"), 1);
54383
+ var import_node_path45 = __toESM(require("path"), 1);
54123
54384
  init_claude_history();
54124
54385
  function readJsonlEntries(file) {
54125
- const raw = import_node_fs40.default.readFileSync(file, "utf8");
54386
+ const raw = import_node_fs41.default.readFileSync(file, "utf8");
54126
54387
  const out = [];
54127
54388
  for (const line of raw.split("\n")) {
54128
54389
  const t = line.trim();
@@ -54135,19 +54396,19 @@ function readJsonlEntries(file) {
54135
54396
  return out;
54136
54397
  }
54137
54398
  function forkSession(input) {
54138
- const baseDir = input.baseDir ?? import_node_path42.default.join(import_node_os16.default.homedir(), ".claude");
54139
- let projectDir = import_node_path42.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
54140
- let sourceFile = import_node_path42.default.join(projectDir, `${input.toolSessionId}.jsonl`);
54141
- if (!import_node_fs40.default.existsSync(sourceFile)) {
54399
+ const baseDir = input.baseDir ?? import_node_path45.default.join(import_node_os16.default.homedir(), ".claude");
54400
+ let projectDir = import_node_path45.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
54401
+ let sourceFile = import_node_path45.default.join(projectDir, `${input.toolSessionId}.jsonl`);
54402
+ if (!import_node_fs41.default.existsSync(sourceFile)) {
54142
54403
  const found = findTranscriptByToolSessionId(
54143
- import_node_path42.default.join(baseDir, "projects"),
54404
+ import_node_path45.default.join(baseDir, "projects"),
54144
54405
  input.toolSessionId
54145
54406
  );
54146
54407
  if (!found) {
54147
54408
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
54148
54409
  }
54149
54410
  sourceFile = found;
54150
- projectDir = import_node_path42.default.dirname(found);
54411
+ projectDir = import_node_path45.default.dirname(found);
54151
54412
  }
54152
54413
  const entries = readJsonlEntries(sourceFile);
54153
54414
  const mainEntries = entries.filter((e) => e.isSidechain !== true);
@@ -54176,9 +54437,9 @@ function forkSession(input) {
54176
54437
  }
54177
54438
  forkedLines.push(JSON.stringify(forked));
54178
54439
  }
54179
- const forkedFilePath = import_node_path42.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
54180
- import_node_fs40.default.mkdirSync(projectDir, { recursive: true });
54181
- import_node_fs40.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
54440
+ const forkedFilePath = import_node_path45.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
54441
+ import_node_fs41.default.mkdirSync(projectDir, { recursive: true });
54442
+ import_node_fs41.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
54182
54443
  return { forkedToolSessionId, forkedFilePath };
54183
54444
  }
54184
54445
 
@@ -54340,21 +54601,34 @@ function buildSessionHandlers(deps) {
54340
54601
  const { broadcast } = await manager.interrupt(args);
54341
54602
  return { response: { type: "session:interrupt", ok: true }, broadcast };
54342
54603
  };
54604
+ const ensureRewindSupported = async (sessionId) => {
54605
+ const file = manager.get({ sessionId }).response;
54606
+ const caps = await getAdapter2(file.tool ?? "claude").capabilities();
54607
+ if (caps.features.rewind === false) {
54608
+ throw new ClawdError(
54609
+ ERROR_CODES.TOOL_NOT_SUPPORTED,
54610
+ `tool ${file.tool ?? "claude"} does not support rewind`
54611
+ );
54612
+ }
54613
+ };
54343
54614
  const rewind = async (frame, _client, ctx) => {
54344
54615
  const args = SessionRewindArgs.parse(frame);
54345
54616
  ensureSessionAccess(ctx, args.sessionId, "send");
54617
+ await ensureRewindSupported(args.sessionId);
54346
54618
  const { response, broadcast } = await manager.rewind(args);
54347
54619
  return { response: { type: "session:rewind", ...response }, broadcast };
54348
54620
  };
54349
54621
  const rewindDiff = async (frame, _client, ctx) => {
54350
54622
  const args = SessionRewindDiffArgs.parse(frame);
54351
54623
  ensureSessionAccess(ctx, args.sessionId, "read");
54624
+ await ensureRewindSupported(args.sessionId);
54352
54625
  const { response } = await manager.rewindDiff(args);
54353
54626
  return { response: { type: "session:rewind-diff", ...response } };
54354
54627
  };
54355
54628
  const rewindableMessageIds = async (frame, _client, ctx) => {
54356
54629
  const args = SessionRewindableMessageIdsArgs.parse(frame);
54357
54630
  ensureSessionAccess(ctx, args.sessionId, "read");
54631
+ await ensureRewindSupported(args.sessionId);
54358
54632
  const { response } = manager.rewindableMessageIds(args);
54359
54633
  return {
54360
54634
  response: { type: "session:rewindable-message-ids", ...response }
@@ -54577,7 +54851,7 @@ function buildPermissionHandlers(deps) {
54577
54851
  }
54578
54852
 
54579
54853
  // src/handlers/history.ts
54580
- var path53 = __toESM(require("path"), 1);
54854
+ var path56 = __toESM(require("path"), 1);
54581
54855
  init_protocol();
54582
54856
 
54583
54857
  // src/session/recent-dirs.ts
@@ -54595,7 +54869,7 @@ function listRecentDirs(store, limit = 50) {
54595
54869
  }
54596
54870
 
54597
54871
  // src/permission/persona-paths.ts
54598
- var path52 = __toESM(require("path"), 1);
54872
+ var path55 = __toESM(require("path"), 1);
54599
54873
  function getAllowedPersonaIds(grants, action) {
54600
54874
  const ids = /* @__PURE__ */ new Set();
54601
54875
  for (const g2 of grants) {
@@ -54608,42 +54882,42 @@ function getAllowedPersonaIds(grants, action) {
54608
54882
  return ids;
54609
54883
  }
54610
54884
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
54611
- const target = path52.resolve(absPath);
54885
+ const target = path55.resolve(absPath);
54612
54886
  if (userWorkDir) {
54613
- const u = path52.resolve(userWorkDir);
54614
- const usep = u.endsWith(path52.sep) ? "" : path52.sep;
54887
+ const u = path55.resolve(userWorkDir);
54888
+ const usep = u.endsWith(path55.sep) ? "" : path55.sep;
54615
54889
  if (target === u || target.startsWith(u + usep)) return true;
54616
54890
  }
54617
- const root = path52.resolve(personaRoot);
54618
- const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
54891
+ const root = path55.resolve(personaRoot);
54892
+ const sep3 = root.endsWith(path55.sep) ? "" : path55.sep;
54619
54893
  if (!target.startsWith(root + sep3)) return false;
54620
- const rel = path52.relative(root, target);
54894
+ const rel = path55.relative(root, target);
54621
54895
  if (!rel || rel.startsWith("..")) return false;
54622
- const personaId = rel.split(path52.sep)[0];
54896
+ const personaId = rel.split(path55.sep)[0];
54623
54897
  if (!personaId) return false;
54624
54898
  const allowed = getAllowedPersonaIds(grants, action);
54625
54899
  if (allowed === "*") return true;
54626
54900
  return allowed.has(personaId);
54627
54901
  }
54628
54902
  function personaIdFromPath(absPath, personaRoot) {
54629
- const root = path52.resolve(personaRoot);
54630
- const target = path52.resolve(absPath);
54631
- const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
54903
+ const root = path55.resolve(personaRoot);
54904
+ const target = path55.resolve(absPath);
54905
+ const sep3 = root.endsWith(path55.sep) ? "" : path55.sep;
54632
54906
  if (!target.startsWith(root + sep3)) return null;
54633
- const rel = path52.relative(root, target);
54907
+ const rel = path55.relative(root, target);
54634
54908
  if (!rel || rel.startsWith("..")) return null;
54635
- const id = rel.split(path52.sep)[0];
54909
+ const id = rel.split(path55.sep)[0];
54636
54910
  return id || null;
54637
54911
  }
54638
54912
  function isPathWithin(dir, absPath) {
54639
- const d = path52.resolve(dir);
54640
- const t = path52.resolve(absPath);
54641
- const sep3 = d.endsWith(path52.sep) ? "" : path52.sep;
54913
+ const d = path55.resolve(dir);
54914
+ const t = path55.resolve(absPath);
54915
+ const sep3 = d.endsWith(path55.sep) ? "" : path55.sep;
54642
54916
  return t === d || t.startsWith(d + sep3);
54643
54917
  }
54644
54918
  function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
54645
54919
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
54646
- return personaIdFromPath(path52.resolve(absPath), personaRoot) === personaId;
54920
+ return personaIdFromPath(path55.resolve(absPath), personaRoot) === personaId;
54647
54921
  }
54648
54922
 
54649
54923
  // src/handlers/history.ts
@@ -54695,7 +54969,7 @@ function buildHistoryHandlers(deps) {
54695
54969
  if (!pid) return false;
54696
54970
  return isGuestPathAllowed(
54697
54971
  ctx.grants,
54698
- path53.join(personaRoot, pid),
54972
+ path56.join(personaRoot, pid),
54699
54973
  personaRoot,
54700
54974
  "read",
54701
54975
  userWorkDir
@@ -54707,7 +54981,7 @@ function buildHistoryHandlers(deps) {
54707
54981
  };
54708
54982
  const list = async (frame, _client, ctx) => {
54709
54983
  const args = HistoryListArgs.parse(frame);
54710
- assertGuestPath(ctx, path53.resolve(args.projectPath), personaRoot, "history:list");
54984
+ assertGuestPath(ctx, path56.resolve(args.projectPath), personaRoot, "history:list");
54711
54985
  const sessions = await history.listSessions(args);
54712
54986
  return { response: { type: "history:list", sessions } };
54713
54987
  };
@@ -54740,13 +55014,13 @@ function buildHistoryHandlers(deps) {
54740
55014
  };
54741
55015
  const subagents = async (frame, _client, ctx) => {
54742
55016
  const args = HistorySubagentsArgs.parse(frame);
54743
- assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
55017
+ assertGuestPath(ctx, path56.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
54744
55018
  const subs = await history.listSubagents(args);
54745
55019
  return { response: { type: "history:subagents", subagents: subs } };
54746
55020
  };
54747
55021
  const subagentRead = async (frame, _client, ctx) => {
54748
55022
  const args = HistorySubagentReadArgs.parse(frame);
54749
- assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
55023
+ assertGuestPath(ctx, path56.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
54750
55024
  const res = await history.readSubagent(args);
54751
55025
  return { response: { type: "history:subagent-read", ...res } };
54752
55026
  };
@@ -54755,7 +55029,7 @@ function buildHistoryHandlers(deps) {
54755
55029
  if (ctx?.principal.kind === "guest" && personaRoot) {
54756
55030
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
54757
55031
  const filtered = dirs.filter(
54758
- (d) => isGuestPathAllowed(ctx.grants, path53.resolve(d.cwd), personaRoot, "read", userWorkDir)
55032
+ (d) => isGuestPathAllowed(ctx.grants, path56.resolve(d.cwd), personaRoot, "read", userWorkDir)
54759
55033
  );
54760
55034
  return { response: { type: "history:recentDirs", dirs: filtered } };
54761
55035
  }
@@ -54772,7 +55046,7 @@ function buildHistoryHandlers(deps) {
54772
55046
  }
54773
55047
 
54774
55048
  // src/handlers/workspace.ts
54775
- var path54 = __toESM(require("path"), 1);
55049
+ var path57 = __toESM(require("path"), 1);
54776
55050
  var os16 = __toESM(require("os"), 1);
54777
55051
  init_protocol();
54778
55052
  init_protocol();
@@ -54814,22 +55088,22 @@ function buildWorkspaceHandlers(deps) {
54814
55088
  const args = WorkspaceListArgs.parse(frame);
54815
55089
  const isGuest = ctx?.principal.kind === "guest";
54816
55090
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
54817
- const resolvedCwd = path54.resolve(args.cwd ?? fallbackCwd);
54818
- const target = args.path ? path54.resolve(resolvedCwd, args.path) : resolvedCwd;
55091
+ const resolvedCwd = path57.resolve(args.cwd ?? fallbackCwd);
55092
+ const target = args.path ? path57.resolve(resolvedCwd, args.path) : resolvedCwd;
54819
55093
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
54820
55094
  const res = workspace.list({ ...args, cwd: resolvedCwd });
54821
55095
  return { response: { type: "workspace:list", ...res } };
54822
55096
  };
54823
55097
  const read = async (frame, _client, ctx) => {
54824
55098
  const args = WorkspaceReadArgs.parse(frame);
54825
- const target = path54.isAbsolute(args.path) ? path54.resolve(args.path) : path54.resolve(args.cwd, args.path);
55099
+ const target = path57.isAbsolute(args.path) ? path57.resolve(args.path) : path57.resolve(args.cwd, args.path);
54826
55100
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
54827
55101
  const res = workspace.read(args);
54828
55102
  return { response: { type: "workspace:read", ...res } };
54829
55103
  };
54830
55104
  const skillsList = async (frame, _client, ctx) => {
54831
55105
  const args = SkillsListArgs.parse(frame);
54832
- const cwdAbs = path54.resolve(args.cwd);
55106
+ const cwdAbs = path57.resolve(args.cwd);
54833
55107
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
54834
55108
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
54835
55109
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -54841,7 +55115,7 @@ function buildWorkspaceHandlers(deps) {
54841
55115
  };
54842
55116
  const agentsList = async (frame, _client, ctx) => {
54843
55117
  const args = AgentsListArgs.parse(frame);
54844
- const cwdAbs = path54.resolve(args.cwd);
55118
+ const cwdAbs = path57.resolve(args.cwd);
54845
55119
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
54846
55120
  if (args.tool === "codex") {
54847
55121
  return { response: { type: "agents:list", agents: [] } };
@@ -54863,20 +55137,20 @@ function buildWorkspaceHandlers(deps) {
54863
55137
  }
54864
55138
 
54865
55139
  // src/handlers/git.ts
54866
- var path56 = __toESM(require("path"), 1);
55140
+ var path59 = __toESM(require("path"), 1);
54867
55141
  init_protocol();
54868
55142
  init_protocol();
54869
55143
 
54870
55144
  // src/workspace/git.ts
54871
- var import_node_child_process10 = require("child_process");
54872
- var import_node_fs41 = __toESM(require("fs"), 1);
54873
- var import_node_path43 = __toESM(require("path"), 1);
55145
+ var import_node_child_process11 = require("child_process");
55146
+ var import_node_fs42 = __toESM(require("fs"), 1);
55147
+ var import_node_path46 = __toESM(require("path"), 1);
54874
55148
  var import_node_util = require("util");
54875
- var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
55149
+ var pexec = (0, import_node_util.promisify)(import_node_child_process11.execFile);
54876
55150
  function normalizePath(p2) {
54877
- const resolved = import_node_path43.default.resolve(p2);
55151
+ const resolved = import_node_path46.default.resolve(p2);
54878
55152
  try {
54879
- return import_node_fs41.default.realpathSync(resolved);
55153
+ return import_node_fs42.default.realpathSync(resolved);
54880
55154
  } catch {
54881
55155
  return resolved;
54882
55156
  }
@@ -54950,7 +55224,7 @@ async function listGitBranches(cwd) {
54950
55224
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
54951
55225
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
54952
55226
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
54953
- if (!isGuestPathAllowed(ctx.grants, path56.resolve(cwd), personaRoot, "read", userWorkDir)) {
55227
+ if (!isGuestPathAllowed(ctx.grants, path59.resolve(cwd), personaRoot, "read", userWorkDir)) {
54954
55228
  throw new ClawdError(
54955
55229
  ERROR_CODES.UNAUTHORIZED,
54956
55230
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -55636,7 +55910,7 @@ function buildPersonaHandlers(deps) {
55636
55910
  }
55637
55911
 
55638
55912
  // src/handlers/attachment.ts
55639
- var import_node_path44 = __toESM(require("path"), 1);
55913
+ var import_node_path47 = __toESM(require("path"), 1);
55640
55914
  init_protocol();
55641
55915
  init_protocol();
55642
55916
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -55716,12 +55990,12 @@ function buildAttachmentHandlers(deps) {
55716
55990
  `session ${args.sessionId} scope unresolved`
55717
55991
  );
55718
55992
  }
55719
- const cwdAbs = import_node_path44.default.resolve(sessionFile.cwd);
55720
- const candidateAbs = import_node_path44.default.isAbsolute(args.relPath) ? import_node_path44.default.resolve(args.relPath) : import_node_path44.default.resolve(cwdAbs, args.relPath);
55993
+ const cwdAbs = import_node_path47.default.resolve(sessionFile.cwd);
55994
+ const candidateAbs = import_node_path47.default.isAbsolute(args.relPath) ? import_node_path47.default.resolve(args.relPath) : import_node_path47.default.resolve(cwdAbs, args.relPath);
55721
55995
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
55722
55996
  const entries = deps.groupFileStore.list(scope, args.sessionId);
55723
55997
  const entry = entries.find((e) => {
55724
- const storedAbs = import_node_path44.default.isAbsolute(e.relPath) ? import_node_path44.default.resolve(e.relPath) : import_node_path44.default.resolve(cwdAbs, e.relPath);
55998
+ const storedAbs = import_node_path47.default.isAbsolute(e.relPath) ? import_node_path47.default.resolve(e.relPath) : import_node_path47.default.resolve(cwdAbs, e.relPath);
55725
55999
  return storedAbs === candidateAbs && !e.stale;
55726
56000
  });
55727
56001
  if (!entry) {
@@ -55746,7 +56020,7 @@ function buildAttachmentHandlers(deps) {
55746
56020
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
55747
56021
  const f = deps.sessionStore.read(sessionId);
55748
56022
  if (!f) return;
55749
- assertGuestAttachmentPath(ctx, import_node_path44.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
56023
+ assertGuestAttachmentPath(ctx, import_node_path47.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
55750
56024
  }
55751
56025
  const groupAdd = async (frame, _client, ctx) => {
55752
56026
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -55761,8 +56035,8 @@ function buildAttachmentHandlers(deps) {
55761
56035
  if (!scope) {
55762
56036
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
55763
56037
  }
55764
- const cwdAbs = import_node_path44.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
55765
- const candidateAbs = import_node_path44.default.isAbsolute(args.relPath) ? import_node_path44.default.resolve(args.relPath) : import_node_path44.default.resolve(cwdAbs, args.relPath);
56038
+ const cwdAbs = import_node_path47.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
56039
+ const candidateAbs = import_node_path47.default.isAbsolute(args.relPath) ? import_node_path47.default.resolve(args.relPath) : import_node_path47.default.resolve(cwdAbs, args.relPath);
55766
56040
  guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
55767
56041
  const from = ctx?.principal.kind === "owner" ? "owner" : "agent";
55768
56042
  const size = 0;
@@ -55821,19 +56095,19 @@ function buildAttachmentHandlers(deps) {
55821
56095
 
55822
56096
  // src/handlers/extension.ts
55823
56097
  var import_promises9 = __toESM(require("fs/promises"), 1);
55824
- var import_node_path49 = __toESM(require("path"), 1);
56098
+ var import_node_path52 = __toESM(require("path"), 1);
55825
56099
  init_protocol();
55826
56100
 
55827
56101
  // src/extension/bundle-zip.ts
55828
56102
  var import_promises6 = __toESM(require("fs/promises"), 1);
55829
- var import_node_path45 = __toESM(require("path"), 1);
56103
+ var import_node_path48 = __toESM(require("path"), 1);
55830
56104
  var import_node_crypto14 = __toESM(require("crypto"), 1);
55831
56105
  var import_jszip2 = __toESM(require_lib3(), 1);
55832
56106
  async function bundleExtensionDir(dir) {
55833
56107
  const entries = await listFilesSorted(dir);
55834
56108
  const zip = new import_jszip2.default();
55835
56109
  for (const rel of entries) {
55836
- const abs = import_node_path45.default.join(dir, rel);
56110
+ const abs = import_node_path48.default.join(dir, rel);
55837
56111
  const content = await import_promises6.default.readFile(abs);
55838
56112
  zip.file(rel, content, { date: FIXED_DATE });
55839
56113
  }
@@ -55854,7 +56128,7 @@ async function listFilesSorted(rootDir) {
55854
56128
  return out;
55855
56129
  }
55856
56130
  async function walk(absRoot, relPrefix, out) {
55857
- const dirAbs = import_node_path45.default.join(absRoot, relPrefix);
56131
+ const dirAbs = import_node_path48.default.join(absRoot, relPrefix);
55858
56132
  const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
55859
56133
  for (const e of entries) {
55860
56134
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -55908,25 +56182,25 @@ function computePublishCheck(args) {
55908
56182
 
55909
56183
  // src/extension/install-flow.ts
55910
56184
  var import_promises7 = __toESM(require("fs/promises"), 1);
55911
- var import_node_path47 = __toESM(require("path"), 1);
56185
+ var import_node_path50 = __toESM(require("path"), 1);
55912
56186
  var import_node_os19 = __toESM(require("os"), 1);
55913
56187
  var import_node_crypto15 = __toESM(require("crypto"), 1);
55914
56188
  var import_jszip3 = __toESM(require_lib3(), 1);
55915
56189
 
55916
56190
  // src/extension/paths.ts
55917
56191
  var import_node_os18 = __toESM(require("os"), 1);
55918
- var import_node_path46 = __toESM(require("path"), 1);
56192
+ var import_node_path49 = __toESM(require("path"), 1);
55919
56193
  function clawdHomeRoot(override) {
55920
- return override ?? process.env.CLAWD_HOME ?? import_node_path46.default.join(import_node_os18.default.homedir(), ".clawd");
56194
+ return override ?? process.env.CLAWD_HOME ?? import_node_path49.default.join(import_node_os18.default.homedir(), ".clawd");
55921
56195
  }
55922
56196
  function extensionsRoot(override) {
55923
- return import_node_path46.default.join(clawdHomeRoot(override), "extensions");
56197
+ return import_node_path49.default.join(clawdHomeRoot(override), "extensions");
55924
56198
  }
55925
56199
  function publishedChannelsFile(override) {
55926
- return import_node_path46.default.join(clawdHomeRoot(override), "extensions-published.json");
56200
+ return import_node_path49.default.join(clawdHomeRoot(override), "extensions-published.json");
55927
56201
  }
55928
56202
  function bundleCacheRoot(override) {
55929
- return import_node_path46.default.join(clawdHomeRoot(override), "extension-bundles");
56203
+ return import_node_path49.default.join(clawdHomeRoot(override), "extension-bundles");
55930
56204
  }
55931
56205
 
55932
56206
  // src/extension/install-flow.ts
@@ -55953,7 +56227,7 @@ async function installFromChannel(args, deps) {
55953
56227
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
55954
56228
  }
55955
56229
  for (const name of Object.keys(zip.files)) {
55956
- if (name.includes("..") || name.startsWith("/") || import_node_path47.default.isAbsolute(name)) {
56230
+ if (name.includes("..") || name.startsWith("/") || import_node_path50.default.isAbsolute(name)) {
55957
56231
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
55958
56232
  }
55959
56233
  }
@@ -55985,7 +56259,7 @@ async function installFromChannel(args, deps) {
55985
56259
  );
55986
56260
  }
55987
56261
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
55988
- const destDir = import_node_path47.default.join(deps.extensionsRoot, localExtId);
56262
+ const destDir = import_node_path50.default.join(deps.extensionsRoot, localExtId);
55989
56263
  let destExists = false;
55990
56264
  try {
55991
56265
  await import_promises7.default.access(destDir);
@@ -55999,16 +56273,16 @@ async function installFromChannel(args, deps) {
55999
56273
  );
56000
56274
  }
56001
56275
  const stage = await import_promises7.default.mkdtemp(
56002
- import_node_path47.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
56276
+ import_node_path50.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
56003
56277
  );
56004
56278
  try {
56005
56279
  for (const [name, entry] of Object.entries(zip.files)) {
56006
- const dest = import_node_path47.default.join(stage, name);
56280
+ const dest = import_node_path50.default.join(stage, name);
56007
56281
  if (entry.dir) {
56008
56282
  await import_promises7.default.mkdir(dest, { recursive: true });
56009
56283
  continue;
56010
56284
  }
56011
- await import_promises7.default.mkdir(import_node_path47.default.dirname(dest), { recursive: true });
56285
+ await import_promises7.default.mkdir(import_node_path50.default.dirname(dest), { recursive: true });
56012
56286
  if (name === "manifest.json") {
56013
56287
  const rewritten = { ...parsed.data, id: localExtId };
56014
56288
  await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -56029,7 +56303,7 @@ async function installFromChannel(args, deps) {
56029
56303
 
56030
56304
  // src/extension/update-flow.ts
56031
56305
  var import_promises8 = __toESM(require("fs/promises"), 1);
56032
- var import_node_path48 = __toESM(require("path"), 1);
56306
+ var import_node_path51 = __toESM(require("path"), 1);
56033
56307
  var import_node_os20 = __toESM(require("os"), 1);
56034
56308
  var import_node_crypto16 = __toESM(require("crypto"), 1);
56035
56309
  var import_jszip4 = __toESM(require_lib3(), 1);
@@ -56046,11 +56320,11 @@ async function updateFromChannel(args, deps) {
56046
56320
  channelRef.extId,
56047
56321
  channelRef.ownerPrincipalId
56048
56322
  );
56049
- const liveDir = import_node_path48.default.join(deps.extensionsRoot, localExtId);
56323
+ const liveDir = import_node_path51.default.join(deps.extensionsRoot, localExtId);
56050
56324
  const prevDir = `${liveDir}.prev`;
56051
56325
  let existingVersion;
56052
56326
  try {
56053
- const raw = await import_promises8.default.readFile(import_node_path48.default.join(liveDir, "manifest.json"), "utf8");
56327
+ const raw = await import_promises8.default.readFile(import_node_path51.default.join(liveDir, "manifest.json"), "utf8");
56054
56328
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
56055
56329
  if (!parsed2.success) {
56056
56330
  throw new UpdateError(
@@ -56083,7 +56357,7 @@ async function updateFromChannel(args, deps) {
56083
56357
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
56084
56358
  }
56085
56359
  for (const name of Object.keys(zip.files)) {
56086
- if (name.includes("..") || name.startsWith("/") || import_node_path48.default.isAbsolute(name)) {
56360
+ if (name.includes("..") || name.startsWith("/") || import_node_path51.default.isAbsolute(name)) {
56087
56361
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
56088
56362
  }
56089
56363
  }
@@ -56118,16 +56392,16 @@ async function updateFromChannel(args, deps) {
56118
56392
  await import_promises8.default.rm(prevDir, { recursive: true, force: true });
56119
56393
  await import_promises8.default.rename(liveDir, prevDir);
56120
56394
  const stage = await import_promises8.default.mkdtemp(
56121
- import_node_path48.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
56395
+ import_node_path51.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
56122
56396
  );
56123
56397
  try {
56124
56398
  for (const [name, entry] of Object.entries(zip.files)) {
56125
- const dest = import_node_path48.default.join(stage, name);
56399
+ const dest = import_node_path51.default.join(stage, name);
56126
56400
  if (entry.dir) {
56127
56401
  await import_promises8.default.mkdir(dest, { recursive: true });
56128
56402
  continue;
56129
56403
  }
56130
- await import_promises8.default.mkdir(import_node_path48.default.dirname(dest), { recursive: true });
56404
+ await import_promises8.default.mkdir(import_node_path51.default.dirname(dest), { recursive: true });
56131
56405
  if (name === "manifest.json") {
56132
56406
  const rewritten = { ...parsed.data, id: localExtId };
56133
56407
  await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -56220,7 +56494,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
56220
56494
  );
56221
56495
  }
56222
56496
  }
56223
- const manifestPath = import_node_path49.default.join(root, extId, "manifest.json");
56497
+ const manifestPath = import_node_path52.default.join(root, extId, "manifest.json");
56224
56498
  const manifest = await readManifest(root, extId);
56225
56499
  const next = { ...manifest, version: newVersion };
56226
56500
  const tmp = `${manifestPath}.tmp`;
@@ -56228,7 +56502,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
56228
56502
  await import_promises9.default.rename(tmp, manifestPath);
56229
56503
  }
56230
56504
  async function readManifest(root, extId) {
56231
- const file = import_node_path49.default.join(root, extId, "manifest.json");
56505
+ const file = import_node_path52.default.join(root, extId, "manifest.json");
56232
56506
  let raw;
56233
56507
  try {
56234
56508
  raw = await import_promises9.default.readFile(file, "utf8");
@@ -56319,7 +56593,7 @@ function buildExtensionHandlers(deps) {
56319
56593
  };
56320
56594
  async function buildSnapshotMeta(extId) {
56321
56595
  const manifest = await readManifest(deps.root, extId);
56322
- const { sha256, buffer } = await bundleExtensionDir(import_node_path49.default.join(deps.root, extId));
56596
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path52.default.join(deps.root, extId));
56323
56597
  return { manifest, contentHash: sha256, buffer };
56324
56598
  }
56325
56599
  const publish = async (frame, _client, ctx) => {
@@ -56500,9 +56774,9 @@ function buildExtensionHandlers(deps) {
56500
56774
  }
56501
56775
 
56502
56776
  // src/app-builder/project-store.ts
56503
- var import_node_fs42 = require("fs");
56504
- var import_node_child_process11 = require("child_process");
56505
- var import_node_path50 = require("path");
56777
+ var import_node_fs43 = require("fs");
56778
+ var import_node_child_process12 = require("child_process");
56779
+ var import_node_path53 = require("path");
56506
56780
  init_protocol();
56507
56781
  var PROJECTS_DIR = "projects";
56508
56782
  var META_FILE = ".clawd-project.json";
@@ -56516,19 +56790,19 @@ var ProjectStore = class {
56516
56790
  root;
56517
56791
  /** projects/<name>/.clawd-project.json 路径 */
56518
56792
  metaPath(name) {
56519
- return (0, import_node_path50.join)(this.projectsRoot(), name, META_FILE);
56793
+ return (0, import_node_path53.join)(this.projectsRoot(), name, META_FILE);
56520
56794
  }
56521
56795
  /** projects/<name>/ 目录路径(cwd 用) */
56522
56796
  projectDir(name) {
56523
- return (0, import_node_path50.join)(this.projectsRoot(), name);
56797
+ return (0, import_node_path53.join)(this.projectsRoot(), name);
56524
56798
  }
56525
56799
  projectsRoot() {
56526
- return (0, import_node_path50.join)(this.root, PROJECTS_DIR);
56800
+ return (0, import_node_path53.join)(this.root, PROJECTS_DIR);
56527
56801
  }
56528
56802
  async list() {
56529
56803
  let entries;
56530
56804
  try {
56531
- entries = await import_node_fs42.promises.readdir(this.projectsRoot());
56805
+ entries = await import_node_fs43.promises.readdir(this.projectsRoot());
56532
56806
  } catch (err) {
56533
56807
  if (err.code === "ENOENT") return [];
56534
56808
  throw err;
@@ -56536,7 +56810,7 @@ var ProjectStore = class {
56536
56810
  const out = [];
56537
56811
  for (const name of entries) {
56538
56812
  try {
56539
- const raw = await import_node_fs42.promises.readFile(this.metaPath(name), "utf8");
56813
+ const raw = await import_node_fs43.promises.readFile(this.metaPath(name), "utf8");
56540
56814
  const json = JSON.parse(raw);
56541
56815
  let migrated = false;
56542
56816
  if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
@@ -56547,7 +56821,7 @@ var ProjectStore = class {
56547
56821
  if (parsed.success) {
56548
56822
  out.push(parsed.data);
56549
56823
  if (migrated) {
56550
- void import_node_fs42.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
56824
+ void import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
56551
56825
  });
56552
56826
  }
56553
56827
  }
@@ -56591,8 +56865,8 @@ var ProjectStore = class {
56591
56865
  throw new Error(`invalid name "${name}": ${validated.error.message}`);
56592
56866
  }
56593
56867
  const dir = this.projectDir(name);
56594
- await import_node_fs42.promises.mkdir(dir, { recursive: true });
56595
- await import_node_fs42.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
56868
+ await import_node_fs43.promises.mkdir(dir, { recursive: true });
56869
+ await import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
56596
56870
  return meta;
56597
56871
  }
56598
56872
  /**
@@ -56606,7 +56880,7 @@ var ProjectStore = class {
56606
56880
  async scaffold(name, templateSrcDir, scaffoldScriptPath) {
56607
56881
  const destDir = this.projectDir(name);
56608
56882
  return await new Promise((resolve6, reject) => {
56609
- const child = (0, import_node_child_process11.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
56883
+ const child = (0, import_node_child_process12.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
56610
56884
  env: { ...process.env, PATH: process.env.PATH ?? "" },
56611
56885
  stdio: ["ignore", "pipe", "pipe"]
56612
56886
  });
@@ -56635,7 +56909,7 @@ var ProjectStore = class {
56635
56909
  }
56636
56910
  async delete(name) {
56637
56911
  const dir = this.projectDir(name);
56638
- await import_node_fs42.promises.rm(dir, { recursive: true, force: true });
56912
+ await import_node_fs43.promises.rm(dir, { recursive: true, force: true });
56639
56913
  }
56640
56914
  async updatePort(name, newPort) {
56641
56915
  if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
@@ -56651,7 +56925,7 @@ var ProjectStore = class {
56651
56925
  throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
56652
56926
  }
56653
56927
  const updated = { ...target, port: newPort };
56654
- await import_node_fs42.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
56928
+ await import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
56655
56929
  return updated;
56656
56930
  }
56657
56931
  /**
@@ -56668,7 +56942,7 @@ var ProjectStore = class {
56668
56942
  if (!validated.success) {
56669
56943
  throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
56670
56944
  }
56671
- await import_node_fs42.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
56945
+ await import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
56672
56946
  return validated.data;
56673
56947
  }
56674
56948
  /**
@@ -56689,7 +56963,7 @@ var ProjectStore = class {
56689
56963
  if (!validated.success) {
56690
56964
  throw new Error(`invalid publishJob: ${validated.error.message}`);
56691
56965
  }
56692
- await import_node_fs42.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
56966
+ await import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
56693
56967
  return validated.data;
56694
56968
  }
56695
56969
  /** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
@@ -56704,13 +56978,13 @@ var ProjectStore = class {
56704
56978
  if (!validated.success) {
56705
56979
  throw new Error(`failed to clear publishJob: ${validated.error.message}`);
56706
56980
  }
56707
- await import_node_fs42.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
56981
+ await import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
56708
56982
  return validated.data;
56709
56983
  }
56710
56984
  };
56711
56985
 
56712
56986
  // src/app-builder/kill-port.ts
56713
- var import_node_child_process12 = require("child_process");
56987
+ var import_node_child_process13 = require("child_process");
56714
56988
  async function killPortOccupants(port, ownedPids, logger) {
56715
56989
  let pids;
56716
56990
  try {
@@ -56752,7 +57026,7 @@ async function killPortOccupants(port, ownedPids, logger) {
56752
57026
  }
56753
57027
  function listPidsOnPort(port) {
56754
57028
  return new Promise((resolve6, reject) => {
56755
- (0, import_node_child_process12.execFile)(
57029
+ (0, import_node_child_process13.execFile)(
56756
57030
  "lsof",
56757
57031
  ["-ti", `:${port}`],
56758
57032
  { timeout: 3e3 },
@@ -56824,9 +57098,9 @@ var PublishJobRegistry = class {
56824
57098
  };
56825
57099
 
56826
57100
  // src/app-builder/publish-job-runner.ts
56827
- var import_node_child_process13 = require("child_process");
56828
- var import_node_fs43 = require("fs");
56829
- var import_node_path51 = require("path");
57101
+ var import_node_child_process14 = require("child_process");
57102
+ var import_node_fs44 = require("fs");
57103
+ var import_node_path54 = require("path");
56830
57104
 
56831
57105
  // src/app-builder/publish-stage-parser.ts
56832
57106
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -56853,15 +57127,15 @@ function tailStderrLines(buf, n) {
56853
57127
  // src/app-builder/publish-job-runner.ts
56854
57128
  async function startPublishJob(deps, args) {
56855
57129
  const { registry: registry2, projectDir } = deps;
56856
- const spawn13 = deps.spawnImpl ?? import_node_child_process13.spawn;
57130
+ const spawn13 = deps.spawnImpl ?? import_node_child_process14.spawn;
56857
57131
  if (registry2.has(args.name)) {
56858
57132
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
56859
57133
  }
56860
57134
  const projDir = projectDir(args.name);
56861
- const logPath = (0, import_node_path51.join)(projDir, ".publish.log");
57135
+ const logPath = (0, import_node_path54.join)(projDir, ".publish.log");
56862
57136
  let logStream = null;
56863
57137
  try {
56864
- logStream = (0, import_node_fs43.createWriteStream)(logPath, { flags: "w" });
57138
+ logStream = (0, import_node_fs44.createWriteStream)(logPath, { flags: "w" });
56865
57139
  } catch {
56866
57140
  logStream = null;
56867
57141
  }
@@ -57118,8 +57392,8 @@ async function recoverInterruptedJobs(deps) {
57118
57392
 
57119
57393
  // src/handlers/app-builder.ts
57120
57394
  init_protocol();
57121
- var import_node_path52 = require("path");
57122
- var import_node_fs44 = require("fs");
57395
+ var import_node_path55 = require("path");
57396
+ var import_node_fs45 = require("fs");
57123
57397
  var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
57124
57398
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
57125
57399
  async function recoverInterruptedPublishJobs(store, logger) {
@@ -57200,7 +57474,7 @@ function buildAppBuilderHandlers(deps) {
57200
57474
  async function listAllUsersProjects() {
57201
57475
  if (!deps.usersRoot || !deps.getStore) return [];
57202
57476
  const getStore = deps.getStore;
57203
- const userIds = await import_node_fs44.promises.readdir(deps.usersRoot).catch(() => []);
57477
+ const userIds = await import_node_fs45.promises.readdir(deps.usersRoot).catch(() => []);
57204
57478
  const perUser = await Promise.all(
57205
57479
  userIds.map((uid) => getStore(uid).list().catch(() => []))
57206
57480
  );
@@ -57276,8 +57550,8 @@ function buildAppBuilderHandlers(deps) {
57276
57550
  const project = await userStore.create(f.name, reservedPorts);
57277
57551
  try {
57278
57552
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
57279
- const templateSrcDir = (0, import_node_path52.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
57280
- const scaffoldScript = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
57553
+ const templateSrcDir = (0, import_node_path55.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
57554
+ const scaffoldScript = (0, import_node_path55.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
57281
57555
  const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
57282
57556
  deps.logger?.info("app-builder.scaffold.done", {
57283
57557
  name: project.name,
@@ -57498,7 +57772,7 @@ function buildAppBuilderHandlers(deps) {
57498
57772
  await userStore.clearPublishJob(args.name);
57499
57773
  }
57500
57774
  const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
57501
- const scriptPath = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "publish.sh");
57775
+ const scriptPath = (0, import_node_path55.join)(deps.deployKitRoot, "scripts", "publish.sh");
57502
57776
  deps.logger?.info("app-builder.publish.start", {
57503
57777
  name: args.name,
57504
57778
  sessionId: boundSession.sessionId,
@@ -57674,7 +57948,7 @@ function buildVisitorHandlers(deps) {
57674
57948
 
57675
57949
  // src/extension/registry.ts
57676
57950
  var import_promises10 = __toESM(require("fs/promises"), 1);
57677
- var import_node_path53 = __toESM(require("path"), 1);
57951
+ var import_node_path56 = __toESM(require("path"), 1);
57678
57952
  async function loadAll(root) {
57679
57953
  let entries;
57680
57954
  try {
@@ -57687,13 +57961,13 @@ async function loadAll(root) {
57687
57961
  for (const ent of entries) {
57688
57962
  if (!ent.isDirectory()) continue;
57689
57963
  if (ent.name.startsWith(".")) continue;
57690
- records.push(await loadOne(import_node_path53.default.join(root, ent.name), ent.name));
57964
+ records.push(await loadOne(import_node_path56.default.join(root, ent.name), ent.name));
57691
57965
  }
57692
57966
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
57693
57967
  return records;
57694
57968
  }
57695
57969
  async function loadOne(dir, dirName) {
57696
- const manifestPath = import_node_path53.default.join(dir, "manifest.json");
57970
+ const manifestPath = import_node_path56.default.join(dir, "manifest.json");
57697
57971
  let raw;
57698
57972
  try {
57699
57973
  raw = await import_promises10.default.readFile(manifestPath, "utf8");
@@ -57738,7 +58012,7 @@ async function loadOne(dir, dirName) {
57738
58012
 
57739
58013
  // src/extension/uninstall.ts
57740
58014
  var import_promises11 = __toESM(require("fs/promises"), 1);
57741
- var import_node_path54 = __toESM(require("path"), 1);
58015
+ var import_node_path57 = __toESM(require("path"), 1);
57742
58016
  var UninstallError = class extends Error {
57743
58017
  constructor(code, message) {
57744
58018
  super(message);
@@ -57747,7 +58021,7 @@ var UninstallError = class extends Error {
57747
58021
  code;
57748
58022
  };
57749
58023
  async function uninstall(deps) {
57750
- const dir = import_node_path54.default.join(deps.root, deps.extId);
58024
+ const dir = import_node_path57.default.join(deps.root, deps.extId);
57751
58025
  try {
57752
58026
  await import_promises11.default.access(dir);
57753
58027
  } catch {
@@ -57764,7 +58038,7 @@ var import_node_crypto18 = require("crypto");
57764
58038
  init_protocol();
57765
58039
 
57766
58040
  // src/peer-ops/run-command.ts
57767
- var import_node_child_process14 = require("child_process");
58041
+ var import_node_child_process15 = require("child_process");
57768
58042
  var import_node_os21 = __toESM(require("os"), 1);
57769
58043
  var DEFAULT_TIMEOUT_MS5 = 3e4;
57770
58044
  var MAX_TIMEOUT_MS = 3e5;
@@ -57772,7 +58046,7 @@ var MAX_OUTPUT_BYTES = 1048576;
57772
58046
  function runCommand(command, opts = {}) {
57773
58047
  const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS5, MAX_TIMEOUT_MS);
57774
58048
  return new Promise((resolve6) => {
57775
- const child = (0, import_node_child_process14.spawn)("bash", ["-c", command], { cwd: import_node_os21.default.homedir() });
58049
+ const child = (0, import_node_child_process15.spawn)("bash", ["-c", command], { cwd: import_node_os21.default.homedir() });
57776
58050
  const out = [];
57777
58051
  const err = [];
57778
58052
  let outBytes = 0;
@@ -57986,7 +58260,7 @@ function buildMethodHandlers(deps) {
57986
58260
  }
57987
58261
 
57988
58262
  // src/app-builder/dev-server-supervisor.ts
57989
- var import_node_child_process15 = require("child_process");
58263
+ var import_node_child_process16 = require("child_process");
57990
58264
  var import_node_events2 = require("events");
57991
58265
  var DEFAULT_READY_PATTERN = /Local:\s+https?:\/\/|Nest application successfully started|server listening on/i;
57992
58266
  var DevServerSupervisor = class extends import_node_events2.EventEmitter {
@@ -58023,7 +58297,7 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
58023
58297
  tunnelHost: args.tunnelHost,
58024
58298
  devCommand: cmd
58025
58299
  });
58026
- const child = (0, import_node_child_process15.spawn)("sh", ["-c", cmd], {
58300
+ const child = (0, import_node_child_process16.spawn)("sh", ["-c", cmd], {
58027
58301
  cwd: args.cwd,
58028
58302
  env,
58029
58303
  stdio: "pipe",
@@ -58466,8 +58740,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
58466
58740
  }
58467
58741
 
58468
58742
  // src/extension/runtime.ts
58469
- var import_node_child_process16 = require("child_process");
58470
- var import_node_path55 = __toESM(require("path"), 1);
58743
+ var import_node_child_process17 = require("child_process");
58744
+ var import_node_path58 = __toESM(require("path"), 1);
58471
58745
  var import_promises12 = require("timers/promises");
58472
58746
 
58473
58747
  // src/extension/port-allocator.ts
@@ -58568,13 +58842,13 @@ var Runtime = class {
58568
58842
  /\$CLAWOS_EXT_PORT/g,
58569
58843
  String(port)
58570
58844
  );
58571
- const dir = import_node_path55.default.join(this.root, extId);
58845
+ const dir = import_node_path58.default.join(this.root, extId);
58572
58846
  const env = {
58573
58847
  ...process.env,
58574
58848
  CLAWOS_EXT_PORT: String(port),
58575
58849
  CLAWOS_EXT_ID: extId
58576
58850
  };
58577
- const child = (0, import_node_child_process16.spawn)("sh", ["-c", cmd], {
58851
+ const child = (0, import_node_child_process17.spawn)("sh", ["-c", cmd], {
58578
58852
  cwd: dir,
58579
58853
  env,
58580
58854
  stdio: ["ignore", "pipe", "pipe"],
@@ -58680,7 +58954,7 @@ ${handle.stderrTail}`
58680
58954
 
58681
58955
  // src/extension/published-channels.ts
58682
58956
  var import_promises13 = __toESM(require("fs/promises"), 1);
58683
- var import_node_path56 = __toESM(require("path"), 1);
58957
+ var import_node_path59 = __toESM(require("path"), 1);
58684
58958
  init_zod();
58685
58959
  var PublishedChannelsError = class extends Error {
58686
58960
  constructor(code, message) {
@@ -58779,7 +59053,7 @@ var PublishedChannelStore = class {
58779
59053
  )
58780
59054
  };
58781
59055
  const tmp = `${this.filePath}.tmp`;
58782
- await import_promises13.default.mkdir(import_node_path56.default.dirname(this.filePath), { recursive: true });
59056
+ await import_promises13.default.mkdir(import_node_path59.default.dirname(this.filePath), { recursive: true });
58783
59057
  await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
58784
59058
  await import_promises13.default.rename(tmp, this.filePath);
58785
59059
  }
@@ -58787,7 +59061,7 @@ var PublishedChannelStore = class {
58787
59061
 
58788
59062
  // src/extension/bundle-cache.ts
58789
59063
  var import_promises14 = __toESM(require("fs/promises"), 1);
58790
- var import_node_path57 = __toESM(require("path"), 1);
59064
+ var import_node_path60 = __toESM(require("path"), 1);
58791
59065
  var BundleCache = class {
58792
59066
  constructor(rootDir) {
58793
59067
  this.rootDir = rootDir;
@@ -58796,14 +59070,14 @@ var BundleCache = class {
58796
59070
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
58797
59071
  async write(snapshotHash, buffer) {
58798
59072
  await import_promises14.default.mkdir(this.rootDir, { recursive: true });
58799
- const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
59073
+ const file = import_node_path60.default.join(this.rootDir, `${snapshotHash}.zip`);
58800
59074
  const tmp = `${file}.tmp`;
58801
59075
  await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
58802
59076
  await import_promises14.default.rename(tmp, file);
58803
59077
  }
58804
59078
  /** Returns the bundle bytes, or null when the file doesn't exist. */
58805
59079
  async read(snapshotHash) {
58806
- const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
59080
+ const file = import_node_path60.default.join(this.rootDir, `${snapshotHash}.zip`);
58807
59081
  try {
58808
59082
  return await import_promises14.default.readFile(file);
58809
59083
  } catch (e) {
@@ -58813,7 +59087,7 @@ var BundleCache = class {
58813
59087
  }
58814
59088
  /** Idempotent — missing file is not an error. */
58815
59089
  async delete(snapshotHash) {
58816
- const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
59090
+ const file = import_node_path60.default.join(this.rootDir, `${snapshotHash}.zip`);
58817
59091
  await import_promises14.default.rm(file, { force: true });
58818
59092
  }
58819
59093
  };
@@ -58836,24 +59110,24 @@ async function startDaemon(config) {
58836
59110
  sampling: logShippingCfg.sampling,
58837
59111
  homeDir: import_node_os22.default.homedir()
58838
59112
  });
58839
- const logDir = import_node_path58.default.join(config.dataDir, "log");
58840
- import_node_fs45.default.mkdirSync(logDir, { recursive: true });
59113
+ const logDir = import_node_path61.default.join(config.dataDir, "log");
59114
+ import_node_fs46.default.mkdirSync(logDir, { recursive: true });
58841
59115
  const logger = createLogger({
58842
59116
  level: config.logLevel,
58843
- file: import_node_path58.default.join(logDir, "clawd.log"),
59117
+ file: import_node_path61.default.join(logDir, "clawd.log"),
58844
59118
  logClient
58845
59119
  });
58846
59120
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
58847
59121
  const screenIdleProbeLogger = createFileOnlyLogger({
58848
- file: import_node_path58.default.join(logDir, "screen-idle-probe.log"),
59122
+ file: import_node_path61.default.join(logDir, "screen-idle-probe.log"),
58849
59123
  level: "debug"
58850
59124
  });
58851
59125
  logger.info("screen-idle probe logger enabled", {
58852
- file: import_node_path58.default.join(logDir, "screen-idle-probe.log")
59126
+ file: import_node_path61.default.join(logDir, "screen-idle-probe.log")
58853
59127
  });
58854
59128
  const CAP_TARGETS = [
58855
- import_node_path58.default.join(logDir, "clawd.log"),
58856
- import_node_path58.default.join(logDir, "screen-idle-probe.log")
59129
+ import_node_path61.default.join(logDir, "clawd.log"),
59130
+ import_node_path61.default.join(logDir, "screen-idle-probe.log")
58857
59131
  ];
58858
59132
  const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
58859
59133
  const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
@@ -59007,8 +59281,8 @@ async function startDaemon(config) {
59007
59281
  const agents = new AgentsScanner();
59008
59282
  const history = new ClaudeHistoryReader();
59009
59283
  let transport = null;
59010
- const personaStore = new PersonaStore(import_node_path58.default.join(config.dataDir, "personas"));
59011
- const usersRoot = import_node_path58.default.join(config.dataDir, "users");
59284
+ const personaStore = new PersonaStore(import_node_path61.default.join(config.dataDir, "personas"));
59285
+ const usersRoot = import_node_path61.default.join(config.dataDir, "users");
59012
59286
  const defaultsRoot = findDefaultsRoot(logger);
59013
59287
  if (defaultsRoot) {
59014
59288
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -59028,7 +59302,7 @@ async function startDaemon(config) {
59028
59302
  migrateCodexSandbox({ store: personaStore, logger });
59029
59303
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
59030
59304
  const dispatchStore = createDispatchStore({
59031
- filePath: import_node_path58.default.join(config.dataDir, "dispatch.json"),
59305
+ filePath: import_node_path61.default.join(config.dataDir, "dispatch.json"),
59032
59306
  now: () => Date.now(),
59033
59307
  onFlushError: (err) => logger.error("dispatch store flush failed", {
59034
59308
  reason: err instanceof Error ? err.message : String(err)
@@ -59043,17 +59317,17 @@ async function startDaemon(config) {
59043
59317
  now: () => Date.now(),
59044
59318
  onCompleted: (sid) => deliverPendingRef?.(sid)
59045
59319
  });
59046
- const here = typeof __dirname === "string" ? __dirname : import_node_path58.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
59320
+ const here = typeof __dirname === "string" ? __dirname : import_node_path61.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
59047
59321
  const mcpConfigs = [];
59048
59322
  const dispatchServerCandidates = [
59049
- import_node_path58.default.join(here, "dispatch", "mcp-server.cjs"),
59323
+ import_node_path61.default.join(here, "dispatch", "mcp-server.cjs"),
59050
59324
  // 生产 dist/index → dist/dispatch/mcp-server.cjs
59051
- import_node_path58.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
59325
+ import_node_path61.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
59052
59326
  // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
59053
59327
  ];
59054
- const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
59328
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs46.default.existsSync(p2));
59055
59329
  if (dispatchServerScriptPath) {
59056
- const dispatchLogPath = import_node_path58.default.join(logDir, "dispatch-mcp-server.log");
59330
+ const dispatchLogPath = import_node_path61.default.join(logDir, "dispatch-mcp-server.log");
59057
59331
  const dispatchCfgPath = writeDispatchMcpConfig({
59058
59332
  dataDir: config.dataDir,
59059
59333
  serverScriptPath: dispatchServerScriptPath,
@@ -59071,12 +59345,12 @@ async function startDaemon(config) {
59071
59345
  });
59072
59346
  }
59073
59347
  const ticketServerCandidates = [
59074
- import_node_path58.default.join(here, "ticket", "mcp-server.cjs"),
59075
- import_node_path58.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
59348
+ import_node_path61.default.join(here, "ticket", "mcp-server.cjs"),
59349
+ import_node_path61.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
59076
59350
  ];
59077
- const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
59351
+ const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs46.default.existsSync(p2));
59078
59352
  if (ticketServerScriptPath) {
59079
- const ticketLogPath = import_node_path58.default.join(logDir, "ticket-mcp-server.log");
59353
+ const ticketLogPath = import_node_path61.default.join(logDir, "ticket-mcp-server.log");
59080
59354
  const ticketCfgPath = writeTicketMcpConfig({
59081
59355
  dataDir: config.dataDir,
59082
59356
  serverScriptPath: ticketServerScriptPath,
@@ -59096,12 +59370,12 @@ async function startDaemon(config) {
59096
59370
  });
59097
59371
  }
59098
59372
  const shiftServerCandidates = [
59099
- import_node_path58.default.join(here, "shift", "mcp-server.cjs"),
59100
- import_node_path58.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
59373
+ import_node_path61.default.join(here, "shift", "mcp-server.cjs"),
59374
+ import_node_path61.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
59101
59375
  ];
59102
- const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
59376
+ const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs46.default.existsSync(p2));
59103
59377
  if (shiftServerScriptPath) {
59104
- const shiftLogPath = import_node_path58.default.join(logDir, "shift-mcp-server.log");
59378
+ const shiftLogPath = import_node_path61.default.join(logDir, "shift-mcp-server.log");
59105
59379
  const shiftCfgPath = await writeShiftMcpConfig({
59106
59380
  dataDir: config.dataDir,
59107
59381
  serverScriptPath: shiftServerScriptPath,
@@ -59120,12 +59394,12 @@ async function startDaemon(config) {
59120
59394
  );
59121
59395
  }
59122
59396
  const inboxServerCandidates = [
59123
- import_node_path58.default.join(here, "inbox", "mcp-server.cjs"),
59124
- import_node_path58.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
59397
+ import_node_path61.default.join(here, "inbox", "mcp-server.cjs"),
59398
+ import_node_path61.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
59125
59399
  ];
59126
- const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
59400
+ const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs46.default.existsSync(p2));
59127
59401
  if (inboxServerScriptPath) {
59128
- const inboxLogPath = import_node_path58.default.join(logDir, "inbox-mcp-server.log");
59402
+ const inboxLogPath = import_node_path61.default.join(logDir, "inbox-mcp-server.log");
59129
59403
  const inboxCfgPath = await writeInboxMcpConfig({
59130
59404
  dataDir: config.dataDir,
59131
59405
  serverScriptPath: inboxServerScriptPath,
@@ -59144,10 +59418,10 @@ async function startDaemon(config) {
59144
59418
  );
59145
59419
  }
59146
59420
  const peerOpsServerCandidates = [
59147
- import_node_path58.default.join(here, "peer-ops", "mcp-server.cjs"),
59148
- import_node_path58.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
59421
+ import_node_path61.default.join(here, "peer-ops", "mcp-server.cjs"),
59422
+ import_node_path61.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
59149
59423
  ];
59150
- const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
59424
+ const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs46.default.existsSync(p2));
59151
59425
  if (peerOpsServerScriptPath) {
59152
59426
  const peerOpsCfgPath = writePeerOpsMcpConfig({
59153
59427
  dataDir: config.dataDir,
@@ -59165,7 +59439,7 @@ async function startDaemon(config) {
59165
59439
  );
59166
59440
  }
59167
59441
  const shiftStore = createShiftStore({
59168
- filePath: import_node_path58.default.join(config.dataDir, "shift.json"),
59442
+ filePath: import_node_path61.default.join(config.dataDir, "shift.json"),
59169
59443
  ownerIdProvider: () => ownerPrincipalId,
59170
59444
  now: () => Date.now()
59171
59445
  });
@@ -59187,7 +59461,10 @@ async function startDaemon(config) {
59187
59461
  getAdapter,
59188
59462
  historyReader: history,
59189
59463
  dataDir: config.dataDir,
59190
- personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
59464
+ personaRoot: import_node_path61.default.join(config.dataDir, "personas"),
59465
+ // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
59466
+ // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
59467
+ getPersonaTool: (personaId) => personaRegistry.get(personaId)?.tool,
59191
59468
  usersRoot,
59192
59469
  personaStore,
59193
59470
  ownerDisplayName,
@@ -59227,10 +59504,10 @@ async function startDaemon(config) {
59227
59504
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
59228
59505
  attachmentGroup: {
59229
59506
  onFileEdit: (input) => {
59230
- const absPath = import_node_path58.default.isAbsolute(input.relPath) ? input.relPath : import_node_path58.default.join(input.cwd, input.relPath);
59507
+ const absPath = import_node_path61.default.isAbsolute(input.relPath) ? input.relPath : import_node_path61.default.join(input.cwd, input.relPath);
59231
59508
  let size = 0;
59232
59509
  try {
59233
- size = import_node_fs45.default.statSync(absPath).size;
59510
+ size = import_node_fs46.default.statSync(absPath).size;
59234
59511
  } catch (err) {
59235
59512
  logger.warn("attachment.onFileEdit stat failed", {
59236
59513
  sessionId: input.sessionId,
@@ -59313,6 +59590,7 @@ async function startDaemon(config) {
59313
59590
  }) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
59314
59591
  registerAdapter("claude", claudeAdapter);
59315
59592
  registerAdapter("codex", new CodexAdapter({ logger, historyReader: new CodexHistoryReader() }));
59593
+ warmCodexFeatureCache();
59316
59594
  const personaRegistry = new PersonaRegistry(personaStore);
59317
59595
  const personaManager = new PersonaManager({
59318
59596
  store: personaStore,
@@ -59460,11 +59738,11 @@ async function startDaemon(config) {
59460
59738
  // 'persona/<pid>/owner',default 走 'default'。
59461
59739
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
59462
59740
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
59463
- personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
59741
+ personaRoot: import_node_path61.default.join(config.dataDir, "personas"),
59464
59742
  usersRoot
59465
59743
  },
59466
59744
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
59467
- personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
59745
+ personaRoot: import_node_path61.default.join(config.dataDir, "personas"),
59468
59746
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
59469
59747
  usersRoot,
59470
59748
  // capability:list / delete handler 依赖
@@ -59575,11 +59853,11 @@ async function startDaemon(config) {
59575
59853
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
59576
59854
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
59577
59855
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
59578
- appBuilderPersonaRoot: import_node_path58.default.join(config.dataDir, "personas", "persona-app-builder"),
59856
+ appBuilderPersonaRoot: import_node_path61.default.join(config.dataDir, "personas", "persona-app-builder"),
59579
59857
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
59580
- deployKitRoot: import_node_path58.default.join(config.dataDir, "deploy-kit"),
59858
+ deployKitRoot: import_node_path61.default.join(config.dataDir, "deploy-kit"),
59581
59859
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
59582
- resolvePersonaRoot: (personaId) => import_node_path58.default.join(config.dataDir, "personas", personaId),
59860
+ resolvePersonaRoot: (personaId) => import_node_path61.default.join(config.dataDir, "personas", personaId),
59583
59861
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
59584
59862
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
59585
59863
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -59610,6 +59888,8 @@ async function startDaemon(config) {
59610
59888
  const dispatchHandlers = buildPersonaDispatchHandlers({
59611
59889
  personaDispatchManager,
59612
59890
  store: dispatchStore,
59891
+ // 续派(spec 2026-07-21):任务包注入 worker session,复用投递同款注入路径。
59892
+ sendFollowUp: (workerSessionId, text) => manager.injectIntoSession(workerSessionId, text),
59613
59893
  logger,
59614
59894
  spawnB: async (args) => {
59615
59895
  logger.info("dispatch.spawnB.start", {
@@ -59623,7 +59903,7 @@ async function startDaemon(config) {
59623
59903
  }
59624
59904
  let sourceJsonlPath = "(no transcript yet \u2014 operate from the task description alone)";
59625
59905
  if (sourceFile && sourceFile.toolSessionId) {
59626
- sourceJsonlPath = import_node_path58.default.join(
59906
+ sourceJsonlPath = import_node_path61.default.join(
59627
59907
  import_node_os22.default.homedir(),
59628
59908
  ".claude",
59629
59909
  "projects",
@@ -59669,7 +59949,9 @@ async function startDaemon(config) {
59669
59949
  });
59670
59950
  },
59671
59951
  // B 角色:判断 targetPersona 是否 public(跨设备授权边界,private 拒)。
59672
- getPersonaPublic: (personaId) => personaRegistry.get(personaId)?.public ?? false
59952
+ getPersonaPublic: (personaId) => personaRegistry.get(personaId)?.public ?? false,
59953
+ // model 校验按 target persona 绑定 tool 选表(claude / codex 模型集不同)
59954
+ getPersonaTool: (personaId) => personaRegistry.get(personaId)?.tool
59673
59955
  });
59674
59956
  handlers = { ...handlers, ...dispatchHandlers };
59675
59957
  const shiftHandlers = buildShiftInternalHandlers({
@@ -59941,8 +60223,8 @@ async function startDaemon(config) {
59941
60223
  const lines = [
59942
60224
  `Tunnel: ${r.url}`,
59943
60225
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
59944
- `Frpc config: ${import_node_path58.default.join(config.dataDir, "frpc.toml")}`,
59945
- `Frpc log: ${import_node_path58.default.join(logDir, "frpc.log")}`
60226
+ `Frpc config: ${import_node_path61.default.join(config.dataDir, "frpc.toml")}`,
60227
+ `Frpc log: ${import_node_path61.default.join(logDir, "frpc.log")}`
59946
60228
  ];
59947
60229
  const width = Math.max(...lines.map((l) => l.length));
59948
60230
  const bar = "\u2550".repeat(width + 4);
@@ -59955,8 +60237,8 @@ ${bar}
59955
60237
 
59956
60238
  `);
59957
60239
  try {
59958
- const connectPath = import_node_path58.default.join(config.dataDir, "connect.txt");
59959
- import_node_fs45.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
60240
+ const connectPath = import_node_path61.default.join(config.dataDir, "connect.txt");
60241
+ import_node_fs46.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
59960
60242
  } catch {
59961
60243
  }
59962
60244
  } catch (err) {
@@ -60028,9 +60310,9 @@ ${bar}
60028
60310
  };
60029
60311
  }
60030
60312
  function migrateDropPersonsDir(dataDir) {
60031
- const dir = import_node_path58.default.join(dataDir, "persons");
60313
+ const dir = import_node_path61.default.join(dataDir, "persons");
60032
60314
  try {
60033
- import_node_fs45.default.rmSync(dir, { recursive: true, force: true });
60315
+ import_node_fs46.default.rmSync(dir, { recursive: true, force: true });
60034
60316
  } catch {
60035
60317
  }
60036
60318
  }