@clawos-dev/clawd 0.2.139-beta.289.7c60f3e → 0.2.140-beta.290.4d01c03

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
@@ -720,8 +720,8 @@ var init_parseUtil = __esm({
720
720
  init_errors2();
721
721
  init_en();
722
722
  makeIssue = (params) => {
723
- const { data, path: path58, errorMaps, issueData } = params;
724
- const fullPath = [...path58, ...issueData.path || []];
723
+ const { data, path: path59, errorMaps, issueData } = params;
724
+ const fullPath = [...path59, ...issueData.path || []];
725
725
  const fullIssue = {
726
726
  ...issueData,
727
727
  path: fullPath
@@ -1032,11 +1032,11 @@ var init_types = __esm({
1032
1032
  init_parseUtil();
1033
1033
  init_util();
1034
1034
  ParseInputLazyPath = class {
1035
- constructor(parent, value, path58, key) {
1035
+ constructor(parent, value, path59, key) {
1036
1036
  this._cachedPath = [];
1037
1037
  this.parent = parent;
1038
1038
  this.data = value;
1039
- this._path = path58;
1039
+ this._path = path59;
1040
1040
  this._key = key;
1041
1041
  }
1042
1042
  get path() {
@@ -4752,6 +4752,13 @@ var init_schemas = __esm({
4752
4752
  * - native `session:*` handler 完全不感知 mirror(UI 操作 mirror 不走 native 路径)
4753
4753
  */
4754
4754
  originOwnerPrincipalId: external_exports.string().min(1).optional(),
4755
+ /**
4756
+ * Dispatch 派生的 session 在 create 时记录源 session 的 sessionId(稳定 key);
4757
+ * sidebar 据此把 dispatch 出来的 sub-session 折叠在源 session 下。非 dispatch session 缺省。
4758
+ * mirror SessionFile 上必须 strip(朋友 daemon 上的 sessionId 在本机无意义,会让本机
4759
+ * 反查路径走错;按 #750 一族防线处理,跟 ownerPersonaId 同地点 strip)。
4760
+ */
4761
+ dispatchedFromSessionId: external_exports.string().min(1).optional(),
4755
4762
  createdAt: external_exports.string().min(1),
4756
4763
  updatedAt: external_exports.string().min(1)
4757
4764
  });
@@ -5926,6 +5933,34 @@ var init_feishu_auth = __esm({
5926
5933
  }
5927
5934
  });
5928
5935
 
5936
+ // ../protocol/src/dispatch.ts
5937
+ var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema;
5938
+ var init_dispatch = __esm({
5939
+ "../protocol/src/dispatch.ts"() {
5940
+ "use strict";
5941
+ init_zod();
5942
+ DispatchOutcomeSchema = external_exports.discriminatedUnion("kind", [
5943
+ external_exports.object({
5944
+ kind: external_exports.literal("success"),
5945
+ text: external_exports.string(),
5946
+ filePaths: external_exports.array(external_exports.string()).optional()
5947
+ }),
5948
+ external_exports.object({
5949
+ kind: external_exports.literal("failure"),
5950
+ reason: external_exports.string()
5951
+ })
5952
+ ]);
5953
+ DispatchRunArgsSchema = external_exports.object({
5954
+ targetPersona: external_exports.string().min(1),
5955
+ prompt: external_exports.string()
5956
+ });
5957
+ DispatchCompleteArgsSchema = external_exports.object({
5958
+ dispatchId: external_exports.string().min(1),
5959
+ outcome: DispatchOutcomeSchema
5960
+ });
5961
+ }
5962
+ });
5963
+
5929
5964
  // ../protocol/src/runtime.ts
5930
5965
  var init_runtime = __esm({
5931
5966
  "../protocol/src/runtime.ts"() {
@@ -5944,6 +5979,7 @@ var init_runtime = __esm({
5944
5979
  init_contact();
5945
5980
  init_extension();
5946
5981
  init_feishu_auth();
5982
+ init_dispatch();
5947
5983
  }
5948
5984
  });
5949
5985
 
@@ -6218,8 +6254,8 @@ var require_req = __commonJS({
6218
6254
  if (req.originalUrl) {
6219
6255
  _req.url = req.originalUrl;
6220
6256
  } else {
6221
- const path58 = req.path;
6222
- _req.url = typeof path58 === "string" ? path58 : req.url ? req.url.path || req.url : void 0;
6257
+ const path59 = req.path;
6258
+ _req.url = typeof path59 === "string" ? path59 : req.url ? req.url.path || req.url : void 0;
6223
6259
  }
6224
6260
  if (req.query) {
6225
6261
  _req.query = req.query;
@@ -6384,14 +6420,14 @@ var require_redact = __commonJS({
6384
6420
  }
6385
6421
  return obj;
6386
6422
  }
6387
- function parsePath(path58) {
6423
+ function parsePath(path59) {
6388
6424
  const parts = [];
6389
6425
  let current = "";
6390
6426
  let inBrackets = false;
6391
6427
  let inQuotes = false;
6392
6428
  let quoteChar = "";
6393
- for (let i = 0; i < path58.length; i++) {
6394
- const char = path58[i];
6429
+ for (let i = 0; i < path59.length; i++) {
6430
+ const char = path59[i];
6395
6431
  if (!inBrackets && char === ".") {
6396
6432
  if (current) {
6397
6433
  parts.push(current);
@@ -6522,10 +6558,10 @@ var require_redact = __commonJS({
6522
6558
  return current;
6523
6559
  }
6524
6560
  function redactPaths(obj, paths, censor, remove = false) {
6525
- for (const path58 of paths) {
6526
- const parts = parsePath(path58);
6561
+ for (const path59 of paths) {
6562
+ const parts = parsePath(path59);
6527
6563
  if (parts.includes("*")) {
6528
- redactWildcardPath(obj, parts, censor, path58, remove);
6564
+ redactWildcardPath(obj, parts, censor, path59, remove);
6529
6565
  } else {
6530
6566
  if (remove) {
6531
6567
  removeKey(obj, parts);
@@ -6610,8 +6646,8 @@ var require_redact = __commonJS({
6610
6646
  }
6611
6647
  } else {
6612
6648
  if (afterWildcard.includes("*")) {
6613
- const wrappedCensor = typeof censor === "function" ? (value, path58) => {
6614
- const fullPath = [...pathArray.slice(0, pathLength), ...path58];
6649
+ const wrappedCensor = typeof censor === "function" ? (value, path59) => {
6650
+ const fullPath = [...pathArray.slice(0, pathLength), ...path59];
6615
6651
  return censor(value, fullPath);
6616
6652
  } : censor;
6617
6653
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -6646,8 +6682,8 @@ var require_redact = __commonJS({
6646
6682
  return null;
6647
6683
  }
6648
6684
  const pathStructure = /* @__PURE__ */ new Map();
6649
- for (const path58 of pathsToClone) {
6650
- const parts = parsePath(path58);
6685
+ for (const path59 of pathsToClone) {
6686
+ const parts = parsePath(path59);
6651
6687
  let current = pathStructure;
6652
6688
  for (let i = 0; i < parts.length; i++) {
6653
6689
  const part = parts[i];
@@ -6699,24 +6735,24 @@ var require_redact = __commonJS({
6699
6735
  }
6700
6736
  return cloneSelectively(obj, pathStructure);
6701
6737
  }
6702
- function validatePath(path58) {
6703
- if (typeof path58 !== "string") {
6738
+ function validatePath(path59) {
6739
+ if (typeof path59 !== "string") {
6704
6740
  throw new Error("Paths must be (non-empty) strings");
6705
6741
  }
6706
- if (path58 === "") {
6742
+ if (path59 === "") {
6707
6743
  throw new Error("Invalid redaction path ()");
6708
6744
  }
6709
- if (path58.includes("..")) {
6710
- throw new Error(`Invalid redaction path (${path58})`);
6745
+ if (path59.includes("..")) {
6746
+ throw new Error(`Invalid redaction path (${path59})`);
6711
6747
  }
6712
- if (path58.includes(",")) {
6713
- throw new Error(`Invalid redaction path (${path58})`);
6748
+ if (path59.includes(",")) {
6749
+ throw new Error(`Invalid redaction path (${path59})`);
6714
6750
  }
6715
6751
  let bracketCount = 0;
6716
6752
  let inQuotes = false;
6717
6753
  let quoteChar = "";
6718
- for (let i = 0; i < path58.length; i++) {
6719
- const char = path58[i];
6754
+ for (let i = 0; i < path59.length; i++) {
6755
+ const char = path59[i];
6720
6756
  if ((char === '"' || char === "'") && bracketCount > 0) {
6721
6757
  if (!inQuotes) {
6722
6758
  inQuotes = true;
@@ -6730,20 +6766,20 @@ var require_redact = __commonJS({
6730
6766
  } else if (char === "]" && !inQuotes) {
6731
6767
  bracketCount--;
6732
6768
  if (bracketCount < 0) {
6733
- throw new Error(`Invalid redaction path (${path58})`);
6769
+ throw new Error(`Invalid redaction path (${path59})`);
6734
6770
  }
6735
6771
  }
6736
6772
  }
6737
6773
  if (bracketCount !== 0) {
6738
- throw new Error(`Invalid redaction path (${path58})`);
6774
+ throw new Error(`Invalid redaction path (${path59})`);
6739
6775
  }
6740
6776
  }
6741
6777
  function validatePaths(paths) {
6742
6778
  if (!Array.isArray(paths)) {
6743
6779
  throw new TypeError("paths must be an array");
6744
6780
  }
6745
- for (const path58 of paths) {
6746
- validatePath(path58);
6781
+ for (const path59 of paths) {
6782
+ validatePath(path59);
6747
6783
  }
6748
6784
  }
6749
6785
  function slowRedact(options = {}) {
@@ -6911,8 +6947,8 @@ var require_redaction = __commonJS({
6911
6947
  if (shape[k2] === null) {
6912
6948
  o[k2] = (value) => topCensor(value, [k2]);
6913
6949
  } else {
6914
- const wrappedCensor = typeof censor === "function" ? (value, path58) => {
6915
- return censor(value, [k2, ...path58]);
6950
+ const wrappedCensor = typeof censor === "function" ? (value, path59) => {
6951
+ return censor(value, [k2, ...path59]);
6916
6952
  } : censor;
6917
6953
  o[k2] = Redact({
6918
6954
  paths: shape[k2],
@@ -7130,10 +7166,10 @@ var require_atomic_sleep = __commonJS({
7130
7166
  var require_sonic_boom = __commonJS({
7131
7167
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
7132
7168
  "use strict";
7133
- var fs51 = require("fs");
7169
+ var fs52 = require("fs");
7134
7170
  var EventEmitter3 = require("events");
7135
7171
  var inherits = require("util").inherits;
7136
- var path58 = require("path");
7172
+ var path59 = require("path");
7137
7173
  var sleep = require_atomic_sleep();
7138
7174
  var assert = require("assert");
7139
7175
  var BUSY_WRITE_TIMEOUT = 100;
@@ -7187,20 +7223,20 @@ var require_sonic_boom = __commonJS({
7187
7223
  const mode = sonic.mode;
7188
7224
  if (sonic.sync) {
7189
7225
  try {
7190
- if (sonic.mkdir) fs51.mkdirSync(path58.dirname(file), { recursive: true });
7191
- const fd = fs51.openSync(file, flags, mode);
7226
+ if (sonic.mkdir) fs52.mkdirSync(path59.dirname(file), { recursive: true });
7227
+ const fd = fs52.openSync(file, flags, mode);
7192
7228
  fileOpened(null, fd);
7193
7229
  } catch (err) {
7194
7230
  fileOpened(err);
7195
7231
  throw err;
7196
7232
  }
7197
7233
  } else if (sonic.mkdir) {
7198
- fs51.mkdir(path58.dirname(file), { recursive: true }, (err) => {
7234
+ fs52.mkdir(path59.dirname(file), { recursive: true }, (err) => {
7199
7235
  if (err) return fileOpened(err);
7200
- fs51.open(file, flags, mode, fileOpened);
7236
+ fs52.open(file, flags, mode, fileOpened);
7201
7237
  });
7202
7238
  } else {
7203
- fs51.open(file, flags, mode, fileOpened);
7239
+ fs52.open(file, flags, mode, fileOpened);
7204
7240
  }
7205
7241
  }
7206
7242
  function SonicBoom(opts) {
@@ -7241,8 +7277,8 @@ var require_sonic_boom = __commonJS({
7241
7277
  this.flush = flushBuffer;
7242
7278
  this.flushSync = flushBufferSync;
7243
7279
  this._actualWrite = actualWriteBuffer;
7244
- fsWriteSync = () => fs51.writeSync(this.fd, this._writingBuf);
7245
- fsWrite = () => fs51.write(this.fd, this._writingBuf, this.release);
7280
+ fsWriteSync = () => fs52.writeSync(this.fd, this._writingBuf);
7281
+ fsWrite = () => fs52.write(this.fd, this._writingBuf, this.release);
7246
7282
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
7247
7283
  this._writingBuf = "";
7248
7284
  this.write = write;
@@ -7251,15 +7287,15 @@ var require_sonic_boom = __commonJS({
7251
7287
  this._actualWrite = actualWrite;
7252
7288
  fsWriteSync = () => {
7253
7289
  if (Buffer.isBuffer(this._writingBuf)) {
7254
- return fs51.writeSync(this.fd, this._writingBuf);
7290
+ return fs52.writeSync(this.fd, this._writingBuf);
7255
7291
  }
7256
- return fs51.writeSync(this.fd, this._writingBuf, "utf8");
7292
+ return fs52.writeSync(this.fd, this._writingBuf, "utf8");
7257
7293
  };
7258
7294
  fsWrite = () => {
7259
7295
  if (Buffer.isBuffer(this._writingBuf)) {
7260
- return fs51.write(this.fd, this._writingBuf, this.release);
7296
+ return fs52.write(this.fd, this._writingBuf, this.release);
7261
7297
  }
7262
- return fs51.write(this.fd, this._writingBuf, "utf8", this.release);
7298
+ return fs52.write(this.fd, this._writingBuf, "utf8", this.release);
7263
7299
  };
7264
7300
  } else {
7265
7301
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -7316,7 +7352,7 @@ var require_sonic_boom = __commonJS({
7316
7352
  }
7317
7353
  }
7318
7354
  if (this._fsync) {
7319
- fs51.fsyncSync(this.fd);
7355
+ fs52.fsyncSync(this.fd);
7320
7356
  }
7321
7357
  const len = this._len;
7322
7358
  if (this._reopening) {
@@ -7430,7 +7466,7 @@ var require_sonic_boom = __commonJS({
7430
7466
  const onDrain = () => {
7431
7467
  if (!this._fsync) {
7432
7468
  try {
7433
- fs51.fsync(this.fd, (err) => {
7469
+ fs52.fsync(this.fd, (err) => {
7434
7470
  this._flushPending = false;
7435
7471
  cb(err);
7436
7472
  });
@@ -7532,7 +7568,7 @@ var require_sonic_boom = __commonJS({
7532
7568
  const fd = this.fd;
7533
7569
  this.once("ready", () => {
7534
7570
  if (fd !== this.fd) {
7535
- fs51.close(fd, (err) => {
7571
+ fs52.close(fd, (err) => {
7536
7572
  if (err) {
7537
7573
  return this.emit("error", err);
7538
7574
  }
@@ -7581,7 +7617,7 @@ var require_sonic_boom = __commonJS({
7581
7617
  buf = this._bufs[0];
7582
7618
  }
7583
7619
  try {
7584
- const n = Buffer.isBuffer(buf) ? fs51.writeSync(this.fd, buf) : fs51.writeSync(this.fd, buf, "utf8");
7620
+ const n = Buffer.isBuffer(buf) ? fs52.writeSync(this.fd, buf) : fs52.writeSync(this.fd, buf, "utf8");
7585
7621
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
7586
7622
  buf = releasedBufObj.writingBuf;
7587
7623
  this._len = releasedBufObj.len;
@@ -7597,7 +7633,7 @@ var require_sonic_boom = __commonJS({
7597
7633
  }
7598
7634
  }
7599
7635
  try {
7600
- fs51.fsyncSync(this.fd);
7636
+ fs52.fsyncSync(this.fd);
7601
7637
  } catch {
7602
7638
  }
7603
7639
  }
@@ -7618,7 +7654,7 @@ var require_sonic_boom = __commonJS({
7618
7654
  buf = mergeBuf(this._bufs[0], this._lens[0]);
7619
7655
  }
7620
7656
  try {
7621
- const n = fs51.writeSync(this.fd, buf);
7657
+ const n = fs52.writeSync(this.fd, buf);
7622
7658
  buf = buf.subarray(n);
7623
7659
  this._len = Math.max(this._len - n, 0);
7624
7660
  if (buf.length <= 0) {
@@ -7646,13 +7682,13 @@ var require_sonic_boom = __commonJS({
7646
7682
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
7647
7683
  if (this.sync) {
7648
7684
  try {
7649
- const written = Buffer.isBuffer(this._writingBuf) ? fs51.writeSync(this.fd, this._writingBuf) : fs51.writeSync(this.fd, this._writingBuf, "utf8");
7685
+ const written = Buffer.isBuffer(this._writingBuf) ? fs52.writeSync(this.fd, this._writingBuf) : fs52.writeSync(this.fd, this._writingBuf, "utf8");
7650
7686
  release(null, written);
7651
7687
  } catch (err) {
7652
7688
  release(err);
7653
7689
  }
7654
7690
  } else {
7655
- fs51.write(this.fd, this._writingBuf, release);
7691
+ fs52.write(this.fd, this._writingBuf, release);
7656
7692
  }
7657
7693
  }
7658
7694
  function actualWriteBuffer() {
@@ -7661,7 +7697,7 @@ var require_sonic_boom = __commonJS({
7661
7697
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
7662
7698
  if (this.sync) {
7663
7699
  try {
7664
- const written = fs51.writeSync(this.fd, this._writingBuf);
7700
+ const written = fs52.writeSync(this.fd, this._writingBuf);
7665
7701
  release(null, written);
7666
7702
  } catch (err) {
7667
7703
  release(err);
@@ -7670,7 +7706,7 @@ var require_sonic_boom = __commonJS({
7670
7706
  if (kCopyBuffer) {
7671
7707
  this._writingBuf = Buffer.from(this._writingBuf);
7672
7708
  }
7673
- fs51.write(this.fd, this._writingBuf, release);
7709
+ fs52.write(this.fd, this._writingBuf, release);
7674
7710
  }
7675
7711
  }
7676
7712
  function actualClose(sonic) {
@@ -7686,12 +7722,12 @@ var require_sonic_boom = __commonJS({
7686
7722
  sonic._lens = [];
7687
7723
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
7688
7724
  try {
7689
- fs51.fsync(sonic.fd, closeWrapped);
7725
+ fs52.fsync(sonic.fd, closeWrapped);
7690
7726
  } catch {
7691
7727
  }
7692
7728
  function closeWrapped() {
7693
7729
  if (sonic.fd !== 1 && sonic.fd !== 2) {
7694
- fs51.close(sonic.fd, done);
7730
+ fs52.close(sonic.fd, done);
7695
7731
  } else {
7696
7732
  done();
7697
7733
  }
@@ -10055,7 +10091,7 @@ var require_multistream = __commonJS({
10055
10091
  var require_pino = __commonJS({
10056
10092
  "../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
10057
10093
  "use strict";
10058
- var os21 = require("os");
10094
+ var os22 = require("os");
10059
10095
  var stdSerializers = require_pino_std_serializers();
10060
10096
  var caller = require_caller();
10061
10097
  var redaction = require_redaction();
@@ -10102,7 +10138,7 @@ var require_pino = __commonJS({
10102
10138
  } = symbols;
10103
10139
  var { epochTime, nullTime } = time;
10104
10140
  var { pid } = process;
10105
- var hostname = os21.hostname();
10141
+ var hostname = os22.hostname();
10106
10142
  var defaultErrorSerializer = stdSerializers.err;
10107
10143
  var defaultOptions = {
10108
10144
  level: "info",
@@ -10826,11 +10862,11 @@ var init_lib = __esm({
10826
10862
  }
10827
10863
  }
10828
10864
  },
10829
- addToPath: function addToPath(path58, added, removed, oldPosInc, options) {
10830
- var last = path58.lastComponent;
10865
+ addToPath: function addToPath(path59, added, removed, oldPosInc, options) {
10866
+ var last = path59.lastComponent;
10831
10867
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
10832
10868
  return {
10833
- oldPos: path58.oldPos + oldPosInc,
10869
+ oldPos: path59.oldPos + oldPosInc,
10834
10870
  lastComponent: {
10835
10871
  count: last.count + 1,
10836
10872
  added,
@@ -10840,7 +10876,7 @@ var init_lib = __esm({
10840
10876
  };
10841
10877
  } else {
10842
10878
  return {
10843
- oldPos: path58.oldPos + oldPosInc,
10879
+ oldPos: path59.oldPos + oldPosInc,
10844
10880
  lastComponent: {
10845
10881
  count: 1,
10846
10882
  added,
@@ -11286,10 +11322,10 @@ function attachmentToHistoryMessage(o, ts) {
11286
11322
  const memories = raw.map((m2) => {
11287
11323
  if (!m2 || typeof m2 !== "object") return null;
11288
11324
  const rec3 = m2;
11289
- const path58 = typeof rec3.path === "string" ? rec3.path : null;
11325
+ const path59 = typeof rec3.path === "string" ? rec3.path : null;
11290
11326
  const content = typeof rec3.content === "string" ? rec3.content : null;
11291
- if (!path58 || content == null) return null;
11292
- const entry = { path: path58, content };
11327
+ if (!path59 || content == null) return null;
11328
+ const entry = { path: path59, content };
11293
11329
  if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
11294
11330
  return entry;
11295
11331
  }).filter((m2) => m2 !== null);
@@ -11809,6 +11845,9 @@ function buildSpawnArgs(ctx) {
11809
11845
  if (ctx.addDirs) {
11810
11846
  for (const dir of ctx.addDirs) args.push("--add-dir", dir);
11811
11847
  }
11848
+ if (ctx.dispatchMcpConfigPath) {
11849
+ args.push("--mcp-config", ctx.dispatchMcpConfigPath);
11850
+ }
11812
11851
  if (ctx.effort) args.push("--effort", ctx.effort);
11813
11852
  if (ctx.toolSessionId) args.push("--resume", ctx.toolSessionId);
11814
11853
  return args;
@@ -12088,10 +12127,10 @@ function parseAttachment(obj) {
12088
12127
  const memories = raw.map((m2) => {
12089
12128
  if (!m2 || typeof m2 !== "object") return null;
12090
12129
  const rec3 = m2;
12091
- const path58 = typeof rec3.path === "string" ? rec3.path : null;
12130
+ const path59 = typeof rec3.path === "string" ? rec3.path : null;
12092
12131
  const content = typeof rec3.content === "string" ? rec3.content : null;
12093
- if (!path58 || content == null) return null;
12094
- const out = { path: path58, content };
12132
+ if (!path59 || content == null) return null;
12133
+ const out = { path: path59, content };
12095
12134
  if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
12096
12135
  return out;
12097
12136
  }).filter((m2) => m2 !== null);
@@ -23878,8 +23917,8 @@ var require_utils = __commonJS({
23878
23917
  var result = transform[inputType][outputType](input);
23879
23918
  return result;
23880
23919
  };
23881
- exports2.resolve = function(path58) {
23882
- var parts = path58.split("/");
23920
+ exports2.resolve = function(path59) {
23921
+ var parts = path59.split("/");
23883
23922
  var result = [];
23884
23923
  for (var index = 0; index < parts.length; index++) {
23885
23924
  var part = parts[index];
@@ -29732,18 +29771,18 @@ var require_object = __commonJS({
29732
29771
  var object = new ZipObject(name, zipObjectContent, o);
29733
29772
  this.files[name] = object;
29734
29773
  };
29735
- var parentFolder = function(path58) {
29736
- if (path58.slice(-1) === "/") {
29737
- path58 = path58.substring(0, path58.length - 1);
29774
+ var parentFolder = function(path59) {
29775
+ if (path59.slice(-1) === "/") {
29776
+ path59 = path59.substring(0, path59.length - 1);
29738
29777
  }
29739
- var lastSlash = path58.lastIndexOf("/");
29740
- return lastSlash > 0 ? path58.substring(0, lastSlash) : "";
29778
+ var lastSlash = path59.lastIndexOf("/");
29779
+ return lastSlash > 0 ? path59.substring(0, lastSlash) : "";
29741
29780
  };
29742
- var forceTrailingSlash = function(path58) {
29743
- if (path58.slice(-1) !== "/") {
29744
- path58 += "/";
29781
+ var forceTrailingSlash = function(path59) {
29782
+ if (path59.slice(-1) !== "/") {
29783
+ path59 += "/";
29745
29784
  }
29746
- return path58;
29785
+ return path59;
29747
29786
  };
29748
29787
  var folderAdd = function(name, createFolders) {
29749
29788
  createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
@@ -30745,7 +30784,7 @@ var require_lib3 = __commonJS({
30745
30784
  // src/run-case/recorder.ts
30746
30785
  function startRunCaseRecorder(opts) {
30747
30786
  const now = opts.now ?? Date.now;
30748
- const dir = import_node_path46.default.dirname(opts.recordPath);
30787
+ const dir = import_node_path47.default.dirname(opts.recordPath);
30749
30788
  let stream = null;
30750
30789
  let closing = false;
30751
30790
  let closedSettled = false;
@@ -30759,8 +30798,8 @@ function startRunCaseRecorder(opts) {
30759
30798
  });
30760
30799
  const ensureStream = () => {
30761
30800
  if (stream) return stream;
30762
- import_node_fs34.default.mkdirSync(dir, { recursive: true });
30763
- stream = import_node_fs34.default.createWriteStream(opts.recordPath, { flags: "a" });
30801
+ import_node_fs35.default.mkdirSync(dir, { recursive: true });
30802
+ stream = import_node_fs35.default.createWriteStream(opts.recordPath, { flags: "a" });
30764
30803
  stream.on("close", () => closedResolve());
30765
30804
  return stream;
30766
30805
  };
@@ -30785,12 +30824,12 @@ function startRunCaseRecorder(opts) {
30785
30824
  };
30786
30825
  return { tap, close, closed };
30787
30826
  }
30788
- var import_node_fs34, import_node_path46;
30827
+ var import_node_fs35, import_node_path47;
30789
30828
  var init_recorder = __esm({
30790
30829
  "src/run-case/recorder.ts"() {
30791
30830
  "use strict";
30792
- import_node_fs34 = __toESM(require("fs"), 1);
30793
- import_node_path46 = __toESM(require("path"), 1);
30831
+ import_node_fs35 = __toESM(require("fs"), 1);
30832
+ import_node_path47 = __toESM(require("path"), 1);
30794
30833
  }
30795
30834
  });
30796
30835
 
@@ -30833,7 +30872,7 @@ var init_wire = __esm({
30833
30872
  // src/run-case/controller.ts
30834
30873
  async function runController(opts) {
30835
30874
  const now = opts.now ?? Date.now;
30836
- const cwd = opts.cwd ?? (0, import_node_fs35.mkdtempSync)(import_node_path47.default.join(import_node_os19.default.tmpdir(), "clawd-runcase-"));
30875
+ const cwd = opts.cwd ?? (0, import_node_fs36.mkdtempSync)(import_node_path48.default.join(import_node_os20.default.tmpdir(), "clawd-runcase-"));
30837
30876
  const ownsCwd = opts.cwd === void 0;
30838
30877
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
30839
30878
  const spawnCtx = { cwd };
@@ -30994,19 +31033,19 @@ async function runController(opts) {
30994
31033
  if (sigintHandler) process.off("SIGINT", sigintHandler);
30995
31034
  if (ownsCwd) {
30996
31035
  try {
30997
- (0, import_node_fs35.rmSync)(cwd, { recursive: true, force: true });
31036
+ (0, import_node_fs36.rmSync)(cwd, { recursive: true, force: true });
30998
31037
  } catch {
30999
31038
  }
31000
31039
  }
31001
31040
  return exitCode ?? 0;
31002
31041
  }
31003
- var import_node_fs35, import_node_os19, import_node_path47;
31042
+ var import_node_fs36, import_node_os20, import_node_path48;
31004
31043
  var init_controller = __esm({
31005
31044
  "src/run-case/controller.ts"() {
31006
31045
  "use strict";
31007
- import_node_fs35 = require("fs");
31008
- import_node_os19 = __toESM(require("os"), 1);
31009
- import_node_path47 = __toESM(require("path"), 1);
31046
+ import_node_fs36 = require("fs");
31047
+ import_node_os20 = __toESM(require("os"), 1);
31048
+ import_node_path48 = __toESM(require("path"), 1);
31010
31049
  init_claude();
31011
31050
  init_stdout_splitter();
31012
31051
  init_permission_stdio();
@@ -31241,8 +31280,59 @@ Env (advanced):
31241
31280
  `;
31242
31281
 
31243
31282
  // src/index.ts
31244
- var import_node_path45 = __toESM(require("path"), 1);
31245
- var import_node_fs33 = __toESM(require("fs"), 1);
31283
+ var import_node_path46 = __toESM(require("path"), 1);
31284
+ var import_node_fs34 = __toESM(require("fs"), 1);
31285
+ var import_node_os19 = __toESM(require("os"), 1);
31286
+
31287
+ // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
31288
+ var byteToHex = [];
31289
+ for (let i = 0; i < 256; ++i) {
31290
+ byteToHex.push((i + 256).toString(16).slice(1));
31291
+ }
31292
+ function unsafeStringify(arr, offset = 0) {
31293
+ return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
31294
+ }
31295
+
31296
+ // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/rng.js
31297
+ var import_node_crypto = __toESM(require("crypto"));
31298
+ var rnds8Pool = new Uint8Array(256);
31299
+ var poolPtr = rnds8Pool.length;
31300
+ function rng() {
31301
+ if (poolPtr > rnds8Pool.length - 16) {
31302
+ import_node_crypto.default.randomFillSync(rnds8Pool);
31303
+ poolPtr = 0;
31304
+ }
31305
+ return rnds8Pool.slice(poolPtr, poolPtr += 16);
31306
+ }
31307
+
31308
+ // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/native.js
31309
+ var import_node_crypto2 = __toESM(require("crypto"));
31310
+ var native_default = {
31311
+ randomUUID: import_node_crypto2.default.randomUUID
31312
+ };
31313
+
31314
+ // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/v4.js
31315
+ function v4(options, buf, offset) {
31316
+ if (native_default.randomUUID && !buf && !options) {
31317
+ return native_default.randomUUID();
31318
+ }
31319
+ options = options || {};
31320
+ const rnds = options.random || (options.rng || rng)();
31321
+ rnds[6] = rnds[6] & 15 | 64;
31322
+ rnds[8] = rnds[8] & 63 | 128;
31323
+ if (buf) {
31324
+ offset = offset || 0;
31325
+ for (let i = 0; i < 16; ++i) {
31326
+ buf[offset + i] = rnds[i];
31327
+ }
31328
+ return buf;
31329
+ }
31330
+ return unsafeStringify(rnds);
31331
+ }
31332
+ var v4_default = v4;
31333
+
31334
+ // src/index.ts
31335
+ var import_node_url2 = require("url");
31246
31336
 
31247
31337
  // src/logger.ts
31248
31338
  var import_node_fs2 = __toESM(require("fs"), 1);
@@ -31484,55 +31574,6 @@ var SessionStoreFactory = class {
31484
31574
  var import_node_fs6 = __toESM(require("fs"), 1);
31485
31575
  var import_node_path6 = __toESM(require("path"), 1);
31486
31576
  var import_node_os2 = __toESM(require("os"), 1);
31487
-
31488
- // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
31489
- var byteToHex = [];
31490
- for (let i = 0; i < 256; ++i) {
31491
- byteToHex.push((i + 256).toString(16).slice(1));
31492
- }
31493
- function unsafeStringify(arr, offset = 0) {
31494
- return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
31495
- }
31496
-
31497
- // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/rng.js
31498
- var import_node_crypto = __toESM(require("crypto"));
31499
- var rnds8Pool = new Uint8Array(256);
31500
- var poolPtr = rnds8Pool.length;
31501
- function rng() {
31502
- if (poolPtr > rnds8Pool.length - 16) {
31503
- import_node_crypto.default.randomFillSync(rnds8Pool);
31504
- poolPtr = 0;
31505
- }
31506
- return rnds8Pool.slice(poolPtr, poolPtr += 16);
31507
- }
31508
-
31509
- // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/native.js
31510
- var import_node_crypto2 = __toESM(require("crypto"));
31511
- var native_default = {
31512
- randomUUID: import_node_crypto2.default.randomUUID
31513
- };
31514
-
31515
- // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/v4.js
31516
- function v4(options, buf, offset) {
31517
- if (native_default.randomUUID && !buf && !options) {
31518
- return native_default.randomUUID();
31519
- }
31520
- options = options || {};
31521
- const rnds = options.random || (options.rng || rng)();
31522
- rnds[6] = rnds[6] & 15 | 64;
31523
- rnds[8] = rnds[8] & 63 | 128;
31524
- if (buf) {
31525
- offset = offset || 0;
31526
- for (let i = 0; i < 16; ++i) {
31527
- buf[offset + i] = rnds[i];
31528
- }
31529
- return buf;
31530
- }
31531
- return unsafeStringify(rnds);
31532
- }
31533
- var v4_default = v4;
31534
-
31535
- // src/session/manager.ts
31536
31577
  init_protocol();
31537
31578
 
31538
31579
  // src/tools/guest-settings.ts
@@ -31657,6 +31698,32 @@ function buildConnectionPrompt(args) {
31657
31698
  return result;
31658
31699
  }
31659
31700
 
31701
+ // src/dispatch/system-prompt.ts
31702
+ var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A persona\uFF08dispatch\uFF09
31703
+
31704
+ \u5F53\u7528\u6237\u6D88\u606F\u91CC\u542B \`@persona/<id>\`\uFF08\u5982 \`@persona/persona-bug-fixer\`\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
31705
+
31706
+ - \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
31707
+ - \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
31708
+
31709
+ tool \u4F1A\u963B\u585E\u6302\u8D77\u7B49\u5BF9\u65B9\u4EBA\u683C\u5E72\u5B8C\uFF0C\u628A outcome\uFF08\u542B text + \u53EF\u9009 filePaths\uFF09\u4F5C\u4E3A tool_result \u56DE\u7ED9\u4F60\uFF0C\u4F60\u518D\u7EFC\u5408\u56DE\u5E94\u7528\u6237\u3002
31710
+
31711
+ - **\u4E0D\u8981**\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF08\u4F60\u4E0D\u662F\u90A3\u4E2A persona\uFF09
31712
+ - **\u4E0D\u8981** in-place \u6A21\u4EFF\u5BF9\u65B9\u4EBA\u683C \u2014\u2014 dispatch \u662F\u771F\u5207\u5230\u53E6\u4E00\u4E2A\u72EC\u7ACB session
31713
+ - \u4E00\u53E5\u8BDD\u91CC\u591A\u4E2A \`@persona/<id>\` \u65F6\u9009\u7B2C\u4E00\u4E2A\uFF08tool \u4E00\u6B21\u53EA\u5904\u7406\u4E00\u4E2A target\uFF09
31714
+ - \u59D4\u6D3E\u5931\u8D25\uFF08tool_result.is_error=true\uFF09\u65F6\u5982\u5B9E\u544A\u8BC9\u7528\u6237\u539F\u56E0\uFF0C**\u4E0D\u8981\u91CD\u8BD5**
31715
+
31716
+ ## \u88AB dispatch \u63A5\u5230\u4EFB\u52A1
31717
+
31718
+ \u5982\u679C\u4F60\u7684 session \u7B2C\u4E00\u6761 user message \u662F \`<system-reminder>You have been dispatched by owner from another persona session ...</system-reminder>\`\uFF0C\u4F60\u662F\u88AB\u53E6\u4E00\u4E2A persona \u59D4\u6D3E\u6765\u5E72\u6D3B\u7684\uFF1A
31719
+
31720
+ - \u4EFB\u52A1\u5728 \`Task:\` \u6BB5
31721
+ - \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
31722
+ - \u5E72\u5B8C\u540E**\u5FC5\u987B**\u8C03 \`mcp__clawd-dispatch__personaDispatchComplete\` \u62A5\u544A\u7ED3\u679C\uFF1A
31723
+ - \u6210\u529F\uFF1A\`{ text: "\u603B\u7ED3/\u7ED3\u8BBA", filePaths?: ["\u4F60\u4EA7\u51FA/\u6539\u7684\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84"] }\`
31724
+ - \u5931\u8D25\uFF1A\`{ isFailure: true, reason: "..." }\`
31725
+ - \u62A5\u544A\u5B8C\u540E\u4F60\u7684 session \u5C31\u7ED3\u675F\u4E86\uFF0C\u4E0D\u8981\u7EE7\u7EED\u8F93\u51FA`;
31726
+
31660
31727
  // src/session/reducer.ts
31661
31728
  function cloneState(s) {
31662
31729
  return {
@@ -31735,6 +31802,9 @@ function buildSpawnContext(state, deps) {
31735
31802
  env.CLAWD_SESSION_ID = file.sessionId;
31736
31803
  const daemonUrl = deps.getDaemonUrl?.() ?? null;
31737
31804
  if (daemonUrl) env.CLAWD_DAEMON_URL = daemonUrl;
31805
+ const dispatchId = deps.lookupDispatchByBSessionId?.(file.sessionId);
31806
+ if (dispatchId) env.CLAWD_DISPATCH_ID = dispatchId;
31807
+ const dispatchMcpConfigPath2 = deps.getDispatchMcpConfigPath?.() ?? null;
31738
31808
  const ctx = {
31739
31809
  cwd: file.cwd,
31740
31810
  toolSessionId: file.toolSessionId,
@@ -31744,7 +31814,10 @@ function buildSpawnContext(state, deps) {
31744
31814
  env,
31745
31815
  // Phase 2 capability platform (plan §3): personaRoot 透传给 buildSpawnArgs;
31746
31816
  // 内部 shouldSandbox(cwd, personaRoot) 决定是否注入 --settings sandbox-settings.
31747
- personaRoot: deps.personaRoot
31817
+ personaRoot: deps.personaRoot,
31818
+ // Persona dispatch:所有 session(A 和 B)都挂同一份 dispatch.mcp.json,让两边的 cc
31819
+ // 都能看到 personaDispatch / personaDispatchComplete tool;按 env 区分实际行为。
31820
+ dispatchMcpConfigPath: dispatchMcpConfigPath2 ?? void 0
31748
31821
  };
31749
31822
  const meta = state.subSessionMeta;
31750
31823
  if (meta?.personaMode) {
@@ -31755,6 +31828,9 @@ function buildSpawnContext(state, deps) {
31755
31828
  workDir: meta.userWorkDir
31756
31829
  });
31757
31830
  }
31831
+ if (dispatchMcpConfigPath2) {
31832
+ ctx.extraSystemPrompt = (ctx.extraSystemPrompt ? ctx.extraSystemPrompt + "\n\n" : "") + DISPATCH_SYSTEM_PROMPT_HINT;
31833
+ }
31758
31834
  if (meta?.extraSettings) {
31759
31835
  ctx.extraSettings = meta.extraSettings;
31760
31836
  }
@@ -32420,35 +32496,6 @@ function startRecorder(opts) {
32420
32496
  };
32421
32497
  }
32422
32498
 
32423
- // src/persona/mention-injection.ts
32424
- var MENTION_RE = /@persona\/([A-Za-z0-9_-]+)(?=\s|$|[^A-Za-z0-9_-])/g;
32425
- function injectPersonaMentions(rawText, store) {
32426
- const resolved = [];
32427
- const body = rawText.replace(MENTION_RE, (match, id) => {
32428
- const meta = store.read(id);
32429
- const personality = store.readPersonality(id);
32430
- if (meta && personality !== null) {
32431
- resolved.push({ label: meta.label, personality });
32432
- return "";
32433
- }
32434
- return match;
32435
- });
32436
- if (resolved.length === 0) {
32437
- return { systemReminder: null, userText: rawText };
32438
- }
32439
- const blocks = resolved.map((r) => {
32440
- const safe = r.personality.replace(/<\/system-reminder>/gi, "</ system-reminder>");
32441
- return `[Acting as persona "${r.label}" for this message]
32442
- ${safe}`;
32443
- });
32444
- return {
32445
- systemReminder: `<system-reminder>
32446
- ${blocks.join("\n\n")}
32447
- </system-reminder>`,
32448
- userText: body.trim()
32449
- };
32450
- }
32451
-
32452
32499
  // src/session/runner.ts
32453
32500
  var DEFAULT_CONTROL_REQUEST_TIMEOUT_MS = 1e4;
32454
32501
  function encodeAllowWithInputControlResponse(requestId, updatedInput) {
@@ -32497,7 +32544,6 @@ var SessionRunner = class {
32497
32544
  }
32498
32545
  // 外部推送 input 到 reducer,然后执行产出的 effects
32499
32546
  input(inputMsg) {
32500
- const personaStore = this.hooks.personaStore;
32501
32547
  const adapter = this.hooks.adapter;
32502
32548
  const deps = {
32503
32549
  // file-sharing (spec §6 PR 3):在 stdout-line 解析时同步观察 file-edit 工具事件,
@@ -32507,20 +32553,10 @@ var SessionRunner = class {
32507
32553
  if (this.hooks.onFileEdit) this.observeForFileEdit(events);
32508
32554
  return events;
32509
32555
  },
32510
- // persona mention injection deps 装配处包一层,对 reducer 完全透明。
32511
- // 命中 mention 时拆成两条 stdin 帧(先 system-reminder 块、后 user 原文):
32512
- // - CC stream-json 按行处理,落盘是两条独立 user message;
32513
- // - 第一条文本起头 `<system-reminder>` classifyUserMessage 命中 UI 折叠;
32514
- // - 第二条正常用户气泡,刷新页面不再暴露 personality 文本。
32515
- encodeStdin: (t, ctx) => {
32516
- if (!personaStore) return adapter.encodeStdin(t, ctx) ?? "";
32517
- const { systemReminder, userText } = injectPersonaMentions(t, personaStore);
32518
- if (systemReminder === null) return adapter.encodeStdin(userText, ctx) ?? "";
32519
- const metaFrame = adapter.encodeStdin(systemReminder, ctx) ?? "";
32520
- if (userText === "") return metaFrame;
32521
- const userFrame = adapter.encodeStdin(userText, ctx) ?? "";
32522
- return metaFrame + userFrame;
32523
- },
32556
+ // Persona dispatch (Task 9):原 in-place `@persona/<id>` 注入路径已删,cc 自己看到字面
32557
+ // token 会调 personaDispatch MCP tool 委派(dispatch.mcp.json 通过 cc --mcp-config 加载,
32558
+ // CLAUDE.md cc 触发条件)。encodeStdin 现在是 adapter 的简单 passthrough。
32559
+ encodeStdin: (t, ctx) => adapter.encodeStdin(t, ctx) ?? "",
32524
32560
  bufferCap: this.hooks.bufferCap ?? 500,
32525
32561
  now: this.hooks.now ?? Date.now,
32526
32562
  resolveContextWindow: this.hooks.resolveContextWindow,
@@ -32530,6 +32566,10 @@ var SessionRunner = class {
32530
32566
  // 单栏 refactor (spec 2026-06-02 §5.1): cc 子进程 env 注入 CLAWD_DAEMON_URL,让 assistant
32531
32567
  // curl daemon HTTP RPC adapter (/api/rpc/<method>) 触发管理操作。null = HTTP adapter 未启。
32532
32568
  getDaemonUrl: this.hooks.getDaemonUrl,
32569
+ // Persona dispatch:透传 dispatch.mcp.json 路径闭包 + B→dispatchId 反查闭包。
32570
+ // 见 reducer.buildSpawnContext 注 CLAWD_DISPATCH_ID env / 派生 SpawnContext.dispatchMcpConfigPath
32571
+ getDispatchMcpConfigPath: this.hooks.getDispatchMcpConfigPath,
32572
+ lookupDispatchByBSessionId: this.hooks.lookupDispatchByBSessionId,
32533
32573
  // ReadyGate v2:透传 mode 让 reducer send / ready-detected 分支决定走暂存队列还是直写
32534
32574
  mode: this.hooks.mode,
32535
32575
  // [RG-DBG] 注入 logger 让 reducer rgDbg 走 pino 进 clawd.log;定位完跟 rgDbg 一起删
@@ -32989,6 +33029,22 @@ function nowIso2(deps) {
32989
33029
  function newSessionId() {
32990
33030
  return v4_default().replace(/-/g, "").slice(0, 16);
32991
33031
  }
33032
+ function buildDispatchTaskPack(args) {
33033
+ return `[Dispatched from owner \u2014 another persona session\u59D4\u6D3E\u7ED9\u4F60\u6267\u884C\u4EFB\u52A1]
33034
+
33035
+ Task:
33036
+ ${args.prompt}
33037
+
33038
+ Source conversation (jsonl, CC stream-json format, one message per line):
33039
+ ${args.sourceJsonlPath}
33040
+ You may read this file with your Read tool to understand context. You do not have to read it all.
33041
+
33042
+ When done, call the MCP tool \`mcp__clawd-dispatch__personaDispatchComplete\` with your result:
33043
+ - Success: { text: "...", filePaths?: ["abs/path", ...] }
33044
+ - Failure: { isFailure: true, reason: "..." }
33045
+
33046
+ dispatchId for this task: ${args.dispatchId}`;
33047
+ }
32992
33048
  function derivePersonaSpawnCwd(file, personaRoot) {
32993
33049
  const personaId = file.ownerPersonaId;
32994
33050
  if (!personaId) return file.cwd;
@@ -33286,7 +33342,8 @@ var SessionManager = class {
33286
33342
  // adapter 自己持有模型表 + 兜底逻辑(contains / opus-1M / [1m] 等),manager 不再 cache 转发
33287
33343
  resolveContextWindow: (tool, modelId) => this.deps.getAdapter(tool).resolveContextWindow(modelId),
33288
33344
  dataDir: this.deps.dataDir,
33289
- personaStore: this.deps.personaStore,
33345
+ // personaStore 不再透给 runner hooks(in-place mention 注入路径已删,runner 不用);
33346
+ // manager 自身的 sandbox 派生仍直接读 this.deps.personaStore。
33290
33347
  ownerDisplayName: this.deps.ownerDisplayName,
33291
33348
  // Phase 2 capability platform (plan §3): 透传 personaRoot, buildSpawnArgs 据
33292
33349
  // cwd 是否在 personaRoot 下自动决定是否注入 --settings sandbox-settings.json.
@@ -33294,6 +33351,10 @@ var SessionManager = class {
33294
33351
  // 单栏 refactor (spec 2026-06-02 §5.1): 透传 daemon HTTP RPC base URL 闭包,
33295
33352
  // reducer 把它注入 cc 子进程 env CLAWD_DAEMON_URL.
33296
33353
  getDaemonUrl: this.deps.getDaemonUrl,
33354
+ // Persona dispatch (Task 7): dispatch.mcp.json 路径 + B sessionId → dispatchId 反查
33355
+ // 闭包透传给 reducer,让 cc spawn 加 --mcp-config flag + B session 注 CLAWD_DISPATCH_ID env.
33356
+ getDispatchMcpConfigPath: this.deps.dispatchMcpConfigPath ? () => this.deps.dispatchMcpConfigPath ?? null : void 0,
33357
+ lookupDispatchByBSessionId: this.deps.personaDispatchManager ? (bSid) => this.deps.personaDispatchManager?.lookupDispatchByBSessionId(bSid) : void 0,
33297
33358
  // file-sharing (spec §6 PR 3):闭包 scope + sessionId,runner 只暴露 tool/relPath/cwd
33298
33359
  onFileEdit: attachmentGroup ? (input) => attachmentGroup.onFileEdit({
33299
33360
  scope,
@@ -33509,15 +33570,20 @@ var SessionManager = class {
33509
33570
  // 强制走 deps.store(即 default scope),不走 scopeForFile:mirror 物理落 default 即可。
33510
33571
  // 远端 creator / origin 字段原值保留(不被本机 ctx 派生覆写)。
33511
33572
  //
33512
- // strip 远端 personaId:mirror SessionFile 上的 ownerPersonaId 是朋友 daemon 的 persona
33513
- // 目录 id,本机不持有对应 persona。留着会让按 ownerPersonaId 反查的本机消费者
33514
- // MyPersonasSection 等)把 mirror 误聚到同 id persona 下。写入前清掉。
33573
+ // strip 远端 personaId / dispatchedFromSessionId:mirror SessionFile 上这两个字段都指向
33574
+ // 朋友 daemon 上的本地 id,本机不持有对应 persona / 源 session。留着会让按这些字段反查的
33575
+ // 本机消费者(MyPersonasSection ownerPersonaId 反查 persona、sidebar
33576
+ // dispatchedFromSessionId 折叠 sub-session)走错分支。写入前清掉。#750 一族防线。
33515
33577
  //
33516
33578
  // 与 manager.create / manager.update 区别:
33517
33579
  // - 不走 newRunner / attachObserver / cwd 校验(mirror 是纯 metadata 层)
33518
33580
  // - 不发 session:info 帧(manager.create / .update 通过 reducer/wireCollector 发 push)
33519
33581
  mirrorUpsert(file) {
33520
- const { ownerPersonaId: _stripped, ...rest } = file;
33582
+ const {
33583
+ ownerPersonaId: _strippedPid,
33584
+ dispatchedFromSessionId: _strippedDsp,
33585
+ ...rest
33586
+ } = file;
33521
33587
  return this.deps.store.write(rest);
33522
33588
  }
33523
33589
  // mirror peer sessions:删本机 mirror SessionFile。mirror 一律落 default(mirrorUpsert
@@ -34102,6 +34168,66 @@ var SessionManager = class {
34102
34168
  this.runners.set(file.sessionId, runner);
34103
34169
  return runner;
34104
34170
  }
34171
+ /**
34172
+ * Persona dispatch: 启动 B session 并投递任务包当第一条 user message。
34173
+ *
34174
+ * - 复用 persona-owner 创建路径(cwd=personaDir、scope=persona-owner、不沙箱)
34175
+ * - SessionFile 上写 dispatchedFromSessionId 关联回 A(UI 折叠用;mirror 一侧 strip)
34176
+ * - 跟 PersonaDispatchManager 双向登记 dispatchId ↔ B sessionId,让后续 reducer
34177
+ * buildSpawnContext 能反查到 dispatchId 注 CLAWD_DISPATCH_ID env
34178
+ * - 投 inject-owner-text 任务包;包尾教 B 用 personaDispatchComplete tool 回传
34179
+ *
34180
+ * cwd 派生与 SessionManager.create 的 owner persona 路径一致(derivePersonaSpawnCwd)。
34181
+ */
34182
+ createDispatchedSession(args) {
34183
+ if (!this.deps.personaRoot) {
34184
+ throw new Error("createDispatchedSession: personaRoot missing in ManagerDeps");
34185
+ }
34186
+ if (!this.deps.personaDispatchManager) {
34187
+ throw new Error("createDispatchedSession: personaDispatchManager missing in ManagerDeps");
34188
+ }
34189
+ const sessionId = newSessionId();
34190
+ const scope = {
34191
+ kind: "persona",
34192
+ personaId: args.targetPersona,
34193
+ mode: "owner"
34194
+ };
34195
+ const cwd = import_node_path6.default.join(this.deps.personaRoot, safeFileName(args.targetPersona));
34196
+ const now = (/* @__PURE__ */ new Date()).toISOString();
34197
+ const file = {
34198
+ sessionId,
34199
+ cwd,
34200
+ tool: "claude",
34201
+ ownerPersonaId: args.targetPersona,
34202
+ dispatchedFromSessionId: args.sourceSessionId,
34203
+ createdAt: now,
34204
+ updatedAt: now
34205
+ };
34206
+ this.storeFor(scope).write(file);
34207
+ this.deps.personaDispatchManager.registerBSession(args.dispatchId, sessionId);
34208
+ this.deps.logger?.info("dispatch.createDispatchedSession.file-written", {
34209
+ dispatchId: args.dispatchId,
34210
+ bSessionId: sessionId,
34211
+ targetPersona: args.targetPersona,
34212
+ cwd
34213
+ });
34214
+ const runner = this.ensureRunnerForScope(file, scope);
34215
+ this.deps.logger?.info("dispatch.createDispatchedSession.runner-ready", {
34216
+ dispatchId: args.dispatchId,
34217
+ bSessionId: sessionId
34218
+ });
34219
+ const taskPack = buildDispatchTaskPack({
34220
+ prompt: args.prompt,
34221
+ sourceJsonlPath: args.sourceJsonlPath,
34222
+ dispatchId: args.dispatchId
34223
+ });
34224
+ runner.input({ kind: "command", command: { kind: "send", text: taskPack } });
34225
+ this.deps.logger?.info("dispatch.createDispatchedSession.task-pack-sent", {
34226
+ dispatchId: args.dispatchId,
34227
+ bSessionId: sessionId
34228
+ });
34229
+ return { sessionId };
34230
+ }
34105
34231
  /**
34106
34232
  * 老板插话:把 'inject-owner-text' input 喂给对应 runner,
34107
34233
  * runner 不存在时按 scope 懒创建。
@@ -35535,8 +35661,8 @@ function turnStartInput(text) {
35535
35661
  const items = [];
35536
35662
  let leftover = text;
35537
35663
  for (const m2 of text.matchAll(SKILL_RE)) {
35538
- const [marker, name, path58] = m2;
35539
- items.push({ type: "skill", name, path: path58 });
35664
+ const [marker, name, path59] = m2;
35665
+ items.push({ type: "skill", name, path: path59 });
35540
35666
  leftover = leftover.replace(marker, "");
35541
35667
  }
35542
35668
  for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
@@ -36763,6 +36889,9 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
36763
36889
  if (ctx.addDirs) {
36764
36890
  for (const dir of ctx.addDirs) args.push("--add-dir", dir);
36765
36891
  }
36892
+ if (ctx.dispatchMcpConfigPath) {
36893
+ args.push("--mcp-config", ctx.dispatchMcpConfigPath);
36894
+ }
36766
36895
  if (ctx.effort) args.push("--effort", ctx.effort);
36767
36896
  return args;
36768
36897
  }
@@ -36780,6 +36909,155 @@ function jsonlExistsForCtx(ctx) {
36780
36909
  // src/index.ts
36781
36910
  init_claude_history();
36782
36911
 
36912
+ // src/dispatch/manager.ts
36913
+ function defer() {
36914
+ let resolve6;
36915
+ const promise = new Promise((r) => {
36916
+ resolve6 = r;
36917
+ });
36918
+ return { promise, resolve: resolve6 };
36919
+ }
36920
+ var PersonaDispatchManager = class {
36921
+ constructor(deps) {
36922
+ this.deps = deps;
36923
+ }
36924
+ deps;
36925
+ map = /* @__PURE__ */ new Map();
36926
+ start(args) {
36927
+ const dispatchId = this.deps.genId();
36928
+ this.map.set(dispatchId, {
36929
+ dispatchId,
36930
+ sourceSessionId: args.sourceSessionId,
36931
+ targetPersona: args.targetPersona,
36932
+ waiters: [],
36933
+ outcome: null
36934
+ });
36935
+ return { dispatchId };
36936
+ }
36937
+ get(dispatchId) {
36938
+ return this.map.get(dispatchId);
36939
+ }
36940
+ async wait(dispatchId) {
36941
+ const state = this.map.get(dispatchId);
36942
+ if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
36943
+ if (state.outcome) return state.outcome;
36944
+ const d = defer();
36945
+ state.waiters.push(d);
36946
+ return d.promise;
36947
+ }
36948
+ complete(dispatchId, outcome) {
36949
+ const state = this.map.get(dispatchId);
36950
+ if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
36951
+ state.outcome = outcome;
36952
+ const waiters = state.waiters;
36953
+ state.waiters = [];
36954
+ for (const w2 of waiters) w2.resolve(outcome);
36955
+ }
36956
+ /** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
36957
+ registerBSession(dispatchId, bSessionId) {
36958
+ const state = this.map.get(dispatchId);
36959
+ if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
36960
+ state.bSessionId = bSessionId;
36961
+ }
36962
+ /** reducer buildSpawnContext 调,按 B 的 sessionId 反查 dispatchId(用于注 CLAWD_DISPATCH_ID env) */
36963
+ lookupDispatchByBSessionId(bSessionId) {
36964
+ for (const state of this.map.values()) {
36965
+ if (state.bSessionId === bSessionId) return state.dispatchId;
36966
+ }
36967
+ return void 0;
36968
+ }
36969
+ };
36970
+
36971
+ // src/dispatch/mcp-config.ts
36972
+ var import_node_fs12 = __toESM(require("fs"), 1);
36973
+ var import_node_path10 = __toESM(require("path"), 1);
36974
+ function dispatchMcpConfigPath(dataDir) {
36975
+ return import_node_path10.default.join(dataDir, "dispatch.mcp.json");
36976
+ }
36977
+ function writeDispatchMcpConfig(args) {
36978
+ const cfgPath = dispatchMcpConfigPath(args.dataDir);
36979
+ const content = {
36980
+ _comment: "daemon \u542F\u52A8\u65F6\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002dispatch-mcp-server.cjs \u662F daemon \u81EA\u5E26\u7684 stdio MCP server\u3002env.CLAWD_DISPATCH_LOG \u6307 server \u5199\u65E5\u5FD7\u7684 append \u6587\u4EF6\u8DEF\u5F84\uFF08dispatch \u6D41\u7A0B\u8282\u70B9 + fetch \u9519\u8BEF\u7EC6\u8282\uFF09\u3002",
36981
+ mcpServers: {
36982
+ "clawd-dispatch": {
36983
+ type: "stdio",
36984
+ command: "node",
36985
+ args: [args.serverScriptPath],
36986
+ ...args.logPath ? { env: { CLAWD_DISPATCH_LOG: args.logPath } } : {}
36987
+ }
36988
+ }
36989
+ };
36990
+ import_node_fs12.default.mkdirSync(args.dataDir, { recursive: true });
36991
+ import_node_fs12.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
36992
+ return cfgPath;
36993
+ }
36994
+
36995
+ // src/handlers/persona-dispatch.ts
36996
+ init_protocol();
36997
+ function buildPersonaDispatchHandlers(deps) {
36998
+ const { personaDispatchManager: mgr, spawnB, logger } = deps;
36999
+ const run = async (frame) => {
37000
+ const { type: _t, requestId: _r, ...rest } = frame;
37001
+ const sourceSessionId = typeof rest.sessionId === "string" ? rest.sessionId : void 0;
37002
+ const args = DispatchRunArgsSchema.parse(rest);
37003
+ if (!sourceSessionId) {
37004
+ throw new Error(
37005
+ "personaDispatch:run requires sessionId (caller must pass x-clawd-session-id header)"
37006
+ );
37007
+ }
37008
+ const { dispatchId } = mgr.start({
37009
+ sourceSessionId,
37010
+ targetPersona: args.targetPersona
37011
+ });
37012
+ logger?.info("dispatch.run.received", {
37013
+ dispatchId,
37014
+ sourceSessionId,
37015
+ targetPersona: args.targetPersona,
37016
+ promptLen: args.prompt.length
37017
+ });
37018
+ void spawnB({
37019
+ dispatchId,
37020
+ sourceSessionId,
37021
+ targetPersona: args.targetPersona,
37022
+ prompt: args.prompt
37023
+ }).then(() => {
37024
+ logger?.info("dispatch.spawnB.ok", { dispatchId });
37025
+ }).catch((err) => {
37026
+ const reason = err instanceof Error ? err.message : String(err);
37027
+ logger?.warn("dispatch.spawnB.failed", { dispatchId, reason });
37028
+ mgr.complete(dispatchId, {
37029
+ kind: "failure",
37030
+ reason: `failed to spawn B: ${reason}`
37031
+ });
37032
+ });
37033
+ logger?.info("dispatch.run.waiting", { dispatchId });
37034
+ const outcome = await mgr.wait(dispatchId);
37035
+ logger?.info("dispatch.run.resolved", {
37036
+ dispatchId,
37037
+ outcomeKind: outcome.kind
37038
+ });
37039
+ return {
37040
+ response: { type: "personaDispatch:run:ok", outcome }
37041
+ };
37042
+ };
37043
+ const complete = async (frame) => {
37044
+ const { type: _t, requestId: _r, ...rest } = frame;
37045
+ const args = DispatchCompleteArgsSchema.parse(rest);
37046
+ logger?.info("dispatch.complete.received", {
37047
+ dispatchId: args.dispatchId,
37048
+ outcomeKind: args.outcome.kind
37049
+ });
37050
+ mgr.complete(args.dispatchId, args.outcome);
37051
+ return {
37052
+ response: { type: "personaDispatch:complete:ok" }
37053
+ };
37054
+ };
37055
+ return {
37056
+ "personaDispatch:run": run,
37057
+ "personaDispatch:complete": complete
37058
+ };
37059
+ }
37060
+
36783
37061
  // src/tools/codex-history.ts
36784
37062
  var import_node_child_process5 = require("child_process");
36785
37063
  var DEFAULT_TIMEOUT_MS = 8e3;
@@ -36966,13 +37244,13 @@ function mapSkillsListResponse(res) {
36966
37244
  const r = s ?? {};
36967
37245
  const name = str3(r.name);
36968
37246
  if (!name) continue;
36969
- const path58 = str3(r.path);
37247
+ const path59 = str3(r.path);
36970
37248
  const description = str3(r.description);
36971
37249
  const isPlugin = name.includes(":");
36972
37250
  out.push({
36973
37251
  name,
36974
37252
  source: isPlugin ? "plugin" : "project",
36975
- ...path58 ? { path: path58 } : {},
37253
+ ...path59 ? { path: path59 } : {},
36976
37254
  ...description ? { description } : {},
36977
37255
  ...isPlugin ? { plugin: name.split(":")[0] } : {}
36978
37256
  });
@@ -37011,23 +37289,23 @@ async function listCodexSkills(cwd, deps = {}) {
37011
37289
  }
37012
37290
 
37013
37291
  // src/workspace/browser.ts
37014
- var import_node_fs12 = __toESM(require("fs"), 1);
37292
+ var import_node_fs13 = __toESM(require("fs"), 1);
37015
37293
  var import_node_os6 = __toESM(require("os"), 1);
37016
- var import_node_path10 = __toESM(require("path"), 1);
37294
+ var import_node_path11 = __toESM(require("path"), 1);
37017
37295
  init_protocol();
37018
37296
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
37019
37297
  function resolveInsideCwd(cwd, subpath) {
37020
- const absCwd = import_node_path10.default.resolve(cwd);
37021
- const joined = import_node_path10.default.resolve(absCwd, subpath ?? ".");
37022
- const rel = import_node_path10.default.relative(absCwd, joined);
37023
- if (rel.startsWith("..") || import_node_path10.default.isAbsolute(rel)) {
37298
+ const absCwd = import_node_path11.default.resolve(cwd);
37299
+ const joined = import_node_path11.default.resolve(absCwd, subpath ?? ".");
37300
+ const rel = import_node_path11.default.relative(absCwd, joined);
37301
+ if (rel.startsWith("..") || import_node_path11.default.isAbsolute(rel)) {
37024
37302
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
37025
37303
  }
37026
37304
  return joined;
37027
37305
  }
37028
37306
  function ensureCwd(cwd) {
37029
37307
  try {
37030
- const stat = import_node_fs12.default.statSync(cwd);
37308
+ const stat = import_node_fs13.default.statSync(cwd);
37031
37309
  if (!stat.isDirectory()) {
37032
37310
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
37033
37311
  }
@@ -37041,7 +37319,7 @@ var WorkspaceBrowser = class {
37041
37319
  const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os6.default.homedir();
37042
37320
  ensureCwd(cwd);
37043
37321
  const full = resolveInsideCwd(cwd, args.path);
37044
- const dirents = import_node_fs12.default.readdirSync(full, { withFileTypes: true });
37322
+ const dirents = import_node_fs13.default.readdirSync(full, { withFileTypes: true });
37045
37323
  const entries = [];
37046
37324
  for (const d of dirents) {
37047
37325
  if (!args.showHidden && d.name.startsWith(".")) continue;
@@ -37051,7 +37329,7 @@ var WorkspaceBrowser = class {
37051
37329
  mtime: ""
37052
37330
  };
37053
37331
  try {
37054
- const st = import_node_fs12.default.statSync(import_node_path10.default.join(full, d.name));
37332
+ const st = import_node_fs13.default.statSync(import_node_path11.default.join(full, d.name));
37055
37333
  entry.mtime = new Date(st.mtimeMs).toISOString();
37056
37334
  if (d.isFile()) entry.size = st.size;
37057
37335
  } catch {
@@ -37067,14 +37345,14 @@ var WorkspaceBrowser = class {
37067
37345
  read(args) {
37068
37346
  ensureCwd(args.cwd);
37069
37347
  const full = resolveInsideCwd(args.cwd, args.path);
37070
- const st = import_node_fs12.default.statSync(full);
37348
+ const st = import_node_fs13.default.statSync(full);
37071
37349
  if (!st.isFile()) {
37072
37350
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
37073
37351
  }
37074
37352
  if (st.size > MAX_FILE_BYTES) {
37075
37353
  throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
37076
37354
  }
37077
- const buf = import_node_fs12.default.readFileSync(full);
37355
+ const buf = import_node_fs13.default.readFileSync(full);
37078
37356
  const isBinary = buf.includes(0);
37079
37357
  if (isBinary) {
37080
37358
  return {
@@ -37096,20 +37374,20 @@ var WorkspaceBrowser = class {
37096
37374
  };
37097
37375
 
37098
37376
  // src/skills/agents-scanner.ts
37099
- var import_node_fs13 = __toESM(require("fs"), 1);
37377
+ var import_node_fs14 = __toESM(require("fs"), 1);
37100
37378
  var import_node_os7 = __toESM(require("os"), 1);
37101
- var import_node_path11 = __toESM(require("path"), 1);
37379
+ var import_node_path12 = __toESM(require("path"), 1);
37102
37380
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
37103
37381
  function isDirLikeSync2(p2) {
37104
37382
  try {
37105
- return import_node_fs13.default.statSync(p2).isDirectory();
37383
+ return import_node_fs14.default.statSync(p2).isDirectory();
37106
37384
  } catch {
37107
37385
  return false;
37108
37386
  }
37109
37387
  }
37110
37388
  function fileExistsSync(p2) {
37111
37389
  try {
37112
- return import_node_fs13.default.statSync(p2).isFile();
37390
+ return import_node_fs14.default.statSync(p2).isFile();
37113
37391
  } catch {
37114
37392
  return false;
37115
37393
  }
@@ -37117,7 +37395,7 @@ function fileExistsSync(p2) {
37117
37395
  function parseAgentFile(filePath) {
37118
37396
  let content;
37119
37397
  try {
37120
- content = import_node_fs13.default.readFileSync(filePath, "utf8");
37398
+ content = import_node_fs14.default.readFileSync(filePath, "utf8");
37121
37399
  } catch {
37122
37400
  return {};
37123
37401
  }
@@ -37130,16 +37408,16 @@ function parseAgentFile(filePath) {
37130
37408
  function scanAgentsDir(dir, source, seen, out) {
37131
37409
  let entries;
37132
37410
  try {
37133
- entries = import_node_fs13.default.readdirSync(dir, { withFileTypes: true });
37411
+ entries = import_node_fs14.default.readdirSync(dir, { withFileTypes: true });
37134
37412
  } catch {
37135
37413
  return;
37136
37414
  }
37137
37415
  for (const ent of entries) {
37138
37416
  if (!ent.name.endsWith(".md")) continue;
37139
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path11.default.join(dir, ent.name)))) {
37417
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path12.default.join(dir, ent.name)))) {
37140
37418
  continue;
37141
37419
  }
37142
- const filePath = import_node_path11.default.join(dir, ent.name);
37420
+ const filePath = import_node_path12.default.join(dir, ent.name);
37143
37421
  const baseName = ent.name.replace(/\.md$/, "");
37144
37422
  if (seen.has(baseName)) continue;
37145
37423
  seen.add(baseName);
@@ -37157,12 +37435,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
37157
37435
  function walk2(dir, namespaces) {
37158
37436
  let entries;
37159
37437
  try {
37160
- entries = import_node_fs13.default.readdirSync(dir, { withFileTypes: true });
37438
+ entries = import_node_fs14.default.readdirSync(dir, { withFileTypes: true });
37161
37439
  } catch {
37162
37440
  return;
37163
37441
  }
37164
37442
  for (const ent of entries) {
37165
- const childPath = import_node_path11.default.join(dir, ent.name);
37443
+ const childPath = import_node_path12.default.join(dir, ent.name);
37166
37444
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
37167
37445
  walk2(childPath, [...namespaces, ent.name]);
37168
37446
  continue;
@@ -37187,13 +37465,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
37187
37465
  walk2(root, []);
37188
37466
  }
37189
37467
  function readInstalledPlugins2(home) {
37190
- const pluginsDir = import_node_path11.default.join(home, ".claude", "plugins");
37191
- const v2 = import_node_path11.default.join(pluginsDir, "installed_plugins_v2.json");
37192
- const v1 = import_node_path11.default.join(pluginsDir, "installed_plugins.json");
37468
+ const pluginsDir = import_node_path12.default.join(home, ".claude", "plugins");
37469
+ const v2 = import_node_path12.default.join(pluginsDir, "installed_plugins_v2.json");
37470
+ const v1 = import_node_path12.default.join(pluginsDir, "installed_plugins.json");
37193
37471
  let raw = null;
37194
37472
  for (const candidate of [v2, v1]) {
37195
37473
  try {
37196
- raw = import_node_fs13.default.readFileSync(candidate, "utf8");
37474
+ raw = import_node_fs14.default.readFileSync(candidate, "utf8");
37197
37475
  break;
37198
37476
  } catch {
37199
37477
  }
@@ -37218,19 +37496,19 @@ function readInstalledPlugins2(home) {
37218
37496
  return out;
37219
37497
  }
37220
37498
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
37221
- let cur = import_node_path11.default.resolve(startCwd);
37222
- const fsRoot = import_node_path11.default.parse(cur).root;
37499
+ let cur = import_node_path12.default.resolve(startCwd);
37500
+ const fsRoot = import_node_path12.default.parse(cur).root;
37223
37501
  while (true) {
37224
- scanAgentsDir(import_node_path11.default.join(cur, ".claude", "agents"), "project", seen, out);
37502
+ scanAgentsDir(import_node_path12.default.join(cur, ".claude", "agents"), "project", seen, out);
37225
37503
  let hasGit = false;
37226
37504
  try {
37227
- hasGit = import_node_fs13.default.existsSync(import_node_path11.default.join(cur, ".git"));
37505
+ hasGit = import_node_fs14.default.existsSync(import_node_path12.default.join(cur, ".git"));
37228
37506
  } catch {
37229
37507
  }
37230
37508
  if (hasGit) return;
37231
37509
  if (cur === home) return;
37232
37510
  if (cur === fsRoot) return;
37233
- const parent = import_node_path11.default.dirname(cur);
37511
+ const parent = import_node_path12.default.dirname(cur);
37234
37512
  if (parent === cur) return;
37235
37513
  cur = parent;
37236
37514
  }
@@ -37265,7 +37543,7 @@ var AgentsScanner = class {
37265
37543
  }
37266
37544
  const fsBlock = [];
37267
37545
  scanAgentsDir(
37268
- import_node_path11.default.join(this.home, ".claude", "agents"),
37546
+ import_node_path12.default.join(this.home, ".claude", "agents"),
37269
37547
  "global",
37270
37548
  seen,
37271
37549
  fsBlock
@@ -37279,7 +37557,7 @@ var AgentsScanner = class {
37279
37557
  ...this.extraPluginRoots
37280
37558
  ];
37281
37559
  for (const { name, root } of plugins) {
37282
- const agentsRoot = import_node_path11.default.join(root, "agents");
37560
+ const agentsRoot = import_node_path12.default.join(root, "agents");
37283
37561
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
37284
37562
  }
37285
37563
  return [...builtinBlock, ...fsBlock];
@@ -37287,15 +37565,15 @@ var AgentsScanner = class {
37287
37565
  };
37288
37566
 
37289
37567
  // src/observer/session-observer.ts
37290
- var import_node_fs15 = __toESM(require("fs"), 1);
37568
+ var import_node_fs16 = __toESM(require("fs"), 1);
37291
37569
  var import_node_os9 = __toESM(require("os"), 1);
37292
- var import_node_path13 = __toESM(require("path"), 1);
37570
+ var import_node_path14 = __toESM(require("path"), 1);
37293
37571
  init_claude_history();
37294
37572
 
37295
37573
  // src/observer/subagent-meta-observer.ts
37296
- var import_node_fs14 = __toESM(require("fs"), 1);
37574
+ var import_node_fs15 = __toESM(require("fs"), 1);
37297
37575
  var import_node_os8 = __toESM(require("os"), 1);
37298
- var import_node_path12 = __toESM(require("path"), 1);
37576
+ var import_node_path13 = __toESM(require("path"), 1);
37299
37577
  init_claude_history();
37300
37578
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
37301
37579
  var SubagentMetaObserver = class {
@@ -37308,7 +37586,7 @@ var SubagentMetaObserver = class {
37308
37586
  watches = /* @__PURE__ */ new Map();
37309
37587
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
37310
37588
  resolveSubagentDir(cwd, toolSessionId) {
37311
- return import_node_path12.default.join(
37589
+ return import_node_path13.default.join(
37312
37590
  this.home,
37313
37591
  ".claude",
37314
37592
  "projects",
@@ -37338,7 +37616,7 @@ var SubagentMetaObserver = class {
37338
37616
  attachWatcher(w2) {
37339
37617
  if (w2.watcher) return;
37340
37618
  try {
37341
- w2.watcher = import_node_fs14.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
37619
+ w2.watcher = import_node_fs15.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
37342
37620
  if (!name) return;
37343
37621
  const m2 = META_RE.exec(String(name));
37344
37622
  if (!m2) return;
@@ -37350,7 +37628,7 @@ var SubagentMetaObserver = class {
37350
37628
  scan(w2) {
37351
37629
  let entries;
37352
37630
  try {
37353
- entries = import_node_fs14.default.readdirSync(w2.dirPath);
37631
+ entries = import_node_fs15.default.readdirSync(w2.dirPath);
37354
37632
  } catch {
37355
37633
  return;
37356
37634
  }
@@ -37364,10 +37642,10 @@ var SubagentMetaObserver = class {
37364
37642
  if (!m2) return;
37365
37643
  const agentId = m2[1];
37366
37644
  if (w2.emitted.has(agentId)) return;
37367
- const file = import_node_path12.default.join(w2.dirPath, name);
37645
+ const file = import_node_path13.default.join(w2.dirPath, name);
37368
37646
  let raw;
37369
37647
  try {
37370
- raw = import_node_fs14.default.readFileSync(file, "utf8");
37648
+ raw = import_node_fs15.default.readFileSync(file, "utf8");
37371
37649
  } catch {
37372
37650
  return;
37373
37651
  }
@@ -37424,14 +37702,14 @@ var SessionObserver = class {
37424
37702
  metaObserver;
37425
37703
  resolveJsonlPath(cwd, toolSessionId, override) {
37426
37704
  if (override) return override;
37427
- return import_node_path13.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
37705
+ return import_node_path14.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
37428
37706
  }
37429
37707
  start(args) {
37430
37708
  this.stop(args.sessionId);
37431
37709
  const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
37432
37710
  let size = 0;
37433
37711
  try {
37434
- size = import_node_fs15.default.statSync(filePath).size;
37712
+ size = import_node_fs16.default.statSync(filePath).size;
37435
37713
  } catch {
37436
37714
  }
37437
37715
  const w2 = {
@@ -37445,10 +37723,10 @@ var SessionObserver = class {
37445
37723
  prevIsRejectSentinel: false
37446
37724
  };
37447
37725
  try {
37448
- import_node_fs15.default.mkdirSync(import_node_path13.default.dirname(filePath), { recursive: true });
37726
+ import_node_fs16.default.mkdirSync(import_node_path14.default.dirname(filePath), { recursive: true });
37449
37727
  } catch {
37450
37728
  }
37451
- w2.watcher = import_node_fs15.default.watch(import_node_path13.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
37729
+ w2.watcher = import_node_fs16.default.watch(import_node_path14.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
37452
37730
  if (!changedName || !filePath.endsWith(changedName)) return;
37453
37731
  this.poll(w2);
37454
37732
  });
@@ -37471,7 +37749,7 @@ var SessionObserver = class {
37471
37749
  // 异常静默吞,不阻塞 watcher 启动
37472
37750
  hydrateMetaTail(w2, maxLines = 200) {
37473
37751
  try {
37474
- const raw = import_node_fs15.default.readFileSync(w2.filePath, "utf8");
37752
+ const raw = import_node_fs16.default.readFileSync(w2.filePath, "utf8");
37475
37753
  if (!raw) return;
37476
37754
  const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
37477
37755
  if (allLines.length === 0) return;
@@ -37495,7 +37773,7 @@ var SessionObserver = class {
37495
37773
  poll(w2) {
37496
37774
  let size = 0;
37497
37775
  try {
37498
- size = import_node_fs15.default.statSync(w2.filePath).size;
37776
+ size = import_node_fs16.default.statSync(w2.filePath).size;
37499
37777
  } catch {
37500
37778
  return;
37501
37779
  }
@@ -37504,11 +37782,11 @@ var SessionObserver = class {
37504
37782
  w2.buf = "";
37505
37783
  }
37506
37784
  if (size === w2.lastSize) return;
37507
- const fd = import_node_fs15.default.openSync(w2.filePath, "r");
37785
+ const fd = import_node_fs16.default.openSync(w2.filePath, "r");
37508
37786
  try {
37509
37787
  const len = size - w2.lastSize;
37510
37788
  const buf = Buffer.alloc(len);
37511
- import_node_fs15.default.readSync(fd, buf, 0, len, w2.lastSize);
37789
+ import_node_fs16.default.readSync(fd, buf, 0, len, w2.lastSize);
37512
37790
  w2.lastSize = size;
37513
37791
  w2.buf += buf.toString("utf8");
37514
37792
  let newlineIndex;
@@ -37531,7 +37809,7 @@ var SessionObserver = class {
37531
37809
  }
37532
37810
  }
37533
37811
  } finally {
37534
- import_node_fs15.default.closeSync(fd);
37812
+ import_node_fs16.default.closeSync(fd);
37535
37813
  }
37536
37814
  }
37537
37815
  // 解析 JSONL 单行:仅当是主链 user 文本行(非 sidechain / 非 sub-agent / message.role='user'
@@ -38254,14 +38532,14 @@ async function authenticate(token, deps) {
38254
38532
  }
38255
38533
 
38256
38534
  // src/permission/capability-store.ts
38257
- var fs18 = __toESM(require("fs"), 1);
38258
- var path18 = __toESM(require("path"), 1);
38535
+ var fs19 = __toESM(require("fs"), 1);
38536
+ var path19 = __toESM(require("path"), 1);
38259
38537
  var CAPABILITIES_FILE_NAME = "capabilities.json";
38260
38538
  var FILE_VERSION = 1;
38261
38539
  var CapabilityStore = class {
38262
38540
  constructor(dataDir) {
38263
38541
  this.dataDir = dataDir;
38264
- fs18.mkdirSync(dataDir, { recursive: true });
38542
+ fs19.mkdirSync(dataDir, { recursive: true });
38265
38543
  this.cache = this.readFromDisk();
38266
38544
  }
38267
38545
  dataDir;
@@ -38285,13 +38563,13 @@ var CapabilityStore = class {
38285
38563
  this.flush();
38286
38564
  }
38287
38565
  filePath() {
38288
- return path18.join(this.dataDir, CAPABILITIES_FILE_NAME);
38566
+ return path19.join(this.dataDir, CAPABILITIES_FILE_NAME);
38289
38567
  }
38290
38568
  readFromDisk() {
38291
38569
  const file = this.filePath();
38292
38570
  let raw;
38293
38571
  try {
38294
- raw = fs18.readFileSync(file, "utf8");
38572
+ raw = fs19.readFileSync(file, "utf8");
38295
38573
  } catch (err) {
38296
38574
  if (err?.code === "ENOENT") return [];
38297
38575
  return [];
@@ -38319,10 +38597,10 @@ var CapabilityStore = class {
38319
38597
  }
38320
38598
  atomicWrite(file, content) {
38321
38599
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
38322
- fs18.writeFileSync(tmp, content, { mode: 384 });
38323
- fs18.renameSync(tmp, file);
38600
+ fs19.writeFileSync(tmp, content, { mode: 384 });
38601
+ fs19.renameSync(tmp, file);
38324
38602
  try {
38325
- fs18.chmodSync(file, 384);
38603
+ fs19.chmodSync(file, 384);
38326
38604
  } catch {
38327
38605
  }
38328
38606
  }
@@ -38415,14 +38693,14 @@ var CapabilityManager = class {
38415
38693
  };
38416
38694
 
38417
38695
  // src/permission/cleanup.ts
38418
- var fs19 = __toESM(require("fs"), 1);
38696
+ var fs20 = __toESM(require("fs"), 1);
38419
38697
  function cleanupGuestSessionsForCapability(cap, factory) {
38420
38698
  const removed = [];
38421
38699
  for (const g2 of cap.grants) {
38422
38700
  if (g2.resource.type !== "persona") continue;
38423
38701
  const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
38424
38702
  try {
38425
- fs19.rmSync(dir, { recursive: true, force: true });
38703
+ fs20.rmSync(dir, { recursive: true, force: true });
38426
38704
  removed.push(dir);
38427
38705
  } catch {
38428
38706
  }
@@ -38431,13 +38709,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
38431
38709
  }
38432
38710
 
38433
38711
  // src/inbox/inbox-store.ts
38434
- var fs20 = __toESM(require("fs"), 1);
38435
- var path19 = __toESM(require("path"), 1);
38712
+ var fs21 = __toESM(require("fs"), 1);
38713
+ var path20 = __toESM(require("path"), 1);
38436
38714
  var INBOX_SUBDIR = "inbox";
38437
38715
  var InboxStore = class {
38438
38716
  constructor(dataDir) {
38439
38717
  this.dataDir = dataDir;
38440
- fs20.mkdirSync(this.dirPath(), { recursive: true });
38718
+ fs21.mkdirSync(this.dirPath(), { recursive: true });
38441
38719
  }
38442
38720
  dataDir;
38443
38721
  /**
@@ -38449,7 +38727,7 @@ var InboxStore = class {
38449
38727
  const file = this.filePath(peerDeviceId);
38450
38728
  let raw;
38451
38729
  try {
38452
- raw = fs20.readFileSync(file, "utf8");
38730
+ raw = fs21.readFileSync(file, "utf8");
38453
38731
  } catch (err) {
38454
38732
  if (err?.code === "ENOENT") return [];
38455
38733
  return [];
@@ -38465,7 +38743,7 @@ var InboxStore = class {
38465
38743
  const dir = this.dirPath();
38466
38744
  let entries;
38467
38745
  try {
38468
- entries = fs20.readdirSync(dir);
38746
+ entries = fs21.readdirSync(dir);
38469
38747
  } catch (err) {
38470
38748
  if (err?.code === "ENOENT") return [];
38471
38749
  return [];
@@ -38481,9 +38759,9 @@ var InboxStore = class {
38481
38759
  if (existing.some((m2) => m2.id === message.id)) return;
38482
38760
  const file = this.filePath(message.peerDeviceId);
38483
38761
  const line = JSON.stringify(message) + "\n";
38484
- fs20.appendFileSync(file, line, { mode: 384 });
38762
+ fs21.appendFileSync(file, line, { mode: 384 });
38485
38763
  try {
38486
- fs20.chmodSync(file, 384);
38764
+ fs21.chmodSync(file, 384);
38487
38765
  } catch {
38488
38766
  }
38489
38767
  }
@@ -38513,7 +38791,7 @@ var InboxStore = class {
38513
38791
  removeByPeerDeviceId(peerDeviceId) {
38514
38792
  const file = this.filePath(peerDeviceId);
38515
38793
  try {
38516
- fs20.unlinkSync(file);
38794
+ fs21.unlinkSync(file);
38517
38795
  } catch (err) {
38518
38796
  if (err?.code === "ENOENT") return;
38519
38797
  }
@@ -38522,18 +38800,18 @@ var InboxStore = class {
38522
38800
  const file = this.filePath(peerDeviceId);
38523
38801
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
38524
38802
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
38525
- fs20.writeFileSync(tmp, content, { mode: 384 });
38526
- fs20.renameSync(tmp, file);
38803
+ fs21.writeFileSync(tmp, content, { mode: 384 });
38804
+ fs21.renameSync(tmp, file);
38527
38805
  try {
38528
- fs20.chmodSync(file, 384);
38806
+ fs21.chmodSync(file, 384);
38529
38807
  } catch {
38530
38808
  }
38531
38809
  }
38532
38810
  dirPath() {
38533
- return path19.join(this.dataDir, INBOX_SUBDIR);
38811
+ return path20.join(this.dataDir, INBOX_SUBDIR);
38534
38812
  }
38535
38813
  filePath(peerDeviceId) {
38536
- return path19.join(this.dirPath(), `${peerDeviceId}.jsonl`);
38814
+ return path20.join(this.dirPath(), `${peerDeviceId}.jsonl`);
38537
38815
  }
38538
38816
  };
38539
38817
  function parseAllLines(raw) {
@@ -38620,8 +38898,8 @@ var InboxManager = class {
38620
38898
  };
38621
38899
 
38622
38900
  // src/state/contact-store.ts
38623
- var fs21 = __toESM(require("fs"), 1);
38624
- var path20 = __toESM(require("path"), 1);
38901
+ var fs22 = __toESM(require("fs"), 1);
38902
+ var path21 = __toESM(require("path"), 1);
38625
38903
  var FILE_NAME = "contacts.json";
38626
38904
  var ContactStore = class {
38627
38905
  constructor(dataDir) {
@@ -38631,10 +38909,10 @@ var ContactStore = class {
38631
38909
  contacts = /* @__PURE__ */ new Map();
38632
38910
  load() {
38633
38911
  this.contacts.clear();
38634
- const file = path20.join(this.dataDir, FILE_NAME);
38912
+ const file = path21.join(this.dataDir, FILE_NAME);
38635
38913
  let raw;
38636
38914
  try {
38637
- raw = fs21.readFileSync(file, "utf8");
38915
+ raw = fs22.readFileSync(file, "utf8");
38638
38916
  } catch (err) {
38639
38917
  if (err?.code !== "ENOENT") this.renameBak(file);
38640
38918
  return;
@@ -38677,20 +38955,20 @@ var ContactStore = class {
38677
38955
  return existed;
38678
38956
  }
38679
38957
  flush() {
38680
- const file = path20.join(this.dataDir, FILE_NAME);
38958
+ const file = path21.join(this.dataDir, FILE_NAME);
38681
38959
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
38682
38960
  const content = JSON.stringify(
38683
38961
  { contacts: Array.from(this.contacts.values()) },
38684
38962
  null,
38685
38963
  2
38686
38964
  );
38687
- fs21.mkdirSync(this.dataDir, { recursive: true });
38688
- fs21.writeFileSync(tmp, content, { mode: 384 });
38689
- fs21.renameSync(tmp, file);
38965
+ fs22.mkdirSync(this.dataDir, { recursive: true });
38966
+ fs22.writeFileSync(tmp, content, { mode: 384 });
38967
+ fs22.renameSync(tmp, file);
38690
38968
  }
38691
38969
  renameBak(file) {
38692
38970
  try {
38693
- fs21.renameSync(file, `${file}.bak`);
38971
+ fs22.renameSync(file, `${file}.bak`);
38694
38972
  } catch {
38695
38973
  }
38696
38974
  }
@@ -38840,61 +39118,61 @@ async function autoReverseContact(args) {
38840
39118
  }
38841
39119
 
38842
39120
  // src/migrations/2026-05-20-flatten-sessions.ts
38843
- var fs22 = __toESM(require("fs"), 1);
38844
- var path21 = __toESM(require("path"), 1);
39121
+ var fs23 = __toESM(require("fs"), 1);
39122
+ var path22 = __toESM(require("path"), 1);
38845
39123
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
38846
39124
  function migrateFlattenSessions(opts) {
38847
39125
  const dataDir = opts.dataDir;
38848
39126
  const now = opts.now ?? Date.now;
38849
- const sessionsDir = path21.join(dataDir, "sessions");
38850
- const flagPath = path21.join(sessionsDir, MIGRATION_FLAG_NAME);
39127
+ const sessionsDir = path22.join(dataDir, "sessions");
39128
+ const flagPath = path22.join(sessionsDir, MIGRATION_FLAG_NAME);
38851
39129
  if (existsSync3(flagPath)) {
38852
39130
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
38853
39131
  }
38854
39132
  let movedBare = 0;
38855
39133
  let movedVmOwner = 0;
38856
39134
  let archivedListener = 0;
38857
- const defaultDir = path21.join(sessionsDir, "default");
39135
+ const defaultDir = path22.join(sessionsDir, "default");
38858
39136
  if (existsSync3(defaultDir)) {
38859
39137
  for (const entry of readdirSafe(defaultDir)) {
38860
39138
  if (!entry.endsWith(".json")) continue;
38861
- const src = path21.join(defaultDir, entry);
38862
- const dst = path21.join(sessionsDir, entry);
38863
- fs22.renameSync(src, dst);
39139
+ const src = path22.join(defaultDir, entry);
39140
+ const dst = path22.join(sessionsDir, entry);
39141
+ fs23.renameSync(src, dst);
38864
39142
  movedBare += 1;
38865
39143
  }
38866
39144
  rmdirIfEmpty(defaultDir);
38867
39145
  }
38868
39146
  for (const pid of readdirSafe(sessionsDir)) {
38869
- const personaDir = path21.join(sessionsDir, pid);
39147
+ const personaDir = path22.join(sessionsDir, pid);
38870
39148
  if (!isDir(personaDir)) continue;
38871
39149
  if (pid === "default") continue;
38872
- const ownerSrc = path21.join(personaDir, "owner");
39150
+ const ownerSrc = path22.join(personaDir, "owner");
38873
39151
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
38874
- const ownerDst = path21.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
38875
- fs22.mkdirSync(ownerDst, { recursive: true });
39152
+ const ownerDst = path22.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
39153
+ fs23.mkdirSync(ownerDst, { recursive: true });
38876
39154
  for (const file of readdirSafe(ownerSrc)) {
38877
39155
  if (!file.endsWith(".json")) continue;
38878
- fs22.renameSync(path21.join(ownerSrc, file), path21.join(ownerDst, file));
39156
+ fs23.renameSync(path22.join(ownerSrc, file), path22.join(ownerDst, file));
38879
39157
  movedVmOwner += 1;
38880
39158
  }
38881
39159
  rmdirIfEmpty(ownerSrc);
38882
39160
  }
38883
- const listenerSrc = path21.join(personaDir, "listener");
39161
+ const listenerSrc = path22.join(personaDir, "listener");
38884
39162
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
38885
- const archiveDst = path21.join(dataDir, ".legacy", `listener-${pid}`);
38886
- fs22.mkdirSync(archiveDst, { recursive: true });
39163
+ const archiveDst = path22.join(dataDir, ".legacy", `listener-${pid}`);
39164
+ fs23.mkdirSync(archiveDst, { recursive: true });
38887
39165
  for (const file of readdirSafe(listenerSrc)) {
38888
39166
  if (!file.endsWith(".json")) continue;
38889
- fs22.renameSync(path21.join(listenerSrc, file), path21.join(archiveDst, file));
39167
+ fs23.renameSync(path22.join(listenerSrc, file), path22.join(archiveDst, file));
38890
39168
  archivedListener += 1;
38891
39169
  }
38892
39170
  rmdirIfEmpty(listenerSrc);
38893
39171
  }
38894
39172
  rmdirIfEmpty(personaDir);
38895
39173
  }
38896
- fs22.mkdirSync(sessionsDir, { recursive: true });
38897
- fs22.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
39174
+ fs23.mkdirSync(sessionsDir, { recursive: true });
39175
+ fs23.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
38898
39176
  return {
38899
39177
  skipped: false,
38900
39178
  flagWritten: true,
@@ -38905,7 +39183,7 @@ function migrateFlattenSessions(opts) {
38905
39183
  }
38906
39184
  function existsSync3(p2) {
38907
39185
  try {
38908
- fs22.statSync(p2);
39186
+ fs23.statSync(p2);
38909
39187
  return true;
38910
39188
  } catch {
38911
39189
  return false;
@@ -38913,31 +39191,31 @@ function existsSync3(p2) {
38913
39191
  }
38914
39192
  function isDir(p2) {
38915
39193
  try {
38916
- return fs22.statSync(p2).isDirectory();
39194
+ return fs23.statSync(p2).isDirectory();
38917
39195
  } catch {
38918
39196
  return false;
38919
39197
  }
38920
39198
  }
38921
39199
  function readdirSafe(p2) {
38922
39200
  try {
38923
- return fs22.readdirSync(p2);
39201
+ return fs23.readdirSync(p2);
38924
39202
  } catch {
38925
39203
  return [];
38926
39204
  }
38927
39205
  }
38928
39206
  function rmdirIfEmpty(p2) {
38929
39207
  try {
38930
- fs22.rmdirSync(p2);
39208
+ fs23.rmdirSync(p2);
38931
39209
  } catch {
38932
39210
  }
38933
39211
  }
38934
39212
 
38935
39213
  // src/transport/http-router.ts
38936
- var import_node_fs17 = __toESM(require("fs"), 1);
38937
- var import_node_path17 = __toESM(require("path"), 1);
39214
+ var import_node_fs18 = __toESM(require("fs"), 1);
39215
+ var import_node_path18 = __toESM(require("path"), 1);
38938
39216
 
38939
39217
  // src/attachment/mime.ts
38940
- var import_node_path14 = __toESM(require("path"), 1);
39218
+ var import_node_path15 = __toESM(require("path"), 1);
38941
39219
  var TEXT_PLAIN = "text/plain; charset=utf-8";
38942
39220
  var EXT_TO_NATIVE_MIME = {
38943
39221
  // 图片
@@ -39044,7 +39322,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
39044
39322
  ".mk"
39045
39323
  ]);
39046
39324
  function lookupMime(filePathOrName) {
39047
- const ext = import_node_path14.default.extname(filePathOrName).toLowerCase();
39325
+ const ext = import_node_path15.default.extname(filePathOrName).toLowerCase();
39048
39326
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
39049
39327
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
39050
39328
  return "application/octet-stream";
@@ -39113,8 +39391,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
39113
39391
  }
39114
39392
 
39115
39393
  // src/attachment/upload.ts
39116
- var import_node_fs16 = __toESM(require("fs"), 1);
39117
- var import_node_path15 = __toESM(require("path"), 1);
39394
+ var import_node_fs17 = __toESM(require("fs"), 1);
39395
+ var import_node_path16 = __toESM(require("path"), 1);
39118
39396
  var import_node_crypto5 = __toESM(require("crypto"), 1);
39119
39397
  var import_promises = require("stream/promises");
39120
39398
  var UploadError = class extends Error {
@@ -39126,22 +39404,22 @@ var UploadError = class extends Error {
39126
39404
  code;
39127
39405
  };
39128
39406
  function assertValidFileName(fileName) {
39129
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path15.default.basename(fileName)) {
39407
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path16.default.basename(fileName)) {
39130
39408
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
39131
39409
  }
39132
39410
  }
39133
39411
  var HASH_PREFIX_LEN = 16;
39134
39412
  async function writeUploadedAttachment(args) {
39135
39413
  assertValidFileName(args.fileName);
39136
- const attachmentsRoot = import_node_path15.default.join(args.sessionDir, ".attachments");
39414
+ const attachmentsRoot = import_node_path16.default.join(args.sessionDir, ".attachments");
39137
39415
  try {
39138
- import_node_fs16.default.mkdirSync(attachmentsRoot, { recursive: true });
39416
+ import_node_fs17.default.mkdirSync(attachmentsRoot, { recursive: true });
39139
39417
  } catch (err) {
39140
39418
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
39141
39419
  }
39142
39420
  const hasher = import_node_crypto5.default.createHash("sha256");
39143
39421
  let actualSize = 0;
39144
- const tmpPath = import_node_path15.default.join(
39422
+ const tmpPath = import_node_path16.default.join(
39145
39423
  attachmentsRoot,
39146
39424
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto5.default.randomBytes(4).toString("hex")}`
39147
39425
  );
@@ -39156,18 +39434,18 @@ async function writeUploadedAttachment(args) {
39156
39434
  yield buf;
39157
39435
  }
39158
39436
  },
39159
- import_node_fs16.default.createWriteStream(tmpPath, { mode: 384 })
39437
+ import_node_fs17.default.createWriteStream(tmpPath, { mode: 384 })
39160
39438
  );
39161
39439
  } catch (err) {
39162
39440
  try {
39163
- import_node_fs16.default.unlinkSync(tmpPath);
39441
+ import_node_fs17.default.unlinkSync(tmpPath);
39164
39442
  } catch {
39165
39443
  }
39166
39444
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
39167
39445
  }
39168
39446
  if (actualSize !== args.contentLength) {
39169
39447
  try {
39170
- import_node_fs16.default.unlinkSync(tmpPath);
39448
+ import_node_fs17.default.unlinkSync(tmpPath);
39171
39449
  } catch {
39172
39450
  }
39173
39451
  throw new UploadError(
@@ -39176,35 +39454,35 @@ async function writeUploadedAttachment(args) {
39176
39454
  );
39177
39455
  }
39178
39456
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
39179
- const hashDir = import_node_path15.default.join(attachmentsRoot, attachmentId);
39457
+ const hashDir = import_node_path16.default.join(attachmentsRoot, attachmentId);
39180
39458
  let finalFileName;
39181
39459
  let hashDirExists = false;
39182
39460
  try {
39183
- hashDirExists = import_node_fs16.default.statSync(hashDir).isDirectory();
39461
+ hashDirExists = import_node_fs17.default.statSync(hashDir).isDirectory();
39184
39462
  } catch {
39185
39463
  }
39186
39464
  if (hashDirExists) {
39187
- const existing = import_node_fs16.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
39465
+ const existing = import_node_fs17.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
39188
39466
  finalFileName = existing[0] ?? args.fileName;
39189
39467
  try {
39190
- import_node_fs16.default.unlinkSync(tmpPath);
39468
+ import_node_fs17.default.unlinkSync(tmpPath);
39191
39469
  } catch {
39192
39470
  }
39193
39471
  } else {
39194
39472
  try {
39195
- import_node_fs16.default.mkdirSync(hashDir, { recursive: true });
39473
+ import_node_fs17.default.mkdirSync(hashDir, { recursive: true });
39196
39474
  finalFileName = args.fileName;
39197
- import_node_fs16.default.renameSync(tmpPath, import_node_path15.default.join(hashDir, finalFileName));
39475
+ import_node_fs17.default.renameSync(tmpPath, import_node_path16.default.join(hashDir, finalFileName));
39198
39476
  } catch (err) {
39199
39477
  try {
39200
- import_node_fs16.default.unlinkSync(tmpPath);
39478
+ import_node_fs17.default.unlinkSync(tmpPath);
39201
39479
  } catch {
39202
39480
  }
39203
39481
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
39204
39482
  }
39205
39483
  }
39206
- const absPath = import_node_path15.default.join(hashDir, finalFileName);
39207
- const relPath = import_node_path15.default.relative(args.sessionDir, absPath);
39484
+ const absPath = import_node_path16.default.join(hashDir, finalFileName);
39485
+ const relPath = import_node_path16.default.relative(args.sessionDir, absPath);
39208
39486
  args.groupFileStore.upsert(args.scope, args.sessionId, {
39209
39487
  relPath: absPath,
39210
39488
  // 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
@@ -39218,7 +39496,7 @@ async function writeUploadedAttachment(args) {
39218
39496
 
39219
39497
  // src/extension/import.ts
39220
39498
  var import_promises2 = __toESM(require("fs/promises"), 1);
39221
- var import_node_path16 = __toESM(require("path"), 1);
39499
+ var import_node_path17 = __toESM(require("path"), 1);
39222
39500
  var import_node_os10 = __toESM(require("os"), 1);
39223
39501
  var import_jszip = __toESM(require_lib3(), 1);
39224
39502
  var ImportError = class extends Error {
@@ -39236,7 +39514,7 @@ async function importZip(buf, root) {
39236
39514
  throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
39237
39515
  }
39238
39516
  for (const name of Object.keys(zip.files)) {
39239
- if (name.includes("..") || name.startsWith("/") || import_node_path16.default.isAbsolute(name)) {
39517
+ if (name.includes("..") || name.startsWith("/") || import_node_path17.default.isAbsolute(name)) {
39240
39518
  throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
39241
39519
  }
39242
39520
  }
@@ -39269,7 +39547,7 @@ async function importZip(buf, root) {
39269
39547
  );
39270
39548
  }
39271
39549
  }
39272
- const destDir = import_node_path16.default.join(root, manifest.id);
39550
+ const destDir = import_node_path17.default.join(root, manifest.id);
39273
39551
  let destExists = false;
39274
39552
  try {
39275
39553
  await import_promises2.default.access(destDir);
@@ -39279,15 +39557,15 @@ async function importZip(buf, root) {
39279
39557
  if (destExists) {
39280
39558
  throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
39281
39559
  }
39282
- const stage = await import_promises2.default.mkdtemp(import_node_path16.default.join(import_node_os10.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
39560
+ const stage = await import_promises2.default.mkdtemp(import_node_path17.default.join(import_node_os10.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
39283
39561
  try {
39284
39562
  for (const [name, entry] of Object.entries(zip.files)) {
39285
- const dest = import_node_path16.default.join(stage, name);
39563
+ const dest = import_node_path17.default.join(stage, name);
39286
39564
  if (entry.dir) {
39287
39565
  await import_promises2.default.mkdir(dest, { recursive: true });
39288
39566
  continue;
39289
39567
  }
39290
- await import_promises2.default.mkdir(import_node_path16.default.dirname(dest), { recursive: true });
39568
+ await import_promises2.default.mkdir(import_node_path17.default.dirname(dest), { recursive: true });
39291
39569
  const content = await entry.async("nodebuffer");
39292
39570
  await import_promises2.default.writeFile(dest, content);
39293
39571
  }
@@ -39312,7 +39590,12 @@ var EXPOSED_RPC_METHODS = [
39312
39590
  "appBuilder.startDevServer",
39313
39591
  "appBuilder.reportStage",
39314
39592
  // 单栏 §5.6.5 fix: UI 切 session 时调(assistant 不需要主动调,但暴露白名单避免误猜成 forbidden)
39315
- "appBuilder.setActiveSession"
39593
+ "appBuilder.setActiveSession",
39594
+ // Persona dispatch (Task 4): A 端 dispatch MCP server 调 run(hold-and-wait 一次);
39595
+ // B 端 dispatch MCP server 调 complete(带 outcome 触发 run 端 resolve)。详见
39596
+ // protocol/src/dispatch.ts。
39597
+ "personaDispatch.run",
39598
+ "personaDispatch.complete"
39316
39599
  ];
39317
39600
  async function handleRpcRequest(input) {
39318
39601
  const { method, body, sessionId, dispatcher } = input;
@@ -39401,7 +39684,7 @@ function isValidUploadFileName(fileName) {
39401
39684
  if (fileName === "." || fileName === "..") return false;
39402
39685
  if (fileName.startsWith(".")) return false;
39403
39686
  if (fileName.includes("/") || fileName.includes("\\")) return false;
39404
- return fileName === import_node_path17.default.basename(fileName);
39687
+ return fileName === import_node_path18.default.basename(fileName);
39405
39688
  }
39406
39689
  function createHttpRouter(deps) {
39407
39690
  return async (req, res) => {
@@ -39448,6 +39731,8 @@ function createHttpRouter(deps) {
39448
39731
  sendJson(res, 403, { code: "NOT_LOOPBACK", message: "RPC adapter only accepts loopback connections" });
39449
39732
  return true;
39450
39733
  }
39734
+ req.socket.setTimeout(0);
39735
+ res.socket?.setTimeout(0);
39451
39736
  const method = url.pathname.slice(RPC_ROUTE_PREFIX.length).split("?")[0] ?? "";
39452
39737
  const sessionId = req.headers["x-clawd-session-id"] ?? void 0;
39453
39738
  let body;
@@ -39630,7 +39915,7 @@ function createHttpRouter(deps) {
39630
39915
  return true;
39631
39916
  }
39632
39917
  let absPath;
39633
- if (import_node_path17.default.isAbsolute(pathParam)) {
39918
+ if (import_node_path18.default.isAbsolute(pathParam)) {
39634
39919
  absPath = pathParam;
39635
39920
  } else if (deps.sessionStore) {
39636
39921
  const file = deps.sessionStore.read(sid);
@@ -39638,7 +39923,7 @@ function createHttpRouter(deps) {
39638
39923
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
39639
39924
  return true;
39640
39925
  }
39641
- absPath = import_node_path17.default.join(file.cwd, pathParam);
39926
+ absPath = import_node_path18.default.join(file.cwd, pathParam);
39642
39927
  } else {
39643
39928
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
39644
39929
  return true;
@@ -39721,7 +40006,7 @@ function withCtx(ctx, body) {
39721
40006
  function streamFile(res, absPath, logger) {
39722
40007
  let stat;
39723
40008
  try {
39724
- stat = import_node_fs17.default.statSync(absPath);
40009
+ stat = import_node_fs18.default.statSync(absPath);
39725
40010
  } catch (err) {
39726
40011
  const code = err?.code;
39727
40012
  if (code === "ENOENT") {
@@ -39736,7 +40021,7 @@ function streamFile(res, absPath, logger) {
39736
40021
  return;
39737
40022
  }
39738
40023
  const mime = lookupMime(absPath);
39739
- const basename = import_node_path17.default.basename(absPath);
40024
+ const basename = import_node_path18.default.basename(absPath);
39740
40025
  res.writeHead(200, {
39741
40026
  "Content-Type": mime,
39742
40027
  "Content-Length": String(stat.size),
@@ -39744,7 +40029,7 @@ function streamFile(res, absPath, logger) {
39744
40029
  // 防止浏览器把任意 mime 当 html 渲染
39745
40030
  "X-Content-Type-Options": "nosniff"
39746
40031
  });
39747
- const stream = import_node_fs17.default.createReadStream(absPath);
40032
+ const stream = import_node_fs18.default.createReadStream(absPath);
39748
40033
  stream.on("error", (err) => {
39749
40034
  logger?.warn("streamFile read error", { absPath, err: err.message });
39750
40035
  res.destroy();
@@ -39753,8 +40038,8 @@ function streamFile(res, absPath, logger) {
39753
40038
  }
39754
40039
 
39755
40040
  // src/attachment/gc.ts
39756
- var import_node_fs18 = __toESM(require("fs"), 1);
39757
- var import_node_path18 = __toESM(require("path"), 1);
40041
+ var import_node_fs19 = __toESM(require("fs"), 1);
40042
+ var import_node_path19 = __toESM(require("path"), 1);
39758
40043
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
39759
40044
  function runAttachmentGc(args) {
39760
40045
  const now = (args.now ?? Date.now)();
@@ -39763,38 +40048,38 @@ function runAttachmentGc(args) {
39763
40048
  for (const { scope, sessionId } of args.sessionScopes) {
39764
40049
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
39765
40050
  if (entry.stale) continue;
39766
- if (import_node_path18.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
40051
+ if (import_node_path19.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
39767
40052
  }
39768
40053
  }
39769
40054
  for (const { scope, sessionId } of args.sessionScopes) {
39770
- const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path18.default.join(
40055
+ const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path19.default.join(
39771
40056
  args.dataDir,
39772
40057
  "sessions",
39773
40058
  ...scopeSubPath(scope).map(safeFileName),
39774
40059
  safeFileName(sessionId)
39775
40060
  );
39776
- const attRoot = import_node_path18.default.join(sessionDir, ".attachments");
40061
+ const attRoot = import_node_path19.default.join(sessionDir, ".attachments");
39777
40062
  let hashDirs;
39778
40063
  try {
39779
- hashDirs = import_node_fs18.default.readdirSync(attRoot);
40064
+ hashDirs = import_node_fs19.default.readdirSync(attRoot);
39780
40065
  } catch (err) {
39781
40066
  if (err.code === "ENOENT") continue;
39782
40067
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
39783
40068
  continue;
39784
40069
  }
39785
40070
  for (const hashDir of hashDirs) {
39786
- const hashDirAbs = import_node_path18.default.join(attRoot, hashDir);
40071
+ const hashDirAbs = import_node_path19.default.join(attRoot, hashDir);
39787
40072
  let files;
39788
40073
  try {
39789
- files = import_node_fs18.default.readdirSync(hashDirAbs);
40074
+ files = import_node_fs19.default.readdirSync(hashDirAbs);
39790
40075
  } catch {
39791
40076
  continue;
39792
40077
  }
39793
40078
  for (const name of files) {
39794
- const file = import_node_path18.default.join(hashDirAbs, name);
40079
+ const file = import_node_path19.default.join(hashDirAbs, name);
39795
40080
  let stat;
39796
40081
  try {
39797
- stat = import_node_fs18.default.statSync(file);
40082
+ stat = import_node_fs19.default.statSync(file);
39798
40083
  } catch {
39799
40084
  continue;
39800
40085
  }
@@ -39803,26 +40088,26 @@ function runAttachmentGc(args) {
39803
40088
  if (age < ttlMs) continue;
39804
40089
  if (liveAbs.has(file)) continue;
39805
40090
  try {
39806
- import_node_fs18.default.unlinkSync(file);
40091
+ import_node_fs19.default.unlinkSync(file);
39807
40092
  } catch (err) {
39808
40093
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
39809
40094
  }
39810
40095
  }
39811
40096
  try {
39812
- if (import_node_fs18.default.readdirSync(hashDirAbs).length === 0) import_node_fs18.default.rmdirSync(hashDirAbs);
40097
+ if (import_node_fs19.default.readdirSync(hashDirAbs).length === 0) import_node_fs19.default.rmdirSync(hashDirAbs);
39813
40098
  } catch {
39814
40099
  }
39815
40100
  }
39816
40101
  try {
39817
- if (import_node_fs18.default.readdirSync(attRoot).length === 0) import_node_fs18.default.rmdirSync(attRoot);
40102
+ if (import_node_fs19.default.readdirSync(attRoot).length === 0) import_node_fs19.default.rmdirSync(attRoot);
39818
40103
  } catch {
39819
40104
  }
39820
40105
  }
39821
40106
  }
39822
40107
 
39823
40108
  // src/attachment/group.ts
39824
- var import_node_fs19 = __toESM(require("fs"), 1);
39825
- var import_node_path19 = __toESM(require("path"), 1);
40109
+ var import_node_fs20 = __toESM(require("fs"), 1);
40110
+ var import_node_path20 = __toESM(require("path"), 1);
39826
40111
  var import_node_crypto6 = __toESM(require("crypto"), 1);
39827
40112
  init_protocol();
39828
40113
  var GroupFileStore = class {
@@ -39834,11 +40119,11 @@ var GroupFileStore = class {
39834
40119
  this.logger = opts.logger;
39835
40120
  }
39836
40121
  rootForScope(scope) {
39837
- return import_node_path19.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
40122
+ return import_node_path20.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
39838
40123
  }
39839
40124
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
39840
40125
  filePath(scope, sessionId) {
39841
- return import_node_path19.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
40126
+ return import_node_path20.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
39842
40127
  }
39843
40128
  cacheKey(scope, sessionId) {
39844
40129
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -39847,7 +40132,7 @@ var GroupFileStore = class {
39847
40132
  readFile(scope, sessionId) {
39848
40133
  const file = this.filePath(scope, sessionId);
39849
40134
  try {
39850
- const raw = import_node_fs19.default.readFileSync(file, "utf8");
40135
+ const raw = import_node_fs20.default.readFileSync(file, "utf8");
39851
40136
  const parsed = JSON.parse(raw);
39852
40137
  if (!Array.isArray(parsed)) {
39853
40138
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -39873,10 +40158,10 @@ var GroupFileStore = class {
39873
40158
  }
39874
40159
  writeFile(scope, sessionId, entries) {
39875
40160
  const file = this.filePath(scope, sessionId);
39876
- import_node_fs19.default.mkdirSync(import_node_path19.default.dirname(file), { recursive: true });
40161
+ import_node_fs20.default.mkdirSync(import_node_path20.default.dirname(file), { recursive: true });
39877
40162
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
39878
- import_node_fs19.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
39879
- import_node_fs19.default.renameSync(tmp, file);
40163
+ import_node_fs20.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
40164
+ import_node_fs20.default.renameSync(tmp, file);
39880
40165
  }
39881
40166
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
39882
40167
  list(scope, sessionId) {
@@ -39962,10 +40247,10 @@ var GroupFileStore = class {
39962
40247
  };
39963
40248
 
39964
40249
  // src/discovery/state-file.ts
39965
- var import_node_fs20 = __toESM(require("fs"), 1);
39966
- var import_node_path20 = __toESM(require("path"), 1);
40250
+ var import_node_fs21 = __toESM(require("fs"), 1);
40251
+ var import_node_path21 = __toESM(require("path"), 1);
39967
40252
  function defaultStateFilePath(dataDir) {
39968
- return import_node_path20.default.join(dataDir, "state.json");
40253
+ return import_node_path21.default.join(dataDir, "state.json");
39969
40254
  }
39970
40255
  function isPidAlive(pid) {
39971
40256
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -39987,7 +40272,7 @@ var StateFileManager = class {
39987
40272
  }
39988
40273
  read() {
39989
40274
  try {
39990
- const raw = import_node_fs20.default.readFileSync(this.file, "utf8");
40275
+ const raw = import_node_fs21.default.readFileSync(this.file, "utf8");
39991
40276
  const parsed = JSON.parse(raw);
39992
40277
  return parsed;
39993
40278
  } catch {
@@ -40001,20 +40286,20 @@ var StateFileManager = class {
40001
40286
  return { status: "stale", existing };
40002
40287
  }
40003
40288
  write(state) {
40004
- import_node_fs20.default.mkdirSync(import_node_path20.default.dirname(this.file), { recursive: true });
40289
+ import_node_fs21.default.mkdirSync(import_node_path21.default.dirname(this.file), { recursive: true });
40005
40290
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
40006
- import_node_fs20.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
40007
- import_node_fs20.default.renameSync(tmp, this.file);
40291
+ import_node_fs21.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
40292
+ import_node_fs21.default.renameSync(tmp, this.file);
40008
40293
  if (process.platform !== "win32") {
40009
40294
  try {
40010
- import_node_fs20.default.chmodSync(this.file, 384);
40295
+ import_node_fs21.default.chmodSync(this.file, 384);
40011
40296
  } catch {
40012
40297
  }
40013
40298
  }
40014
40299
  }
40015
40300
  delete() {
40016
40301
  try {
40017
- import_node_fs20.default.unlinkSync(this.file);
40302
+ import_node_fs21.default.unlinkSync(this.file);
40018
40303
  } catch {
40019
40304
  }
40020
40305
  }
@@ -40029,14 +40314,14 @@ function readDaemonSourceFromEnv(env = process.env) {
40029
40314
  }
40030
40315
 
40031
40316
  // src/tunnel/tunnel-manager.ts
40032
- var import_node_fs24 = __toESM(require("fs"), 1);
40033
- var import_node_path24 = __toESM(require("path"), 1);
40317
+ var import_node_fs25 = __toESM(require("fs"), 1);
40318
+ var import_node_path25 = __toESM(require("path"), 1);
40034
40319
  var import_node_crypto7 = __toESM(require("crypto"), 1);
40035
40320
  var import_node_child_process9 = require("child_process");
40036
40321
 
40037
40322
  // src/tunnel/tunnel-store.ts
40038
- var import_node_fs21 = __toESM(require("fs"), 1);
40039
- var import_node_path21 = __toESM(require("path"), 1);
40323
+ var import_node_fs22 = __toESM(require("fs"), 1);
40324
+ var import_node_path22 = __toESM(require("path"), 1);
40040
40325
  var TunnelStore = class {
40041
40326
  constructor(filePath) {
40042
40327
  this.filePath = filePath;
@@ -40044,7 +40329,7 @@ var TunnelStore = class {
40044
40329
  filePath;
40045
40330
  async get() {
40046
40331
  try {
40047
- const raw = await import_node_fs21.default.promises.readFile(this.filePath, "utf8");
40332
+ const raw = await import_node_fs22.default.promises.readFile(this.filePath, "utf8");
40048
40333
  const obj = JSON.parse(raw);
40049
40334
  if (!isPersistedTunnel(obj)) return null;
40050
40335
  return obj;
@@ -40055,22 +40340,22 @@ var TunnelStore = class {
40055
40340
  }
40056
40341
  }
40057
40342
  async set(v2) {
40058
- const dir = import_node_path21.default.dirname(this.filePath);
40059
- await import_node_fs21.default.promises.mkdir(dir, { recursive: true });
40343
+ const dir = import_node_path22.default.dirname(this.filePath);
40344
+ await import_node_fs22.default.promises.mkdir(dir, { recursive: true });
40060
40345
  const data = JSON.stringify(v2, null, 2);
40061
40346
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
40062
- await import_node_fs21.default.promises.writeFile(tmp, data, { mode: 384 });
40347
+ await import_node_fs22.default.promises.writeFile(tmp, data, { mode: 384 });
40063
40348
  if (process.platform !== "win32") {
40064
40349
  try {
40065
- await import_node_fs21.default.promises.chmod(tmp, 384);
40350
+ await import_node_fs22.default.promises.chmod(tmp, 384);
40066
40351
  } catch {
40067
40352
  }
40068
40353
  }
40069
- await import_node_fs21.default.promises.rename(tmp, this.filePath);
40354
+ await import_node_fs22.default.promises.rename(tmp, this.filePath);
40070
40355
  }
40071
40356
  async clear() {
40072
40357
  try {
40073
- await import_node_fs21.default.promises.unlink(this.filePath);
40358
+ await import_node_fs22.default.promises.unlink(this.filePath);
40074
40359
  } catch (err) {
40075
40360
  const code = err?.code;
40076
40361
  if (code !== "ENOENT") throw err;
@@ -40165,9 +40450,9 @@ function escape(v2) {
40165
40450
  }
40166
40451
 
40167
40452
  // src/tunnel/frpc-binary.ts
40168
- var import_node_fs22 = __toESM(require("fs"), 1);
40453
+ var import_node_fs23 = __toESM(require("fs"), 1);
40169
40454
  var import_node_os11 = __toESM(require("os"), 1);
40170
- var import_node_path22 = __toESM(require("path"), 1);
40455
+ var import_node_path23 = __toESM(require("path"), 1);
40171
40456
  var import_node_child_process7 = require("child_process");
40172
40457
  var import_node_stream2 = require("stream");
40173
40458
  var import_promises3 = require("stream/promises");
@@ -40199,20 +40484,20 @@ function frpcDownloadUrl(version2, p2) {
40199
40484
  }
40200
40485
  async function ensureFrpcBinary(opts) {
40201
40486
  if (opts.override) {
40202
- if (!import_node_fs22.default.existsSync(opts.override)) {
40487
+ if (!import_node_fs23.default.existsSync(opts.override)) {
40203
40488
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
40204
40489
  }
40205
40490
  return opts.override;
40206
40491
  }
40207
40492
  const version2 = opts.version ?? FRPC_VERSION;
40208
40493
  const platform = opts.platform ?? detectPlatform();
40209
- const binDir = import_node_path22.default.join(opts.dataDir, "bin");
40210
- import_node_fs22.default.mkdirSync(binDir, { recursive: true });
40494
+ const binDir = import_node_path23.default.join(opts.dataDir, "bin");
40495
+ import_node_fs23.default.mkdirSync(binDir, { recursive: true });
40211
40496
  cleanupStaleArtifacts(binDir);
40212
- const stableBin = import_node_path22.default.join(binDir, "frpc");
40213
- if (import_node_fs22.default.existsSync(stableBin)) return stableBin;
40497
+ const stableBin = import_node_path23.default.join(binDir, "frpc");
40498
+ if (import_node_fs23.default.existsSync(stableBin)) return stableBin;
40214
40499
  const partialBin = `${stableBin}.partial`;
40215
- const tarballPath = import_node_path22.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
40500
+ const tarballPath = import_node_path23.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
40216
40501
  try {
40217
40502
  const url = frpcDownloadUrl(version2, platform);
40218
40503
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -40221,8 +40506,8 @@ async function ensureFrpcBinary(opts) {
40221
40506
  } else {
40222
40507
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
40223
40508
  }
40224
- import_node_fs22.default.chmodSync(partialBin, 493);
40225
- import_node_fs22.default.renameSync(partialBin, stableBin);
40509
+ import_node_fs23.default.chmodSync(partialBin, 493);
40510
+ import_node_fs23.default.renameSync(partialBin, stableBin);
40226
40511
  } finally {
40227
40512
  safeUnlink(tarballPath);
40228
40513
  safeUnlink(partialBin);
@@ -40232,15 +40517,15 @@ async function ensureFrpcBinary(opts) {
40232
40517
  function cleanupStaleArtifacts(binDir) {
40233
40518
  let entries;
40234
40519
  try {
40235
- entries = import_node_fs22.default.readdirSync(binDir);
40520
+ entries = import_node_fs23.default.readdirSync(binDir);
40236
40521
  } catch {
40237
40522
  return;
40238
40523
  }
40239
40524
  for (const name of entries) {
40240
40525
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
40241
- const full = import_node_path22.default.join(binDir, name);
40526
+ const full = import_node_path23.default.join(binDir, name);
40242
40527
  try {
40243
- import_node_fs22.default.rmSync(full, { recursive: true, force: true });
40528
+ import_node_fs23.default.rmSync(full, { recursive: true, force: true });
40244
40529
  } catch {
40245
40530
  }
40246
40531
  }
@@ -40248,7 +40533,7 @@ function cleanupStaleArtifacts(binDir) {
40248
40533
  }
40249
40534
  function safeUnlink(p2) {
40250
40535
  try {
40251
- import_node_fs22.default.unlinkSync(p2);
40536
+ import_node_fs23.default.unlinkSync(p2);
40252
40537
  } catch {
40253
40538
  }
40254
40539
  }
@@ -40259,13 +40544,13 @@ async function downloadToFile(url, dest, fetchImpl) {
40259
40544
  if (!res.ok || !res.body) {
40260
40545
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
40261
40546
  }
40262
- const out = import_node_fs22.default.createWriteStream(dest);
40547
+ const out = import_node_fs23.default.createWriteStream(dest);
40263
40548
  const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
40264
40549
  await (0, import_promises3.pipeline)(nodeStream, out);
40265
40550
  }
40266
40551
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
40267
- const work = import_node_path22.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
40268
- import_node_fs22.default.mkdirSync(work, { recursive: true });
40552
+ const work = import_node_path23.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
40553
+ import_node_fs23.default.mkdirSync(work, { recursive: true });
40269
40554
  try {
40270
40555
  await new Promise((resolve6, reject) => {
40271
40556
  const proc = (0, import_node_child_process7.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -40273,32 +40558,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
40273
40558
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
40274
40559
  });
40275
40560
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
40276
- const src = import_node_path22.default.join(work, dirName, "frpc");
40277
- if (!import_node_fs22.default.existsSync(src)) {
40561
+ const src = import_node_path23.default.join(work, dirName, "frpc");
40562
+ if (!import_node_fs23.default.existsSync(src)) {
40278
40563
  throw new Error(`frpc not found inside tarball at ${src}`);
40279
40564
  }
40280
- import_node_fs22.default.copyFileSync(src, destBin);
40565
+ import_node_fs23.default.copyFileSync(src, destBin);
40281
40566
  } finally {
40282
- import_node_fs22.default.rmSync(work, { recursive: true, force: true });
40567
+ import_node_fs23.default.rmSync(work, { recursive: true, force: true });
40283
40568
  }
40284
40569
  }
40285
40570
 
40286
40571
  // src/tunnel/frpc-process.ts
40287
- var import_node_fs23 = __toESM(require("fs"), 1);
40288
- var import_node_path23 = __toESM(require("path"), 1);
40572
+ var import_node_fs24 = __toESM(require("fs"), 1);
40573
+ var import_node_path24 = __toESM(require("path"), 1);
40289
40574
  var import_node_child_process8 = require("child_process");
40290
40575
  function frpcPidFilePath(dataDir) {
40291
- return import_node_path23.default.join(dataDir, "frpc.pid");
40576
+ return import_node_path24.default.join(dataDir, "frpc.pid");
40292
40577
  }
40293
40578
  function writeFrpcPid(dataDir, pid) {
40294
40579
  try {
40295
- import_node_fs23.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
40580
+ import_node_fs24.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
40296
40581
  } catch {
40297
40582
  }
40298
40583
  }
40299
40584
  function clearFrpcPid(dataDir) {
40300
40585
  try {
40301
- import_node_fs23.default.unlinkSync(frpcPidFilePath(dataDir));
40586
+ import_node_fs24.default.unlinkSync(frpcPidFilePath(dataDir));
40302
40587
  } catch {
40303
40588
  }
40304
40589
  }
@@ -40314,7 +40599,7 @@ function defaultIsPidAlive(pid) {
40314
40599
  }
40315
40600
  function defaultReadPidFile(file) {
40316
40601
  try {
40317
- return import_node_fs23.default.readFileSync(file, "utf8");
40602
+ return import_node_fs24.default.readFileSync(file, "utf8");
40318
40603
  } catch {
40319
40604
  return null;
40320
40605
  }
@@ -40330,7 +40615,7 @@ function defaultSleep(ms) {
40330
40615
  }
40331
40616
  async function killStaleFrpc(deps) {
40332
40617
  const pidFile = frpcPidFilePath(deps.dataDir);
40333
- const tomlPath = import_node_path23.default.join(deps.dataDir, "frpc.toml");
40618
+ const tomlPath = import_node_path24.default.join(deps.dataDir, "frpc.toml");
40334
40619
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
40335
40620
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
40336
40621
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -40354,7 +40639,7 @@ async function killStaleFrpc(deps) {
40354
40639
  }
40355
40640
  if (victims.size === 0) {
40356
40641
  try {
40357
- import_node_fs23.default.unlinkSync(pidFile);
40642
+ import_node_fs24.default.unlinkSync(pidFile);
40358
40643
  } catch {
40359
40644
  }
40360
40645
  return;
@@ -40365,7 +40650,7 @@ async function killStaleFrpc(deps) {
40365
40650
  }
40366
40651
  await sleep(deps.reapWaitMs ?? 300);
40367
40652
  try {
40368
- import_node_fs23.default.unlinkSync(pidFile);
40653
+ import_node_fs24.default.unlinkSync(pidFile);
40369
40654
  } catch {
40370
40655
  }
40371
40656
  }
@@ -40402,7 +40687,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
40402
40687
  var TunnelManager = class {
40403
40688
  constructor(deps) {
40404
40689
  this.deps = deps;
40405
- this.store = deps.store ?? new TunnelStore(import_node_path24.default.join(deps.dataDir, "tunnel.json"));
40690
+ this.store = deps.store ?? new TunnelStore(import_node_path25.default.join(deps.dataDir, "tunnel.json"));
40406
40691
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
40407
40692
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
40408
40693
  }
@@ -40529,7 +40814,7 @@ var TunnelManager = class {
40529
40814
  dataDir: this.deps.dataDir,
40530
40815
  override: this.deps.frpcBinaryOverride ?? void 0
40531
40816
  });
40532
- const tomlPath = import_node_path24.default.join(this.deps.dataDir, "frpc.toml");
40817
+ const tomlPath = import_node_path25.default.join(this.deps.dataDir, "frpc.toml");
40533
40818
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
40534
40819
  const toml = buildFrpcToml({
40535
40820
  serverAddr: t.frpsHost,
@@ -40540,12 +40825,12 @@ var TunnelManager = class {
40540
40825
  localPort,
40541
40826
  logLevel: "info"
40542
40827
  });
40543
- await import_node_fs24.default.promises.writeFile(tomlPath, toml, { mode: 384 });
40828
+ await import_node_fs25.default.promises.writeFile(tomlPath, toml, { mode: 384 });
40544
40829
  const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
40545
40830
  stdio: ["ignore", "pipe", "pipe"]
40546
40831
  });
40547
- const logFilePath = import_node_path24.default.join(this.deps.dataDir, "frpc.log");
40548
- const logStream = import_node_fs24.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
40832
+ const logFilePath = import_node_path25.default.join(this.deps.dataDir, "frpc.log");
40833
+ const logStream = import_node_fs25.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
40549
40834
  logStream.on("error", () => {
40550
40835
  });
40551
40836
  const tee = (chunk) => {
@@ -40628,27 +40913,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
40628
40913
 
40629
40914
  // src/tunnel/device-key.ts
40630
40915
  var import_node_os12 = __toESM(require("os"), 1);
40631
- var import_node_path25 = __toESM(require("path"), 1);
40916
+ var import_node_path26 = __toESM(require("path"), 1);
40632
40917
  var import_node_crypto8 = __toESM(require("crypto"), 1);
40633
40918
  var DERIVE_SALT = "clawd-tunnel-device-v1";
40634
40919
  function deriveStableDeviceKey(opts = {}) {
40635
40920
  const hostname = opts.hostname ?? import_node_os12.default.hostname();
40636
40921
  const uid = opts.uid ?? (typeof import_node_os12.default.userInfo === "function" ? import_node_os12.default.userInfo().uid : 0);
40637
40922
  const home = opts.home ?? import_node_os12.default.homedir();
40638
- const defaultDataDir = import_node_path25.default.resolve(import_node_path25.default.join(home, ".clawd"));
40639
- const normalizedDataDir = opts.dataDir ? import_node_path25.default.resolve(opts.dataDir) : null;
40923
+ const defaultDataDir = import_node_path26.default.resolve(import_node_path26.default.join(home, ".clawd"));
40924
+ const normalizedDataDir = opts.dataDir ? import_node_path26.default.resolve(opts.dataDir) : null;
40640
40925
  const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
40641
40926
  const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
40642
40927
  return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
40643
40928
  }
40644
40929
 
40645
40930
  // src/auth-store.ts
40646
- var import_node_fs25 = __toESM(require("fs"), 1);
40647
- var import_node_path26 = __toESM(require("path"), 1);
40931
+ var import_node_fs26 = __toESM(require("fs"), 1);
40932
+ var import_node_path27 = __toESM(require("path"), 1);
40648
40933
  var import_node_crypto9 = __toESM(require("crypto"), 1);
40649
40934
  var AUTH_FILE_NAME = "auth.json";
40650
40935
  function authFilePath(dataDir) {
40651
- return import_node_path26.default.join(dataDir, AUTH_FILE_NAME);
40936
+ return import_node_path27.default.join(dataDir, AUTH_FILE_NAME);
40652
40937
  }
40653
40938
  function loadOrCreateAuthFile(opts) {
40654
40939
  const file = authFilePath(opts.dataDir);
@@ -40682,7 +40967,7 @@ function defaultGenerateOwnerPrincipalId() {
40682
40967
  }
40683
40968
  function readAuthFile(file) {
40684
40969
  try {
40685
- const raw = import_node_fs25.default.readFileSync(file, "utf8");
40970
+ const raw = import_node_fs26.default.readFileSync(file, "utf8");
40686
40971
  const parsed = JSON.parse(raw);
40687
40972
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
40688
40973
  return null;
@@ -40701,25 +40986,25 @@ function readAuthFile(file) {
40701
40986
  }
40702
40987
  }
40703
40988
  function writeAuthFile(file, content) {
40704
- import_node_fs25.default.mkdirSync(import_node_path26.default.dirname(file), { recursive: true });
40705
- import_node_fs25.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
40989
+ import_node_fs26.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
40990
+ import_node_fs26.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
40706
40991
  try {
40707
- import_node_fs25.default.chmodSync(file, 384);
40992
+ import_node_fs26.default.chmodSync(file, 384);
40708
40993
  } catch {
40709
40994
  }
40710
40995
  }
40711
40996
 
40712
40997
  // src/owner-profile.ts
40713
- var import_node_fs26 = __toESM(require("fs"), 1);
40998
+ var import_node_fs27 = __toESM(require("fs"), 1);
40714
40999
  var import_node_os13 = __toESM(require("os"), 1);
40715
- var import_node_path27 = __toESM(require("path"), 1);
41000
+ var import_node_path28 = __toESM(require("path"), 1);
40716
41001
  var PROFILE_FILENAME = "profile.json";
40717
41002
  function loadOwnerDisplayName(dataDir) {
40718
41003
  const fallback = import_node_os13.default.userInfo().username;
40719
- const profilePath = import_node_path27.default.join(dataDir, PROFILE_FILENAME);
41004
+ const profilePath = import_node_path28.default.join(dataDir, PROFILE_FILENAME);
40720
41005
  let raw;
40721
41006
  try {
40722
- raw = import_node_fs26.default.readFileSync(profilePath, "utf8");
41007
+ raw = import_node_fs27.default.readFileSync(profilePath, "utf8");
40723
41008
  } catch {
40724
41009
  return fallback;
40725
41010
  }
@@ -40742,18 +41027,18 @@ function loadOwnerDisplayName(dataDir) {
40742
41027
  }
40743
41028
 
40744
41029
  // src/feishu-auth/owner-identity-store.ts
40745
- var import_node_fs27 = __toESM(require("fs"), 1);
40746
- var import_node_path28 = __toESM(require("path"), 1);
41030
+ var import_node_fs28 = __toESM(require("fs"), 1);
41031
+ var import_node_path29 = __toESM(require("path"), 1);
40747
41032
  var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
40748
41033
  var OwnerIdentityStore = class {
40749
41034
  file;
40750
41035
  constructor(dataDir) {
40751
- this.file = import_node_path28.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
41036
+ this.file = import_node_path29.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
40752
41037
  }
40753
41038
  read() {
40754
41039
  let raw;
40755
41040
  try {
40756
- raw = import_node_fs27.default.readFileSync(this.file, "utf8");
41041
+ raw = import_node_fs28.default.readFileSync(this.file, "utf8");
40757
41042
  } catch {
40758
41043
  return null;
40759
41044
  }
@@ -40780,16 +41065,16 @@ var OwnerIdentityStore = class {
40780
41065
  };
40781
41066
  }
40782
41067
  write(record) {
40783
- import_node_fs27.default.mkdirSync(import_node_path28.default.dirname(this.file), { recursive: true });
40784
- import_node_fs27.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
41068
+ import_node_fs28.default.mkdirSync(import_node_path29.default.dirname(this.file), { recursive: true });
41069
+ import_node_fs28.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
40785
41070
  try {
40786
- import_node_fs27.default.chmodSync(this.file, 384);
41071
+ import_node_fs28.default.chmodSync(this.file, 384);
40787
41072
  } catch {
40788
41073
  }
40789
41074
  }
40790
41075
  clear() {
40791
41076
  try {
40792
- import_node_fs27.default.unlinkSync(this.file);
41077
+ import_node_fs28.default.unlinkSync(this.file);
40793
41078
  } catch (err) {
40794
41079
  const code = err?.code;
40795
41080
  if (code !== "ENOENT") throw err;
@@ -40908,9 +41193,9 @@ var CentralClientError = class extends Error {
40908
41193
  code;
40909
41194
  cause;
40910
41195
  };
40911
- async function centralRequest(opts, path58, init) {
41196
+ async function centralRequest(opts, path59, init) {
40912
41197
  const f = opts.fetchImpl ?? globalThis.fetch;
40913
- const url = `${opts.api.replace(/\/+$/, "")}${path58}`;
41198
+ const url = `${opts.api.replace(/\/+$/, "")}${path59}`;
40914
41199
  const ctrl = new AbortController();
40915
41200
  const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
40916
41201
  let res;
@@ -41052,8 +41337,8 @@ function verifyConnectToken(args) {
41052
41337
  }
41053
41338
 
41054
41339
  // src/feishu-auth/server-key.ts
41055
- var fs36 = __toESM(require("fs"), 1);
41056
- var path37 = __toESM(require("path"), 1);
41340
+ var fs37 = __toESM(require("fs"), 1);
41341
+ var path38 = __toESM(require("path"), 1);
41057
41342
  var FILE_NAME2 = "server-signing-key.json";
41058
41343
  var ServerKeyStore = class {
41059
41344
  constructor(dataDir) {
@@ -41061,12 +41346,12 @@ var ServerKeyStore = class {
41061
41346
  }
41062
41347
  dataDir;
41063
41348
  filePath() {
41064
- return path37.join(this.dataDir, FILE_NAME2);
41349
+ return path38.join(this.dataDir, FILE_NAME2);
41065
41350
  }
41066
41351
  /** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
41067
41352
  read() {
41068
41353
  try {
41069
- const raw = fs36.readFileSync(this.filePath(), "utf8");
41354
+ const raw = fs37.readFileSync(this.filePath(), "utf8");
41070
41355
  const parsed = JSON.parse(raw);
41071
41356
  if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
41072
41357
  return parsed.publicKeyPem;
@@ -41081,12 +41366,12 @@ var ServerKeyStore = class {
41081
41366
  publicKeyPem,
41082
41367
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
41083
41368
  };
41084
- fs36.mkdirSync(this.dataDir, { recursive: true });
41085
- fs36.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
41369
+ fs37.mkdirSync(this.dataDir, { recursive: true });
41370
+ fs37.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
41086
41371
  }
41087
41372
  clear() {
41088
41373
  try {
41089
- fs36.unlinkSync(this.filePath());
41374
+ fs37.unlinkSync(this.filePath());
41090
41375
  } catch {
41091
41376
  }
41092
41377
  }
@@ -41099,12 +41384,12 @@ init_protocol();
41099
41384
  init_protocol();
41100
41385
 
41101
41386
  // src/session/fork.ts
41102
- var import_node_fs28 = __toESM(require("fs"), 1);
41387
+ var import_node_fs29 = __toESM(require("fs"), 1);
41103
41388
  var import_node_os14 = __toESM(require("os"), 1);
41104
- var import_node_path29 = __toESM(require("path"), 1);
41389
+ var import_node_path30 = __toESM(require("path"), 1);
41105
41390
  init_claude_history();
41106
41391
  function readJsonlEntries(file) {
41107
- const raw = import_node_fs28.default.readFileSync(file, "utf8");
41392
+ const raw = import_node_fs29.default.readFileSync(file, "utf8");
41108
41393
  const out = [];
41109
41394
  for (const line of raw.split("\n")) {
41110
41395
  const t = line.trim();
@@ -41117,10 +41402,10 @@ function readJsonlEntries(file) {
41117
41402
  return out;
41118
41403
  }
41119
41404
  function forkSession(input) {
41120
- const baseDir = input.baseDir ?? import_node_path29.default.join(import_node_os14.default.homedir(), ".claude");
41121
- const projectDir = import_node_path29.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
41122
- const sourceFile = import_node_path29.default.join(projectDir, `${input.toolSessionId}.jsonl`);
41123
- if (!import_node_fs28.default.existsSync(sourceFile)) {
41405
+ const baseDir = input.baseDir ?? import_node_path30.default.join(import_node_os14.default.homedir(), ".claude");
41406
+ const projectDir = import_node_path30.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
41407
+ const sourceFile = import_node_path30.default.join(projectDir, `${input.toolSessionId}.jsonl`);
41408
+ if (!import_node_fs29.default.existsSync(sourceFile)) {
41124
41409
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
41125
41410
  }
41126
41411
  const entries = readJsonlEntries(sourceFile);
@@ -41150,9 +41435,9 @@ function forkSession(input) {
41150
41435
  }
41151
41436
  forkedLines.push(JSON.stringify(forked));
41152
41437
  }
41153
- const forkedFilePath = import_node_path29.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
41154
- import_node_fs28.default.mkdirSync(projectDir, { recursive: true });
41155
- import_node_fs28.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
41438
+ const forkedFilePath = import_node_path30.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
41439
+ import_node_fs29.default.mkdirSync(projectDir, { recursive: true });
41440
+ import_node_fs29.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
41156
41441
  return { forkedToolSessionId, forkedFilePath };
41157
41442
  }
41158
41443
 
@@ -41528,7 +41813,7 @@ function buildPermissionHandlers(deps) {
41528
41813
  }
41529
41814
 
41530
41815
  // src/handlers/history.ts
41531
- var path40 = __toESM(require("path"), 1);
41816
+ var path41 = __toESM(require("path"), 1);
41532
41817
  init_protocol();
41533
41818
 
41534
41819
  // src/session/recent-dirs.ts
@@ -41546,7 +41831,7 @@ function listRecentDirs(store, limit = 50) {
41546
41831
  }
41547
41832
 
41548
41833
  // src/permission/persona-paths.ts
41549
- var path39 = __toESM(require("path"), 1);
41834
+ var path40 = __toESM(require("path"), 1);
41550
41835
  function getAllowedPersonaIds(grants, action) {
41551
41836
  const ids = /* @__PURE__ */ new Set();
41552
41837
  for (const g2 of grants) {
@@ -41559,31 +41844,31 @@ function getAllowedPersonaIds(grants, action) {
41559
41844
  return ids;
41560
41845
  }
41561
41846
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
41562
- const target = path39.resolve(absPath);
41847
+ const target = path40.resolve(absPath);
41563
41848
  if (userWorkDir) {
41564
- const u = path39.resolve(userWorkDir);
41565
- const usep = u.endsWith(path39.sep) ? "" : path39.sep;
41849
+ const u = path40.resolve(userWorkDir);
41850
+ const usep = u.endsWith(path40.sep) ? "" : path40.sep;
41566
41851
  if (target === u || target.startsWith(u + usep)) return true;
41567
41852
  }
41568
- const root = path39.resolve(personaRoot);
41569
- const sep2 = root.endsWith(path39.sep) ? "" : path39.sep;
41853
+ const root = path40.resolve(personaRoot);
41854
+ const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
41570
41855
  if (!target.startsWith(root + sep2)) return false;
41571
- const rel = path39.relative(root, target);
41856
+ const rel = path40.relative(root, target);
41572
41857
  if (!rel || rel.startsWith("..")) return false;
41573
- const personaId = rel.split(path39.sep)[0];
41858
+ const personaId = rel.split(path40.sep)[0];
41574
41859
  if (!personaId) return false;
41575
41860
  const allowed = getAllowedPersonaIds(grants, action);
41576
41861
  if (allowed === "*") return true;
41577
41862
  return allowed.has(personaId);
41578
41863
  }
41579
41864
  function personaIdFromPath(absPath, personaRoot) {
41580
- const root = path39.resolve(personaRoot);
41581
- const target = path39.resolve(absPath);
41582
- const sep2 = root.endsWith(path39.sep) ? "" : path39.sep;
41865
+ const root = path40.resolve(personaRoot);
41866
+ const target = path40.resolve(absPath);
41867
+ const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
41583
41868
  if (!target.startsWith(root + sep2)) return null;
41584
- const rel = path39.relative(root, target);
41869
+ const rel = path40.relative(root, target);
41585
41870
  if (!rel || rel.startsWith("..")) return null;
41586
- const id = rel.split(path39.sep)[0];
41871
+ const id = rel.split(path40.sep)[0];
41587
41872
  return id || null;
41588
41873
  }
41589
41874
 
@@ -41610,7 +41895,7 @@ function buildHistoryHandlers(deps) {
41610
41895
  if (!pid) return false;
41611
41896
  return isGuestPathAllowed(
41612
41897
  ctx.grants,
41613
- path40.join(personaRoot, pid),
41898
+ path41.join(personaRoot, pid),
41614
41899
  personaRoot,
41615
41900
  "read",
41616
41901
  userWorkDir
@@ -41622,7 +41907,7 @@ function buildHistoryHandlers(deps) {
41622
41907
  };
41623
41908
  const list = async (frame, _client, ctx) => {
41624
41909
  const args = HistoryListArgs.parse(frame);
41625
- assertGuestPath(ctx, path40.resolve(args.projectPath), personaRoot, "history:list");
41910
+ assertGuestPath(ctx, path41.resolve(args.projectPath), personaRoot, "history:list");
41626
41911
  const sessions = await history.listSessions(args);
41627
41912
  return { response: { type: "history:list", sessions } };
41628
41913
  };
@@ -41654,13 +41939,13 @@ function buildHistoryHandlers(deps) {
41654
41939
  };
41655
41940
  const subagents = async (frame, _client, ctx) => {
41656
41941
  const args = HistorySubagentsArgs.parse(frame);
41657
- assertGuestPath(ctx, path40.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
41942
+ assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
41658
41943
  const subs = await history.listSubagents(args);
41659
41944
  return { response: { type: "history:subagents", subagents: subs } };
41660
41945
  };
41661
41946
  const subagentRead = async (frame, _client, ctx) => {
41662
41947
  const args = HistorySubagentReadArgs.parse(frame);
41663
- assertGuestPath(ctx, path40.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
41948
+ assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
41664
41949
  const res = await history.readSubagent(args);
41665
41950
  return { response: { type: "history:subagent-read", ...res } };
41666
41951
  };
@@ -41669,7 +41954,7 @@ function buildHistoryHandlers(deps) {
41669
41954
  if (ctx?.principal.kind === "guest" && personaRoot) {
41670
41955
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
41671
41956
  const filtered = dirs.filter(
41672
- (d) => isGuestPathAllowed(ctx.grants, path40.resolve(d.cwd), personaRoot, "read", userWorkDir)
41957
+ (d) => isGuestPathAllowed(ctx.grants, path41.resolve(d.cwd), personaRoot, "read", userWorkDir)
41673
41958
  );
41674
41959
  return { response: { type: "history:recentDirs", dirs: filtered } };
41675
41960
  }
@@ -41686,7 +41971,7 @@ function buildHistoryHandlers(deps) {
41686
41971
  }
41687
41972
 
41688
41973
  // src/handlers/workspace.ts
41689
- var path41 = __toESM(require("path"), 1);
41974
+ var path42 = __toESM(require("path"), 1);
41690
41975
  var os15 = __toESM(require("os"), 1);
41691
41976
  init_protocol();
41692
41977
  init_protocol();
@@ -41728,22 +42013,22 @@ function buildWorkspaceHandlers(deps) {
41728
42013
  const args = WorkspaceListArgs.parse(frame);
41729
42014
  const isGuest = ctx?.principal.kind === "guest";
41730
42015
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os15.homedir();
41731
- const resolvedCwd = path41.resolve(args.cwd ?? fallbackCwd);
41732
- const target = args.path ? path41.resolve(resolvedCwd, args.path) : resolvedCwd;
42016
+ const resolvedCwd = path42.resolve(args.cwd ?? fallbackCwd);
42017
+ const target = args.path ? path42.resolve(resolvedCwd, args.path) : resolvedCwd;
41733
42018
  assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
41734
42019
  const res = workspace.list({ ...args, cwd: resolvedCwd });
41735
42020
  return { response: { type: "workspace:list", ...res } };
41736
42021
  };
41737
42022
  const read = async (frame, _client, ctx) => {
41738
42023
  const args = WorkspaceReadArgs.parse(frame);
41739
- const target = path41.isAbsolute(args.path) ? path41.resolve(args.path) : path41.resolve(args.cwd, args.path);
42024
+ const target = path42.isAbsolute(args.path) ? path42.resolve(args.path) : path42.resolve(args.cwd, args.path);
41740
42025
  assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
41741
42026
  const res = workspace.read(args);
41742
42027
  return { response: { type: "workspace:read", ...res } };
41743
42028
  };
41744
42029
  const skillsList = async (frame, _client, ctx) => {
41745
42030
  const args = SkillsListArgs.parse(frame);
41746
- const cwdAbs = path41.resolve(args.cwd);
42031
+ const cwdAbs = path42.resolve(args.cwd);
41747
42032
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
41748
42033
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
41749
42034
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -41755,7 +42040,7 @@ function buildWorkspaceHandlers(deps) {
41755
42040
  };
41756
42041
  const agentsList = async (frame, _client, ctx) => {
41757
42042
  const args = AgentsListArgs.parse(frame);
41758
- const cwdAbs = path41.resolve(args.cwd);
42043
+ const cwdAbs = path42.resolve(args.cwd);
41759
42044
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
41760
42045
  if (args.tool === "codex") {
41761
42046
  return { response: { type: "agents:list", agents: [] } };
@@ -41777,20 +42062,20 @@ function buildWorkspaceHandlers(deps) {
41777
42062
  }
41778
42063
 
41779
42064
  // src/handlers/git.ts
41780
- var path43 = __toESM(require("path"), 1);
42065
+ var path44 = __toESM(require("path"), 1);
41781
42066
  init_protocol();
41782
42067
  init_protocol();
41783
42068
 
41784
42069
  // src/workspace/git.ts
41785
42070
  var import_node_child_process10 = require("child_process");
41786
- var import_node_fs29 = __toESM(require("fs"), 1);
41787
- var import_node_path30 = __toESM(require("path"), 1);
42071
+ var import_node_fs30 = __toESM(require("fs"), 1);
42072
+ var import_node_path31 = __toESM(require("path"), 1);
41788
42073
  var import_node_util = require("util");
41789
42074
  var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
41790
42075
  function normalizePath(p2) {
41791
- const resolved = import_node_path30.default.resolve(p2);
42076
+ const resolved = import_node_path31.default.resolve(p2);
41792
42077
  try {
41793
- return import_node_fs29.default.realpathSync(resolved);
42078
+ return import_node_fs30.default.realpathSync(resolved);
41794
42079
  } catch {
41795
42080
  return resolved;
41796
42081
  }
@@ -41864,7 +42149,7 @@ async function listGitBranches(cwd) {
41864
42149
  function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
41865
42150
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
41866
42151
  const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
41867
- if (!isGuestPathAllowed(ctx.grants, path43.resolve(cwd), personaRoot, "read", userWorkDir)) {
42152
+ if (!isGuestPathAllowed(ctx.grants, path44.resolve(cwd), personaRoot, "read", userWorkDir)) {
41868
42153
  throw new ClawdError(
41869
42154
  ERROR_CODES.UNAUTHORIZED,
41870
42155
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -42378,7 +42663,7 @@ function buildPersonaHandlers(deps) {
42378
42663
  }
42379
42664
 
42380
42665
  // src/handlers/attachment.ts
42381
- var import_node_path31 = __toESM(require("path"), 1);
42666
+ var import_node_path32 = __toESM(require("path"), 1);
42382
42667
  init_protocol();
42383
42668
  init_protocol();
42384
42669
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -42433,12 +42718,12 @@ function buildAttachmentHandlers(deps) {
42433
42718
  `session ${args.sessionId} scope unresolved`
42434
42719
  );
42435
42720
  }
42436
- const cwdAbs = import_node_path31.default.resolve(sessionFile.cwd);
42437
- const candidateAbs = import_node_path31.default.isAbsolute(args.relPath) ? import_node_path31.default.resolve(args.relPath) : import_node_path31.default.resolve(cwdAbs, args.relPath);
42721
+ const cwdAbs = import_node_path32.default.resolve(sessionFile.cwd);
42722
+ const candidateAbs = import_node_path32.default.isAbsolute(args.relPath) ? import_node_path32.default.resolve(args.relPath) : import_node_path32.default.resolve(cwdAbs, args.relPath);
42438
42723
  assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl", deps.usersRoot);
42439
42724
  const entries = deps.groupFileStore.list(scope, args.sessionId);
42440
42725
  const entry = entries.find((e) => {
42441
- const storedAbs = import_node_path31.default.isAbsolute(e.relPath) ? import_node_path31.default.resolve(e.relPath) : import_node_path31.default.resolve(cwdAbs, e.relPath);
42726
+ const storedAbs = import_node_path32.default.isAbsolute(e.relPath) ? import_node_path32.default.resolve(e.relPath) : import_node_path32.default.resolve(cwdAbs, e.relPath);
42442
42727
  return storedAbs === candidateAbs && !e.stale;
42443
42728
  });
42444
42729
  if (!entry) {
@@ -42462,7 +42747,7 @@ function buildAttachmentHandlers(deps) {
42462
42747
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
42463
42748
  const f = deps.sessionStore.read(sessionId);
42464
42749
  if (!f) return;
42465
- assertGuestAttachmentPath(ctx, import_node_path31.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
42750
+ assertGuestAttachmentPath(ctx, import_node_path32.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
42466
42751
  }
42467
42752
  const groupAdd = async (frame, _client, ctx) => {
42468
42753
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -42534,19 +42819,19 @@ function buildAttachmentHandlers(deps) {
42534
42819
 
42535
42820
  // src/handlers/extension.ts
42536
42821
  var import_promises7 = __toESM(require("fs/promises"), 1);
42537
- var import_node_path36 = __toESM(require("path"), 1);
42822
+ var import_node_path37 = __toESM(require("path"), 1);
42538
42823
  init_protocol();
42539
42824
 
42540
42825
  // src/extension/bundle-zip.ts
42541
42826
  var import_promises4 = __toESM(require("fs/promises"), 1);
42542
- var import_node_path32 = __toESM(require("path"), 1);
42827
+ var import_node_path33 = __toESM(require("path"), 1);
42543
42828
  var import_node_crypto11 = __toESM(require("crypto"), 1);
42544
42829
  var import_jszip2 = __toESM(require_lib3(), 1);
42545
42830
  async function bundleExtensionDir(dir) {
42546
42831
  const entries = await listFilesSorted(dir);
42547
42832
  const zip = new import_jszip2.default();
42548
42833
  for (const rel of entries) {
42549
- const abs = import_node_path32.default.join(dir, rel);
42834
+ const abs = import_node_path33.default.join(dir, rel);
42550
42835
  const content = await import_promises4.default.readFile(abs);
42551
42836
  zip.file(rel, content, { date: FIXED_DATE });
42552
42837
  }
@@ -42567,7 +42852,7 @@ async function listFilesSorted(rootDir) {
42567
42852
  return out;
42568
42853
  }
42569
42854
  async function walk(absRoot, relPrefix, out) {
42570
- const dirAbs = import_node_path32.default.join(absRoot, relPrefix);
42855
+ const dirAbs = import_node_path33.default.join(absRoot, relPrefix);
42571
42856
  const entries = await import_promises4.default.readdir(dirAbs, { withFileTypes: true });
42572
42857
  for (const e of entries) {
42573
42858
  if (IGNORE_BASENAMES.has(e.name)) continue;
@@ -42621,25 +42906,25 @@ function computePublishCheck(args) {
42621
42906
 
42622
42907
  // src/extension/install-flow.ts
42623
42908
  var import_promises5 = __toESM(require("fs/promises"), 1);
42624
- var import_node_path34 = __toESM(require("path"), 1);
42909
+ var import_node_path35 = __toESM(require("path"), 1);
42625
42910
  var import_node_os17 = __toESM(require("os"), 1);
42626
42911
  var import_node_crypto12 = __toESM(require("crypto"), 1);
42627
42912
  var import_jszip3 = __toESM(require_lib3(), 1);
42628
42913
 
42629
42914
  // src/extension/paths.ts
42630
42915
  var import_node_os16 = __toESM(require("os"), 1);
42631
- var import_node_path33 = __toESM(require("path"), 1);
42916
+ var import_node_path34 = __toESM(require("path"), 1);
42632
42917
  function clawdHomeRoot(override) {
42633
- return override ?? process.env.CLAWD_HOME ?? import_node_path33.default.join(import_node_os16.default.homedir(), ".clawd");
42918
+ return override ?? process.env.CLAWD_HOME ?? import_node_path34.default.join(import_node_os16.default.homedir(), ".clawd");
42634
42919
  }
42635
42920
  function extensionsRoot(override) {
42636
- return import_node_path33.default.join(clawdHomeRoot(override), "extensions");
42921
+ return import_node_path34.default.join(clawdHomeRoot(override), "extensions");
42637
42922
  }
42638
42923
  function publishedChannelsFile(override) {
42639
- return import_node_path33.default.join(clawdHomeRoot(override), "extensions-published.json");
42924
+ return import_node_path34.default.join(clawdHomeRoot(override), "extensions-published.json");
42640
42925
  }
42641
42926
  function bundleCacheRoot(override) {
42642
- return import_node_path33.default.join(clawdHomeRoot(override), "extension-bundles");
42927
+ return import_node_path34.default.join(clawdHomeRoot(override), "extension-bundles");
42643
42928
  }
42644
42929
 
42645
42930
  // src/extension/install-flow.ts
@@ -42666,7 +42951,7 @@ async function installFromChannel(args, deps) {
42666
42951
  throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
42667
42952
  }
42668
42953
  for (const name of Object.keys(zip.files)) {
42669
- if (name.includes("..") || name.startsWith("/") || import_node_path34.default.isAbsolute(name)) {
42954
+ if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
42670
42955
  throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
42671
42956
  }
42672
42957
  }
@@ -42698,7 +42983,7 @@ async function installFromChannel(args, deps) {
42698
42983
  );
42699
42984
  }
42700
42985
  const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
42701
- const destDir = import_node_path34.default.join(deps.extensionsRoot, localExtId);
42986
+ const destDir = import_node_path35.default.join(deps.extensionsRoot, localExtId);
42702
42987
  let destExists = false;
42703
42988
  try {
42704
42989
  await import_promises5.default.access(destDir);
@@ -42712,16 +42997,16 @@ async function installFromChannel(args, deps) {
42712
42997
  );
42713
42998
  }
42714
42999
  const stage = await import_promises5.default.mkdtemp(
42715
- import_node_path34.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
43000
+ import_node_path35.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
42716
43001
  );
42717
43002
  try {
42718
43003
  for (const [name, entry] of Object.entries(zip.files)) {
42719
- const dest = import_node_path34.default.join(stage, name);
43004
+ const dest = import_node_path35.default.join(stage, name);
42720
43005
  if (entry.dir) {
42721
43006
  await import_promises5.default.mkdir(dest, { recursive: true });
42722
43007
  continue;
42723
43008
  }
42724
- await import_promises5.default.mkdir(import_node_path34.default.dirname(dest), { recursive: true });
43009
+ await import_promises5.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
42725
43010
  if (name === "manifest.json") {
42726
43011
  const rewritten = { ...parsed.data, id: localExtId };
42727
43012
  await import_promises5.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -42742,7 +43027,7 @@ async function installFromChannel(args, deps) {
42742
43027
 
42743
43028
  // src/extension/update-flow.ts
42744
43029
  var import_promises6 = __toESM(require("fs/promises"), 1);
42745
- var import_node_path35 = __toESM(require("path"), 1);
43030
+ var import_node_path36 = __toESM(require("path"), 1);
42746
43031
  var import_node_os18 = __toESM(require("os"), 1);
42747
43032
  var import_node_crypto13 = __toESM(require("crypto"), 1);
42748
43033
  var import_jszip4 = __toESM(require_lib3(), 1);
@@ -42759,11 +43044,11 @@ async function updateFromChannel(args, deps) {
42759
43044
  channelRef.extId,
42760
43045
  channelRef.ownerPrincipalId
42761
43046
  );
42762
- const liveDir = import_node_path35.default.join(deps.extensionsRoot, localExtId);
43047
+ const liveDir = import_node_path36.default.join(deps.extensionsRoot, localExtId);
42763
43048
  const prevDir = `${liveDir}.prev`;
42764
43049
  let existingVersion;
42765
43050
  try {
42766
- const raw = await import_promises6.default.readFile(import_node_path35.default.join(liveDir, "manifest.json"), "utf8");
43051
+ const raw = await import_promises6.default.readFile(import_node_path36.default.join(liveDir, "manifest.json"), "utf8");
42767
43052
  const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
42768
43053
  if (!parsed2.success) {
42769
43054
  throw new UpdateError(
@@ -42796,7 +43081,7 @@ async function updateFromChannel(args, deps) {
42796
43081
  throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
42797
43082
  }
42798
43083
  for (const name of Object.keys(zip.files)) {
42799
- if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
43084
+ if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
42800
43085
  throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
42801
43086
  }
42802
43087
  }
@@ -42831,16 +43116,16 @@ async function updateFromChannel(args, deps) {
42831
43116
  await import_promises6.default.rm(prevDir, { recursive: true, force: true });
42832
43117
  await import_promises6.default.rename(liveDir, prevDir);
42833
43118
  const stage = await import_promises6.default.mkdtemp(
42834
- import_node_path35.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
43119
+ import_node_path36.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
42835
43120
  );
42836
43121
  try {
42837
43122
  for (const [name, entry] of Object.entries(zip.files)) {
42838
- const dest = import_node_path35.default.join(stage, name);
43123
+ const dest = import_node_path36.default.join(stage, name);
42839
43124
  if (entry.dir) {
42840
43125
  await import_promises6.default.mkdir(dest, { recursive: true });
42841
43126
  continue;
42842
43127
  }
42843
- await import_promises6.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
43128
+ await import_promises6.default.mkdir(import_node_path36.default.dirname(dest), { recursive: true });
42844
43129
  if (name === "manifest.json") {
42845
43130
  const rewritten = { ...parsed.data, id: localExtId };
42846
43131
  await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
@@ -42933,7 +43218,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
42933
43218
  );
42934
43219
  }
42935
43220
  }
42936
- const manifestPath = import_node_path36.default.join(root, extId, "manifest.json");
43221
+ const manifestPath = import_node_path37.default.join(root, extId, "manifest.json");
42937
43222
  const manifest = await readManifest(root, extId);
42938
43223
  const next = { ...manifest, version: newVersion };
42939
43224
  const tmp = `${manifestPath}.tmp`;
@@ -42941,7 +43226,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
42941
43226
  await import_promises7.default.rename(tmp, manifestPath);
42942
43227
  }
42943
43228
  async function readManifest(root, extId) {
42944
- const file = import_node_path36.default.join(root, extId, "manifest.json");
43229
+ const file = import_node_path37.default.join(root, extId, "manifest.json");
42945
43230
  let raw;
42946
43231
  try {
42947
43232
  raw = await import_promises7.default.readFile(file, "utf8");
@@ -43032,7 +43317,7 @@ function buildExtensionHandlers(deps) {
43032
43317
  };
43033
43318
  async function buildSnapshotMeta(extId) {
43034
43319
  const manifest = await readManifest(deps.root, extId);
43035
- const { sha256, buffer } = await bundleExtensionDir(import_node_path36.default.join(deps.root, extId));
43320
+ const { sha256, buffer } = await bundleExtensionDir(import_node_path37.default.join(deps.root, extId));
43036
43321
  return { manifest, contentHash: sha256, buffer };
43037
43322
  }
43038
43323
  const publish = async (frame, _client, ctx) => {
@@ -43328,8 +43613,8 @@ var PublishJobRegistry = class {
43328
43613
 
43329
43614
  // src/app-builder/publish-job-runner.ts
43330
43615
  var import_node_child_process12 = require("child_process");
43331
- var import_node_fs30 = require("fs");
43332
- var import_node_path37 = require("path");
43616
+ var import_node_fs31 = require("fs");
43617
+ var import_node_path38 = require("path");
43333
43618
 
43334
43619
  // src/app-builder/publish-stage-parser.ts
43335
43620
  var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
@@ -43361,10 +43646,10 @@ async function startPublishJob(deps, args) {
43361
43646
  return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
43362
43647
  }
43363
43648
  const projDir = projectDir(args.name);
43364
- const logPath = (0, import_node_path37.join)(projDir, ".publish.log");
43649
+ const logPath = (0, import_node_path38.join)(projDir, ".publish.log");
43365
43650
  let logStream = null;
43366
43651
  try {
43367
- logStream = (0, import_node_fs30.createWriteStream)(logPath, { flags: "w" });
43652
+ logStream = (0, import_node_fs31.createWriteStream)(logPath, { flags: "w" });
43368
43653
  } catch {
43369
43654
  logStream = null;
43370
43655
  }
@@ -43621,8 +43906,8 @@ async function recoverInterruptedJobs(deps) {
43621
43906
 
43622
43907
  // src/handlers/app-builder.ts
43623
43908
  init_protocol();
43624
- var import_node_path38 = require("path");
43625
- var import_node_fs31 = require("fs");
43909
+ var import_node_path39 = require("path");
43910
+ var import_node_fs32 = require("fs");
43626
43911
  var APP_BUILDER_PERSONAS = ["persona-app-builder"];
43627
43912
  var PUBLISH_SCRIPT_REL = "extension-kit/scripts/publish.sh";
43628
43913
  var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
@@ -43704,7 +43989,7 @@ function buildAppBuilderHandlers(deps) {
43704
43989
  async function listAllUsersProjects() {
43705
43990
  if (!deps.usersRoot || !deps.getStore) return [];
43706
43991
  const getStore = deps.getStore;
43707
- const userIds = await import_node_fs31.promises.readdir(deps.usersRoot).catch(() => []);
43992
+ const userIds = await import_node_fs32.promises.readdir(deps.usersRoot).catch(() => []);
43708
43993
  const perUser = await Promise.all(
43709
43994
  userIds.map((uid) => getStore(uid).list().catch(() => []))
43710
43995
  );
@@ -43998,7 +44283,7 @@ function buildAppBuilderHandlers(deps) {
43998
44283
  });
43999
44284
  await userStore.clearPublishJob(args.name);
44000
44285
  }
44001
- const scriptPath = (0, import_node_path38.join)(deps.personaRoot, PUBLISH_SCRIPT_REL);
44286
+ const scriptPath = (0, import_node_path39.join)(deps.personaRoot, PUBLISH_SCRIPT_REL);
44002
44287
  deps.logger?.info("app-builder.publish.start", {
44003
44288
  name: args.name,
44004
44289
  sessionId: boundSession.sessionId,
@@ -44092,7 +44377,7 @@ function buildAppBuilderHandlers(deps) {
44092
44377
 
44093
44378
  // src/extension/registry.ts
44094
44379
  var import_promises8 = __toESM(require("fs/promises"), 1);
44095
- var import_node_path39 = __toESM(require("path"), 1);
44380
+ var import_node_path40 = __toESM(require("path"), 1);
44096
44381
  async function loadAll(root) {
44097
44382
  let entries;
44098
44383
  try {
@@ -44105,13 +44390,13 @@ async function loadAll(root) {
44105
44390
  for (const ent of entries) {
44106
44391
  if (!ent.isDirectory()) continue;
44107
44392
  if (ent.name.startsWith(".")) continue;
44108
- records.push(await loadOne(import_node_path39.default.join(root, ent.name), ent.name));
44393
+ records.push(await loadOne(import_node_path40.default.join(root, ent.name), ent.name));
44109
44394
  }
44110
44395
  records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
44111
44396
  return records;
44112
44397
  }
44113
44398
  async function loadOne(dir, dirName) {
44114
- const manifestPath = import_node_path39.default.join(dir, "manifest.json");
44399
+ const manifestPath = import_node_path40.default.join(dir, "manifest.json");
44115
44400
  let raw;
44116
44401
  try {
44117
44402
  raw = await import_promises8.default.readFile(manifestPath, "utf8");
@@ -44156,7 +44441,7 @@ async function loadOne(dir, dirName) {
44156
44441
 
44157
44442
  // src/extension/uninstall.ts
44158
44443
  var import_promises9 = __toESM(require("fs/promises"), 1);
44159
- var import_node_path40 = __toESM(require("path"), 1);
44444
+ var import_node_path41 = __toESM(require("path"), 1);
44160
44445
  var UninstallError = class extends Error {
44161
44446
  constructor(code, message) {
44162
44447
  super(message);
@@ -44165,7 +44450,7 @@ var UninstallError = class extends Error {
44165
44450
  code;
44166
44451
  };
44167
44452
  async function uninstall(deps) {
44168
- const dir = import_node_path40.default.join(deps.root, deps.extId);
44453
+ const dir = import_node_path41.default.join(deps.root, deps.extId);
44169
44454
  try {
44170
44455
  await import_promises9.default.access(dir);
44171
44456
  } catch {
@@ -44244,9 +44529,9 @@ function buildMethodHandlers(deps) {
44244
44529
  }
44245
44530
 
44246
44531
  // src/app-builder/project-store.ts
44247
- var import_node_fs32 = require("fs");
44532
+ var import_node_fs33 = require("fs");
44248
44533
  var import_node_child_process13 = require("child_process");
44249
- var import_node_path41 = require("path");
44534
+ var import_node_path42 = require("path");
44250
44535
  init_protocol();
44251
44536
  var PROJECTS_DIR = "projects";
44252
44537
  var META_FILE = ".clawd-project.json";
@@ -44261,19 +44546,19 @@ var ProjectStore = class {
44261
44546
  root;
44262
44547
  /** projects/<name>/.clawd-project.json 路径 */
44263
44548
  metaPath(name) {
44264
- return (0, import_node_path41.join)(this.projectsRoot(), name, META_FILE);
44549
+ return (0, import_node_path42.join)(this.projectsRoot(), name, META_FILE);
44265
44550
  }
44266
44551
  /** projects/<name>/ 目录路径(cwd 用) */
44267
44552
  projectDir(name) {
44268
- return (0, import_node_path41.join)(this.projectsRoot(), name);
44553
+ return (0, import_node_path42.join)(this.projectsRoot(), name);
44269
44554
  }
44270
44555
  projectsRoot() {
44271
- return (0, import_node_path41.join)(this.root, PROJECTS_DIR);
44556
+ return (0, import_node_path42.join)(this.root, PROJECTS_DIR);
44272
44557
  }
44273
44558
  async list() {
44274
44559
  let entries;
44275
44560
  try {
44276
- entries = await import_node_fs32.promises.readdir(this.projectsRoot());
44561
+ entries = await import_node_fs33.promises.readdir(this.projectsRoot());
44277
44562
  } catch (err) {
44278
44563
  if (err.code === "ENOENT") return [];
44279
44564
  throw err;
@@ -44281,7 +44566,7 @@ var ProjectStore = class {
44281
44566
  const out = [];
44282
44567
  for (const name of entries) {
44283
44568
  try {
44284
- const raw = await import_node_fs32.promises.readFile(this.metaPath(name), "utf8");
44569
+ const raw = await import_node_fs33.promises.readFile(this.metaPath(name), "utf8");
44285
44570
  const json = JSON.parse(raw);
44286
44571
  let migrated = false;
44287
44572
  if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
@@ -44292,7 +44577,7 @@ var ProjectStore = class {
44292
44577
  if (parsed.success) {
44293
44578
  out.push(parsed.data);
44294
44579
  if (migrated) {
44295
- void import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
44580
+ void import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
44296
44581
  });
44297
44582
  }
44298
44583
  }
@@ -44336,8 +44621,8 @@ var ProjectStore = class {
44336
44621
  throw new Error(`invalid name "${name}": ${validated.error.message}`);
44337
44622
  }
44338
44623
  const dir = this.projectDir(name);
44339
- await import_node_fs32.promises.mkdir(dir, { recursive: true });
44340
- await import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
44624
+ await import_node_fs33.promises.mkdir(dir, { recursive: true });
44625
+ await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
44341
44626
  return meta;
44342
44627
  }
44343
44628
  /**
@@ -44349,7 +44634,7 @@ var ProjectStore = class {
44349
44634
  * 代码再参考"。assistant 进 project 时目录已是完整模板,直接 pnpm install 即可。
44350
44635
  */
44351
44636
  async scaffold(name, template = DEFAULT_TEMPLATE, personaRoot = this.root) {
44352
- const scriptPath = (0, import_node_path41.join)(personaRoot, SCAFFOLD_SCRIPT_REL);
44637
+ const scriptPath = (0, import_node_path42.join)(personaRoot, SCAFFOLD_SCRIPT_REL);
44353
44638
  const destDir = this.projectDir(name);
44354
44639
  return await new Promise((resolve6, reject) => {
44355
44640
  const child = (0, import_node_child_process13.spawn)("bash", [scriptPath, name, template, destDir], {
@@ -44382,7 +44667,7 @@ var ProjectStore = class {
44382
44667
  }
44383
44668
  async delete(name) {
44384
44669
  const dir = this.projectDir(name);
44385
- await import_node_fs32.promises.rm(dir, { recursive: true, force: true });
44670
+ await import_node_fs33.promises.rm(dir, { recursive: true, force: true });
44386
44671
  }
44387
44672
  async updatePort(name, newPort) {
44388
44673
  if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
@@ -44398,7 +44683,7 @@ var ProjectStore = class {
44398
44683
  throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
44399
44684
  }
44400
44685
  const updated = { ...target, port: newPort };
44401
- await import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
44686
+ await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
44402
44687
  return updated;
44403
44688
  }
44404
44689
  /**
@@ -44415,7 +44700,7 @@ var ProjectStore = class {
44415
44700
  if (!validated.success) {
44416
44701
  throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
44417
44702
  }
44418
- await import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
44703
+ await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
44419
44704
  return validated.data;
44420
44705
  }
44421
44706
  /**
@@ -44436,7 +44721,7 @@ var ProjectStore = class {
44436
44721
  if (!validated.success) {
44437
44722
  throw new Error(`invalid publishJob: ${validated.error.message}`);
44438
44723
  }
44439
- await import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
44724
+ await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
44440
44725
  return validated.data;
44441
44726
  }
44442
44727
  /** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
@@ -44451,7 +44736,7 @@ var ProjectStore = class {
44451
44736
  if (!validated.success) {
44452
44737
  throw new Error(`failed to clear publishJob: ${validated.error.message}`);
44453
44738
  }
44454
- await import_node_fs32.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
44739
+ await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
44455
44740
  return validated.data;
44456
44741
  }
44457
44742
  };
@@ -44887,7 +45172,7 @@ function computeGrantForFrame(method, frame) {
44887
45172
 
44888
45173
  // src/extension/runtime.ts
44889
45174
  var import_node_child_process15 = require("child_process");
44890
- var import_node_path42 = __toESM(require("path"), 1);
45175
+ var import_node_path43 = __toESM(require("path"), 1);
44891
45176
  var import_promises10 = require("timers/promises");
44892
45177
 
44893
45178
  // src/extension/port-allocator.ts
@@ -44988,7 +45273,7 @@ var Runtime = class {
44988
45273
  /\$CLAWOS_EXT_PORT/g,
44989
45274
  String(port)
44990
45275
  );
44991
- const dir = import_node_path42.default.join(this.root, extId);
45276
+ const dir = import_node_path43.default.join(this.root, extId);
44992
45277
  const env = {
44993
45278
  ...process.env,
44994
45279
  CLAWOS_EXT_PORT: String(port),
@@ -45100,7 +45385,7 @@ ${handle.stderrTail}`
45100
45385
 
45101
45386
  // src/extension/published-channels.ts
45102
45387
  var import_promises11 = __toESM(require("fs/promises"), 1);
45103
- var import_node_path43 = __toESM(require("path"), 1);
45388
+ var import_node_path44 = __toESM(require("path"), 1);
45104
45389
  init_zod();
45105
45390
  var PublishedChannelsError = class extends Error {
45106
45391
  constructor(code, message) {
@@ -45199,7 +45484,7 @@ var PublishedChannelStore = class {
45199
45484
  )
45200
45485
  };
45201
45486
  const tmp = `${this.filePath}.tmp`;
45202
- await import_promises11.default.mkdir(import_node_path43.default.dirname(this.filePath), { recursive: true });
45487
+ await import_promises11.default.mkdir(import_node_path44.default.dirname(this.filePath), { recursive: true });
45203
45488
  await import_promises11.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
45204
45489
  await import_promises11.default.rename(tmp, this.filePath);
45205
45490
  }
@@ -45207,7 +45492,7 @@ var PublishedChannelStore = class {
45207
45492
 
45208
45493
  // src/extension/bundle-cache.ts
45209
45494
  var import_promises12 = __toESM(require("fs/promises"), 1);
45210
- var import_node_path44 = __toESM(require("path"), 1);
45495
+ var import_node_path45 = __toESM(require("path"), 1);
45211
45496
  var BundleCache = class {
45212
45497
  constructor(rootDir) {
45213
45498
  this.rootDir = rootDir;
@@ -45216,14 +45501,14 @@ var BundleCache = class {
45216
45501
  /** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
45217
45502
  async write(snapshotHash, buffer) {
45218
45503
  await import_promises12.default.mkdir(this.rootDir, { recursive: true });
45219
- const file = import_node_path44.default.join(this.rootDir, `${snapshotHash}.zip`);
45504
+ const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
45220
45505
  const tmp = `${file}.tmp`;
45221
45506
  await import_promises12.default.writeFile(tmp, buffer, { mode: 384 });
45222
45507
  await import_promises12.default.rename(tmp, file);
45223
45508
  }
45224
45509
  /** Returns the bundle bytes, or null when the file doesn't exist. */
45225
45510
  async read(snapshotHash) {
45226
- const file = import_node_path44.default.join(this.rootDir, `${snapshotHash}.zip`);
45511
+ const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
45227
45512
  try {
45228
45513
  return await import_promises12.default.readFile(file);
45229
45514
  } catch (e) {
@@ -45233,16 +45518,17 @@ var BundleCache = class {
45233
45518
  }
45234
45519
  /** Idempotent — missing file is not an error. */
45235
45520
  async delete(snapshotHash) {
45236
- const file = import_node_path44.default.join(this.rootDir, `${snapshotHash}.zip`);
45521
+ const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
45237
45522
  await import_promises12.default.rm(file, { force: true });
45238
45523
  }
45239
45524
  };
45240
45525
 
45241
45526
  // src/index.ts
45527
+ var import_meta4 = {};
45242
45528
  async function startDaemon(config) {
45243
45529
  const logger = createLogger({
45244
45530
  level: config.logLevel,
45245
- file: import_node_path45.default.join(config.dataDir, "clawd.log")
45531
+ file: import_node_path46.default.join(config.dataDir, "clawd.log")
45246
45532
  });
45247
45533
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
45248
45534
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -45378,8 +45664,8 @@ async function startDaemon(config) {
45378
45664
  const agents = new AgentsScanner();
45379
45665
  const history = new ClaudeHistoryReader();
45380
45666
  let transport = null;
45381
- const personaStore = new PersonaStore(import_node_path45.default.join(config.dataDir, "personas"));
45382
- const usersRoot = import_node_path45.default.join(config.dataDir, "users");
45667
+ const personaStore = new PersonaStore(import_node_path46.default.join(config.dataDir, "personas"));
45668
+ const usersRoot = import_node_path46.default.join(config.dataDir, "users");
45383
45669
  const defaultsRoot = findDefaultsRoot();
45384
45670
  if (defaultsRoot) {
45385
45671
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -45390,6 +45676,33 @@ async function startDaemon(config) {
45390
45676
  migrateAgentsMirror({ store: personaStore, logger });
45391
45677
  migrateCodexSandbox({ store: personaStore, logger });
45392
45678
  const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
45679
+ const personaDispatchManager = new PersonaDispatchManager({ genId: () => v4_default() });
45680
+ const here = typeof __dirname === "string" ? __dirname : import_node_path46.default.dirname((0, import_node_url2.fileURLToPath)(import_meta4.url));
45681
+ const dispatchServerCandidates = [
45682
+ import_node_path46.default.join(here, "dispatch", "mcp-server.cjs"),
45683
+ // 生产 dist/index → dist/dispatch/mcp-server.cjs
45684
+ import_node_path46.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
45685
+ // dev tsx src/index → ../dist/dispatch/mcp-server.cjs
45686
+ ];
45687
+ const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs34.default.existsSync(p2));
45688
+ let dispatchMcpConfigPath2;
45689
+ if (dispatchServerScriptPath) {
45690
+ const dispatchLogPath = import_node_path46.default.join(config.dataDir, "dispatch-mcp-server.log");
45691
+ dispatchMcpConfigPath2 = writeDispatchMcpConfig({
45692
+ dataDir: config.dataDir,
45693
+ serverScriptPath: dispatchServerScriptPath,
45694
+ logPath: dispatchLogPath
45695
+ });
45696
+ logger.info("dispatch.mcp.json written", {
45697
+ path: dispatchMcpConfigPath2,
45698
+ server: dispatchServerScriptPath,
45699
+ serverLog: dispatchLogPath
45700
+ });
45701
+ } else {
45702
+ logger.warn("dispatch-mcp-server.cjs not found; persona dispatch disabled (dev tsx \u6A21\u5F0F\u4E0B\u9700\u5148\u8DD1\u8FC7 build)", {
45703
+ tried: dispatchServerCandidates
45704
+ });
45705
+ }
45393
45706
  const manager = new SessionManager({
45394
45707
  store,
45395
45708
  // Phase 2 (capability platform plan §1): factory 注入后 manager.storeFor 走
@@ -45399,7 +45712,7 @@ async function startDaemon(config) {
45399
45712
  getAdapter,
45400
45713
  historyReader: history,
45401
45714
  dataDir: config.dataDir,
45402
- personaRoot: import_node_path45.default.join(config.dataDir, "personas"),
45715
+ personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
45403
45716
  usersRoot,
45404
45717
  personaStore,
45405
45718
  ownerDisplayName,
@@ -45410,6 +45723,12 @@ async function startDaemon(config) {
45410
45723
  // 127.0.0.1(不是 config.host)—— cc 跑在本机,loopback 最稳;外部访问限制 + http-router
45411
45724
  // 的 isLoopback 兜底已确保安全。
45412
45725
  getDaemonUrl: () => `http://127.0.0.1:${config.port}`,
45726
+ // Persona dispatch (Task 8): manager 通过这两个 deps 跟 PersonaDispatchManager 协作。
45727
+ // - personaDispatchManager: manager.createDispatchedSession 用它 registerBSession;
45728
+ // reducer 通过闭包反查 dispatchId 注 CLAWD_DISPATCH_ID env。
45729
+ // - dispatchMcpConfigPath: reducer 透传到 SpawnContext,cc spawn 加 --mcp-config flag。
45730
+ personaDispatchManager,
45731
+ dispatchMcpConfigPath: dispatchMcpConfigPath2,
45413
45732
  broadcastFrame: (frame, target) => {
45414
45733
  if (target === "all") {
45415
45734
  transport?.broadcastAll(frame);
@@ -45429,10 +45748,10 @@ async function startDaemon(config) {
45429
45748
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
45430
45749
  attachmentGroup: {
45431
45750
  onFileEdit: (input) => {
45432
- const absPath = import_node_path45.default.isAbsolute(input.relPath) ? input.relPath : import_node_path45.default.join(input.cwd, input.relPath);
45751
+ const absPath = import_node_path46.default.isAbsolute(input.relPath) ? input.relPath : import_node_path46.default.join(input.cwd, input.relPath);
45433
45752
  let size = 0;
45434
45753
  try {
45435
- size = import_node_fs33.default.statSync(absPath).size;
45754
+ size = import_node_fs34.default.statSync(absPath).size;
45436
45755
  } catch (err) {
45437
45756
  logger.warn("attachment.onFileEdit stat failed", {
45438
45757
  sessionId: input.sessionId,
@@ -45618,11 +45937,11 @@ async function startDaemon(config) {
45618
45937
  // 'persona/<pid>/owner',default 走 'default'。
45619
45938
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
45620
45939
  // guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
45621
- personaRoot: import_node_path45.default.join(config.dataDir, "personas"),
45940
+ personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
45622
45941
  usersRoot
45623
45942
  },
45624
45943
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
45625
- personaRoot: import_node_path45.default.join(config.dataDir, "personas"),
45944
+ personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
45626
45945
  // v2 多人 persona 隔离:handler 派生 guest user-dir 放行
45627
45946
  usersRoot,
45628
45947
  // capability:list / delete handler 依赖
@@ -45711,7 +46030,7 @@ async function startDaemon(config) {
45711
46030
  // 发布上线脚手架化 (spec 2026-06-03 §5.2):
45712
46031
  // appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
45713
46032
  // dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
45714
- appBuilderPersonaRoot: import_node_path45.default.join(config.dataDir, "personas", "persona-app-builder"),
46033
+ appBuilderPersonaRoot: import_node_path46.default.join(config.dataDir, "personas", "persona-app-builder"),
45715
46034
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
45716
46035
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
45717
46036
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -45732,6 +46051,41 @@ async function startDaemon(config) {
45732
46051
  logger
45733
46052
  });
45734
46053
  let handlers = makeHandlers();
46054
+ const dispatchHandlers = buildPersonaDispatchHandlers({
46055
+ personaDispatchManager,
46056
+ logger,
46057
+ spawnB: async (args) => {
46058
+ logger.info("dispatch.spawnB.start", {
46059
+ dispatchId: args.dispatchId,
46060
+ targetPersona: args.targetPersona,
46061
+ sourceSessionId: args.sourceSessionId
46062
+ });
46063
+ const sourceFile = manager.findOwnedSession(args.sourceSessionId);
46064
+ if (!sourceFile) {
46065
+ throw new Error(`personaDispatch:run source session not found: ${args.sourceSessionId}`);
46066
+ }
46067
+ const sourceJsonlPath = sourceFile.toolSessionId ? import_node_path46.default.join(
46068
+ import_node_os19.default.homedir(),
46069
+ ".claude",
46070
+ "projects",
46071
+ cwdToHashDir(sourceFile.cwd),
46072
+ `${sourceFile.toolSessionId}.jsonl`
46073
+ ) : "(no transcript yet \u2014 operate from the task description alone)";
46074
+ logger.info("dispatch.spawnB.source-resolved", {
46075
+ dispatchId: args.dispatchId,
46076
+ sourceJsonlPath,
46077
+ hasToolSessionId: Boolean(sourceFile.toolSessionId)
46078
+ });
46079
+ manager.createDispatchedSession({
46080
+ dispatchId: args.dispatchId,
46081
+ sourceSessionId: args.sourceSessionId,
46082
+ targetPersona: args.targetPersona,
46083
+ prompt: args.prompt,
46084
+ sourceJsonlPath
46085
+ });
46086
+ }
46087
+ });
46088
+ handlers = { ...handlers, ...dispatchHandlers };
45735
46089
  const authResolver = new AuthContextResolver({
45736
46090
  ownerToken: resolvedAuthToken
45737
46091
  });
@@ -45960,8 +46314,8 @@ async function startDaemon(config) {
45960
46314
  const lines = [
45961
46315
  `Tunnel: ${r.url}`,
45962
46316
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
45963
- `Frpc config: ${import_node_path45.default.join(config.dataDir, "frpc.toml")}`,
45964
- `Frpc log: ${import_node_path45.default.join(config.dataDir, "frpc.log")}`
46317
+ `Frpc config: ${import_node_path46.default.join(config.dataDir, "frpc.toml")}`,
46318
+ `Frpc log: ${import_node_path46.default.join(config.dataDir, "frpc.log")}`
45965
46319
  ];
45966
46320
  const width = Math.max(...lines.map((l) => l.length));
45967
46321
  const bar = "\u2550".repeat(width + 4);
@@ -45974,8 +46328,8 @@ ${bar}
45974
46328
 
45975
46329
  `);
45976
46330
  try {
45977
- const connectPath = import_node_path45.default.join(config.dataDir, "connect.txt");
45978
- import_node_fs33.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
46331
+ const connectPath = import_node_path46.default.join(config.dataDir, "connect.txt");
46332
+ import_node_fs34.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
45979
46333
  } catch {
45980
46334
  }
45981
46335
  } catch (err) {
@@ -46046,9 +46400,9 @@ ${bar}
46046
46400
  };
46047
46401
  }
46048
46402
  function migrateDropPersonsDir(dataDir) {
46049
- const dir = import_node_path45.default.join(dataDir, "persons");
46403
+ const dir = import_node_path46.default.join(dataDir, "persons");
46050
46404
  try {
46051
- import_node_fs33.default.rmSync(dir, { recursive: true, force: true });
46405
+ import_node_fs34.default.rmSync(dir, { recursive: true, force: true });
46052
46406
  } catch {
46053
46407
  }
46054
46408
  }