@clawos-dev/clawd 0.2.89 → 0.2.90

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.
Files changed (2) hide show
  1. package/dist/cli.cjs +598 -487
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -651,8 +651,8 @@ var init_parseUtil = __esm({
651
651
  init_errors2();
652
652
  init_en();
653
653
  makeIssue = (params) => {
654
- const { data, path: path46, errorMaps, issueData } = params;
655
- const fullPath = [...path46, ...issueData.path || []];
654
+ const { data, path: path47, errorMaps, issueData } = params;
655
+ const fullPath = [...path47, ...issueData.path || []];
656
656
  const fullIssue = {
657
657
  ...issueData,
658
658
  path: fullPath
@@ -963,11 +963,11 @@ var init_types = __esm({
963
963
  init_parseUtil();
964
964
  init_util();
965
965
  ParseInputLazyPath = class {
966
- constructor(parent, value, path46, key) {
966
+ constructor(parent, value, path47, key) {
967
967
  this._cachedPath = [];
968
968
  this.parent = parent;
969
969
  this.data = value;
970
- this._path = path46;
970
+ this._path = path47;
971
971
  this._key = key;
972
972
  }
973
973
  get path() {
@@ -5635,8 +5635,8 @@ var require_req = __commonJS({
5635
5635
  if (req.originalUrl) {
5636
5636
  _req.url = req.originalUrl;
5637
5637
  } else {
5638
- const path46 = req.path;
5639
- _req.url = typeof path46 === "string" ? path46 : req.url ? req.url.path || req.url : void 0;
5638
+ const path47 = req.path;
5639
+ _req.url = typeof path47 === "string" ? path47 : req.url ? req.url.path || req.url : void 0;
5640
5640
  }
5641
5641
  if (req.query) {
5642
5642
  _req.query = req.query;
@@ -5801,14 +5801,14 @@ var require_redact = __commonJS({
5801
5801
  }
5802
5802
  return obj;
5803
5803
  }
5804
- function parsePath(path46) {
5804
+ function parsePath(path47) {
5805
5805
  const parts = [];
5806
5806
  let current = "";
5807
5807
  let inBrackets = false;
5808
5808
  let inQuotes = false;
5809
5809
  let quoteChar = "";
5810
- for (let i = 0; i < path46.length; i++) {
5811
- const char = path46[i];
5810
+ for (let i = 0; i < path47.length; i++) {
5811
+ const char = path47[i];
5812
5812
  if (!inBrackets && char === ".") {
5813
5813
  if (current) {
5814
5814
  parts.push(current);
@@ -5939,10 +5939,10 @@ var require_redact = __commonJS({
5939
5939
  return current;
5940
5940
  }
5941
5941
  function redactPaths(obj, paths, censor, remove = false) {
5942
- for (const path46 of paths) {
5943
- const parts = parsePath(path46);
5942
+ for (const path47 of paths) {
5943
+ const parts = parsePath(path47);
5944
5944
  if (parts.includes("*")) {
5945
- redactWildcardPath(obj, parts, censor, path46, remove);
5945
+ redactWildcardPath(obj, parts, censor, path47, remove);
5946
5946
  } else {
5947
5947
  if (remove) {
5948
5948
  removeKey(obj, parts);
@@ -6027,8 +6027,8 @@ var require_redact = __commonJS({
6027
6027
  }
6028
6028
  } else {
6029
6029
  if (afterWildcard.includes("*")) {
6030
- const wrappedCensor = typeof censor === "function" ? (value, path46) => {
6031
- const fullPath = [...pathArray.slice(0, pathLength), ...path46];
6030
+ const wrappedCensor = typeof censor === "function" ? (value, path47) => {
6031
+ const fullPath = [...pathArray.slice(0, pathLength), ...path47];
6032
6032
  return censor(value, fullPath);
6033
6033
  } : censor;
6034
6034
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -6063,8 +6063,8 @@ var require_redact = __commonJS({
6063
6063
  return null;
6064
6064
  }
6065
6065
  const pathStructure = /* @__PURE__ */ new Map();
6066
- for (const path46 of pathsToClone) {
6067
- const parts = parsePath(path46);
6066
+ for (const path47 of pathsToClone) {
6067
+ const parts = parsePath(path47);
6068
6068
  let current = pathStructure;
6069
6069
  for (let i = 0; i < parts.length; i++) {
6070
6070
  const part = parts[i];
@@ -6116,24 +6116,24 @@ var require_redact = __commonJS({
6116
6116
  }
6117
6117
  return cloneSelectively(obj, pathStructure);
6118
6118
  }
6119
- function validatePath(path46) {
6120
- if (typeof path46 !== "string") {
6119
+ function validatePath(path47) {
6120
+ if (typeof path47 !== "string") {
6121
6121
  throw new Error("Paths must be (non-empty) strings");
6122
6122
  }
6123
- if (path46 === "") {
6123
+ if (path47 === "") {
6124
6124
  throw new Error("Invalid redaction path ()");
6125
6125
  }
6126
- if (path46.includes("..")) {
6127
- throw new Error(`Invalid redaction path (${path46})`);
6126
+ if (path47.includes("..")) {
6127
+ throw new Error(`Invalid redaction path (${path47})`);
6128
6128
  }
6129
- if (path46.includes(",")) {
6130
- throw new Error(`Invalid redaction path (${path46})`);
6129
+ if (path47.includes(",")) {
6130
+ throw new Error(`Invalid redaction path (${path47})`);
6131
6131
  }
6132
6132
  let bracketCount = 0;
6133
6133
  let inQuotes = false;
6134
6134
  let quoteChar = "";
6135
- for (let i = 0; i < path46.length; i++) {
6136
- const char = path46[i];
6135
+ for (let i = 0; i < path47.length; i++) {
6136
+ const char = path47[i];
6137
6137
  if ((char === '"' || char === "'") && bracketCount > 0) {
6138
6138
  if (!inQuotes) {
6139
6139
  inQuotes = true;
@@ -6147,20 +6147,20 @@ var require_redact = __commonJS({
6147
6147
  } else if (char === "]" && !inQuotes) {
6148
6148
  bracketCount--;
6149
6149
  if (bracketCount < 0) {
6150
- throw new Error(`Invalid redaction path (${path46})`);
6150
+ throw new Error(`Invalid redaction path (${path47})`);
6151
6151
  }
6152
6152
  }
6153
6153
  }
6154
6154
  if (bracketCount !== 0) {
6155
- throw new Error(`Invalid redaction path (${path46})`);
6155
+ throw new Error(`Invalid redaction path (${path47})`);
6156
6156
  }
6157
6157
  }
6158
6158
  function validatePaths(paths) {
6159
6159
  if (!Array.isArray(paths)) {
6160
6160
  throw new TypeError("paths must be an array");
6161
6161
  }
6162
- for (const path46 of paths) {
6163
- validatePath(path46);
6162
+ for (const path47 of paths) {
6163
+ validatePath(path47);
6164
6164
  }
6165
6165
  }
6166
6166
  function slowRedact(options = {}) {
@@ -6328,8 +6328,8 @@ var require_redaction = __commonJS({
6328
6328
  if (shape[k2] === null) {
6329
6329
  o[k2] = (value) => topCensor(value, [k2]);
6330
6330
  } else {
6331
- const wrappedCensor = typeof censor === "function" ? (value, path46) => {
6332
- return censor(value, [k2, ...path46]);
6331
+ const wrappedCensor = typeof censor === "function" ? (value, path47) => {
6332
+ return censor(value, [k2, ...path47]);
6333
6333
  } : censor;
6334
6334
  o[k2] = Redact({
6335
6335
  paths: shape[k2],
@@ -6547,10 +6547,10 @@ var require_atomic_sleep = __commonJS({
6547
6547
  var require_sonic_boom = __commonJS({
6548
6548
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
6549
6549
  "use strict";
6550
- var fs37 = require("fs");
6550
+ var fs38 = require("fs");
6551
6551
  var EventEmitter2 = require("events");
6552
6552
  var inherits = require("util").inherits;
6553
- var path46 = require("path");
6553
+ var path47 = require("path");
6554
6554
  var sleep = require_atomic_sleep();
6555
6555
  var assert = require("assert");
6556
6556
  var BUSY_WRITE_TIMEOUT = 100;
@@ -6604,20 +6604,20 @@ var require_sonic_boom = __commonJS({
6604
6604
  const mode = sonic.mode;
6605
6605
  if (sonic.sync) {
6606
6606
  try {
6607
- if (sonic.mkdir) fs37.mkdirSync(path46.dirname(file), { recursive: true });
6608
- const fd = fs37.openSync(file, flags, mode);
6607
+ if (sonic.mkdir) fs38.mkdirSync(path47.dirname(file), { recursive: true });
6608
+ const fd = fs38.openSync(file, flags, mode);
6609
6609
  fileOpened(null, fd);
6610
6610
  } catch (err) {
6611
6611
  fileOpened(err);
6612
6612
  throw err;
6613
6613
  }
6614
6614
  } else if (sonic.mkdir) {
6615
- fs37.mkdir(path46.dirname(file), { recursive: true }, (err) => {
6615
+ fs38.mkdir(path47.dirname(file), { recursive: true }, (err) => {
6616
6616
  if (err) return fileOpened(err);
6617
- fs37.open(file, flags, mode, fileOpened);
6617
+ fs38.open(file, flags, mode, fileOpened);
6618
6618
  });
6619
6619
  } else {
6620
- fs37.open(file, flags, mode, fileOpened);
6620
+ fs38.open(file, flags, mode, fileOpened);
6621
6621
  }
6622
6622
  }
6623
6623
  function SonicBoom(opts) {
@@ -6658,8 +6658,8 @@ var require_sonic_boom = __commonJS({
6658
6658
  this.flush = flushBuffer;
6659
6659
  this.flushSync = flushBufferSync;
6660
6660
  this._actualWrite = actualWriteBuffer;
6661
- fsWriteSync = () => fs37.writeSync(this.fd, this._writingBuf);
6662
- fsWrite = () => fs37.write(this.fd, this._writingBuf, this.release);
6661
+ fsWriteSync = () => fs38.writeSync(this.fd, this._writingBuf);
6662
+ fsWrite = () => fs38.write(this.fd, this._writingBuf, this.release);
6663
6663
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
6664
6664
  this._writingBuf = "";
6665
6665
  this.write = write;
@@ -6668,15 +6668,15 @@ var require_sonic_boom = __commonJS({
6668
6668
  this._actualWrite = actualWrite;
6669
6669
  fsWriteSync = () => {
6670
6670
  if (Buffer.isBuffer(this._writingBuf)) {
6671
- return fs37.writeSync(this.fd, this._writingBuf);
6671
+ return fs38.writeSync(this.fd, this._writingBuf);
6672
6672
  }
6673
- return fs37.writeSync(this.fd, this._writingBuf, "utf8");
6673
+ return fs38.writeSync(this.fd, this._writingBuf, "utf8");
6674
6674
  };
6675
6675
  fsWrite = () => {
6676
6676
  if (Buffer.isBuffer(this._writingBuf)) {
6677
- return fs37.write(this.fd, this._writingBuf, this.release);
6677
+ return fs38.write(this.fd, this._writingBuf, this.release);
6678
6678
  }
6679
- return fs37.write(this.fd, this._writingBuf, "utf8", this.release);
6679
+ return fs38.write(this.fd, this._writingBuf, "utf8", this.release);
6680
6680
  };
6681
6681
  } else {
6682
6682
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -6733,7 +6733,7 @@ var require_sonic_boom = __commonJS({
6733
6733
  }
6734
6734
  }
6735
6735
  if (this._fsync) {
6736
- fs37.fsyncSync(this.fd);
6736
+ fs38.fsyncSync(this.fd);
6737
6737
  }
6738
6738
  const len = this._len;
6739
6739
  if (this._reopening) {
@@ -6847,7 +6847,7 @@ var require_sonic_boom = __commonJS({
6847
6847
  const onDrain = () => {
6848
6848
  if (!this._fsync) {
6849
6849
  try {
6850
- fs37.fsync(this.fd, (err) => {
6850
+ fs38.fsync(this.fd, (err) => {
6851
6851
  this._flushPending = false;
6852
6852
  cb(err);
6853
6853
  });
@@ -6949,7 +6949,7 @@ var require_sonic_boom = __commonJS({
6949
6949
  const fd = this.fd;
6950
6950
  this.once("ready", () => {
6951
6951
  if (fd !== this.fd) {
6952
- fs37.close(fd, (err) => {
6952
+ fs38.close(fd, (err) => {
6953
6953
  if (err) {
6954
6954
  return this.emit("error", err);
6955
6955
  }
@@ -6998,7 +6998,7 @@ var require_sonic_boom = __commonJS({
6998
6998
  buf = this._bufs[0];
6999
6999
  }
7000
7000
  try {
7001
- const n = Buffer.isBuffer(buf) ? fs37.writeSync(this.fd, buf) : fs37.writeSync(this.fd, buf, "utf8");
7001
+ const n = Buffer.isBuffer(buf) ? fs38.writeSync(this.fd, buf) : fs38.writeSync(this.fd, buf, "utf8");
7002
7002
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
7003
7003
  buf = releasedBufObj.writingBuf;
7004
7004
  this._len = releasedBufObj.len;
@@ -7014,7 +7014,7 @@ var require_sonic_boom = __commonJS({
7014
7014
  }
7015
7015
  }
7016
7016
  try {
7017
- fs37.fsyncSync(this.fd);
7017
+ fs38.fsyncSync(this.fd);
7018
7018
  } catch {
7019
7019
  }
7020
7020
  }
@@ -7035,7 +7035,7 @@ var require_sonic_boom = __commonJS({
7035
7035
  buf = mergeBuf(this._bufs[0], this._lens[0]);
7036
7036
  }
7037
7037
  try {
7038
- const n = fs37.writeSync(this.fd, buf);
7038
+ const n = fs38.writeSync(this.fd, buf);
7039
7039
  buf = buf.subarray(n);
7040
7040
  this._len = Math.max(this._len - n, 0);
7041
7041
  if (buf.length <= 0) {
@@ -7063,13 +7063,13 @@ var require_sonic_boom = __commonJS({
7063
7063
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
7064
7064
  if (this.sync) {
7065
7065
  try {
7066
- const written = Buffer.isBuffer(this._writingBuf) ? fs37.writeSync(this.fd, this._writingBuf) : fs37.writeSync(this.fd, this._writingBuf, "utf8");
7066
+ const written = Buffer.isBuffer(this._writingBuf) ? fs38.writeSync(this.fd, this._writingBuf) : fs38.writeSync(this.fd, this._writingBuf, "utf8");
7067
7067
  release(null, written);
7068
7068
  } catch (err) {
7069
7069
  release(err);
7070
7070
  }
7071
7071
  } else {
7072
- fs37.write(this.fd, this._writingBuf, release);
7072
+ fs38.write(this.fd, this._writingBuf, release);
7073
7073
  }
7074
7074
  }
7075
7075
  function actualWriteBuffer() {
@@ -7078,7 +7078,7 @@ var require_sonic_boom = __commonJS({
7078
7078
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
7079
7079
  if (this.sync) {
7080
7080
  try {
7081
- const written = fs37.writeSync(this.fd, this._writingBuf);
7081
+ const written = fs38.writeSync(this.fd, this._writingBuf);
7082
7082
  release(null, written);
7083
7083
  } catch (err) {
7084
7084
  release(err);
@@ -7087,7 +7087,7 @@ var require_sonic_boom = __commonJS({
7087
7087
  if (kCopyBuffer) {
7088
7088
  this._writingBuf = Buffer.from(this._writingBuf);
7089
7089
  }
7090
- fs37.write(this.fd, this._writingBuf, release);
7090
+ fs38.write(this.fd, this._writingBuf, release);
7091
7091
  }
7092
7092
  }
7093
7093
  function actualClose(sonic) {
@@ -7103,12 +7103,12 @@ var require_sonic_boom = __commonJS({
7103
7103
  sonic._lens = [];
7104
7104
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
7105
7105
  try {
7106
- fs37.fsync(sonic.fd, closeWrapped);
7106
+ fs38.fsync(sonic.fd, closeWrapped);
7107
7107
  } catch {
7108
7108
  }
7109
7109
  function closeWrapped() {
7110
7110
  if (sonic.fd !== 1 && sonic.fd !== 2) {
7111
- fs37.close(sonic.fd, done);
7111
+ fs38.close(sonic.fd, done);
7112
7112
  } else {
7113
7113
  done();
7114
7114
  }
@@ -10243,11 +10243,11 @@ var init_lib = __esm({
10243
10243
  }
10244
10244
  }
10245
10245
  },
10246
- addToPath: function addToPath(path46, added, removed, oldPosInc, options) {
10247
- var last = path46.lastComponent;
10246
+ addToPath: function addToPath(path47, added, removed, oldPosInc, options) {
10247
+ var last = path47.lastComponent;
10248
10248
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
10249
10249
  return {
10250
- oldPos: path46.oldPos + oldPosInc,
10250
+ oldPos: path47.oldPos + oldPosInc,
10251
10251
  lastComponent: {
10252
10252
  count: last.count + 1,
10253
10253
  added,
@@ -10257,7 +10257,7 @@ var init_lib = __esm({
10257
10257
  };
10258
10258
  } else {
10259
10259
  return {
10260
- oldPos: path46.oldPos + oldPosInc,
10260
+ oldPos: path47.oldPos + oldPosInc,
10261
10261
  lastComponent: {
10262
10262
  count: 1,
10263
10263
  added,
@@ -10503,7 +10503,7 @@ function hashDirToCwd(hash) {
10503
10503
  }
10504
10504
  function safeStatMtime(p2) {
10505
10505
  try {
10506
- return import_node_fs7.default.statSync(p2).mtimeMs;
10506
+ return import_node_fs8.default.statSync(p2).mtimeMs;
10507
10507
  } catch {
10508
10508
  return 0;
10509
10509
  }
@@ -10511,7 +10511,7 @@ function safeStatMtime(p2) {
10511
10511
  function readJsonlLines(file) {
10512
10512
  let raw;
10513
10513
  try {
10514
- raw = import_node_fs7.default.readFileSync(file, "utf8");
10514
+ raw = import_node_fs8.default.readFileSync(file, "utf8");
10515
10515
  } catch (err) {
10516
10516
  if (err.code === "ENOENT") return [];
10517
10517
  throw err;
@@ -10688,10 +10688,10 @@ function attachmentToHistoryMessage(o, ts) {
10688
10688
  const memories = raw.map((m2) => {
10689
10689
  if (!m2 || typeof m2 !== "object") return null;
10690
10690
  const rec = m2;
10691
- const path46 = typeof rec.path === "string" ? rec.path : null;
10691
+ const path47 = typeof rec.path === "string" ? rec.path : null;
10692
10692
  const content = typeof rec.content === "string" ? rec.content : null;
10693
- if (!path46 || content == null) return null;
10694
- const entry = { path: path46, content };
10693
+ if (!path47 || content == null) return null;
10694
+ const entry = { path: path47, content };
10695
10695
  if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
10696
10696
  return entry;
10697
10697
  }).filter((m2) => m2 !== null);
@@ -10727,8 +10727,8 @@ function attachmentDeferredToolsText(a) {
10727
10727
  function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
10728
10728
  if (backupFileName === null) return null;
10729
10729
  try {
10730
- return import_node_fs7.default.readFileSync(
10731
- import_node_path8.default.join(fileHistoryRoot, toolSessionId, backupFileName),
10730
+ return import_node_fs8.default.readFileSync(
10731
+ import_node_path9.default.join(fileHistoryRoot, toolSessionId, backupFileName),
10732
10732
  "utf8"
10733
10733
  );
10734
10734
  } catch {
@@ -10737,19 +10737,19 @@ function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
10737
10737
  }
10738
10738
  function readCurrentContent(filePath) {
10739
10739
  try {
10740
- return import_node_fs7.default.readFileSync(filePath, "utf8");
10740
+ return import_node_fs8.default.readFileSync(filePath, "utf8");
10741
10741
  } catch (err) {
10742
10742
  if (err.code === "ENOENT") return null;
10743
10743
  return null;
10744
10744
  }
10745
10745
  }
10746
- var import_node_fs7, import_node_os3, import_node_path8, TASK_NOTIFICATION_RE, TASK_ID_RE, TOOL_USE_ID_RE, SLASH_COMMAND_RE, LOCAL_COMMAND_RE, SYSTEM_REMINDER_RE, OPENSPEC_BLOCK_RE, SKILL_HINT_RE, ATTACHMENT_SILENT_SUBTYPES, ClaudeHistoryReader;
10746
+ var import_node_fs8, import_node_os3, import_node_path9, TASK_NOTIFICATION_RE, TASK_ID_RE, TOOL_USE_ID_RE, SLASH_COMMAND_RE, LOCAL_COMMAND_RE, SYSTEM_REMINDER_RE, OPENSPEC_BLOCK_RE, SKILL_HINT_RE, ATTACHMENT_SILENT_SUBTYPES, ClaudeHistoryReader;
10747
10747
  var init_claude_history = __esm({
10748
10748
  "src/tools/claude-history.ts"() {
10749
10749
  "use strict";
10750
- import_node_fs7 = __toESM(require("fs"), 1);
10750
+ import_node_fs8 = __toESM(require("fs"), 1);
10751
10751
  import_node_os3 = __toESM(require("os"), 1);
10752
- import_node_path8 = __toESM(require("path"), 1);
10752
+ import_node_path9 = __toESM(require("path"), 1);
10753
10753
  init_lib();
10754
10754
  init_tool_result_extra();
10755
10755
  TASK_NOTIFICATION_RE = /<task-notification\b[\s\S]*?<\/task-notification>/i;
@@ -10773,14 +10773,14 @@ var init_claude_history = __esm({
10773
10773
  // 每次 user 提交前 trackEdit 拷一份,作为 rewind 回退目标
10774
10774
  fileHistoryRoot;
10775
10775
  constructor(opts = {}) {
10776
- const base = opts.baseDir ?? import_node_path8.default.join(import_node_os3.default.homedir(), ".claude");
10777
- this.projectsRoot = import_node_path8.default.join(base, "projects");
10778
- this.fileHistoryRoot = import_node_path8.default.join(base, "file-history");
10776
+ const base = opts.baseDir ?? import_node_path9.default.join(import_node_os3.default.homedir(), ".claude");
10777
+ this.projectsRoot = import_node_path9.default.join(base, "projects");
10778
+ this.fileHistoryRoot = import_node_path9.default.join(base, "file-history");
10779
10779
  }
10780
10780
  async listProjects() {
10781
10781
  let entries;
10782
10782
  try {
10783
- entries = import_node_fs7.default.readdirSync(this.projectsRoot, { withFileTypes: true });
10783
+ entries = import_node_fs8.default.readdirSync(this.projectsRoot, { withFileTypes: true });
10784
10784
  } catch (err) {
10785
10785
  if (err.code === "ENOENT") return [];
10786
10786
  throw err;
@@ -10788,9 +10788,9 @@ var init_claude_history = __esm({
10788
10788
  const out = [];
10789
10789
  for (const ent of entries) {
10790
10790
  if (!ent.isDirectory()) continue;
10791
- const dir = import_node_path8.default.join(this.projectsRoot, ent.name);
10792
- const files = import_node_fs7.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
10793
- const updatedAtMs = files.reduce((m2, f) => Math.max(m2, safeStatMtime(import_node_path8.default.join(dir, f))), 0);
10791
+ const dir = import_node_path9.default.join(this.projectsRoot, ent.name);
10792
+ const files = import_node_fs8.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
10793
+ const updatedAtMs = files.reduce((m2, f) => Math.max(m2, safeStatMtime(import_node_path9.default.join(dir, f))), 0);
10794
10794
  out.push({
10795
10795
  projectPath: hashDirToCwd(ent.name),
10796
10796
  hashDir: ent.name,
@@ -10802,17 +10802,17 @@ var init_claude_history = __esm({
10802
10802
  return out;
10803
10803
  }
10804
10804
  async listSessions(args) {
10805
- const dir = import_node_path8.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
10805
+ const dir = import_node_path9.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
10806
10806
  let files;
10807
10807
  try {
10808
- files = import_node_fs7.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
10808
+ files = import_node_fs8.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
10809
10809
  } catch (err) {
10810
10810
  if (err.code === "ENOENT") return [];
10811
10811
  throw err;
10812
10812
  }
10813
10813
  const out = [];
10814
10814
  for (const f of files) {
10815
- const full = import_node_path8.default.join(dir, f);
10815
+ const full = import_node_path9.default.join(dir, f);
10816
10816
  const toolSessionId = f.slice(0, -".jsonl".length);
10817
10817
  const lines = readJsonlLines(full);
10818
10818
  let summary = "";
@@ -10867,7 +10867,7 @@ var init_claude_history = __esm({
10867
10867
  return out;
10868
10868
  }
10869
10869
  async read(args) {
10870
- const file = import_node_path8.default.join(
10870
+ const file = import_node_path9.default.join(
10871
10871
  this.projectsRoot,
10872
10872
  cwdToHashDir(args.cwd),
10873
10873
  `${args.toolSessionId}.jsonl`
@@ -10900,7 +10900,7 @@ var init_claude_history = __esm({
10900
10900
  // 独立目录路径:<projectsRoot>/<cwdHash>/<toolSessionId>/subagents/*.jsonl
10901
10901
  // 返回 null 表示目录不存在(调用方回退旧实现);返回空数组表示目录存在但无 jsonl
10902
10902
  listSubagentsFromDirectory(cwd, toolSessionId) {
10903
- const dir = import_node_path8.default.join(
10903
+ const dir = import_node_path9.default.join(
10904
10904
  this.projectsRoot,
10905
10905
  cwdToHashDir(cwd),
10906
10906
  toolSessionId,
@@ -10908,7 +10908,7 @@ var init_claude_history = __esm({
10908
10908
  );
10909
10909
  let entries;
10910
10910
  try {
10911
- entries = import_node_fs7.default.readdirSync(dir, { withFileTypes: true });
10911
+ entries = import_node_fs8.default.readdirSync(dir, { withFileTypes: true });
10912
10912
  } catch (err) {
10913
10913
  if (err.code === "ENOENT") return null;
10914
10914
  return null;
@@ -10918,7 +10918,7 @@ var init_claude_history = __esm({
10918
10918
  if (!e.isFile()) continue;
10919
10919
  if (!e.name.startsWith("agent-") || !e.name.endsWith(".jsonl")) continue;
10920
10920
  const subagentId = e.name.slice("agent-".length, -".jsonl".length);
10921
- const filePath = import_node_path8.default.join(dir, e.name);
10921
+ const filePath = import_node_path9.default.join(dir, e.name);
10922
10922
  const lines = readJsonlLines(filePath);
10923
10923
  let firstText = "";
10924
10924
  let messageCount = 0;
@@ -10935,7 +10935,7 @@ var init_claude_history = __esm({
10935
10935
  return out;
10936
10936
  }
10937
10937
  listSubagentsFromMainJsonl(cwd, toolSessionId) {
10938
- const file = import_node_path8.default.join(
10938
+ const file = import_node_path9.default.join(
10939
10939
  this.projectsRoot,
10940
10940
  cwdToHashDir(cwd),
10941
10941
  `${toolSessionId}.jsonl`
@@ -10970,7 +10970,7 @@ var init_claude_history = __esm({
10970
10970
  }
10971
10971
  // 独立文件路径:agent-<subagentId>.jsonl;文件不存在返回 null 让调用方回退旧实现
10972
10972
  readSubagentFromFile(cwd, toolSessionId, subagentId) {
10973
- const file = import_node_path8.default.join(
10973
+ const file = import_node_path9.default.join(
10974
10974
  this.projectsRoot,
10975
10975
  cwdToHashDir(cwd),
10976
10976
  toolSessionId,
@@ -10979,7 +10979,7 @@ var init_claude_history = __esm({
10979
10979
  );
10980
10980
  let exists = false;
10981
10981
  try {
10982
- exists = import_node_fs7.default.statSync(file).isFile();
10982
+ exists = import_node_fs8.default.statSync(file).isFile();
10983
10983
  } catch {
10984
10984
  return null;
10985
10985
  }
@@ -10998,7 +10998,7 @@ var init_claude_history = __esm({
10998
10998
  * "那一刻每个 tracked 文件对应的 backup 文件名"
10999
10999
  */
11000
11000
  readFileHistorySnapshots(args) {
11001
- const file = import_node_path8.default.join(
11001
+ const file = import_node_path9.default.join(
11002
11002
  this.projectsRoot,
11003
11003
  cwdToHashDir(args.cwd),
11004
11004
  `${args.toolSessionId}.jsonl`
@@ -11043,7 +11043,7 @@ var init_claude_history = __esm({
11043
11043
  for (const [anchorId, target] of snapshots) {
11044
11044
  let hasAny = false;
11045
11045
  for (const [rawPath, backup] of Object.entries(target)) {
11046
- const absPath = import_node_path8.default.isAbsolute(rawPath) ? rawPath : import_node_path8.default.join(args.cwd, rawPath);
11046
+ const absPath = import_node_path9.default.isAbsolute(rawPath) ? rawPath : import_node_path9.default.join(args.cwd, rawPath);
11047
11047
  const backupContent = readBackupContent(
11048
11048
  this.fileHistoryRoot,
11049
11049
  args.toolSessionId,
@@ -11083,7 +11083,7 @@ var init_claude_history = __esm({
11083
11083
  let totalInsertions = 0;
11084
11084
  let totalDeletions = 0;
11085
11085
  for (const [rawPath, backup] of Object.entries(target)) {
11086
- const absPath = import_node_path8.default.isAbsolute(rawPath) ? rawPath : import_node_path8.default.join(args.cwd, rawPath);
11086
+ const absPath = import_node_path9.default.isAbsolute(rawPath) ? rawPath : import_node_path9.default.join(args.cwd, rawPath);
11087
11087
  const backupContent = readBackupContent(
11088
11088
  this.fileHistoryRoot,
11089
11089
  args.toolSessionId,
@@ -11130,7 +11130,7 @@ var init_claude_history = __esm({
11130
11130
  };
11131
11131
  }
11132
11132
  readSubagentFromMainJsonl(cwd, toolSessionId, subagentId) {
11133
- const file = import_node_path8.default.join(
11133
+ const file = import_node_path9.default.join(
11134
11134
  this.projectsRoot,
11135
11135
  cwdToHashDir(cwd),
11136
11136
  `${toolSessionId}.jsonl`
@@ -11154,48 +11154,48 @@ var init_claude_history = __esm({
11154
11154
  // src/tools/sandbox.ts
11155
11155
  function shouldSandbox(cwd, personaRoot) {
11156
11156
  if (!personaRoot) return false;
11157
- const sep3 = personaRoot.endsWith(path12.sep) ? "" : path12.sep;
11157
+ const sep3 = personaRoot.endsWith(path13.sep) ? "" : path13.sep;
11158
11158
  return cwd.startsWith(personaRoot + sep3) && cwd !== personaRoot;
11159
11159
  }
11160
11160
  function inferSandboxSettingsPath(cwd, personaRoot) {
11161
11161
  if (!shouldSandbox(cwd, personaRoot)) return null;
11162
- const rel = path12.relative(personaRoot, cwd);
11163
- const personaId = rel.split(path12.sep)[0];
11162
+ const rel = path13.relative(personaRoot, cwd);
11163
+ const personaId = rel.split(path13.sep)[0];
11164
11164
  if (!personaId) return null;
11165
- return path12.join(personaRoot, personaId, ".clawd", "sandbox-settings.json");
11165
+ return path13.join(personaRoot, personaId, ".clawd", "sandbox-settings.json");
11166
11166
  }
11167
- var path12;
11167
+ var path13;
11168
11168
  var init_sandbox = __esm({
11169
11169
  "src/tools/sandbox.ts"() {
11170
11170
  "use strict";
11171
- path12 = __toESM(require("path"), 1);
11171
+ path13 = __toESM(require("path"), 1);
11172
11172
  }
11173
11173
  });
11174
11174
 
11175
11175
  // src/tools/claude.ts
11176
11176
  function macOSDesktopCandidates(home) {
11177
11177
  return [
11178
- import_node_path9.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
11178
+ import_node_path10.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
11179
11179
  "/Applications/Claude.app/Contents/Resources/app.asar.unpacked/node_modules/@anthropic-ai/claude-code/cli.js"
11180
11180
  ];
11181
11181
  }
11182
11182
  function probeViaWhich() {
11183
11183
  try {
11184
11184
  const out = (0, import_node_child_process2.execFileSync)("which", ["claude"], { encoding: "utf8" }).trim();
11185
- if (out && import_node_fs8.default.existsSync(out)) return out;
11185
+ if (out && import_node_fs9.default.existsSync(out)) return out;
11186
11186
  } catch {
11187
11187
  }
11188
11188
  return null;
11189
11189
  }
11190
11190
  async function probeClaude(env = process.env, home = import_node_os4.default.homedir()) {
11191
- if (env.CLAUDE_BIN && import_node_fs8.default.existsSync(env.CLAUDE_BIN)) {
11191
+ if (env.CLAUDE_BIN && import_node_fs9.default.existsSync(env.CLAUDE_BIN)) {
11192
11192
  return { available: true, path: env.CLAUDE_BIN };
11193
11193
  }
11194
11194
  const w2 = probeViaWhich();
11195
11195
  if (w2) return { available: true, path: w2 };
11196
11196
  if (process.platform === "darwin") {
11197
11197
  for (const candidate of macOSDesktopCandidates(home)) {
11198
- if (import_node_fs8.default.existsSync(candidate)) {
11198
+ if (import_node_fs9.default.existsSync(candidate)) {
11199
11199
  return { available: true, path: candidate };
11200
11200
  }
11201
11201
  }
@@ -11517,10 +11517,10 @@ function parseAttachment(obj) {
11517
11517
  const memories = raw.map((m2) => {
11518
11518
  if (!m2 || typeof m2 !== "object") return null;
11519
11519
  const rec = m2;
11520
- const path46 = typeof rec.path === "string" ? rec.path : null;
11520
+ const path47 = typeof rec.path === "string" ? rec.path : null;
11521
11521
  const content = typeof rec.content === "string" ? rec.content : null;
11522
- if (!path46 || content == null) return null;
11523
- const out = { path: path46, content };
11522
+ if (!path47 || content == null) return null;
11523
+ const out = { path: path47, content };
11524
11524
  if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
11525
11525
  return out;
11526
11526
  }).filter((m2) => m2 !== null);
@@ -11624,15 +11624,15 @@ function encodeClaudeStdin(text) {
11624
11624
  };
11625
11625
  return JSON.stringify(frame) + "\n";
11626
11626
  }
11627
- var import_node_child_process, import_node_child_process2, import_node_fs8, import_node_os4, import_node_path9, ATTACHMENT_SILENT_SUBTYPES2, unknownTypeHandler, ATTACHMENT_RE, IMAGE_EXT_MIME, CLAUDE_MODELS, CLAUDE_PERMISSION_MODES, CLAUDE_CAPABILITIES, ClaudeAdapter;
11627
+ var import_node_child_process, import_node_child_process2, import_node_fs9, import_node_os4, import_node_path10, ATTACHMENT_SILENT_SUBTYPES2, unknownTypeHandler, ATTACHMENT_RE, IMAGE_EXT_MIME, CLAUDE_MODELS, CLAUDE_PERMISSION_MODES, CLAUDE_CAPABILITIES, ClaudeAdapter;
11628
11628
  var init_claude = __esm({
11629
11629
  "src/tools/claude.ts"() {
11630
11630
  "use strict";
11631
11631
  import_node_child_process = require("child_process");
11632
11632
  import_node_child_process2 = require("child_process");
11633
- import_node_fs8 = __toESM(require("fs"), 1);
11633
+ import_node_fs9 = __toESM(require("fs"), 1);
11634
11634
  import_node_os4 = __toESM(require("os"), 1);
11635
- import_node_path9 = __toESM(require("path"), 1);
11635
+ import_node_path10 = __toESM(require("path"), 1);
11636
11636
  init_protocol();
11637
11637
  init_claude_history();
11638
11638
  init_tool_result_extra();
@@ -20435,7 +20435,7 @@ var require_websocket_server = __commonJS({
20435
20435
  // src/run-case/recorder.ts
20436
20436
  function startRunCaseRecorder(opts) {
20437
20437
  const now = opts.now ?? Date.now;
20438
- const dir = import_node_path32.default.dirname(opts.recordPath);
20438
+ const dir = import_node_path33.default.dirname(opts.recordPath);
20439
20439
  let stream = null;
20440
20440
  let closing = false;
20441
20441
  let closedSettled = false;
@@ -20449,8 +20449,8 @@ function startRunCaseRecorder(opts) {
20449
20449
  });
20450
20450
  const ensureStream = () => {
20451
20451
  if (stream) return stream;
20452
- import_node_fs29.default.mkdirSync(dir, { recursive: true });
20453
- stream = import_node_fs29.default.createWriteStream(opts.recordPath, { flags: "a" });
20452
+ import_node_fs30.default.mkdirSync(dir, { recursive: true });
20453
+ stream = import_node_fs30.default.createWriteStream(opts.recordPath, { flags: "a" });
20454
20454
  stream.on("close", () => closedResolve());
20455
20455
  return stream;
20456
20456
  };
@@ -20475,12 +20475,12 @@ function startRunCaseRecorder(opts) {
20475
20475
  };
20476
20476
  return { tap, close, closed };
20477
20477
  }
20478
- var import_node_fs29, import_node_path32;
20478
+ var import_node_fs30, import_node_path33;
20479
20479
  var init_recorder = __esm({
20480
20480
  "src/run-case/recorder.ts"() {
20481
20481
  "use strict";
20482
- import_node_fs29 = __toESM(require("fs"), 1);
20483
- import_node_path32 = __toESM(require("path"), 1);
20482
+ import_node_fs30 = __toESM(require("fs"), 1);
20483
+ import_node_path33 = __toESM(require("path"), 1);
20484
20484
  }
20485
20485
  });
20486
20486
 
@@ -20523,7 +20523,7 @@ var init_wire = __esm({
20523
20523
  // src/run-case/controller.ts
20524
20524
  async function runController(opts) {
20525
20525
  const now = opts.now ?? Date.now;
20526
- const cwd = opts.cwd ?? (0, import_node_fs30.mkdtempSync)(import_node_path33.default.join(import_node_os15.default.tmpdir(), "clawd-runcase-"));
20526
+ const cwd = opts.cwd ?? (0, import_node_fs31.mkdtempSync)(import_node_path34.default.join(import_node_os15.default.tmpdir(), "clawd-runcase-"));
20527
20527
  const ownsCwd = opts.cwd === void 0;
20528
20528
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
20529
20529
  const spawnCtx = { cwd };
@@ -20684,19 +20684,19 @@ async function runController(opts) {
20684
20684
  if (sigintHandler) process.off("SIGINT", sigintHandler);
20685
20685
  if (ownsCwd) {
20686
20686
  try {
20687
- (0, import_node_fs30.rmSync)(cwd, { recursive: true, force: true });
20687
+ (0, import_node_fs31.rmSync)(cwd, { recursive: true, force: true });
20688
20688
  } catch {
20689
20689
  }
20690
20690
  }
20691
20691
  return exitCode ?? 0;
20692
20692
  }
20693
- var import_node_fs30, import_node_os15, import_node_path33;
20693
+ var import_node_fs31, import_node_os15, import_node_path34;
20694
20694
  var init_controller = __esm({
20695
20695
  "src/run-case/controller.ts"() {
20696
20696
  "use strict";
20697
- import_node_fs30 = require("fs");
20697
+ import_node_fs31 = require("fs");
20698
20698
  import_node_os15 = __toESM(require("os"), 1);
20699
- import_node_path33 = __toESM(require("path"), 1);
20699
+ import_node_path34 = __toESM(require("path"), 1);
20700
20700
  init_claude();
20701
20701
  init_stdout_splitter();
20702
20702
  init_permission_stdio();
@@ -20928,8 +20928,8 @@ Env (advanced):
20928
20928
  `;
20929
20929
 
20930
20930
  // src/index.ts
20931
- var import_node_path31 = __toESM(require("path"), 1);
20932
- var import_node_fs28 = __toESM(require("fs"), 1);
20931
+ var import_node_path32 = __toESM(require("path"), 1);
20932
+ var import_node_fs29 = __toESM(require("fs"), 1);
20933
20933
 
20934
20934
  // src/logger.ts
20935
20935
  var import_node_fs2 = __toESM(require("fs"), 1);
@@ -21153,8 +21153,8 @@ var SessionStoreFactory = class {
21153
21153
  };
21154
21154
 
21155
21155
  // src/session/manager.ts
21156
- var import_node_fs5 = __toESM(require("fs"), 1);
21157
- var import_node_path6 = __toESM(require("path"), 1);
21156
+ var import_node_fs6 = __toESM(require("fs"), 1);
21157
+ var import_node_path7 = __toESM(require("path"), 1);
21158
21158
 
21159
21159
  // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
21160
21160
  var byteToHex = [];
@@ -22398,6 +22398,62 @@ function extractEditPath(input) {
22398
22398
  return candidate || null;
22399
22399
  }
22400
22400
 
22401
+ // src/debug/pty-probe.ts
22402
+ var import_node_fs5 = __toESM(require("fs"), 1);
22403
+ var import_node_path6 = __toESM(require("path"), 1);
22404
+ var PROBE_DIR = "/tmp/clawd-probe";
22405
+ var EVENTS_FILE = import_node_path6.default.join(PROBE_DIR, "events.jsonl");
22406
+ var inited = false;
22407
+ function ensureDir() {
22408
+ if (inited) return true;
22409
+ try {
22410
+ import_node_fs5.default.mkdirSync(PROBE_DIR, { recursive: true });
22411
+ inited = true;
22412
+ return true;
22413
+ } catch {
22414
+ return false;
22415
+ }
22416
+ }
22417
+ function probeEvent(event, data = {}) {
22418
+ try {
22419
+ if (!ensureDir()) return;
22420
+ const line = JSON.stringify({ ts: Date.now(), event, ...data }) + "\n";
22421
+ import_node_fs5.default.appendFileSync(EVENTS_FILE, line);
22422
+ } catch {
22423
+ }
22424
+ }
22425
+ function probeDumpReplay(sessionId, payload) {
22426
+ try {
22427
+ if (!ensureDir()) return "";
22428
+ const file = import_node_path6.default.join(PROBE_DIR, `replay-${sessionId}-${Date.now()}.ans`);
22429
+ import_node_fs5.default.writeFileSync(file, payload, "utf8");
22430
+ return file;
22431
+ } catch {
22432
+ return "";
22433
+ }
22434
+ }
22435
+ var _throttle = /* @__PURE__ */ new Map();
22436
+ function probePtyDataThrottled(tsid, len, tail) {
22437
+ const now = Date.now();
22438
+ let s = _throttle.get(tsid);
22439
+ if (!s) {
22440
+ s = { last: 0, bytes: 0, chunks: 0 };
22441
+ _throttle.set(tsid, s);
22442
+ }
22443
+ s.bytes += len;
22444
+ s.chunks += 1;
22445
+ if (now - s.last >= 1e3) {
22446
+ probeEvent("pty.data", {
22447
+ tsid,
22448
+ chunks: s.chunks,
22449
+ accumBytes: s.bytes,
22450
+ lastChunkLen: len,
22451
+ tailHex: tail.subarray(Math.max(0, tail.length - 32)).toString("hex")
22452
+ });
22453
+ s.last = now;
22454
+ }
22455
+ }
22456
+
22401
22457
  // src/session/manager.ts
22402
22458
  function compressFrameForWire(frame) {
22403
22459
  if (frame.type !== "session:status") return frame;
@@ -22461,7 +22517,7 @@ function derivePersonaSpawnCwd(file, personaRoot) {
22461
22517
  `derivePersonaSpawnCwd: personaRoot missing for owner session ${file.sessionId} (ownerPersonaId=${personaId})`
22462
22518
  );
22463
22519
  }
22464
- return import_node_path6.default.join(personaRoot, safeFileName(personaId));
22520
+ return import_node_path7.default.join(personaRoot, safeFileName(personaId));
22465
22521
  }
22466
22522
  function makeInitialState(file, subSessionMeta) {
22467
22523
  return {
@@ -22575,10 +22631,10 @@ var SessionManager = class {
22575
22631
  // <dataDir>/sessions/ 列子目录 (排除 'default').
22576
22632
  listPersonaIdsOnDisk() {
22577
22633
  if (!this.deps.dataDir) return [];
22578
- const root = this.deps.storeFactory ? import_node_path6.default.join(this.deps.dataDir, "personas") : import_node_path6.default.join(this.deps.dataDir, "sessions");
22634
+ const root = this.deps.storeFactory ? import_node_path7.default.join(this.deps.dataDir, "personas") : import_node_path7.default.join(this.deps.dataDir, "sessions");
22579
22635
  let entries;
22580
22636
  try {
22581
- entries = import_node_fs5.default.readdirSync(root, { withFileTypes: true });
22637
+ entries = import_node_fs6.default.readdirSync(root, { withFileTypes: true });
22582
22638
  } catch (err) {
22583
22639
  const code = err?.code;
22584
22640
  if (code === "ENOENT") return [];
@@ -22591,7 +22647,7 @@ var SessionManager = class {
22591
22647
  // 只在 storeFactory 注入 (新布局) 下生效, 老布局无 guest 目录.
22592
22648
  listGuestCapIdsForPersona(personaId) {
22593
22649
  if (!this.deps.dataDir || !this.deps.storeFactory) return [];
22594
- const root = import_node_path6.default.join(
22650
+ const root = import_node_path7.default.join(
22595
22651
  this.deps.dataDir,
22596
22652
  "personas",
22597
22653
  personaId,
@@ -22601,7 +22657,7 @@ var SessionManager = class {
22601
22657
  );
22602
22658
  let entries;
22603
22659
  try {
22604
- entries = import_node_fs5.default.readdirSync(root, { withFileTypes: true });
22660
+ entries = import_node_fs6.default.readdirSync(root, { withFileTypes: true });
22605
22661
  } catch (err) {
22606
22662
  const code = err?.code;
22607
22663
  if (code === "ENOENT") return [];
@@ -22838,7 +22894,7 @@ var SessionManager = class {
22838
22894
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "cwd required when ownerPersonaId is absent");
22839
22895
  }
22840
22896
  try {
22841
- const stat = import_node_fs5.default.statSync(cwd);
22897
+ const stat = import_node_fs6.default.statSync(cwd);
22842
22898
  if (!stat.isDirectory()) throw new Error("not dir");
22843
22899
  } catch {
22844
22900
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `cwd not a directory: ${cwd}`);
@@ -23374,7 +23430,7 @@ var SessionManager = class {
23374
23430
  */
23375
23431
  createForScope(args) {
23376
23432
  try {
23377
- const stat = import_node_fs5.default.statSync(args.cwd);
23433
+ const stat = import_node_fs6.default.statSync(args.cwd);
23378
23434
  if (!stat.isDirectory()) throw new Error("not dir");
23379
23435
  } catch {
23380
23436
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `cwd not a directory: ${args.cwd}`);
@@ -23709,15 +23765,27 @@ var SessionManager = class {
23709
23765
  }
23710
23766
  /** spawn 进程 exit 时调用,清理映射防止后续 input 写到已死 pty + 释放 replay 闭包 */
23711
23767
  unregisterPty(toolSessionId) {
23768
+ const hadReplay = this.ptyReplaysByToolSid.has(toolSessionId);
23712
23769
  this.ptyTransports.delete(toolSessionId);
23713
23770
  this.ptyReplaysByToolSid.delete(toolSessionId);
23771
+ probeEvent("pty.unregister", {
23772
+ tsid: toolSessionId,
23773
+ hadReplay,
23774
+ replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
23775
+ });
23714
23776
  }
23715
23777
  /**
23716
23778
  * ClaudeTuiAdapter.spawn 创建 detector 后调用,注册当前屏幕快照闭包。
23717
23779
  * 同一 toolSessionId 重 spawn 会覆盖;unregisterPty 时一并删除。
23718
23780
  */
23719
23781
  registerPtyReplay(toolSessionId, replay) {
23782
+ const overwrite = this.ptyReplaysByToolSid.has(toolSessionId);
23720
23783
  this.ptyReplaysByToolSid.set(toolSessionId, replay);
23784
+ probeEvent("pty.register", {
23785
+ tsid: toolSessionId,
23786
+ overwrite,
23787
+ replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
23788
+ });
23721
23789
  }
23722
23790
  /**
23723
23791
  * 新 client subscribe 时拉当前屏幕快照。返回 null 表示无可重放数据:
@@ -23726,14 +23794,47 @@ var SessionManager = class {
23726
23794
  * 调用方(onSubscribe hook)按返回值非空时构造 session:pty + session:control 帧定向回放
23727
23795
  */
23728
23796
  getPtyReplay(sessionId) {
23729
- if (this.deps.mode !== "tui") return null;
23797
+ if (this.deps.mode !== "tui") {
23798
+ probeEvent("replay.request", { sid: sessionId, result: "not-tui-mode" });
23799
+ return null;
23800
+ }
23730
23801
  const runner = this.runners.get(sessionId);
23731
- if (!runner) return null;
23802
+ if (!runner) {
23803
+ probeEvent("replay.request", {
23804
+ sid: sessionId,
23805
+ result: "no-runner",
23806
+ runnerKeys: Array.from(this.runners.keys())
23807
+ });
23808
+ return null;
23809
+ }
23732
23810
  const tsid = runner.getState().file.toolSessionId;
23733
- if (!tsid) return null;
23811
+ if (!tsid) {
23812
+ probeEvent("replay.request", { sid: sessionId, result: "no-tsid" });
23813
+ return null;
23814
+ }
23734
23815
  const replay = this.ptyReplaysByToolSid.get(tsid);
23735
- if (!replay) return null;
23736
- return replay();
23816
+ if (!replay) {
23817
+ probeEvent("replay.request", {
23818
+ sid: sessionId,
23819
+ tsid,
23820
+ result: "no-replay-closure",
23821
+ replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
23822
+ });
23823
+ return null;
23824
+ }
23825
+ const snap = replay();
23826
+ const dumpFile = probeDumpReplay(sessionId, snap.data);
23827
+ probeEvent("replay.dump", {
23828
+ sid: sessionId,
23829
+ tsid,
23830
+ bytes: snap.data.length,
23831
+ popupKind: snap.popupKind,
23832
+ headHex: Buffer.from(snap.data, "utf8").subarray(0, 32).toString("hex"),
23833
+ dumpFile,
23834
+ runnerKeys: Array.from(this.runners.keys()),
23835
+ replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
23836
+ });
23837
+ return snap;
23737
23838
  }
23738
23839
  /**
23739
23840
  * handler tui:pty:input / tui:pty:resize 入口:传 wire 层 sessionId(16 字符),
@@ -23796,8 +23897,8 @@ var SessionManager = class {
23796
23897
  };
23797
23898
 
23798
23899
  // src/persona/store.ts
23799
- var fs6 = __toESM(require("fs"), 1);
23800
- var path8 = __toESM(require("path"), 1);
23900
+ var fs7 = __toESM(require("fs"), 1);
23901
+ var path9 = __toESM(require("path"), 1);
23801
23902
  init_protocol();
23802
23903
  var DEFAULT_SETTINGS = {
23803
23904
  permissions: {
@@ -23822,17 +23923,17 @@ var DEFAULT_SETTINGS = {
23822
23923
  var PersonaStore = class {
23823
23924
  constructor(root) {
23824
23925
  this.root = root;
23825
- fs6.mkdirSync(root, { recursive: true });
23926
+ fs7.mkdirSync(root, { recursive: true });
23826
23927
  }
23827
23928
  root;
23828
23929
  personaDir(personaId) {
23829
- return path8.join(this.root, safeFileName(personaId));
23930
+ return path9.join(this.root, safeFileName(personaId));
23830
23931
  }
23831
23932
  metaPath(personaId) {
23832
- return path8.join(this.personaDir(personaId), ".clawd", "persona.json");
23933
+ return path9.join(this.personaDir(personaId), ".clawd", "persona.json");
23833
23934
  }
23834
23935
  claudeMdPath(personaId) {
23835
- return path8.join(this.personaDir(personaId), "CLAUDE.md");
23936
+ return path9.join(this.personaDir(personaId), "CLAUDE.md");
23836
23937
  }
23837
23938
  /**
23838
23939
  * Sandbox settings 落盘路径 —— 故意放在 `.clawd/` 而不是 `.claude/`,让 CC 的
@@ -23842,11 +23943,11 @@ var PersonaStore = class {
23842
23943
  * 加载 persona 人格,只有 listener 多一层 OS sandbox。
23843
23944
  */
23844
23945
  sandboxSettingsPath(personaId) {
23845
- return path8.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
23946
+ return path9.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
23846
23947
  }
23847
23948
  write(persona, personality) {
23848
23949
  const dir = this.personaDir(persona.personaId);
23849
- fs6.mkdirSync(path8.join(dir, ".clawd"), { recursive: true });
23950
+ fs7.mkdirSync(path9.join(dir, ".clawd"), { recursive: true });
23850
23951
  this.atomicWrite(this.claudeMdPath(persona.personaId), personality);
23851
23952
  this.atomicWrite(
23852
23953
  this.sandboxSettingsPath(persona.personaId),
@@ -23862,8 +23963,8 @@ var PersonaStore = class {
23862
23963
  }
23863
23964
  read(personaId) {
23864
23965
  const p2 = this.metaPath(personaId);
23865
- if (!fs6.existsSync(p2)) return null;
23866
- const raw = JSON.parse(fs6.readFileSync(p2, "utf8"));
23966
+ if (!fs7.existsSync(p2)) return null;
23967
+ const raw = JSON.parse(fs7.readFileSync(p2, "utf8"));
23867
23968
  if (raw && typeof raw === "object" && "tokenMap" in raw) {
23868
23969
  delete raw.tokenMap;
23869
23970
  this.atomicWrite(p2, JSON.stringify(raw, null, 2));
@@ -23871,12 +23972,12 @@ var PersonaStore = class {
23871
23972
  return PersonaFileSchema.parse(raw);
23872
23973
  }
23873
23974
  has(personaId) {
23874
- return fs6.existsSync(this.metaPath(personaId));
23975
+ return fs7.existsSync(this.metaPath(personaId));
23875
23976
  }
23876
23977
  readPersonality(personaId) {
23877
23978
  const p2 = this.claudeMdPath(personaId);
23878
- if (!fs6.existsSync(p2)) return null;
23879
- return fs6.readFileSync(p2, "utf8");
23979
+ if (!fs7.existsSync(p2)) return null;
23980
+ return fs7.readFileSync(p2, "utf8");
23880
23981
  }
23881
23982
  /**
23882
23983
  * 读 sandbox-settings.json 当前内容;文件不存在 / JSON 解析失败均返回 null。
@@ -23884,23 +23985,23 @@ var PersonaStore = class {
23884
23985
  */
23885
23986
  readSandboxSettings(personaId) {
23886
23987
  const p2 = this.sandboxSettingsPath(personaId);
23887
- if (!fs6.existsSync(p2)) return null;
23988
+ if (!fs7.existsSync(p2)) return null;
23888
23989
  try {
23889
- return JSON.parse(fs6.readFileSync(p2, "utf8"));
23990
+ return JSON.parse(fs7.readFileSync(p2, "utf8"));
23890
23991
  } catch {
23891
23992
  return null;
23892
23993
  }
23893
23994
  }
23894
23995
  /** Persona 私有 skills 目录路径:<personaDir>/.claude/skills */
23895
23996
  skillsDir(personaId) {
23896
- return path8.join(this.personaDir(personaId), ".claude", "skills");
23997
+ return path9.join(this.personaDir(personaId), ".claude", "skills");
23897
23998
  }
23898
23999
  /**
23899
24000
  * Claude Code 项目级 settings 路径:`<personaDir>/.claude/settings.json`。
23900
24001
  * 这里只读 `enabledPlugins` 字段,由 owner 通过 CC `/plugin` 之类命令维护,daemon 不写。
23901
24002
  */
23902
24003
  claudeSettingsPath(personaId) {
23903
- return path8.join(this.personaDir(personaId), ".claude", "settings.json");
24004
+ return path9.join(this.personaDir(personaId), ".claude", "settings.json");
23904
24005
  }
23905
24006
  /**
23906
24007
  * 读取 persona 的 `.claude/settings.json` 中 `enabledPlugins` map,把 value === true
@@ -23915,10 +24016,10 @@ var PersonaStore = class {
23915
24016
  */
23916
24017
  readEnabledPlugins(personaId) {
23917
24018
  const p2 = this.claudeSettingsPath(personaId);
23918
- if (!fs6.existsSync(p2)) return [];
24019
+ if (!fs7.existsSync(p2)) return [];
23919
24020
  let raw;
23920
24021
  try {
23921
- raw = JSON.parse(fs6.readFileSync(p2, "utf8"));
24022
+ raw = JSON.parse(fs7.readFileSync(p2, "utf8"));
23922
24023
  } catch {
23923
24024
  return [];
23924
24025
  }
@@ -23932,22 +24033,22 @@ var PersonaStore = class {
23932
24033
  return out;
23933
24034
  }
23934
24035
  list() {
23935
- if (!fs6.existsSync(this.root)) return [];
23936
- return fs6.readdirSync(this.root).filter((name) => {
23937
- return fs6.existsSync(path8.join(this.root, name, ".clawd", "persona.json"));
24036
+ if (!fs7.existsSync(this.root)) return [];
24037
+ return fs7.readdirSync(this.root).filter((name) => {
24038
+ return fs7.existsSync(path9.join(this.root, name, ".clawd", "persona.json"));
23938
24039
  });
23939
24040
  }
23940
24041
  remove(personaId) {
23941
24042
  const dir = this.personaDir(personaId);
23942
- if (fs6.existsSync(dir)) fs6.rmSync(dir, { recursive: true, force: true });
24043
+ if (fs7.existsSync(dir)) fs7.rmSync(dir, { recursive: true, force: true });
23943
24044
  }
23944
24045
  personaDirPath(personaId) {
23945
24046
  return this.personaDir(personaId);
23946
24047
  }
23947
24048
  atomicWrite(file, content) {
23948
24049
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
23949
- fs6.writeFileSync(tmp, content, { mode: 384 });
23950
- fs6.renameSync(tmp, file);
24050
+ fs7.writeFileSync(tmp, content, { mode: 384 });
24051
+ fs7.renameSync(tmp, file);
23951
24052
  }
23952
24053
  };
23953
24054
 
@@ -23993,9 +24094,9 @@ var PersonaRegistry = class {
23993
24094
  var import_node_crypto3 = __toESM(require("crypto"), 1);
23994
24095
 
23995
24096
  // src/skills/scanner.ts
23996
- var import_node_fs6 = __toESM(require("fs"), 1);
24097
+ var import_node_fs7 = __toESM(require("fs"), 1);
23997
24098
  var import_node_os2 = __toESM(require("os"), 1);
23998
- var import_node_path7 = __toESM(require("path"), 1);
24099
+ var import_node_path8 = __toESM(require("path"), 1);
23999
24100
 
24000
24101
  // src/skills/frontmatter.ts
24001
24102
  var STRIP_QUOTES = /^["']|["']$/g;
@@ -24104,7 +24205,7 @@ function parseDescription(content) {
24104
24205
  }
24105
24206
  function isDirLikeSync(p2) {
24106
24207
  try {
24107
- return import_node_fs6.default.statSync(p2).isDirectory();
24208
+ return import_node_fs7.default.statSync(p2).isDirectory();
24108
24209
  } catch {
24109
24210
  return false;
24110
24211
  }
@@ -24112,19 +24213,19 @@ function isDirLikeSync(p2) {
24112
24213
  function scanSkillDir(dir, source, seen, out, pluginName) {
24113
24214
  let entries;
24114
24215
  try {
24115
- entries = import_node_fs6.default.readdirSync(dir, { withFileTypes: true });
24216
+ entries = import_node_fs7.default.readdirSync(dir, { withFileTypes: true });
24116
24217
  } catch {
24117
24218
  return;
24118
24219
  }
24119
24220
  for (const ent of entries) {
24120
- const entryPath = import_node_path7.default.join(dir, ent.name);
24221
+ const entryPath = import_node_path8.default.join(dir, ent.name);
24121
24222
  if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
24122
24223
  let content;
24123
24224
  try {
24124
- content = import_node_fs6.default.readFileSync(import_node_path7.default.join(entryPath, "SKILL.md"), "utf8");
24225
+ content = import_node_fs7.default.readFileSync(import_node_path8.default.join(entryPath, "SKILL.md"), "utf8");
24125
24226
  } catch {
24126
24227
  try {
24127
- content = import_node_fs6.default.readFileSync(import_node_path7.default.join(entryPath, "skill.md"), "utf8");
24228
+ content = import_node_fs7.default.readFileSync(import_node_path8.default.join(entryPath, "skill.md"), "utf8");
24128
24229
  } catch {
24129
24230
  continue;
24130
24231
  }
@@ -24148,26 +24249,26 @@ function listSkillsForDir(dir, source) {
24148
24249
  function scanCommandDir(dir, source, seen, out, pluginName) {
24149
24250
  let entries;
24150
24251
  try {
24151
- entries = import_node_fs6.default.readdirSync(dir, { withFileTypes: true });
24252
+ entries = import_node_fs7.default.readdirSync(dir, { withFileTypes: true });
24152
24253
  } catch {
24153
24254
  return;
24154
24255
  }
24155
24256
  for (const ent of entries) {
24156
- const entryPath = import_node_path7.default.join(dir, ent.name);
24257
+ const entryPath = import_node_path8.default.join(dir, ent.name);
24157
24258
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
24158
24259
  const ns = ent.name;
24159
24260
  let subEntries;
24160
24261
  try {
24161
- subEntries = import_node_fs6.default.readdirSync(entryPath, { withFileTypes: true });
24262
+ subEntries = import_node_fs7.default.readdirSync(entryPath, { withFileTypes: true });
24162
24263
  } catch {
24163
24264
  continue;
24164
24265
  }
24165
24266
  for (const se of subEntries) {
24166
24267
  if (!se.name.endsWith(".md")) continue;
24167
- const sePath = import_node_path7.default.join(entryPath, se.name);
24268
+ const sePath = import_node_path8.default.join(entryPath, se.name);
24168
24269
  let content;
24169
24270
  try {
24170
- content = import_node_fs6.default.readFileSync(sePath, "utf8");
24271
+ content = import_node_fs7.default.readFileSync(sePath, "utf8");
24171
24272
  } catch {
24172
24273
  continue;
24173
24274
  }
@@ -24184,7 +24285,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
24184
24285
  } else if (ent.name.endsWith(".md")) {
24185
24286
  let content;
24186
24287
  try {
24187
- content = import_node_fs6.default.readFileSync(entryPath, "utf8");
24288
+ content = import_node_fs7.default.readFileSync(entryPath, "utf8");
24188
24289
  } catch {
24189
24290
  continue;
24190
24291
  }
@@ -24200,10 +24301,10 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
24200
24301
  }
24201
24302
  }
24202
24303
  function readInstalledPlugins(home) {
24203
- const file = import_node_path7.default.join(home, ".claude", "plugins", "installed_plugins.json");
24304
+ const file = import_node_path8.default.join(home, ".claude", "plugins", "installed_plugins.json");
24204
24305
  let raw;
24205
24306
  try {
24206
- raw = import_node_fs6.default.readFileSync(file, "utf8");
24307
+ raw = import_node_fs7.default.readFileSync(file, "utf8");
24207
24308
  } catch {
24208
24309
  return [];
24209
24310
  }
@@ -24251,14 +24352,14 @@ var SkillsScanner = class {
24251
24352
  });
24252
24353
  }
24253
24354
  const fsBlock = [];
24254
- scanSkillDir(import_node_path7.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
24255
- scanCommandDir(import_node_path7.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
24256
- scanSkillDir(import_node_path7.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
24257
- scanCommandDir(import_node_path7.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
24355
+ scanSkillDir(import_node_path8.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
24356
+ scanCommandDir(import_node_path8.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
24357
+ scanSkillDir(import_node_path8.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
24358
+ scanCommandDir(import_node_path8.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
24258
24359
  const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
24259
24360
  for (const { name, root } of plugins) {
24260
- scanSkillDir(import_node_path7.default.join(root, "skills"), "plugin", seen, fsBlock, name);
24261
- scanCommandDir(import_node_path7.default.join(root, "commands"), "plugin", seen, fsBlock, name);
24361
+ scanSkillDir(import_node_path8.default.join(root, "skills"), "plugin", seen, fsBlock, name);
24362
+ scanCommandDir(import_node_path8.default.join(root, "commands"), "plugin", seen, fsBlock, name);
24262
24363
  }
24263
24364
  fsBlock.sort((a, b2) => a.name < b2.name ? -1 : a.name > b2.name ? 1 : 0);
24264
24365
  return [...builtinBlock, ...fsBlock];
@@ -24363,8 +24464,8 @@ var PersonaManager = class {
24363
24464
  };
24364
24465
 
24365
24466
  // src/persona/seed.ts
24366
- var fs8 = __toESM(require("fs"), 1);
24367
- var path10 = __toESM(require("path"), 1);
24467
+ var fs9 = __toESM(require("fs"), 1);
24468
+ var path11 = __toESM(require("path"), 1);
24368
24469
  var import_node_url = require("url");
24369
24470
  var import_meta = {};
24370
24471
  var DEFAULT_PERSONAS = [
@@ -24400,18 +24501,18 @@ var DEFAULT_PERSONAS = [
24400
24501
  function findDefaultsRoot() {
24401
24502
  const candidates = [];
24402
24503
  try {
24403
- const here = path10.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
24404
- candidates.push(path10.resolve(here, "defaults"));
24405
- candidates.push(path10.resolve(here, "persona-defaults"));
24504
+ const here = path11.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
24505
+ candidates.push(path11.resolve(here, "defaults"));
24506
+ candidates.push(path11.resolve(here, "persona-defaults"));
24406
24507
  } catch {
24407
24508
  }
24408
24509
  if (process.argv[1]) {
24409
- const argvDir = path10.dirname(process.argv[1]);
24410
- candidates.push(path10.resolve(argvDir, "persona-defaults"));
24510
+ const argvDir = path11.dirname(process.argv[1]);
24511
+ candidates.push(path11.resolve(argvDir, "persona-defaults"));
24411
24512
  }
24412
24513
  for (const c of candidates) {
24413
24514
  try {
24414
- if (fs8.statSync(c).isDirectory()) return c;
24515
+ if (fs9.statSync(c).isDirectory()) return c;
24415
24516
  } catch {
24416
24517
  }
24417
24518
  }
@@ -24424,8 +24525,8 @@ function seedDefaultPersonas(args) {
24424
24525
  args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
24425
24526
  continue;
24426
24527
  }
24427
- const bundleDir = path10.join(args.defaultsRoot, entry.personaId);
24428
- if (!fs8.existsSync(bundleDir)) {
24528
+ const bundleDir = path11.join(args.defaultsRoot, entry.personaId);
24529
+ if (!fs9.existsSync(bundleDir)) {
24429
24530
  args.logger.warn("persona.seed.skip", {
24430
24531
  personaId: entry.personaId,
24431
24532
  reason: "bundle-missing",
@@ -24433,8 +24534,8 @@ function seedDefaultPersonas(args) {
24433
24534
  });
24434
24535
  continue;
24435
24536
  }
24436
- const claudeMdPath = path10.join(bundleDir, "CLAUDE.md");
24437
- if (!fs8.existsSync(claudeMdPath)) {
24537
+ const claudeMdPath = path11.join(bundleDir, "CLAUDE.md");
24538
+ if (!fs9.existsSync(claudeMdPath)) {
24438
24539
  args.logger.warn("persona.seed.skip", {
24439
24540
  personaId: entry.personaId,
24440
24541
  reason: "no-CLAUDE.md",
@@ -24442,7 +24543,7 @@ function seedDefaultPersonas(args) {
24442
24543
  });
24443
24544
  continue;
24444
24545
  }
24445
- const personality = fs8.readFileSync(claudeMdPath, "utf8");
24546
+ const personality = fs9.readFileSync(claudeMdPath, "utf8");
24446
24547
  const now = Date.now();
24447
24548
  const persona = {
24448
24549
  personaId: entry.personaId,
@@ -24459,14 +24560,14 @@ function seedDefaultPersonas(args) {
24459
24560
  }
24460
24561
  }
24461
24562
  function copyBundleExtras(srcDir, dstDir) {
24462
- for (const entry of fs8.readdirSync(srcDir, { withFileTypes: true })) {
24563
+ for (const entry of fs9.readdirSync(srcDir, { withFileTypes: true })) {
24463
24564
  if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
24464
- const srcPath = path10.join(srcDir, entry.name);
24465
- const dstPath = path10.join(dstDir, entry.name);
24565
+ const srcPath = path11.join(srcDir, entry.name);
24566
+ const dstPath = path11.join(dstDir, entry.name);
24466
24567
  if (entry.isDirectory()) {
24467
- fs8.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
24568
+ fs9.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
24468
24569
  } else if (entry.isFile()) {
24469
- fs8.copyFileSync(srcPath, dstPath);
24570
+ fs9.copyFileSync(srcPath, dstPath);
24470
24571
  }
24471
24572
  }
24472
24573
  }
@@ -24475,9 +24576,9 @@ function copyBundleExtras(srcDir, dstDir) {
24475
24576
  init_claude();
24476
24577
 
24477
24578
  // src/tools/claude-tui.ts
24478
- var import_node_fs9 = __toESM(require("fs"), 1);
24579
+ var import_node_fs10 = __toESM(require("fs"), 1);
24479
24580
  var import_node_os5 = __toESM(require("os"), 1);
24480
- var import_node_path10 = __toESM(require("path"), 1);
24581
+ var import_node_path11 = __toESM(require("path"), 1);
24481
24582
  var import_headless = __toESM(require_xterm_headless(), 1);
24482
24583
 
24483
24584
  // ../node_modules/.pnpm/@xterm+addon-serialize@0.14.0/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs
@@ -25197,6 +25298,11 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
25197
25298
  cwd: ctx.cwd,
25198
25299
  toolSessionId: ctx.toolSessionId
25199
25300
  });
25301
+ probeEvent("pty.spawn", {
25302
+ tsid: ctx.toolSessionId,
25303
+ isResume: jsonlExistsForCtx(ctx),
25304
+ cwd: ctx.cwd
25305
+ });
25200
25306
  const pty = spawnPty({
25201
25307
  command: cmd,
25202
25308
  args,
@@ -25238,8 +25344,12 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
25238
25344
  this.tuiOpts.onPtyData(ctx.toolSessionId, data.toString("base64"));
25239
25345
  }
25240
25346
  void detector.writeBytes(data.toString("utf8"));
25347
+ if (ctx.toolSessionId) {
25348
+ probePtyDataThrottled(ctx.toolSessionId, data.length, data);
25349
+ }
25241
25350
  });
25242
25351
  ptyChild.on("exit", () => {
25352
+ probeEvent("pty.exit", { tsid: ctx.toolSessionId });
25243
25353
  if (ctx.toolSessionId && this.tuiOpts.onPtyUnregister) {
25244
25354
  this.tuiOpts.onPtyUnregister(ctx.toolSessionId);
25245
25355
  }
@@ -25312,9 +25422,9 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
25312
25422
  function jsonlExistsForCtx(ctx) {
25313
25423
  if (!ctx.toolSessionId) return false;
25314
25424
  const home = import_node_os5.default.homedir();
25315
- const file = import_node_path10.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
25425
+ const file = import_node_path11.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
25316
25426
  try {
25317
- return import_node_fs9.default.statSync(file).isFile();
25427
+ return import_node_fs10.default.statSync(file).isFile();
25318
25428
  } catch {
25319
25429
  return false;
25320
25430
  }
@@ -25324,23 +25434,23 @@ function jsonlExistsForCtx(ctx) {
25324
25434
  init_claude_history();
25325
25435
 
25326
25436
  // src/workspace/browser.ts
25327
- var import_node_fs10 = __toESM(require("fs"), 1);
25437
+ var import_node_fs11 = __toESM(require("fs"), 1);
25328
25438
  var import_node_os6 = __toESM(require("os"), 1);
25329
- var import_node_path11 = __toESM(require("path"), 1);
25439
+ var import_node_path12 = __toESM(require("path"), 1);
25330
25440
  init_protocol();
25331
25441
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
25332
25442
  function resolveInsideCwd(cwd, subpath) {
25333
- const absCwd = import_node_path11.default.resolve(cwd);
25334
- const joined = import_node_path11.default.resolve(absCwd, subpath ?? ".");
25335
- const rel = import_node_path11.default.relative(absCwd, joined);
25336
- if (rel.startsWith("..") || import_node_path11.default.isAbsolute(rel)) {
25443
+ const absCwd = import_node_path12.default.resolve(cwd);
25444
+ const joined = import_node_path12.default.resolve(absCwd, subpath ?? ".");
25445
+ const rel = import_node_path12.default.relative(absCwd, joined);
25446
+ if (rel.startsWith("..") || import_node_path12.default.isAbsolute(rel)) {
25337
25447
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
25338
25448
  }
25339
25449
  return joined;
25340
25450
  }
25341
25451
  function ensureCwd(cwd) {
25342
25452
  try {
25343
- const stat = import_node_fs10.default.statSync(cwd);
25453
+ const stat = import_node_fs11.default.statSync(cwd);
25344
25454
  if (!stat.isDirectory()) {
25345
25455
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
25346
25456
  }
@@ -25354,7 +25464,7 @@ var WorkspaceBrowser = class {
25354
25464
  const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os6.default.homedir();
25355
25465
  ensureCwd(cwd);
25356
25466
  const full = resolveInsideCwd(cwd, args.path);
25357
- const dirents = import_node_fs10.default.readdirSync(full, { withFileTypes: true });
25467
+ const dirents = import_node_fs11.default.readdirSync(full, { withFileTypes: true });
25358
25468
  const entries = [];
25359
25469
  for (const d of dirents) {
25360
25470
  if (!args.showHidden && d.name.startsWith(".")) continue;
@@ -25364,7 +25474,7 @@ var WorkspaceBrowser = class {
25364
25474
  mtime: ""
25365
25475
  };
25366
25476
  try {
25367
- const st = import_node_fs10.default.statSync(import_node_path11.default.join(full, d.name));
25477
+ const st = import_node_fs11.default.statSync(import_node_path12.default.join(full, d.name));
25368
25478
  entry.mtime = new Date(st.mtimeMs).toISOString();
25369
25479
  if (d.isFile()) entry.size = st.size;
25370
25480
  } catch {
@@ -25380,14 +25490,14 @@ var WorkspaceBrowser = class {
25380
25490
  read(args) {
25381
25491
  ensureCwd(args.cwd);
25382
25492
  const full = resolveInsideCwd(args.cwd, args.path);
25383
- const st = import_node_fs10.default.statSync(full);
25493
+ const st = import_node_fs11.default.statSync(full);
25384
25494
  if (!st.isFile()) {
25385
25495
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
25386
25496
  }
25387
25497
  if (st.size > MAX_FILE_BYTES) {
25388
25498
  throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
25389
25499
  }
25390
- const buf = import_node_fs10.default.readFileSync(full);
25500
+ const buf = import_node_fs11.default.readFileSync(full);
25391
25501
  const isBinary = buf.includes(0);
25392
25502
  if (isBinary) {
25393
25503
  return {
@@ -25409,20 +25519,20 @@ var WorkspaceBrowser = class {
25409
25519
  };
25410
25520
 
25411
25521
  // src/skills/agents-scanner.ts
25412
- var import_node_fs11 = __toESM(require("fs"), 1);
25522
+ var import_node_fs12 = __toESM(require("fs"), 1);
25413
25523
  var import_node_os7 = __toESM(require("os"), 1);
25414
- var import_node_path12 = __toESM(require("path"), 1);
25524
+ var import_node_path13 = __toESM(require("path"), 1);
25415
25525
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
25416
25526
  function isDirLikeSync2(p2) {
25417
25527
  try {
25418
- return import_node_fs11.default.statSync(p2).isDirectory();
25528
+ return import_node_fs12.default.statSync(p2).isDirectory();
25419
25529
  } catch {
25420
25530
  return false;
25421
25531
  }
25422
25532
  }
25423
25533
  function fileExistsSync(p2) {
25424
25534
  try {
25425
- return import_node_fs11.default.statSync(p2).isFile();
25535
+ return import_node_fs12.default.statSync(p2).isFile();
25426
25536
  } catch {
25427
25537
  return false;
25428
25538
  }
@@ -25430,7 +25540,7 @@ function fileExistsSync(p2) {
25430
25540
  function parseAgentFile(filePath) {
25431
25541
  let content;
25432
25542
  try {
25433
- content = import_node_fs11.default.readFileSync(filePath, "utf8");
25543
+ content = import_node_fs12.default.readFileSync(filePath, "utf8");
25434
25544
  } catch {
25435
25545
  return {};
25436
25546
  }
@@ -25443,16 +25553,16 @@ function parseAgentFile(filePath) {
25443
25553
  function scanAgentsDir(dir, source, seen, out) {
25444
25554
  let entries;
25445
25555
  try {
25446
- entries = import_node_fs11.default.readdirSync(dir, { withFileTypes: true });
25556
+ entries = import_node_fs12.default.readdirSync(dir, { withFileTypes: true });
25447
25557
  } catch {
25448
25558
  return;
25449
25559
  }
25450
25560
  for (const ent of entries) {
25451
25561
  if (!ent.name.endsWith(".md")) continue;
25452
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path12.default.join(dir, ent.name)))) {
25562
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path13.default.join(dir, ent.name)))) {
25453
25563
  continue;
25454
25564
  }
25455
- const filePath = import_node_path12.default.join(dir, ent.name);
25565
+ const filePath = import_node_path13.default.join(dir, ent.name);
25456
25566
  const baseName = ent.name.replace(/\.md$/, "");
25457
25567
  if (seen.has(baseName)) continue;
25458
25568
  seen.add(baseName);
@@ -25470,12 +25580,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
25470
25580
  function walk(dir, namespaces) {
25471
25581
  let entries;
25472
25582
  try {
25473
- entries = import_node_fs11.default.readdirSync(dir, { withFileTypes: true });
25583
+ entries = import_node_fs12.default.readdirSync(dir, { withFileTypes: true });
25474
25584
  } catch {
25475
25585
  return;
25476
25586
  }
25477
25587
  for (const ent of entries) {
25478
- const childPath = import_node_path12.default.join(dir, ent.name);
25588
+ const childPath = import_node_path13.default.join(dir, ent.name);
25479
25589
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
25480
25590
  walk(childPath, [...namespaces, ent.name]);
25481
25591
  continue;
@@ -25500,13 +25610,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
25500
25610
  walk(root, []);
25501
25611
  }
25502
25612
  function readInstalledPlugins2(home) {
25503
- const pluginsDir = import_node_path12.default.join(home, ".claude", "plugins");
25504
- const v2 = import_node_path12.default.join(pluginsDir, "installed_plugins_v2.json");
25505
- const v1 = import_node_path12.default.join(pluginsDir, "installed_plugins.json");
25613
+ const pluginsDir = import_node_path13.default.join(home, ".claude", "plugins");
25614
+ const v2 = import_node_path13.default.join(pluginsDir, "installed_plugins_v2.json");
25615
+ const v1 = import_node_path13.default.join(pluginsDir, "installed_plugins.json");
25506
25616
  let raw = null;
25507
25617
  for (const candidate of [v2, v1]) {
25508
25618
  try {
25509
- raw = import_node_fs11.default.readFileSync(candidate, "utf8");
25619
+ raw = import_node_fs12.default.readFileSync(candidate, "utf8");
25510
25620
  break;
25511
25621
  } catch {
25512
25622
  }
@@ -25531,19 +25641,19 @@ function readInstalledPlugins2(home) {
25531
25641
  return out;
25532
25642
  }
25533
25643
  function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
25534
- let cur = import_node_path12.default.resolve(startCwd);
25535
- const fsRoot = import_node_path12.default.parse(cur).root;
25644
+ let cur = import_node_path13.default.resolve(startCwd);
25645
+ const fsRoot = import_node_path13.default.parse(cur).root;
25536
25646
  while (true) {
25537
- scanAgentsDir(import_node_path12.default.join(cur, ".claude", "agents"), "project", seen, out);
25647
+ scanAgentsDir(import_node_path13.default.join(cur, ".claude", "agents"), "project", seen, out);
25538
25648
  let hasGit = false;
25539
25649
  try {
25540
- hasGit = import_node_fs11.default.existsSync(import_node_path12.default.join(cur, ".git"));
25650
+ hasGit = import_node_fs12.default.existsSync(import_node_path13.default.join(cur, ".git"));
25541
25651
  } catch {
25542
25652
  }
25543
25653
  if (hasGit) return;
25544
25654
  if (cur === home) return;
25545
25655
  if (cur === fsRoot) return;
25546
- const parent = import_node_path12.default.dirname(cur);
25656
+ const parent = import_node_path13.default.dirname(cur);
25547
25657
  if (parent === cur) return;
25548
25658
  cur = parent;
25549
25659
  }
@@ -25578,7 +25688,7 @@ var AgentsScanner = class {
25578
25688
  }
25579
25689
  const fsBlock = [];
25580
25690
  scanAgentsDir(
25581
- import_node_path12.default.join(this.home, ".claude", "agents"),
25691
+ import_node_path13.default.join(this.home, ".claude", "agents"),
25582
25692
  "global",
25583
25693
  seen,
25584
25694
  fsBlock
@@ -25592,7 +25702,7 @@ var AgentsScanner = class {
25592
25702
  ...this.extraPluginRoots
25593
25703
  ];
25594
25704
  for (const { name, root } of plugins) {
25595
- const agentsRoot = import_node_path12.default.join(root, "agents");
25705
+ const agentsRoot = import_node_path13.default.join(root, "agents");
25596
25706
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
25597
25707
  }
25598
25708
  return [...builtinBlock, ...fsBlock];
@@ -25600,15 +25710,15 @@ var AgentsScanner = class {
25600
25710
  };
25601
25711
 
25602
25712
  // src/observer/session-observer.ts
25603
- var import_node_fs13 = __toESM(require("fs"), 1);
25713
+ var import_node_fs14 = __toESM(require("fs"), 1);
25604
25714
  var import_node_os9 = __toESM(require("os"), 1);
25605
- var import_node_path14 = __toESM(require("path"), 1);
25715
+ var import_node_path15 = __toESM(require("path"), 1);
25606
25716
  init_claude_history();
25607
25717
 
25608
25718
  // src/observer/subagent-meta-observer.ts
25609
- var import_node_fs12 = __toESM(require("fs"), 1);
25719
+ var import_node_fs13 = __toESM(require("fs"), 1);
25610
25720
  var import_node_os8 = __toESM(require("os"), 1);
25611
- var import_node_path13 = __toESM(require("path"), 1);
25721
+ var import_node_path14 = __toESM(require("path"), 1);
25612
25722
  init_claude_history();
25613
25723
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
25614
25724
  var SubagentMetaObserver = class {
@@ -25621,7 +25731,7 @@ var SubagentMetaObserver = class {
25621
25731
  watches = /* @__PURE__ */ new Map();
25622
25732
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
25623
25733
  resolveSubagentDir(cwd, toolSessionId) {
25624
- return import_node_path13.default.join(
25734
+ return import_node_path14.default.join(
25625
25735
  this.home,
25626
25736
  ".claude",
25627
25737
  "projects",
@@ -25651,7 +25761,7 @@ var SubagentMetaObserver = class {
25651
25761
  attachWatcher(w2) {
25652
25762
  if (w2.watcher) return;
25653
25763
  try {
25654
- w2.watcher = import_node_fs12.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
25764
+ w2.watcher = import_node_fs13.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
25655
25765
  if (!name) return;
25656
25766
  const m2 = META_RE.exec(String(name));
25657
25767
  if (!m2) return;
@@ -25663,7 +25773,7 @@ var SubagentMetaObserver = class {
25663
25773
  scan(w2) {
25664
25774
  let entries;
25665
25775
  try {
25666
- entries = import_node_fs12.default.readdirSync(w2.dirPath);
25776
+ entries = import_node_fs13.default.readdirSync(w2.dirPath);
25667
25777
  } catch {
25668
25778
  return;
25669
25779
  }
@@ -25677,10 +25787,10 @@ var SubagentMetaObserver = class {
25677
25787
  if (!m2) return;
25678
25788
  const agentId = m2[1];
25679
25789
  if (w2.emitted.has(agentId)) return;
25680
- const file = import_node_path13.default.join(w2.dirPath, name);
25790
+ const file = import_node_path14.default.join(w2.dirPath, name);
25681
25791
  let raw;
25682
25792
  try {
25683
- raw = import_node_fs12.default.readFileSync(file, "utf8");
25793
+ raw = import_node_fs13.default.readFileSync(file, "utf8");
25684
25794
  } catch {
25685
25795
  return;
25686
25796
  }
@@ -25737,14 +25847,14 @@ var SessionObserver = class {
25737
25847
  metaObserver;
25738
25848
  resolveJsonlPath(cwd, toolSessionId, override) {
25739
25849
  if (override) return override;
25740
- return import_node_path14.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
25850
+ return import_node_path15.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
25741
25851
  }
25742
25852
  start(args) {
25743
25853
  this.stop(args.sessionId);
25744
25854
  const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
25745
25855
  let size = 0;
25746
25856
  try {
25747
- size = import_node_fs13.default.statSync(filePath).size;
25857
+ size = import_node_fs14.default.statSync(filePath).size;
25748
25858
  } catch {
25749
25859
  }
25750
25860
  const w2 = {
@@ -25757,10 +25867,10 @@ var SessionObserver = class {
25757
25867
  adapter: args.adapter
25758
25868
  };
25759
25869
  try {
25760
- import_node_fs13.default.mkdirSync(import_node_path14.default.dirname(filePath), { recursive: true });
25870
+ import_node_fs14.default.mkdirSync(import_node_path15.default.dirname(filePath), { recursive: true });
25761
25871
  } catch {
25762
25872
  }
25763
- w2.watcher = import_node_fs13.default.watch(import_node_path14.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
25873
+ w2.watcher = import_node_fs14.default.watch(import_node_path15.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
25764
25874
  if (!changedName || !filePath.endsWith(changedName)) return;
25765
25875
  this.poll(w2);
25766
25876
  });
@@ -25783,7 +25893,7 @@ var SessionObserver = class {
25783
25893
  // 异常静默吞,不阻塞 watcher 启动
25784
25894
  hydrateMetaTail(w2, maxLines = 200) {
25785
25895
  try {
25786
- const raw = import_node_fs13.default.readFileSync(w2.filePath, "utf8");
25896
+ const raw = import_node_fs14.default.readFileSync(w2.filePath, "utf8");
25787
25897
  if (!raw) return;
25788
25898
  const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
25789
25899
  if (allLines.length === 0) return;
@@ -25807,7 +25917,7 @@ var SessionObserver = class {
25807
25917
  poll(w2) {
25808
25918
  let size = 0;
25809
25919
  try {
25810
- size = import_node_fs13.default.statSync(w2.filePath).size;
25920
+ size = import_node_fs14.default.statSync(w2.filePath).size;
25811
25921
  } catch {
25812
25922
  return;
25813
25923
  }
@@ -25816,11 +25926,11 @@ var SessionObserver = class {
25816
25926
  w2.buf = "";
25817
25927
  }
25818
25928
  if (size === w2.lastSize) return;
25819
- const fd = import_node_fs13.default.openSync(w2.filePath, "r");
25929
+ const fd = import_node_fs14.default.openSync(w2.filePath, "r");
25820
25930
  try {
25821
25931
  const len = size - w2.lastSize;
25822
25932
  const buf = Buffer.alloc(len);
25823
- import_node_fs13.default.readSync(fd, buf, 0, len, w2.lastSize);
25933
+ import_node_fs14.default.readSync(fd, buf, 0, len, w2.lastSize);
25824
25934
  w2.lastSize = size;
25825
25935
  w2.buf += buf.toString("utf8");
25826
25936
  let newlineIndex;
@@ -25834,7 +25944,7 @@ var SessionObserver = class {
25834
25944
  }
25835
25945
  }
25836
25946
  } finally {
25837
- import_node_fs13.default.closeSync(fd);
25947
+ import_node_fs14.default.closeSync(fd);
25838
25948
  }
25839
25949
  }
25840
25950
  // 解析 JSONL 单行:仅当是主链 user 文本行(非 sidechain / 非 sub-agent / message.role='user'
@@ -26494,14 +26604,14 @@ function authenticate(token, deps) {
26494
26604
  }
26495
26605
 
26496
26606
  // src/permission/capability-store.ts
26497
- var fs16 = __toESM(require("fs"), 1);
26498
- var path19 = __toESM(require("path"), 1);
26607
+ var fs17 = __toESM(require("fs"), 1);
26608
+ var path20 = __toESM(require("path"), 1);
26499
26609
  var CAPABILITIES_FILE_NAME = "capabilities.json";
26500
26610
  var FILE_VERSION = 1;
26501
26611
  var CapabilityStore = class {
26502
26612
  constructor(dataDir) {
26503
26613
  this.dataDir = dataDir;
26504
- fs16.mkdirSync(dataDir, { recursive: true });
26614
+ fs17.mkdirSync(dataDir, { recursive: true });
26505
26615
  this.cache = this.readFromDisk();
26506
26616
  }
26507
26617
  dataDir;
@@ -26525,13 +26635,13 @@ var CapabilityStore = class {
26525
26635
  this.flush();
26526
26636
  }
26527
26637
  filePath() {
26528
- return path19.join(this.dataDir, CAPABILITIES_FILE_NAME);
26638
+ return path20.join(this.dataDir, CAPABILITIES_FILE_NAME);
26529
26639
  }
26530
26640
  readFromDisk() {
26531
26641
  const file = this.filePath();
26532
26642
  let raw;
26533
26643
  try {
26534
- raw = fs16.readFileSync(file, "utf8");
26644
+ raw = fs17.readFileSync(file, "utf8");
26535
26645
  } catch (err) {
26536
26646
  if (err?.code === "ENOENT") return [];
26537
26647
  return [];
@@ -26559,10 +26669,10 @@ var CapabilityStore = class {
26559
26669
  }
26560
26670
  atomicWrite(file, content) {
26561
26671
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
26562
- fs16.writeFileSync(tmp, content, { mode: 384 });
26563
- fs16.renameSync(tmp, file);
26672
+ fs17.writeFileSync(tmp, content, { mode: 384 });
26673
+ fs17.renameSync(tmp, file);
26564
26674
  try {
26565
- fs16.chmodSync(file, 384);
26675
+ fs17.chmodSync(file, 384);
26566
26676
  } catch {
26567
26677
  }
26568
26678
  }
@@ -26655,14 +26765,14 @@ var CapabilityManager = class {
26655
26765
  };
26656
26766
 
26657
26767
  // src/permission/cleanup.ts
26658
- var fs17 = __toESM(require("fs"), 1);
26768
+ var fs18 = __toESM(require("fs"), 1);
26659
26769
  function cleanupGuestSessionsForCapability(cap, factory) {
26660
26770
  const removed = [];
26661
26771
  for (const g2 of cap.grants) {
26662
26772
  if (g2.resource.type !== "persona") continue;
26663
26773
  const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
26664
26774
  try {
26665
- fs17.rmSync(dir, { recursive: true, force: true });
26775
+ fs18.rmSync(dir, { recursive: true, force: true });
26666
26776
  removed.push(dir);
26667
26777
  } catch {
26668
26778
  }
@@ -26671,13 +26781,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
26671
26781
  }
26672
26782
 
26673
26783
  // src/permission/personal-capability.ts
26674
- var import_node_fs14 = __toESM(require("fs"), 1);
26675
- var import_node_path15 = __toESM(require("path"), 1);
26784
+ var import_node_fs15 = __toESM(require("fs"), 1);
26785
+ var import_node_path16 = __toESM(require("path"), 1);
26676
26786
  var import_node_crypto4 = __toESM(require("crypto"), 1);
26677
26787
  var PERSONAL_CAP_FILE_NAME = "personal-capability.json";
26678
26788
  var PERSONAL_CAP_DISPLAY_NAME = "personal";
26679
26789
  function personalCapFilePath(dataDir) {
26680
- return import_node_path15.default.join(dataDir, PERSONAL_CAP_FILE_NAME);
26790
+ return import_node_path16.default.join(dataDir, PERSONAL_CAP_FILE_NAME);
26681
26791
  }
26682
26792
  function loadOrCreatePersonalCapability(opts) {
26683
26793
  const file = personalCapFilePath(opts.dataDir);
@@ -26707,7 +26817,7 @@ function loadOrCreatePersonalCapability(opts) {
26707
26817
  function readFile(file) {
26708
26818
  let raw;
26709
26819
  try {
26710
- raw = import_node_fs14.default.readFileSync(file, "utf8");
26820
+ raw = import_node_fs15.default.readFileSync(file, "utf8");
26711
26821
  } catch (err) {
26712
26822
  const code = err?.code;
26713
26823
  if (code === "ENOENT") return null;
@@ -26728,10 +26838,10 @@ function readFile(file) {
26728
26838
  return { token: obj.token, capability: capParsed.data };
26729
26839
  }
26730
26840
  function writeFile(file, content) {
26731
- import_node_fs14.default.mkdirSync(import_node_path15.default.dirname(file), { recursive: true });
26732
- import_node_fs14.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
26841
+ import_node_fs15.default.mkdirSync(import_node_path16.default.dirname(file), { recursive: true });
26842
+ import_node_fs15.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
26733
26843
  try {
26734
- import_node_fs14.default.chmodSync(file, 384);
26844
+ import_node_fs15.default.chmodSync(file, 384);
26735
26845
  } catch {
26736
26846
  }
26737
26847
  }
@@ -26746,13 +26856,13 @@ function sha256Hex2(s) {
26746
26856
  }
26747
26857
 
26748
26858
  // src/inbox/inbox-store.ts
26749
- var fs19 = __toESM(require("fs"), 1);
26750
- var path21 = __toESM(require("path"), 1);
26859
+ var fs20 = __toESM(require("fs"), 1);
26860
+ var path22 = __toESM(require("path"), 1);
26751
26861
  var INBOX_SUBDIR = "inbox";
26752
26862
  var InboxStore = class {
26753
26863
  constructor(dataDir) {
26754
26864
  this.dataDir = dataDir;
26755
- fs19.mkdirSync(this.dirPath(), { recursive: true });
26865
+ fs20.mkdirSync(this.dirPath(), { recursive: true });
26756
26866
  }
26757
26867
  dataDir;
26758
26868
  /**
@@ -26764,7 +26874,7 @@ var InboxStore = class {
26764
26874
  const file = this.filePath(peerOwnerId);
26765
26875
  let raw;
26766
26876
  try {
26767
- raw = fs19.readFileSync(file, "utf8");
26877
+ raw = fs20.readFileSync(file, "utf8");
26768
26878
  } catch (err) {
26769
26879
  if (err?.code === "ENOENT") return [];
26770
26880
  return [];
@@ -26780,7 +26890,7 @@ var InboxStore = class {
26780
26890
  const dir = this.dirPath();
26781
26891
  let entries;
26782
26892
  try {
26783
- entries = fs19.readdirSync(dir);
26893
+ entries = fs20.readdirSync(dir);
26784
26894
  } catch (err) {
26785
26895
  if (err?.code === "ENOENT") return [];
26786
26896
  return [];
@@ -26796,9 +26906,9 @@ var InboxStore = class {
26796
26906
  if (existing.some((m2) => m2.id === message.id)) return;
26797
26907
  const file = this.filePath(message.peerOwnerId);
26798
26908
  const line = JSON.stringify(message) + "\n";
26799
- fs19.appendFileSync(file, line, { mode: 384 });
26909
+ fs20.appendFileSync(file, line, { mode: 384 });
26800
26910
  try {
26801
- fs19.chmodSync(file, 384);
26911
+ fs20.chmodSync(file, 384);
26802
26912
  } catch {
26803
26913
  }
26804
26914
  }
@@ -26828,7 +26938,7 @@ var InboxStore = class {
26828
26938
  removeByPeerOwnerId(peerOwnerId) {
26829
26939
  const file = this.filePath(peerOwnerId);
26830
26940
  try {
26831
- fs19.unlinkSync(file);
26941
+ fs20.unlinkSync(file);
26832
26942
  } catch (err) {
26833
26943
  if (err?.code === "ENOENT") return;
26834
26944
  }
@@ -26837,18 +26947,18 @@ var InboxStore = class {
26837
26947
  const file = this.filePath(peerOwnerId);
26838
26948
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
26839
26949
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
26840
- fs19.writeFileSync(tmp, content, { mode: 384 });
26841
- fs19.renameSync(tmp, file);
26950
+ fs20.writeFileSync(tmp, content, { mode: 384 });
26951
+ fs20.renameSync(tmp, file);
26842
26952
  try {
26843
- fs19.chmodSync(file, 384);
26953
+ fs20.chmodSync(file, 384);
26844
26954
  } catch {
26845
26955
  }
26846
26956
  }
26847
26957
  dirPath() {
26848
- return path21.join(this.dataDir, INBOX_SUBDIR);
26958
+ return path22.join(this.dataDir, INBOX_SUBDIR);
26849
26959
  }
26850
26960
  filePath(peerOwnerId) {
26851
- return path21.join(this.dirPath(), `${peerOwnerId}.jsonl`);
26961
+ return path22.join(this.dirPath(), `${peerOwnerId}.jsonl`);
26852
26962
  }
26853
26963
  };
26854
26964
  function parseAllLines(raw) {
@@ -26935,8 +27045,8 @@ var InboxManager = class {
26935
27045
  };
26936
27046
 
26937
27047
  // src/state/received-capability-store.ts
26938
- var fs20 = __toESM(require("fs"), 1);
26939
- var path22 = __toESM(require("path"), 1);
27048
+ var fs21 = __toESM(require("fs"), 1);
27049
+ var path23 = __toESM(require("path"), 1);
26940
27050
  var FILE_NAME = "received-capabilities.json";
26941
27051
  var ReceivedCapabilityStore = class {
26942
27052
  constructor(dataDir) {
@@ -26946,10 +27056,10 @@ var ReceivedCapabilityStore = class {
26946
27056
  caps = /* @__PURE__ */ new Map();
26947
27057
  load() {
26948
27058
  this.caps.clear();
26949
- const file = path22.join(this.dataDir, FILE_NAME);
27059
+ const file = path23.join(this.dataDir, FILE_NAME);
26950
27060
  let raw;
26951
27061
  try {
26952
- raw = fs20.readFileSync(file, "utf8");
27062
+ raw = fs21.readFileSync(file, "utf8");
26953
27063
  } catch (err) {
26954
27064
  if (err?.code !== "ENOENT") this.renameBak(file);
26955
27065
  return;
@@ -26986,20 +27096,20 @@ var ReceivedCapabilityStore = class {
26986
27096
  this.flush();
26987
27097
  }
26988
27098
  flush() {
26989
- const file = path22.join(this.dataDir, FILE_NAME);
27099
+ const file = path23.join(this.dataDir, FILE_NAME);
26990
27100
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
26991
27101
  const content = JSON.stringify(
26992
27102
  { receivedCaps: Array.from(this.caps.values()) },
26993
27103
  null,
26994
27104
  2
26995
27105
  );
26996
- fs20.mkdirSync(this.dataDir, { recursive: true });
26997
- fs20.writeFileSync(tmp, content, { mode: 384 });
26998
- fs20.renameSync(tmp, file);
27106
+ fs21.mkdirSync(this.dataDir, { recursive: true });
27107
+ fs21.writeFileSync(tmp, content, { mode: 384 });
27108
+ fs21.renameSync(tmp, file);
26999
27109
  }
27000
27110
  renameBak(file) {
27001
27111
  try {
27002
- fs20.renameSync(file, `${file}.bak`);
27112
+ fs21.renameSync(file, `${file}.bak`);
27003
27113
  } catch {
27004
27114
  }
27005
27115
  }
@@ -27097,61 +27207,61 @@ async function connectRemote(args) {
27097
27207
  }
27098
27208
 
27099
27209
  // src/migrations/2026-05-20-flatten-sessions.ts
27100
- var fs21 = __toESM(require("fs"), 1);
27101
- var path23 = __toESM(require("path"), 1);
27210
+ var fs22 = __toESM(require("fs"), 1);
27211
+ var path24 = __toESM(require("path"), 1);
27102
27212
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
27103
27213
  function migrateFlattenSessions(opts) {
27104
27214
  const dataDir = opts.dataDir;
27105
27215
  const now = opts.now ?? Date.now;
27106
- const sessionsDir = path23.join(dataDir, "sessions");
27107
- const flagPath = path23.join(sessionsDir, MIGRATION_FLAG_NAME);
27216
+ const sessionsDir = path24.join(dataDir, "sessions");
27217
+ const flagPath = path24.join(sessionsDir, MIGRATION_FLAG_NAME);
27108
27218
  if (existsSync3(flagPath)) {
27109
27219
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
27110
27220
  }
27111
27221
  let movedBare = 0;
27112
27222
  let movedVmOwner = 0;
27113
27223
  let archivedListener = 0;
27114
- const defaultDir = path23.join(sessionsDir, "default");
27224
+ const defaultDir = path24.join(sessionsDir, "default");
27115
27225
  if (existsSync3(defaultDir)) {
27116
27226
  for (const entry of readdirSafe(defaultDir)) {
27117
27227
  if (!entry.endsWith(".json")) continue;
27118
- const src = path23.join(defaultDir, entry);
27119
- const dst = path23.join(sessionsDir, entry);
27120
- fs21.renameSync(src, dst);
27228
+ const src = path24.join(defaultDir, entry);
27229
+ const dst = path24.join(sessionsDir, entry);
27230
+ fs22.renameSync(src, dst);
27121
27231
  movedBare += 1;
27122
27232
  }
27123
27233
  rmdirIfEmpty(defaultDir);
27124
27234
  }
27125
27235
  for (const pid of readdirSafe(sessionsDir)) {
27126
- const personaDir = path23.join(sessionsDir, pid);
27236
+ const personaDir = path24.join(sessionsDir, pid);
27127
27237
  if (!isDir(personaDir)) continue;
27128
27238
  if (pid === "default") continue;
27129
- const ownerSrc = path23.join(personaDir, "owner");
27239
+ const ownerSrc = path24.join(personaDir, "owner");
27130
27240
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
27131
- const ownerDst = path23.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
27132
- fs21.mkdirSync(ownerDst, { recursive: true });
27241
+ const ownerDst = path24.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
27242
+ fs22.mkdirSync(ownerDst, { recursive: true });
27133
27243
  for (const file of readdirSafe(ownerSrc)) {
27134
27244
  if (!file.endsWith(".json")) continue;
27135
- fs21.renameSync(path23.join(ownerSrc, file), path23.join(ownerDst, file));
27245
+ fs22.renameSync(path24.join(ownerSrc, file), path24.join(ownerDst, file));
27136
27246
  movedVmOwner += 1;
27137
27247
  }
27138
27248
  rmdirIfEmpty(ownerSrc);
27139
27249
  }
27140
- const listenerSrc = path23.join(personaDir, "listener");
27250
+ const listenerSrc = path24.join(personaDir, "listener");
27141
27251
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
27142
- const archiveDst = path23.join(dataDir, ".legacy", `listener-${pid}`);
27143
- fs21.mkdirSync(archiveDst, { recursive: true });
27252
+ const archiveDst = path24.join(dataDir, ".legacy", `listener-${pid}`);
27253
+ fs22.mkdirSync(archiveDst, { recursive: true });
27144
27254
  for (const file of readdirSafe(listenerSrc)) {
27145
27255
  if (!file.endsWith(".json")) continue;
27146
- fs21.renameSync(path23.join(listenerSrc, file), path23.join(archiveDst, file));
27256
+ fs22.renameSync(path24.join(listenerSrc, file), path24.join(archiveDst, file));
27147
27257
  archivedListener += 1;
27148
27258
  }
27149
27259
  rmdirIfEmpty(listenerSrc);
27150
27260
  }
27151
27261
  rmdirIfEmpty(personaDir);
27152
27262
  }
27153
- fs21.mkdirSync(sessionsDir, { recursive: true });
27154
- fs21.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
27263
+ fs22.mkdirSync(sessionsDir, { recursive: true });
27264
+ fs22.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
27155
27265
  return {
27156
27266
  skipped: false,
27157
27267
  flagWritten: true,
@@ -27162,7 +27272,7 @@ function migrateFlattenSessions(opts) {
27162
27272
  }
27163
27273
  function existsSync3(p2) {
27164
27274
  try {
27165
- fs21.statSync(p2);
27275
+ fs22.statSync(p2);
27166
27276
  return true;
27167
27277
  } catch {
27168
27278
  return false;
@@ -27170,31 +27280,31 @@ function existsSync3(p2) {
27170
27280
  }
27171
27281
  function isDir(p2) {
27172
27282
  try {
27173
- return fs21.statSync(p2).isDirectory();
27283
+ return fs22.statSync(p2).isDirectory();
27174
27284
  } catch {
27175
27285
  return false;
27176
27286
  }
27177
27287
  }
27178
27288
  function readdirSafe(p2) {
27179
27289
  try {
27180
- return fs21.readdirSync(p2);
27290
+ return fs22.readdirSync(p2);
27181
27291
  } catch {
27182
27292
  return [];
27183
27293
  }
27184
27294
  }
27185
27295
  function rmdirIfEmpty(p2) {
27186
27296
  try {
27187
- fs21.rmdirSync(p2);
27297
+ fs22.rmdirSync(p2);
27188
27298
  } catch {
27189
27299
  }
27190
27300
  }
27191
27301
 
27192
27302
  // src/transport/http-router.ts
27193
- var import_node_fs16 = __toESM(require("fs"), 1);
27194
- var import_node_path18 = __toESM(require("path"), 1);
27303
+ var import_node_fs17 = __toESM(require("fs"), 1);
27304
+ var import_node_path19 = __toESM(require("path"), 1);
27195
27305
 
27196
27306
  // src/attachment/mime.ts
27197
- var import_node_path16 = __toESM(require("path"), 1);
27307
+ var import_node_path17 = __toESM(require("path"), 1);
27198
27308
  var TEXT_PLAIN = "text/plain; charset=utf-8";
27199
27309
  var EXT_TO_NATIVE_MIME = {
27200
27310
  // 图片
@@ -27301,7 +27411,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
27301
27411
  ".mk"
27302
27412
  ]);
27303
27413
  function lookupMime(filePathOrName) {
27304
- const ext = import_node_path16.default.extname(filePathOrName).toLowerCase();
27414
+ const ext = import_node_path17.default.extname(filePathOrName).toLowerCase();
27305
27415
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
27306
27416
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
27307
27417
  return "application/octet-stream";
@@ -27370,8 +27480,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
27370
27480
  }
27371
27481
 
27372
27482
  // src/attachment/upload.ts
27373
- var import_node_fs15 = __toESM(require("fs"), 1);
27374
- var import_node_path17 = __toESM(require("path"), 1);
27483
+ var import_node_fs16 = __toESM(require("fs"), 1);
27484
+ var import_node_path18 = __toESM(require("path"), 1);
27375
27485
  var import_node_crypto6 = __toESM(require("crypto"), 1);
27376
27486
  var import_promises = require("stream/promises");
27377
27487
  var UploadError = class extends Error {
@@ -27383,22 +27493,22 @@ var UploadError = class extends Error {
27383
27493
  code;
27384
27494
  };
27385
27495
  function assertValidFileName(fileName) {
27386
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path17.default.basename(fileName)) {
27496
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path18.default.basename(fileName)) {
27387
27497
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
27388
27498
  }
27389
27499
  }
27390
27500
  var HASH_PREFIX_LEN = 16;
27391
27501
  async function writeUploadedAttachment(args) {
27392
27502
  assertValidFileName(args.fileName);
27393
- const attachmentsRoot = import_node_path17.default.join(args.sessionDir, ".attachments");
27503
+ const attachmentsRoot = import_node_path18.default.join(args.sessionDir, ".attachments");
27394
27504
  try {
27395
- import_node_fs15.default.mkdirSync(attachmentsRoot, { recursive: true });
27505
+ import_node_fs16.default.mkdirSync(attachmentsRoot, { recursive: true });
27396
27506
  } catch (err) {
27397
27507
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
27398
27508
  }
27399
27509
  const hasher = import_node_crypto6.default.createHash("sha256");
27400
27510
  let actualSize = 0;
27401
- const tmpPath = import_node_path17.default.join(
27511
+ const tmpPath = import_node_path18.default.join(
27402
27512
  attachmentsRoot,
27403
27513
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto6.default.randomBytes(4).toString("hex")}`
27404
27514
  );
@@ -27413,18 +27523,18 @@ async function writeUploadedAttachment(args) {
27413
27523
  yield buf;
27414
27524
  }
27415
27525
  },
27416
- import_node_fs15.default.createWriteStream(tmpPath, { mode: 384 })
27526
+ import_node_fs16.default.createWriteStream(tmpPath, { mode: 384 })
27417
27527
  );
27418
27528
  } catch (err) {
27419
27529
  try {
27420
- import_node_fs15.default.unlinkSync(tmpPath);
27530
+ import_node_fs16.default.unlinkSync(tmpPath);
27421
27531
  } catch {
27422
27532
  }
27423
27533
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
27424
27534
  }
27425
27535
  if (actualSize !== args.contentLength) {
27426
27536
  try {
27427
- import_node_fs15.default.unlinkSync(tmpPath);
27537
+ import_node_fs16.default.unlinkSync(tmpPath);
27428
27538
  } catch {
27429
27539
  }
27430
27540
  throw new UploadError(
@@ -27433,35 +27543,35 @@ async function writeUploadedAttachment(args) {
27433
27543
  );
27434
27544
  }
27435
27545
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
27436
- const hashDir = import_node_path17.default.join(attachmentsRoot, attachmentId);
27546
+ const hashDir = import_node_path18.default.join(attachmentsRoot, attachmentId);
27437
27547
  let finalFileName;
27438
27548
  let hashDirExists = false;
27439
27549
  try {
27440
- hashDirExists = import_node_fs15.default.statSync(hashDir).isDirectory();
27550
+ hashDirExists = import_node_fs16.default.statSync(hashDir).isDirectory();
27441
27551
  } catch {
27442
27552
  }
27443
27553
  if (hashDirExists) {
27444
- const existing = import_node_fs15.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
27554
+ const existing = import_node_fs16.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
27445
27555
  finalFileName = existing[0] ?? args.fileName;
27446
27556
  try {
27447
- import_node_fs15.default.unlinkSync(tmpPath);
27557
+ import_node_fs16.default.unlinkSync(tmpPath);
27448
27558
  } catch {
27449
27559
  }
27450
27560
  } else {
27451
27561
  try {
27452
- import_node_fs15.default.mkdirSync(hashDir, { recursive: true });
27562
+ import_node_fs16.default.mkdirSync(hashDir, { recursive: true });
27453
27563
  finalFileName = args.fileName;
27454
- import_node_fs15.default.renameSync(tmpPath, import_node_path17.default.join(hashDir, finalFileName));
27564
+ import_node_fs16.default.renameSync(tmpPath, import_node_path18.default.join(hashDir, finalFileName));
27455
27565
  } catch (err) {
27456
27566
  try {
27457
- import_node_fs15.default.unlinkSync(tmpPath);
27567
+ import_node_fs16.default.unlinkSync(tmpPath);
27458
27568
  } catch {
27459
27569
  }
27460
27570
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
27461
27571
  }
27462
27572
  }
27463
- const absPath = import_node_path17.default.join(hashDir, finalFileName);
27464
- const relPath = import_node_path17.default.relative(args.sessionDir, absPath);
27573
+ const absPath = import_node_path18.default.join(hashDir, finalFileName);
27574
+ const relPath = import_node_path18.default.relative(args.sessionDir, absPath);
27465
27575
  args.groupFileStore.upsert(args.scope, args.sessionId, {
27466
27576
  relPath: absPath,
27467
27577
  // 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
@@ -27498,7 +27608,7 @@ function isValidUploadFileName(fileName) {
27498
27608
  if (fileName === "." || fileName === "..") return false;
27499
27609
  if (fileName.startsWith(".")) return false;
27500
27610
  if (fileName.includes("/") || fileName.includes("\\")) return false;
27501
- return fileName === import_node_path18.default.basename(fileName);
27611
+ return fileName === import_node_path19.default.basename(fileName);
27502
27612
  }
27503
27613
  function createHttpRouter(deps) {
27504
27614
  return async (req, res) => {
@@ -27668,7 +27778,7 @@ function createHttpRouter(deps) {
27668
27778
  return true;
27669
27779
  }
27670
27780
  let absPath;
27671
- if (import_node_path18.default.isAbsolute(pathParam)) {
27781
+ if (import_node_path19.default.isAbsolute(pathParam)) {
27672
27782
  absPath = pathParam;
27673
27783
  } else if (deps.sessionStore) {
27674
27784
  const file = deps.sessionStore.read(sid);
@@ -27676,7 +27786,7 @@ function createHttpRouter(deps) {
27676
27786
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
27677
27787
  return true;
27678
27788
  }
27679
- absPath = import_node_path18.default.join(file.cwd, pathParam);
27789
+ absPath = import_node_path19.default.join(file.cwd, pathParam);
27680
27790
  } else {
27681
27791
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
27682
27792
  return true;
@@ -27709,7 +27819,7 @@ function withCtx(ctx, body) {
27709
27819
  function streamFile(res, absPath, logger) {
27710
27820
  let stat;
27711
27821
  try {
27712
- stat = import_node_fs16.default.statSync(absPath);
27822
+ stat = import_node_fs17.default.statSync(absPath);
27713
27823
  } catch (err) {
27714
27824
  const code = err?.code;
27715
27825
  if (code === "ENOENT") {
@@ -27724,7 +27834,7 @@ function streamFile(res, absPath, logger) {
27724
27834
  return;
27725
27835
  }
27726
27836
  const mime = lookupMime(absPath);
27727
- const basename = import_node_path18.default.basename(absPath);
27837
+ const basename = import_node_path19.default.basename(absPath);
27728
27838
  res.writeHead(200, {
27729
27839
  "Content-Type": mime,
27730
27840
  "Content-Length": String(stat.size),
@@ -27732,7 +27842,7 @@ function streamFile(res, absPath, logger) {
27732
27842
  // 防止浏览器把任意 mime 当 html 渲染
27733
27843
  "X-Content-Type-Options": "nosniff"
27734
27844
  });
27735
- const stream = import_node_fs16.default.createReadStream(absPath);
27845
+ const stream = import_node_fs17.default.createReadStream(absPath);
27736
27846
  stream.on("error", (err) => {
27737
27847
  logger?.warn("streamFile read error", { absPath, err: err.message });
27738
27848
  res.destroy();
@@ -27741,8 +27851,8 @@ function streamFile(res, absPath, logger) {
27741
27851
  }
27742
27852
 
27743
27853
  // src/attachment/gc.ts
27744
- var import_node_fs17 = __toESM(require("fs"), 1);
27745
- var import_node_path19 = __toESM(require("path"), 1);
27854
+ var import_node_fs18 = __toESM(require("fs"), 1);
27855
+ var import_node_path20 = __toESM(require("path"), 1);
27746
27856
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
27747
27857
  function runAttachmentGc(args) {
27748
27858
  const now = (args.now ?? Date.now)();
@@ -27751,38 +27861,38 @@ function runAttachmentGc(args) {
27751
27861
  for (const { scope, sessionId } of args.sessionScopes) {
27752
27862
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
27753
27863
  if (entry.stale) continue;
27754
- if (import_node_path19.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
27864
+ if (import_node_path20.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
27755
27865
  }
27756
27866
  }
27757
27867
  for (const { scope, sessionId } of args.sessionScopes) {
27758
- const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path19.default.join(
27868
+ const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path20.default.join(
27759
27869
  args.dataDir,
27760
27870
  "sessions",
27761
27871
  ...scopeSubPath(scope).map(safeFileName),
27762
27872
  safeFileName(sessionId)
27763
27873
  );
27764
- const attRoot = import_node_path19.default.join(sessionDir, ".attachments");
27874
+ const attRoot = import_node_path20.default.join(sessionDir, ".attachments");
27765
27875
  let hashDirs;
27766
27876
  try {
27767
- hashDirs = import_node_fs17.default.readdirSync(attRoot);
27877
+ hashDirs = import_node_fs18.default.readdirSync(attRoot);
27768
27878
  } catch (err) {
27769
27879
  if (err.code === "ENOENT") continue;
27770
27880
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
27771
27881
  continue;
27772
27882
  }
27773
27883
  for (const hashDir of hashDirs) {
27774
- const hashDirAbs = import_node_path19.default.join(attRoot, hashDir);
27884
+ const hashDirAbs = import_node_path20.default.join(attRoot, hashDir);
27775
27885
  let files;
27776
27886
  try {
27777
- files = import_node_fs17.default.readdirSync(hashDirAbs);
27887
+ files = import_node_fs18.default.readdirSync(hashDirAbs);
27778
27888
  } catch {
27779
27889
  continue;
27780
27890
  }
27781
27891
  for (const name of files) {
27782
- const file = import_node_path19.default.join(hashDirAbs, name);
27892
+ const file = import_node_path20.default.join(hashDirAbs, name);
27783
27893
  let stat;
27784
27894
  try {
27785
- stat = import_node_fs17.default.statSync(file);
27895
+ stat = import_node_fs18.default.statSync(file);
27786
27896
  } catch {
27787
27897
  continue;
27788
27898
  }
@@ -27791,26 +27901,26 @@ function runAttachmentGc(args) {
27791
27901
  if (age < ttlMs) continue;
27792
27902
  if (liveAbs.has(file)) continue;
27793
27903
  try {
27794
- import_node_fs17.default.unlinkSync(file);
27904
+ import_node_fs18.default.unlinkSync(file);
27795
27905
  } catch (err) {
27796
27906
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
27797
27907
  }
27798
27908
  }
27799
27909
  try {
27800
- if (import_node_fs17.default.readdirSync(hashDirAbs).length === 0) import_node_fs17.default.rmdirSync(hashDirAbs);
27910
+ if (import_node_fs18.default.readdirSync(hashDirAbs).length === 0) import_node_fs18.default.rmdirSync(hashDirAbs);
27801
27911
  } catch {
27802
27912
  }
27803
27913
  }
27804
27914
  try {
27805
- if (import_node_fs17.default.readdirSync(attRoot).length === 0) import_node_fs17.default.rmdirSync(attRoot);
27915
+ if (import_node_fs18.default.readdirSync(attRoot).length === 0) import_node_fs18.default.rmdirSync(attRoot);
27806
27916
  } catch {
27807
27917
  }
27808
27918
  }
27809
27919
  }
27810
27920
 
27811
27921
  // src/attachment/group.ts
27812
- var import_node_fs18 = __toESM(require("fs"), 1);
27813
- var import_node_path20 = __toESM(require("path"), 1);
27922
+ var import_node_fs19 = __toESM(require("fs"), 1);
27923
+ var import_node_path21 = __toESM(require("path"), 1);
27814
27924
  var import_node_crypto7 = __toESM(require("crypto"), 1);
27815
27925
  init_protocol();
27816
27926
  var GroupFileStore = class {
@@ -27822,11 +27932,11 @@ var GroupFileStore = class {
27822
27932
  this.logger = opts.logger;
27823
27933
  }
27824
27934
  rootForScope(scope) {
27825
- return import_node_path20.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
27935
+ return import_node_path21.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
27826
27936
  }
27827
27937
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
27828
27938
  filePath(scope, sessionId) {
27829
- return import_node_path20.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
27939
+ return import_node_path21.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
27830
27940
  }
27831
27941
  cacheKey(scope, sessionId) {
27832
27942
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -27835,7 +27945,7 @@ var GroupFileStore = class {
27835
27945
  readFile(scope, sessionId) {
27836
27946
  const file = this.filePath(scope, sessionId);
27837
27947
  try {
27838
- const raw = import_node_fs18.default.readFileSync(file, "utf8");
27948
+ const raw = import_node_fs19.default.readFileSync(file, "utf8");
27839
27949
  const parsed = JSON.parse(raw);
27840
27950
  if (!Array.isArray(parsed)) {
27841
27951
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -27861,10 +27971,10 @@ var GroupFileStore = class {
27861
27971
  }
27862
27972
  writeFile(scope, sessionId, entries) {
27863
27973
  const file = this.filePath(scope, sessionId);
27864
- import_node_fs18.default.mkdirSync(import_node_path20.default.dirname(file), { recursive: true });
27974
+ import_node_fs19.default.mkdirSync(import_node_path21.default.dirname(file), { recursive: true });
27865
27975
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
27866
- import_node_fs18.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
27867
- import_node_fs18.default.renameSync(tmp, file);
27976
+ import_node_fs19.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
27977
+ import_node_fs19.default.renameSync(tmp, file);
27868
27978
  }
27869
27979
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
27870
27980
  list(scope, sessionId) {
@@ -27950,10 +28060,10 @@ var GroupFileStore = class {
27950
28060
  };
27951
28061
 
27952
28062
  // src/discovery/state-file.ts
27953
- var import_node_fs19 = __toESM(require("fs"), 1);
27954
- var import_node_path21 = __toESM(require("path"), 1);
28063
+ var import_node_fs20 = __toESM(require("fs"), 1);
28064
+ var import_node_path22 = __toESM(require("path"), 1);
27955
28065
  function defaultStateFilePath(dataDir) {
27956
- return import_node_path21.default.join(dataDir, "state.json");
28066
+ return import_node_path22.default.join(dataDir, "state.json");
27957
28067
  }
27958
28068
  function isPidAlive(pid) {
27959
28069
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -27975,7 +28085,7 @@ var StateFileManager = class {
27975
28085
  }
27976
28086
  read() {
27977
28087
  try {
27978
- const raw = import_node_fs19.default.readFileSync(this.file, "utf8");
28088
+ const raw = import_node_fs20.default.readFileSync(this.file, "utf8");
27979
28089
  const parsed = JSON.parse(raw);
27980
28090
  return parsed;
27981
28091
  } catch {
@@ -27989,34 +28099,34 @@ var StateFileManager = class {
27989
28099
  return { status: "stale", existing };
27990
28100
  }
27991
28101
  write(state) {
27992
- import_node_fs19.default.mkdirSync(import_node_path21.default.dirname(this.file), { recursive: true });
28102
+ import_node_fs20.default.mkdirSync(import_node_path22.default.dirname(this.file), { recursive: true });
27993
28103
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
27994
- import_node_fs19.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
27995
- import_node_fs19.default.renameSync(tmp, this.file);
28104
+ import_node_fs20.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
28105
+ import_node_fs20.default.renameSync(tmp, this.file);
27996
28106
  if (process.platform !== "win32") {
27997
28107
  try {
27998
- import_node_fs19.default.chmodSync(this.file, 384);
28108
+ import_node_fs20.default.chmodSync(this.file, 384);
27999
28109
  } catch {
28000
28110
  }
28001
28111
  }
28002
28112
  }
28003
28113
  delete() {
28004
28114
  try {
28005
- import_node_fs19.default.unlinkSync(this.file);
28115
+ import_node_fs20.default.unlinkSync(this.file);
28006
28116
  } catch {
28007
28117
  }
28008
28118
  }
28009
28119
  };
28010
28120
 
28011
28121
  // src/tunnel/tunnel-manager.ts
28012
- var import_node_fs23 = __toESM(require("fs"), 1);
28013
- var import_node_path25 = __toESM(require("path"), 1);
28122
+ var import_node_fs24 = __toESM(require("fs"), 1);
28123
+ var import_node_path26 = __toESM(require("path"), 1);
28014
28124
  var import_node_crypto8 = __toESM(require("crypto"), 1);
28015
28125
  var import_node_child_process5 = require("child_process");
28016
28126
 
28017
28127
  // src/tunnel/tunnel-store.ts
28018
- var import_node_fs20 = __toESM(require("fs"), 1);
28019
- var import_node_path22 = __toESM(require("path"), 1);
28128
+ var import_node_fs21 = __toESM(require("fs"), 1);
28129
+ var import_node_path23 = __toESM(require("path"), 1);
28020
28130
  var TunnelStore = class {
28021
28131
  constructor(filePath) {
28022
28132
  this.filePath = filePath;
@@ -28024,7 +28134,7 @@ var TunnelStore = class {
28024
28134
  filePath;
28025
28135
  async get() {
28026
28136
  try {
28027
- const raw = await import_node_fs20.default.promises.readFile(this.filePath, "utf8");
28137
+ const raw = await import_node_fs21.default.promises.readFile(this.filePath, "utf8");
28028
28138
  const obj = JSON.parse(raw);
28029
28139
  if (!isPersistedTunnel(obj)) return null;
28030
28140
  return obj;
@@ -28035,22 +28145,22 @@ var TunnelStore = class {
28035
28145
  }
28036
28146
  }
28037
28147
  async set(v2) {
28038
- const dir = import_node_path22.default.dirname(this.filePath);
28039
- await import_node_fs20.default.promises.mkdir(dir, { recursive: true });
28148
+ const dir = import_node_path23.default.dirname(this.filePath);
28149
+ await import_node_fs21.default.promises.mkdir(dir, { recursive: true });
28040
28150
  const data = JSON.stringify(v2, null, 2);
28041
28151
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
28042
- await import_node_fs20.default.promises.writeFile(tmp, data, { mode: 384 });
28152
+ await import_node_fs21.default.promises.writeFile(tmp, data, { mode: 384 });
28043
28153
  if (process.platform !== "win32") {
28044
28154
  try {
28045
- await import_node_fs20.default.promises.chmod(tmp, 384);
28155
+ await import_node_fs21.default.promises.chmod(tmp, 384);
28046
28156
  } catch {
28047
28157
  }
28048
28158
  }
28049
- await import_node_fs20.default.promises.rename(tmp, this.filePath);
28159
+ await import_node_fs21.default.promises.rename(tmp, this.filePath);
28050
28160
  }
28051
28161
  async clear() {
28052
28162
  try {
28053
- await import_node_fs20.default.promises.unlink(this.filePath);
28163
+ await import_node_fs21.default.promises.unlink(this.filePath);
28054
28164
  } catch (err) {
28055
28165
  const code = err?.code;
28056
28166
  if (code !== "ENOENT") throw err;
@@ -28145,9 +28255,9 @@ function escape(v2) {
28145
28255
  }
28146
28256
 
28147
28257
  // src/tunnel/frpc-binary.ts
28148
- var import_node_fs21 = __toESM(require("fs"), 1);
28258
+ var import_node_fs22 = __toESM(require("fs"), 1);
28149
28259
  var import_node_os10 = __toESM(require("os"), 1);
28150
- var import_node_path23 = __toESM(require("path"), 1);
28260
+ var import_node_path24 = __toESM(require("path"), 1);
28151
28261
  var import_node_child_process3 = require("child_process");
28152
28262
  var import_node_stream2 = require("stream");
28153
28263
  var import_promises2 = require("stream/promises");
@@ -28179,20 +28289,20 @@ function frpcDownloadUrl(version2, p2) {
28179
28289
  }
28180
28290
  async function ensureFrpcBinary(opts) {
28181
28291
  if (opts.override) {
28182
- if (!import_node_fs21.default.existsSync(opts.override)) {
28292
+ if (!import_node_fs22.default.existsSync(opts.override)) {
28183
28293
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
28184
28294
  }
28185
28295
  return opts.override;
28186
28296
  }
28187
28297
  const version2 = opts.version ?? FRPC_VERSION;
28188
28298
  const platform = opts.platform ?? detectPlatform();
28189
- const binDir = import_node_path23.default.join(opts.dataDir, "bin");
28190
- import_node_fs21.default.mkdirSync(binDir, { recursive: true });
28299
+ const binDir = import_node_path24.default.join(opts.dataDir, "bin");
28300
+ import_node_fs22.default.mkdirSync(binDir, { recursive: true });
28191
28301
  cleanupStaleArtifacts(binDir);
28192
- const stableBin = import_node_path23.default.join(binDir, "frpc");
28193
- if (import_node_fs21.default.existsSync(stableBin)) return stableBin;
28302
+ const stableBin = import_node_path24.default.join(binDir, "frpc");
28303
+ if (import_node_fs22.default.existsSync(stableBin)) return stableBin;
28194
28304
  const partialBin = `${stableBin}.partial`;
28195
- const tarballPath = import_node_path23.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
28305
+ const tarballPath = import_node_path24.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
28196
28306
  try {
28197
28307
  const url = frpcDownloadUrl(version2, platform);
28198
28308
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -28201,8 +28311,8 @@ async function ensureFrpcBinary(opts) {
28201
28311
  } else {
28202
28312
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
28203
28313
  }
28204
- import_node_fs21.default.chmodSync(partialBin, 493);
28205
- import_node_fs21.default.renameSync(partialBin, stableBin);
28314
+ import_node_fs22.default.chmodSync(partialBin, 493);
28315
+ import_node_fs22.default.renameSync(partialBin, stableBin);
28206
28316
  } finally {
28207
28317
  safeUnlink(tarballPath);
28208
28318
  safeUnlink(partialBin);
@@ -28212,15 +28322,15 @@ async function ensureFrpcBinary(opts) {
28212
28322
  function cleanupStaleArtifacts(binDir) {
28213
28323
  let entries;
28214
28324
  try {
28215
- entries = import_node_fs21.default.readdirSync(binDir);
28325
+ entries = import_node_fs22.default.readdirSync(binDir);
28216
28326
  } catch {
28217
28327
  return;
28218
28328
  }
28219
28329
  for (const name of entries) {
28220
28330
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
28221
- const full = import_node_path23.default.join(binDir, name);
28331
+ const full = import_node_path24.default.join(binDir, name);
28222
28332
  try {
28223
- import_node_fs21.default.rmSync(full, { recursive: true, force: true });
28333
+ import_node_fs22.default.rmSync(full, { recursive: true, force: true });
28224
28334
  } catch {
28225
28335
  }
28226
28336
  }
@@ -28228,7 +28338,7 @@ function cleanupStaleArtifacts(binDir) {
28228
28338
  }
28229
28339
  function safeUnlink(p2) {
28230
28340
  try {
28231
- import_node_fs21.default.unlinkSync(p2);
28341
+ import_node_fs22.default.unlinkSync(p2);
28232
28342
  } catch {
28233
28343
  }
28234
28344
  }
@@ -28239,13 +28349,13 @@ async function downloadToFile(url, dest, fetchImpl) {
28239
28349
  if (!res.ok || !res.body) {
28240
28350
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
28241
28351
  }
28242
- const out = import_node_fs21.default.createWriteStream(dest);
28352
+ const out = import_node_fs22.default.createWriteStream(dest);
28243
28353
  const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
28244
28354
  await (0, import_promises2.pipeline)(nodeStream, out);
28245
28355
  }
28246
28356
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
28247
- const work = import_node_path23.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
28248
- import_node_fs21.default.mkdirSync(work, { recursive: true });
28357
+ const work = import_node_path24.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
28358
+ import_node_fs22.default.mkdirSync(work, { recursive: true });
28249
28359
  try {
28250
28360
  await new Promise((resolve6, reject) => {
28251
28361
  const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -28253,32 +28363,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
28253
28363
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
28254
28364
  });
28255
28365
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
28256
- const src = import_node_path23.default.join(work, dirName, "frpc");
28257
- if (!import_node_fs21.default.existsSync(src)) {
28366
+ const src = import_node_path24.default.join(work, dirName, "frpc");
28367
+ if (!import_node_fs22.default.existsSync(src)) {
28258
28368
  throw new Error(`frpc not found inside tarball at ${src}`);
28259
28369
  }
28260
- import_node_fs21.default.copyFileSync(src, destBin);
28370
+ import_node_fs22.default.copyFileSync(src, destBin);
28261
28371
  } finally {
28262
- import_node_fs21.default.rmSync(work, { recursive: true, force: true });
28372
+ import_node_fs22.default.rmSync(work, { recursive: true, force: true });
28263
28373
  }
28264
28374
  }
28265
28375
 
28266
28376
  // src/tunnel/frpc-process.ts
28267
- var import_node_fs22 = __toESM(require("fs"), 1);
28268
- var import_node_path24 = __toESM(require("path"), 1);
28377
+ var import_node_fs23 = __toESM(require("fs"), 1);
28378
+ var import_node_path25 = __toESM(require("path"), 1);
28269
28379
  var import_node_child_process4 = require("child_process");
28270
28380
  function frpcPidFilePath(dataDir) {
28271
- return import_node_path24.default.join(dataDir, "frpc.pid");
28381
+ return import_node_path25.default.join(dataDir, "frpc.pid");
28272
28382
  }
28273
28383
  function writeFrpcPid(dataDir, pid) {
28274
28384
  try {
28275
- import_node_fs22.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
28385
+ import_node_fs23.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
28276
28386
  } catch {
28277
28387
  }
28278
28388
  }
28279
28389
  function clearFrpcPid(dataDir) {
28280
28390
  try {
28281
- import_node_fs22.default.unlinkSync(frpcPidFilePath(dataDir));
28391
+ import_node_fs23.default.unlinkSync(frpcPidFilePath(dataDir));
28282
28392
  } catch {
28283
28393
  }
28284
28394
  }
@@ -28294,7 +28404,7 @@ function defaultIsPidAlive(pid) {
28294
28404
  }
28295
28405
  function defaultReadPidFile(file) {
28296
28406
  try {
28297
- return import_node_fs22.default.readFileSync(file, "utf8");
28407
+ return import_node_fs23.default.readFileSync(file, "utf8");
28298
28408
  } catch {
28299
28409
  return null;
28300
28410
  }
@@ -28310,7 +28420,7 @@ function defaultSleep(ms) {
28310
28420
  }
28311
28421
  async function killStaleFrpc(deps) {
28312
28422
  const pidFile = frpcPidFilePath(deps.dataDir);
28313
- const tomlPath = import_node_path24.default.join(deps.dataDir, "frpc.toml");
28423
+ const tomlPath = import_node_path25.default.join(deps.dataDir, "frpc.toml");
28314
28424
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
28315
28425
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
28316
28426
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -28334,7 +28444,7 @@ async function killStaleFrpc(deps) {
28334
28444
  }
28335
28445
  if (victims.size === 0) {
28336
28446
  try {
28337
- import_node_fs22.default.unlinkSync(pidFile);
28447
+ import_node_fs23.default.unlinkSync(pidFile);
28338
28448
  } catch {
28339
28449
  }
28340
28450
  return;
@@ -28345,7 +28455,7 @@ async function killStaleFrpc(deps) {
28345
28455
  }
28346
28456
  await sleep(deps.reapWaitMs ?? 300);
28347
28457
  try {
28348
- import_node_fs22.default.unlinkSync(pidFile);
28458
+ import_node_fs23.default.unlinkSync(pidFile);
28349
28459
  } catch {
28350
28460
  }
28351
28461
  }
@@ -28382,7 +28492,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
28382
28492
  var TunnelManager = class {
28383
28493
  constructor(deps) {
28384
28494
  this.deps = deps;
28385
- this.store = deps.store ?? new TunnelStore(import_node_path25.default.join(deps.dataDir, "tunnel.json"));
28495
+ this.store = deps.store ?? new TunnelStore(import_node_path26.default.join(deps.dataDir, "tunnel.json"));
28386
28496
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
28387
28497
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
28388
28498
  }
@@ -28509,7 +28619,7 @@ var TunnelManager = class {
28509
28619
  dataDir: this.deps.dataDir,
28510
28620
  override: this.deps.frpcBinaryOverride ?? void 0
28511
28621
  });
28512
- const tomlPath = import_node_path25.default.join(this.deps.dataDir, "frpc.toml");
28622
+ const tomlPath = import_node_path26.default.join(this.deps.dataDir, "frpc.toml");
28513
28623
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto8.default.randomBytes(3).toString("hex")}`;
28514
28624
  const toml = buildFrpcToml({
28515
28625
  serverAddr: t.frpsHost,
@@ -28520,12 +28630,12 @@ var TunnelManager = class {
28520
28630
  localPort,
28521
28631
  logLevel: "info"
28522
28632
  });
28523
- await import_node_fs23.default.promises.writeFile(tomlPath, toml, { mode: 384 });
28633
+ await import_node_fs24.default.promises.writeFile(tomlPath, toml, { mode: 384 });
28524
28634
  const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
28525
28635
  stdio: ["ignore", "pipe", "pipe"]
28526
28636
  });
28527
- const logFilePath = import_node_path25.default.join(this.deps.dataDir, "frpc.log");
28528
- const logStream = import_node_fs23.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
28637
+ const logFilePath = import_node_path26.default.join(this.deps.dataDir, "frpc.log");
28638
+ const logStream = import_node_fs24.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
28529
28639
  logStream.on("error", () => {
28530
28640
  });
28531
28641
  const tee = (chunk) => {
@@ -28618,12 +28728,12 @@ function deriveStableDeviceKey(opts = {}) {
28618
28728
  }
28619
28729
 
28620
28730
  // src/auth-store.ts
28621
- var import_node_fs24 = __toESM(require("fs"), 1);
28622
- var import_node_path26 = __toESM(require("path"), 1);
28731
+ var import_node_fs25 = __toESM(require("fs"), 1);
28732
+ var import_node_path27 = __toESM(require("path"), 1);
28623
28733
  var import_node_crypto10 = __toESM(require("crypto"), 1);
28624
28734
  var AUTH_FILE_NAME = "auth.json";
28625
28735
  function authFilePath(dataDir) {
28626
- return import_node_path26.default.join(dataDir, AUTH_FILE_NAME);
28736
+ return import_node_path27.default.join(dataDir, AUTH_FILE_NAME);
28627
28737
  }
28628
28738
  function loadOrCreateAuthFile(opts) {
28629
28739
  const file = authFilePath(opts.dataDir);
@@ -28655,7 +28765,7 @@ function defaultGenerateOwnerPrincipalId() {
28655
28765
  }
28656
28766
  function readAuthFile(file) {
28657
28767
  try {
28658
- const raw = import_node_fs24.default.readFileSync(file, "utf8");
28768
+ const raw = import_node_fs25.default.readFileSync(file, "utf8");
28659
28769
  const parsed = JSON.parse(raw);
28660
28770
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
28661
28771
  return null;
@@ -28673,25 +28783,25 @@ function readAuthFile(file) {
28673
28783
  }
28674
28784
  }
28675
28785
  function writeAuthFile(file, content) {
28676
- import_node_fs24.default.mkdirSync(import_node_path26.default.dirname(file), { recursive: true });
28677
- import_node_fs24.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
28786
+ import_node_fs25.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
28787
+ import_node_fs25.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
28678
28788
  try {
28679
- import_node_fs24.default.chmodSync(file, 384);
28789
+ import_node_fs25.default.chmodSync(file, 384);
28680
28790
  } catch {
28681
28791
  }
28682
28792
  }
28683
28793
 
28684
28794
  // src/owner-profile.ts
28685
- var import_node_fs25 = __toESM(require("fs"), 1);
28795
+ var import_node_fs26 = __toESM(require("fs"), 1);
28686
28796
  var import_node_os12 = __toESM(require("os"), 1);
28687
- var import_node_path27 = __toESM(require("path"), 1);
28797
+ var import_node_path28 = __toESM(require("path"), 1);
28688
28798
  var PROFILE_FILENAME = "profile.json";
28689
28799
  function loadOwnerDisplayName(dataDir) {
28690
28800
  const fallback = import_node_os12.default.userInfo().username;
28691
- const profilePath = import_node_path27.default.join(dataDir, PROFILE_FILENAME);
28801
+ const profilePath = import_node_path28.default.join(dataDir, PROFILE_FILENAME);
28692
28802
  let raw;
28693
28803
  try {
28694
- raw = import_node_fs25.default.readFileSync(profilePath, "utf8");
28804
+ raw = import_node_fs26.default.readFileSync(profilePath, "utf8");
28695
28805
  } catch {
28696
28806
  return fallback;
28697
28807
  }
@@ -28720,12 +28830,12 @@ init_protocol();
28720
28830
  init_protocol();
28721
28831
 
28722
28832
  // src/session/fork.ts
28723
- var import_node_fs26 = __toESM(require("fs"), 1);
28833
+ var import_node_fs27 = __toESM(require("fs"), 1);
28724
28834
  var import_node_os13 = __toESM(require("os"), 1);
28725
- var import_node_path28 = __toESM(require("path"), 1);
28835
+ var import_node_path29 = __toESM(require("path"), 1);
28726
28836
  init_claude_history();
28727
28837
  function readJsonlEntries(file) {
28728
- const raw = import_node_fs26.default.readFileSync(file, "utf8");
28838
+ const raw = import_node_fs27.default.readFileSync(file, "utf8");
28729
28839
  const out = [];
28730
28840
  for (const line of raw.split("\n")) {
28731
28841
  const t = line.trim();
@@ -28738,10 +28848,10 @@ function readJsonlEntries(file) {
28738
28848
  return out;
28739
28849
  }
28740
28850
  function forkSession(input) {
28741
- const baseDir = input.baseDir ?? import_node_path28.default.join(import_node_os13.default.homedir(), ".claude");
28742
- const projectDir = import_node_path28.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
28743
- const sourceFile = import_node_path28.default.join(projectDir, `${input.toolSessionId}.jsonl`);
28744
- if (!import_node_fs26.default.existsSync(sourceFile)) {
28851
+ const baseDir = input.baseDir ?? import_node_path29.default.join(import_node_os13.default.homedir(), ".claude");
28852
+ const projectDir = import_node_path29.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
28853
+ const sourceFile = import_node_path29.default.join(projectDir, `${input.toolSessionId}.jsonl`);
28854
+ if (!import_node_fs27.default.existsSync(sourceFile)) {
28745
28855
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
28746
28856
  }
28747
28857
  const entries = readJsonlEntries(sourceFile);
@@ -28771,9 +28881,9 @@ function forkSession(input) {
28771
28881
  }
28772
28882
  forkedLines.push(JSON.stringify(forked));
28773
28883
  }
28774
- const forkedFilePath = import_node_path28.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
28775
- import_node_fs26.default.mkdirSync(projectDir, { recursive: true });
28776
- import_node_fs26.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
28884
+ const forkedFilePath = import_node_path29.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
28885
+ import_node_fs27.default.mkdirSync(projectDir, { recursive: true });
28886
+ import_node_fs27.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
28777
28887
  return { forkedToolSessionId, forkedFilePath };
28778
28888
  }
28779
28889
 
@@ -29129,7 +29239,7 @@ function buildPermissionHandlers(deps) {
29129
29239
  }
29130
29240
 
29131
29241
  // src/handlers/history.ts
29132
- var path38 = __toESM(require("path"), 1);
29242
+ var path39 = __toESM(require("path"), 1);
29133
29243
  init_protocol();
29134
29244
 
29135
29245
  // src/session/recent-dirs.ts
@@ -29147,7 +29257,7 @@ function listRecentDirs(store, limit = 50) {
29147
29257
  }
29148
29258
 
29149
29259
  // src/permission/persona-paths.ts
29150
- var path37 = __toESM(require("path"), 1);
29260
+ var path38 = __toESM(require("path"), 1);
29151
29261
  function getAllowedPersonaIds(grants, action) {
29152
29262
  const ids = /* @__PURE__ */ new Set();
29153
29263
  for (const g2 of grants) {
@@ -29160,26 +29270,26 @@ function getAllowedPersonaIds(grants, action) {
29160
29270
  return ids;
29161
29271
  }
29162
29272
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read") {
29163
- const root = path37.resolve(personaRoot);
29164
- const target = path37.resolve(absPath);
29165
- const sep3 = root.endsWith(path37.sep) ? "" : path37.sep;
29273
+ const root = path38.resolve(personaRoot);
29274
+ const target = path38.resolve(absPath);
29275
+ const sep3 = root.endsWith(path38.sep) ? "" : path38.sep;
29166
29276
  if (!target.startsWith(root + sep3)) return false;
29167
- const rel = path37.relative(root, target);
29277
+ const rel = path38.relative(root, target);
29168
29278
  if (!rel || rel.startsWith("..")) return false;
29169
- const personaId = rel.split(path37.sep)[0];
29279
+ const personaId = rel.split(path38.sep)[0];
29170
29280
  if (!personaId) return false;
29171
29281
  const allowed = getAllowedPersonaIds(grants, action);
29172
29282
  if (allowed === "*") return true;
29173
29283
  return allowed.has(personaId);
29174
29284
  }
29175
29285
  function personaIdFromPath(absPath, personaRoot) {
29176
- const root = path37.resolve(personaRoot);
29177
- const target = path37.resolve(absPath);
29178
- const sep3 = root.endsWith(path37.sep) ? "" : path37.sep;
29286
+ const root = path38.resolve(personaRoot);
29287
+ const target = path38.resolve(absPath);
29288
+ const sep3 = root.endsWith(path38.sep) ? "" : path38.sep;
29179
29289
  if (!target.startsWith(root + sep3)) return null;
29180
- const rel = path37.relative(root, target);
29290
+ const rel = path38.relative(root, target);
29181
29291
  if (!rel || rel.startsWith("..")) return null;
29182
- const id = rel.split(path37.sep)[0];
29292
+ const id = rel.split(path38.sep)[0];
29183
29293
  return id || null;
29184
29294
  }
29185
29295
 
@@ -29204,7 +29314,7 @@ function buildHistoryHandlers(deps) {
29204
29314
  if (!pid) return false;
29205
29315
  return isGuestPathAllowed(
29206
29316
  ctx.grants,
29207
- path38.join(personaRoot, pid),
29317
+ path39.join(personaRoot, pid),
29208
29318
  personaRoot,
29209
29319
  "read"
29210
29320
  );
@@ -29215,7 +29325,7 @@ function buildHistoryHandlers(deps) {
29215
29325
  };
29216
29326
  const list = async (frame, _client, ctx) => {
29217
29327
  const args = HistoryListArgs.parse(frame);
29218
- assertGuestPath(ctx, path38.resolve(args.projectPath), personaRoot, "history:list");
29328
+ assertGuestPath(ctx, path39.resolve(args.projectPath), personaRoot, "history:list");
29219
29329
  const sessions = await history.listSessions(args);
29220
29330
  return { response: { type: "history:list", sessions } };
29221
29331
  };
@@ -29247,13 +29357,13 @@ function buildHistoryHandlers(deps) {
29247
29357
  };
29248
29358
  const subagents = async (frame, _client, ctx) => {
29249
29359
  const args = HistorySubagentsArgs.parse(frame);
29250
- assertGuestPath(ctx, path38.resolve(args.cwd), personaRoot, "history:subagents");
29360
+ assertGuestPath(ctx, path39.resolve(args.cwd), personaRoot, "history:subagents");
29251
29361
  const subs = await history.listSubagents(args);
29252
29362
  return { response: { type: "history:subagents", subagents: subs } };
29253
29363
  };
29254
29364
  const subagentRead = async (frame, _client, ctx) => {
29255
29365
  const args = HistorySubagentReadArgs.parse(frame);
29256
- assertGuestPath(ctx, path38.resolve(args.cwd), personaRoot, "history:subagent-read");
29366
+ assertGuestPath(ctx, path39.resolve(args.cwd), personaRoot, "history:subagent-read");
29257
29367
  const res = await history.readSubagent(args);
29258
29368
  return { response: { type: "history:subagent-read", ...res } };
29259
29369
  };
@@ -29261,7 +29371,7 @@ function buildHistoryHandlers(deps) {
29261
29371
  const dirs = listRecentDirs(store);
29262
29372
  if (ctx?.principal.kind === "guest" && personaRoot) {
29263
29373
  const filtered = dirs.filter(
29264
- (d) => isGuestPathAllowed(ctx.grants, path38.resolve(d.cwd), personaRoot, "read")
29374
+ (d) => isGuestPathAllowed(ctx.grants, path39.resolve(d.cwd), personaRoot, "read")
29265
29375
  );
29266
29376
  return { response: { type: "history:recentDirs", dirs: filtered } };
29267
29377
  }
@@ -29278,7 +29388,7 @@ function buildHistoryHandlers(deps) {
29278
29388
  }
29279
29389
 
29280
29390
  // src/handlers/workspace.ts
29281
- var path39 = __toESM(require("path"), 1);
29391
+ var path40 = __toESM(require("path"), 1);
29282
29392
  var os14 = __toESM(require("os"), 1);
29283
29393
  init_protocol();
29284
29394
  init_protocol();
@@ -29319,22 +29429,22 @@ function buildWorkspaceHandlers(deps) {
29319
29429
  const args = WorkspaceListArgs.parse(frame);
29320
29430
  const isGuest = ctx?.principal.kind === "guest";
29321
29431
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os14.homedir();
29322
- const resolvedCwd = path39.resolve(args.cwd ?? fallbackCwd);
29323
- const target = args.path ? path39.resolve(resolvedCwd, args.path) : resolvedCwd;
29432
+ const resolvedCwd = path40.resolve(args.cwd ?? fallbackCwd);
29433
+ const target = args.path ? path40.resolve(resolvedCwd, args.path) : resolvedCwd;
29324
29434
  assertGuestPath2(ctx, target, personaRoot, "workspace:list");
29325
29435
  const res = workspace.list({ ...args, cwd: resolvedCwd });
29326
29436
  return { response: { type: "workspace:list", ...res } };
29327
29437
  };
29328
29438
  const read = async (frame, _client, ctx) => {
29329
29439
  const args = WorkspaceReadArgs.parse(frame);
29330
- const target = path39.isAbsolute(args.path) ? path39.resolve(args.path) : path39.resolve(args.cwd, args.path);
29440
+ const target = path40.isAbsolute(args.path) ? path40.resolve(args.path) : path40.resolve(args.cwd, args.path);
29331
29441
  assertGuestPath2(ctx, target, personaRoot, "workspace:read");
29332
29442
  const res = workspace.read(args);
29333
29443
  return { response: { type: "workspace:read", ...res } };
29334
29444
  };
29335
29445
  const skillsList = async (frame, _client, ctx) => {
29336
29446
  const args = SkillsListArgs.parse(frame);
29337
- const cwdAbs = path39.resolve(args.cwd);
29447
+ const cwdAbs = path40.resolve(args.cwd);
29338
29448
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
29339
29449
  const list2 = skills.list(args);
29340
29450
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -29346,7 +29456,7 @@ function buildWorkspaceHandlers(deps) {
29346
29456
  };
29347
29457
  const agentsList = async (frame, _client, ctx) => {
29348
29458
  const args = AgentsListArgs.parse(frame);
29349
- const cwdAbs = path39.resolve(args.cwd);
29459
+ const cwdAbs = path40.resolve(args.cwd);
29350
29460
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
29351
29461
  const list2 = agents.list(args);
29352
29462
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -29365,20 +29475,20 @@ function buildWorkspaceHandlers(deps) {
29365
29475
  }
29366
29476
 
29367
29477
  // src/handlers/git.ts
29368
- var path41 = __toESM(require("path"), 1);
29478
+ var path42 = __toESM(require("path"), 1);
29369
29479
  init_protocol();
29370
29480
  init_protocol();
29371
29481
 
29372
29482
  // src/workspace/git.ts
29373
29483
  var import_node_child_process6 = require("child_process");
29374
- var import_node_fs27 = __toESM(require("fs"), 1);
29375
- var import_node_path29 = __toESM(require("path"), 1);
29484
+ var import_node_fs28 = __toESM(require("fs"), 1);
29485
+ var import_node_path30 = __toESM(require("path"), 1);
29376
29486
  var import_node_util = require("util");
29377
29487
  var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
29378
29488
  function normalizePath(p2) {
29379
- const resolved = import_node_path29.default.resolve(p2);
29489
+ const resolved = import_node_path30.default.resolve(p2);
29380
29490
  try {
29381
- return import_node_fs27.default.realpathSync(resolved);
29491
+ return import_node_fs28.default.realpathSync(resolved);
29382
29492
  } catch {
29383
29493
  return resolved;
29384
29494
  }
@@ -29451,7 +29561,7 @@ async function listGitBranches(cwd) {
29451
29561
  // src/handlers/git.ts
29452
29562
  function assertGuestCwd(ctx, cwd, personaRoot, method) {
29453
29563
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
29454
- if (!isGuestPathAllowed(ctx.grants, path41.resolve(cwd), personaRoot, "read")) {
29564
+ if (!isGuestPathAllowed(ctx.grants, path42.resolve(cwd), personaRoot, "read")) {
29455
29565
  throw new ClawdError(
29456
29566
  ERROR_CODES.UNAUTHORIZED,
29457
29567
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -29938,7 +30048,7 @@ function buildPersonaHandlers(deps) {
29938
30048
  }
29939
30049
 
29940
30050
  // src/handlers/attachment.ts
29941
- var import_node_path30 = __toESM(require("path"), 1);
30051
+ var import_node_path31 = __toESM(require("path"), 1);
29942
30052
  init_protocol();
29943
30053
  init_protocol();
29944
30054
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -29992,12 +30102,12 @@ function buildAttachmentHandlers(deps) {
29992
30102
  `session ${args.sessionId} scope unresolved`
29993
30103
  );
29994
30104
  }
29995
- const cwdAbs = import_node_path30.default.resolve(sessionFile.cwd);
29996
- const candidateAbs = import_node_path30.default.isAbsolute(args.relPath) ? import_node_path30.default.resolve(args.relPath) : import_node_path30.default.resolve(cwdAbs, args.relPath);
30105
+ const cwdAbs = import_node_path31.default.resolve(sessionFile.cwd);
30106
+ const candidateAbs = import_node_path31.default.isAbsolute(args.relPath) ? import_node_path31.default.resolve(args.relPath) : import_node_path31.default.resolve(cwdAbs, args.relPath);
29997
30107
  assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
29998
30108
  const entries = deps.groupFileStore.list(scope, args.sessionId);
29999
30109
  const entry = entries.find((e) => {
30000
- const storedAbs = import_node_path30.default.isAbsolute(e.relPath) ? import_node_path30.default.resolve(e.relPath) : import_node_path30.default.resolve(cwdAbs, e.relPath);
30110
+ const storedAbs = import_node_path31.default.isAbsolute(e.relPath) ? import_node_path31.default.resolve(e.relPath) : import_node_path31.default.resolve(cwdAbs, e.relPath);
30001
30111
  return storedAbs === candidateAbs && !e.stale;
30002
30112
  });
30003
30113
  if (!entry) {
@@ -30021,7 +30131,7 @@ function buildAttachmentHandlers(deps) {
30021
30131
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
30022
30132
  const f = deps.sessionStore.read(sessionId);
30023
30133
  if (!f) return;
30024
- assertGuestAttachmentPath(ctx, import_node_path30.default.resolve(f.cwd), deps.personaRoot, method);
30134
+ assertGuestAttachmentPath(ctx, import_node_path31.default.resolve(f.cwd), deps.personaRoot, method);
30025
30135
  }
30026
30136
  const groupAdd = async (frame, _client, ctx) => {
30027
30137
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -30263,7 +30373,7 @@ function computeGrantForFrame(method, frame) {
30263
30373
  async function startDaemon(config) {
30264
30374
  const logger = createLogger({
30265
30375
  level: config.logLevel,
30266
- file: import_node_path31.default.join(config.dataDir, "clawd.log")
30376
+ file: import_node_path32.default.join(config.dataDir, "clawd.log")
30267
30377
  });
30268
30378
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
30269
30379
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -30350,7 +30460,7 @@ async function startDaemon(config) {
30350
30460
  const agents = new AgentsScanner();
30351
30461
  const history = new ClaudeHistoryReader();
30352
30462
  let transport = null;
30353
- const personaStore = new PersonaStore(import_node_path31.default.join(config.dataDir, "personas"));
30463
+ const personaStore = new PersonaStore(import_node_path32.default.join(config.dataDir, "personas"));
30354
30464
  const defaultsRoot = findDefaultsRoot();
30355
30465
  if (defaultsRoot) {
30356
30466
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -30367,7 +30477,7 @@ async function startDaemon(config) {
30367
30477
  getAdapter,
30368
30478
  historyReader: history,
30369
30479
  dataDir: config.dataDir,
30370
- personaRoot: import_node_path31.default.join(config.dataDir, "personas"),
30480
+ personaRoot: import_node_path32.default.join(config.dataDir, "personas"),
30371
30481
  personaStore,
30372
30482
  ownerDisplayName,
30373
30483
  ownerPrincipalId,
@@ -30391,10 +30501,10 @@ async function startDaemon(config) {
30391
30501
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
30392
30502
  attachmentGroup: {
30393
30503
  onFileEdit: (input) => {
30394
- const absPath = import_node_path31.default.isAbsolute(input.relPath) ? input.relPath : import_node_path31.default.join(input.cwd, input.relPath);
30504
+ const absPath = import_node_path32.default.isAbsolute(input.relPath) ? input.relPath : import_node_path32.default.join(input.cwd, input.relPath);
30395
30505
  let size = 0;
30396
30506
  try {
30397
- size = import_node_fs28.default.statSync(absPath).size;
30507
+ size = import_node_fs29.default.statSync(absPath).size;
30398
30508
  } catch (err) {
30399
30509
  logger.warn("attachment.onFileEdit stat failed", {
30400
30510
  sessionId: input.sessionId,
@@ -30512,10 +30622,10 @@ async function startDaemon(config) {
30512
30622
  // 'persona/<pid>/owner',default 走 'default'。
30513
30623
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
30514
30624
  // guest path guard:candidate 必须在 personaRoot 子树下
30515
- personaRoot: import_node_path31.default.join(config.dataDir, "personas")
30625
+ personaRoot: import_node_path32.default.join(config.dataDir, "personas")
30516
30626
  },
30517
30627
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
30518
- personaRoot: import_node_path31.default.join(config.dataDir, "personas"),
30628
+ personaRoot: import_node_path32.default.join(config.dataDir, "personas"),
30519
30629
  // capability:list / delete handler 依赖
30520
30630
  capabilityManager,
30521
30631
  // personal-cap:get 返回的 shareBaseUrl 用此 base URL:
@@ -30608,6 +30718,7 @@ async function startDaemon(config) {
30608
30718
  // 形状与 reducer permission_request 分支构造的 session:question 帧一致;UI 不区分
30609
30719
  // 首播 vs 重放(last-write-wins,详见 protocol/events.ts JSDoc)。
30610
30720
  onSubscribe: (client, sessionId) => {
30721
+ probeEvent("subscribe", { sid: sessionId });
30611
30722
  const runner = manager.getActive(sessionId);
30612
30723
  if (!runner) return;
30613
30724
  const pendingQuestions = runner.getState().pendingQuestions ?? {};
@@ -30728,8 +30839,8 @@ async function startDaemon(config) {
30728
30839
  const lines = [
30729
30840
  `Tunnel: ${r.url}`,
30730
30841
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
30731
- `Frpc config: ${import_node_path31.default.join(config.dataDir, "frpc.toml")}`,
30732
- `Frpc log: ${import_node_path31.default.join(config.dataDir, "frpc.log")}`
30842
+ `Frpc config: ${import_node_path32.default.join(config.dataDir, "frpc.toml")}`,
30843
+ `Frpc log: ${import_node_path32.default.join(config.dataDir, "frpc.log")}`
30733
30844
  ];
30734
30845
  const width = Math.max(...lines.map((l) => l.length));
30735
30846
  const bar = "\u2550".repeat(width + 4);
@@ -30742,8 +30853,8 @@ ${bar}
30742
30853
 
30743
30854
  `);
30744
30855
  try {
30745
- const connectPath = import_node_path31.default.join(config.dataDir, "connect.txt");
30746
- import_node_fs28.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
30856
+ const connectPath = import_node_path32.default.join(config.dataDir, "connect.txt");
30857
+ import_node_fs29.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
30747
30858
  } catch {
30748
30859
  }
30749
30860
  } catch (err) {
@@ -30808,9 +30919,9 @@ ${bar}
30808
30919
  };
30809
30920
  }
30810
30921
  function migrateDropPersonsDir(dataDir) {
30811
- const dir = import_node_path31.default.join(dataDir, "persons");
30922
+ const dir = import_node_path32.default.join(dataDir, "persons");
30812
30923
  try {
30813
- import_node_fs28.default.rmSync(dir, { recursive: true, force: true });
30924
+ import_node_fs29.default.rmSync(dir, { recursive: true, force: true });
30814
30925
  } catch {
30815
30926
  }
30816
30927
  }