@clawos-dev/clawd 0.2.89 → 0.2.90-beta.169.a6af395

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 +600 -587
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -65,14 +65,6 @@ var init_methods = __esm({
65
65
  "session:unsubscribe",
66
66
  "session:pin",
67
67
  "session:reorderPins",
68
- // mirror peer sessions (2026-05-26): owner-only RPC,写/删本机 mirror SessionFile —
69
- // mirror 是「**我**在朋友 daemon 上自己创建的 session」的本机持久化副本(不是朋友的会话),
70
- // 方便 sidebar 跨设备聚合。daemon dumb 写删,**不广播任何 push 帧** (不发 session:info /
71
- // session:deleted);UI 是写入唯一源,双写完成后通过 cache.setData('sessions', ...) 同步
72
- // 本地 sidebar state。native session:* handler 完全不感知 mirror (UI 操作 mirror 不复用
73
- // native 路径)。
74
- "peerSession:upsert",
75
- "peerSession:remove",
76
68
  "permission:respond",
77
69
  // AskUserQuestion 表单回写:UI 答完所有 question 后调用,daemon 把答案合并进 updated_input
78
70
  // 写一条 control_response 到 CC stdin(详见 events.ts session:question JSDoc)
@@ -651,8 +643,8 @@ var init_parseUtil = __esm({
651
643
  init_errors2();
652
644
  init_en();
653
645
  makeIssue = (params) => {
654
- const { data, path: path46, errorMaps, issueData } = params;
655
- const fullPath = [...path46, ...issueData.path || []];
646
+ const { data, path: path47, errorMaps, issueData } = params;
647
+ const fullPath = [...path47, ...issueData.path || []];
656
648
  const fullIssue = {
657
649
  ...issueData,
658
650
  path: fullPath
@@ -963,11 +955,11 @@ var init_types = __esm({
963
955
  init_parseUtil();
964
956
  init_util();
965
957
  ParseInputLazyPath = class {
966
- constructor(parent, value, path46, key) {
958
+ constructor(parent, value, path47, key) {
967
959
  this._cachedPath = [];
968
960
  this.parent = parent;
969
961
  this.data = value;
970
- this._path = path46;
962
+ this._path = path47;
971
963
  this._key = key;
972
964
  }
973
965
  get path() {
@@ -4501,7 +4493,7 @@ var init_persona_schemas = __esm({
4501
4493
  });
4502
4494
 
4503
4495
  // ../protocol/src/schemas.ts
4504
- var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionSubscribeArgs, SessionPinArgs, PeerSessionUpsertArgs, PeerSessionUpsertResponseSchema, PeerSessionRemoveArgs, PeerSessionRemoveResponseSchema, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, AuthRequestFrameSchema, AuthOkFrameSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema;
4496
+ var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionSubscribeArgs, SessionPinArgs, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, AuthRequestFrameSchema, AuthOkFrameSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema;
4505
4497
  var init_schemas = __esm({
4506
4498
  "../protocol/src/schemas.ts"() {
4507
4499
  "use strict";
@@ -4629,35 +4621,6 @@ var init_schemas = __esm({
4629
4621
  * 当前为 caller 自报,daemon 不密码学验证真伪;强身份验签是独立工作(B 方案)。
4630
4622
  */
4631
4623
  creatorOwnerPrincipalId: external_exports.string().min(1).optional(),
4632
- /**
4633
- * Mirror peer sessions (2026-05-26): mirror 标识。**我在朋友 daemon 上以 guest ctx
4634
- * 创建的 session**,远端是 source of truth,本机是该 session 的持久化副本,方便
4635
- * sidebar 跨设备聚合。字段值是远端 daemon 的 ownerPrincipalId(即我接入的那位朋友)。
4636
- *
4637
- * 语义关键澄清:mirror **不是朋友创建给我的会话**——它是我自己的会话,只是在朋友
4638
- * 的机器上跑。sidebar chip 显示 `@<朋友>` 暗示「位置」,不是「来源」。
4639
- *
4640
- * - undefined / 缺省 → 本机 native session(在我自己机器上跑)
4641
- * - 非空 → 我的会话在该 ownerPrincipalId 朋友的 daemon 上跑,本机为持久化副本
4642
- *
4643
- * 与 `creatorPrincipalId` / `creatorOwnerPrincipalId` 在四类 session 下取值矩阵:
4644
- * | 形态 | creatorPrincipalId | creatorOwnerPrincipalId | originOwnerPrincipalId |
4645
- * |-------------------------------------|--------------------------|-------------------------|------------------------|
4646
- * | 本机 owner 自创 | 本机 ownerPrincipalId | 本机 ownerPrincipalId | undefined |
4647
- * | 本机被别人通过 personal token 接入创建 | 远端接入者 cap.id | 远端接入者 ownerPrincipalId | undefined |
4648
- * | 我在朋友 daemon 上以 guest ctx 创建(mirror 回本机) | 朋友 daemon personal cap.id | 我自己 ownerPrincipalId | 朋友 ownerPrincipalId |
4649
- *
4650
- * UI 用法:
4651
- * - sidebar Active/Pinned/Recents 过滤:`origin 非空 → 一律视作 self`(绕过 #739 隔离)
4652
- * - 行内显示 `@<朋友>` chip 暗示位置
4653
- * - 进 ChatPanel 时按 origin 路由到 `pool.ensureRemoteForOwner(origin)` 走远端
4654
- *
4655
- * daemon 用法:
4656
- * - `peerSession:upsert` / `peerSession:remove` 一族 RPC 专管 mirror 写删;
4657
- * daemon dumb write/delete,**不广播任何 push 帧**,UI 是写入唯一源
4658
- * - native `session:*` handler 完全不感知 mirror(UI 操作 mirror 不走 native 路径)
4659
- */
4660
- originOwnerPrincipalId: external_exports.string().min(1).optional(),
4661
4624
  createdAt: external_exports.string().min(1),
4662
4625
  updatedAt: external_exports.string().min(1)
4663
4626
  });
@@ -5013,14 +4976,6 @@ var init_schemas = __esm({
5013
4976
  sessionId: external_exports.string().min(1),
5014
4977
  pinned: external_exports.boolean()
5015
4978
  });
5016
- PeerSessionUpsertArgs = SessionFileSchema;
5017
- PeerSessionUpsertResponseSchema = external_exports.object({
5018
- type: external_exports.literal("peerSession:upsert:ok")
5019
- });
5020
- PeerSessionRemoveArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
5021
- PeerSessionRemoveResponseSchema = external_exports.object({
5022
- type: external_exports.literal("peerSession:remove:ok")
5023
- });
5024
4979
  SessionReorderPinsArgs = external_exports.object({
5025
4980
  orderedIds: external_exports.array(external_exports.string().min(1)).min(1)
5026
4981
  });
@@ -5635,8 +5590,8 @@ var require_req = __commonJS({
5635
5590
  if (req.originalUrl) {
5636
5591
  _req.url = req.originalUrl;
5637
5592
  } else {
5638
- const path46 = req.path;
5639
- _req.url = typeof path46 === "string" ? path46 : req.url ? req.url.path || req.url : void 0;
5593
+ const path47 = req.path;
5594
+ _req.url = typeof path47 === "string" ? path47 : req.url ? req.url.path || req.url : void 0;
5640
5595
  }
5641
5596
  if (req.query) {
5642
5597
  _req.query = req.query;
@@ -5801,14 +5756,14 @@ var require_redact = __commonJS({
5801
5756
  }
5802
5757
  return obj;
5803
5758
  }
5804
- function parsePath(path46) {
5759
+ function parsePath(path47) {
5805
5760
  const parts = [];
5806
5761
  let current = "";
5807
5762
  let inBrackets = false;
5808
5763
  let inQuotes = false;
5809
5764
  let quoteChar = "";
5810
- for (let i = 0; i < path46.length; i++) {
5811
- const char = path46[i];
5765
+ for (let i = 0; i < path47.length; i++) {
5766
+ const char = path47[i];
5812
5767
  if (!inBrackets && char === ".") {
5813
5768
  if (current) {
5814
5769
  parts.push(current);
@@ -5939,10 +5894,10 @@ var require_redact = __commonJS({
5939
5894
  return current;
5940
5895
  }
5941
5896
  function redactPaths(obj, paths, censor, remove = false) {
5942
- for (const path46 of paths) {
5943
- const parts = parsePath(path46);
5897
+ for (const path47 of paths) {
5898
+ const parts = parsePath(path47);
5944
5899
  if (parts.includes("*")) {
5945
- redactWildcardPath(obj, parts, censor, path46, remove);
5900
+ redactWildcardPath(obj, parts, censor, path47, remove);
5946
5901
  } else {
5947
5902
  if (remove) {
5948
5903
  removeKey(obj, parts);
@@ -6027,8 +5982,8 @@ var require_redact = __commonJS({
6027
5982
  }
6028
5983
  } else {
6029
5984
  if (afterWildcard.includes("*")) {
6030
- const wrappedCensor = typeof censor === "function" ? (value, path46) => {
6031
- const fullPath = [...pathArray.slice(0, pathLength), ...path46];
5985
+ const wrappedCensor = typeof censor === "function" ? (value, path47) => {
5986
+ const fullPath = [...pathArray.slice(0, pathLength), ...path47];
6032
5987
  return censor(value, fullPath);
6033
5988
  } : censor;
6034
5989
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -6063,8 +6018,8 @@ var require_redact = __commonJS({
6063
6018
  return null;
6064
6019
  }
6065
6020
  const pathStructure = /* @__PURE__ */ new Map();
6066
- for (const path46 of pathsToClone) {
6067
- const parts = parsePath(path46);
6021
+ for (const path47 of pathsToClone) {
6022
+ const parts = parsePath(path47);
6068
6023
  let current = pathStructure;
6069
6024
  for (let i = 0; i < parts.length; i++) {
6070
6025
  const part = parts[i];
@@ -6116,24 +6071,24 @@ var require_redact = __commonJS({
6116
6071
  }
6117
6072
  return cloneSelectively(obj, pathStructure);
6118
6073
  }
6119
- function validatePath(path46) {
6120
- if (typeof path46 !== "string") {
6074
+ function validatePath(path47) {
6075
+ if (typeof path47 !== "string") {
6121
6076
  throw new Error("Paths must be (non-empty) strings");
6122
6077
  }
6123
- if (path46 === "") {
6078
+ if (path47 === "") {
6124
6079
  throw new Error("Invalid redaction path ()");
6125
6080
  }
6126
- if (path46.includes("..")) {
6127
- throw new Error(`Invalid redaction path (${path46})`);
6081
+ if (path47.includes("..")) {
6082
+ throw new Error(`Invalid redaction path (${path47})`);
6128
6083
  }
6129
- if (path46.includes(",")) {
6130
- throw new Error(`Invalid redaction path (${path46})`);
6084
+ if (path47.includes(",")) {
6085
+ throw new Error(`Invalid redaction path (${path47})`);
6131
6086
  }
6132
6087
  let bracketCount = 0;
6133
6088
  let inQuotes = false;
6134
6089
  let quoteChar = "";
6135
- for (let i = 0; i < path46.length; i++) {
6136
- const char = path46[i];
6090
+ for (let i = 0; i < path47.length; i++) {
6091
+ const char = path47[i];
6137
6092
  if ((char === '"' || char === "'") && bracketCount > 0) {
6138
6093
  if (!inQuotes) {
6139
6094
  inQuotes = true;
@@ -6147,20 +6102,20 @@ var require_redact = __commonJS({
6147
6102
  } else if (char === "]" && !inQuotes) {
6148
6103
  bracketCount--;
6149
6104
  if (bracketCount < 0) {
6150
- throw new Error(`Invalid redaction path (${path46})`);
6105
+ throw new Error(`Invalid redaction path (${path47})`);
6151
6106
  }
6152
6107
  }
6153
6108
  }
6154
6109
  if (bracketCount !== 0) {
6155
- throw new Error(`Invalid redaction path (${path46})`);
6110
+ throw new Error(`Invalid redaction path (${path47})`);
6156
6111
  }
6157
6112
  }
6158
6113
  function validatePaths(paths) {
6159
6114
  if (!Array.isArray(paths)) {
6160
6115
  throw new TypeError("paths must be an array");
6161
6116
  }
6162
- for (const path46 of paths) {
6163
- validatePath(path46);
6117
+ for (const path47 of paths) {
6118
+ validatePath(path47);
6164
6119
  }
6165
6120
  }
6166
6121
  function slowRedact(options = {}) {
@@ -6328,8 +6283,8 @@ var require_redaction = __commonJS({
6328
6283
  if (shape[k2] === null) {
6329
6284
  o[k2] = (value) => topCensor(value, [k2]);
6330
6285
  } else {
6331
- const wrappedCensor = typeof censor === "function" ? (value, path46) => {
6332
- return censor(value, [k2, ...path46]);
6286
+ const wrappedCensor = typeof censor === "function" ? (value, path47) => {
6287
+ return censor(value, [k2, ...path47]);
6333
6288
  } : censor;
6334
6289
  o[k2] = Redact({
6335
6290
  paths: shape[k2],
@@ -6547,10 +6502,10 @@ var require_atomic_sleep = __commonJS({
6547
6502
  var require_sonic_boom = __commonJS({
6548
6503
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
6549
6504
  "use strict";
6550
- var fs37 = require("fs");
6505
+ var fs38 = require("fs");
6551
6506
  var EventEmitter2 = require("events");
6552
6507
  var inherits = require("util").inherits;
6553
- var path46 = require("path");
6508
+ var path47 = require("path");
6554
6509
  var sleep = require_atomic_sleep();
6555
6510
  var assert = require("assert");
6556
6511
  var BUSY_WRITE_TIMEOUT = 100;
@@ -6604,20 +6559,20 @@ var require_sonic_boom = __commonJS({
6604
6559
  const mode = sonic.mode;
6605
6560
  if (sonic.sync) {
6606
6561
  try {
6607
- if (sonic.mkdir) fs37.mkdirSync(path46.dirname(file), { recursive: true });
6608
- const fd = fs37.openSync(file, flags, mode);
6562
+ if (sonic.mkdir) fs38.mkdirSync(path47.dirname(file), { recursive: true });
6563
+ const fd = fs38.openSync(file, flags, mode);
6609
6564
  fileOpened(null, fd);
6610
6565
  } catch (err) {
6611
6566
  fileOpened(err);
6612
6567
  throw err;
6613
6568
  }
6614
6569
  } else if (sonic.mkdir) {
6615
- fs37.mkdir(path46.dirname(file), { recursive: true }, (err) => {
6570
+ fs38.mkdir(path47.dirname(file), { recursive: true }, (err) => {
6616
6571
  if (err) return fileOpened(err);
6617
- fs37.open(file, flags, mode, fileOpened);
6572
+ fs38.open(file, flags, mode, fileOpened);
6618
6573
  });
6619
6574
  } else {
6620
- fs37.open(file, flags, mode, fileOpened);
6575
+ fs38.open(file, flags, mode, fileOpened);
6621
6576
  }
6622
6577
  }
6623
6578
  function SonicBoom(opts) {
@@ -6658,8 +6613,8 @@ var require_sonic_boom = __commonJS({
6658
6613
  this.flush = flushBuffer;
6659
6614
  this.flushSync = flushBufferSync;
6660
6615
  this._actualWrite = actualWriteBuffer;
6661
- fsWriteSync = () => fs37.writeSync(this.fd, this._writingBuf);
6662
- fsWrite = () => fs37.write(this.fd, this._writingBuf, this.release);
6616
+ fsWriteSync = () => fs38.writeSync(this.fd, this._writingBuf);
6617
+ fsWrite = () => fs38.write(this.fd, this._writingBuf, this.release);
6663
6618
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
6664
6619
  this._writingBuf = "";
6665
6620
  this.write = write;
@@ -6668,15 +6623,15 @@ var require_sonic_boom = __commonJS({
6668
6623
  this._actualWrite = actualWrite;
6669
6624
  fsWriteSync = () => {
6670
6625
  if (Buffer.isBuffer(this._writingBuf)) {
6671
- return fs37.writeSync(this.fd, this._writingBuf);
6626
+ return fs38.writeSync(this.fd, this._writingBuf);
6672
6627
  }
6673
- return fs37.writeSync(this.fd, this._writingBuf, "utf8");
6628
+ return fs38.writeSync(this.fd, this._writingBuf, "utf8");
6674
6629
  };
6675
6630
  fsWrite = () => {
6676
6631
  if (Buffer.isBuffer(this._writingBuf)) {
6677
- return fs37.write(this.fd, this._writingBuf, this.release);
6632
+ return fs38.write(this.fd, this._writingBuf, this.release);
6678
6633
  }
6679
- return fs37.write(this.fd, this._writingBuf, "utf8", this.release);
6634
+ return fs38.write(this.fd, this._writingBuf, "utf8", this.release);
6680
6635
  };
6681
6636
  } else {
6682
6637
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -6733,7 +6688,7 @@ var require_sonic_boom = __commonJS({
6733
6688
  }
6734
6689
  }
6735
6690
  if (this._fsync) {
6736
- fs37.fsyncSync(this.fd);
6691
+ fs38.fsyncSync(this.fd);
6737
6692
  }
6738
6693
  const len = this._len;
6739
6694
  if (this._reopening) {
@@ -6847,7 +6802,7 @@ var require_sonic_boom = __commonJS({
6847
6802
  const onDrain = () => {
6848
6803
  if (!this._fsync) {
6849
6804
  try {
6850
- fs37.fsync(this.fd, (err) => {
6805
+ fs38.fsync(this.fd, (err) => {
6851
6806
  this._flushPending = false;
6852
6807
  cb(err);
6853
6808
  });
@@ -6949,7 +6904,7 @@ var require_sonic_boom = __commonJS({
6949
6904
  const fd = this.fd;
6950
6905
  this.once("ready", () => {
6951
6906
  if (fd !== this.fd) {
6952
- fs37.close(fd, (err) => {
6907
+ fs38.close(fd, (err) => {
6953
6908
  if (err) {
6954
6909
  return this.emit("error", err);
6955
6910
  }
@@ -6998,7 +6953,7 @@ var require_sonic_boom = __commonJS({
6998
6953
  buf = this._bufs[0];
6999
6954
  }
7000
6955
  try {
7001
- const n = Buffer.isBuffer(buf) ? fs37.writeSync(this.fd, buf) : fs37.writeSync(this.fd, buf, "utf8");
6956
+ const n = Buffer.isBuffer(buf) ? fs38.writeSync(this.fd, buf) : fs38.writeSync(this.fd, buf, "utf8");
7002
6957
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
7003
6958
  buf = releasedBufObj.writingBuf;
7004
6959
  this._len = releasedBufObj.len;
@@ -7014,7 +6969,7 @@ var require_sonic_boom = __commonJS({
7014
6969
  }
7015
6970
  }
7016
6971
  try {
7017
- fs37.fsyncSync(this.fd);
6972
+ fs38.fsyncSync(this.fd);
7018
6973
  } catch {
7019
6974
  }
7020
6975
  }
@@ -7035,7 +6990,7 @@ var require_sonic_boom = __commonJS({
7035
6990
  buf = mergeBuf(this._bufs[0], this._lens[0]);
7036
6991
  }
7037
6992
  try {
7038
- const n = fs37.writeSync(this.fd, buf);
6993
+ const n = fs38.writeSync(this.fd, buf);
7039
6994
  buf = buf.subarray(n);
7040
6995
  this._len = Math.max(this._len - n, 0);
7041
6996
  if (buf.length <= 0) {
@@ -7063,13 +7018,13 @@ var require_sonic_boom = __commonJS({
7063
7018
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
7064
7019
  if (this.sync) {
7065
7020
  try {
7066
- const written = Buffer.isBuffer(this._writingBuf) ? fs37.writeSync(this.fd, this._writingBuf) : fs37.writeSync(this.fd, this._writingBuf, "utf8");
7021
+ const written = Buffer.isBuffer(this._writingBuf) ? fs38.writeSync(this.fd, this._writingBuf) : fs38.writeSync(this.fd, this._writingBuf, "utf8");
7067
7022
  release(null, written);
7068
7023
  } catch (err) {
7069
7024
  release(err);
7070
7025
  }
7071
7026
  } else {
7072
- fs37.write(this.fd, this._writingBuf, release);
7027
+ fs38.write(this.fd, this._writingBuf, release);
7073
7028
  }
7074
7029
  }
7075
7030
  function actualWriteBuffer() {
@@ -7078,7 +7033,7 @@ var require_sonic_boom = __commonJS({
7078
7033
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
7079
7034
  if (this.sync) {
7080
7035
  try {
7081
- const written = fs37.writeSync(this.fd, this._writingBuf);
7036
+ const written = fs38.writeSync(this.fd, this._writingBuf);
7082
7037
  release(null, written);
7083
7038
  } catch (err) {
7084
7039
  release(err);
@@ -7087,7 +7042,7 @@ var require_sonic_boom = __commonJS({
7087
7042
  if (kCopyBuffer) {
7088
7043
  this._writingBuf = Buffer.from(this._writingBuf);
7089
7044
  }
7090
- fs37.write(this.fd, this._writingBuf, release);
7045
+ fs38.write(this.fd, this._writingBuf, release);
7091
7046
  }
7092
7047
  }
7093
7048
  function actualClose(sonic) {
@@ -7103,12 +7058,12 @@ var require_sonic_boom = __commonJS({
7103
7058
  sonic._lens = [];
7104
7059
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
7105
7060
  try {
7106
- fs37.fsync(sonic.fd, closeWrapped);
7061
+ fs38.fsync(sonic.fd, closeWrapped);
7107
7062
  } catch {
7108
7063
  }
7109
7064
  function closeWrapped() {
7110
7065
  if (sonic.fd !== 1 && sonic.fd !== 2) {
7111
- fs37.close(sonic.fd, done);
7066
+ fs38.close(sonic.fd, done);
7112
7067
  } else {
7113
7068
  done();
7114
7069
  }
@@ -10243,11 +10198,11 @@ var init_lib = __esm({
10243
10198
  }
10244
10199
  }
10245
10200
  },
10246
- addToPath: function addToPath(path46, added, removed, oldPosInc, options) {
10247
- var last = path46.lastComponent;
10201
+ addToPath: function addToPath(path47, added, removed, oldPosInc, options) {
10202
+ var last = path47.lastComponent;
10248
10203
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
10249
10204
  return {
10250
- oldPos: path46.oldPos + oldPosInc,
10205
+ oldPos: path47.oldPos + oldPosInc,
10251
10206
  lastComponent: {
10252
10207
  count: last.count + 1,
10253
10208
  added,
@@ -10257,7 +10212,7 @@ var init_lib = __esm({
10257
10212
  };
10258
10213
  } else {
10259
10214
  return {
10260
- oldPos: path46.oldPos + oldPosInc,
10215
+ oldPos: path47.oldPos + oldPosInc,
10261
10216
  lastComponent: {
10262
10217
  count: 1,
10263
10218
  added,
@@ -10503,7 +10458,7 @@ function hashDirToCwd(hash) {
10503
10458
  }
10504
10459
  function safeStatMtime(p2) {
10505
10460
  try {
10506
- return import_node_fs7.default.statSync(p2).mtimeMs;
10461
+ return import_node_fs8.default.statSync(p2).mtimeMs;
10507
10462
  } catch {
10508
10463
  return 0;
10509
10464
  }
@@ -10511,7 +10466,7 @@ function safeStatMtime(p2) {
10511
10466
  function readJsonlLines(file) {
10512
10467
  let raw;
10513
10468
  try {
10514
- raw = import_node_fs7.default.readFileSync(file, "utf8");
10469
+ raw = import_node_fs8.default.readFileSync(file, "utf8");
10515
10470
  } catch (err) {
10516
10471
  if (err.code === "ENOENT") return [];
10517
10472
  throw err;
@@ -10688,10 +10643,10 @@ function attachmentToHistoryMessage(o, ts) {
10688
10643
  const memories = raw.map((m2) => {
10689
10644
  if (!m2 || typeof m2 !== "object") return null;
10690
10645
  const rec = m2;
10691
- const path46 = typeof rec.path === "string" ? rec.path : null;
10646
+ const path47 = typeof rec.path === "string" ? rec.path : null;
10692
10647
  const content = typeof rec.content === "string" ? rec.content : null;
10693
- if (!path46 || content == null) return null;
10694
- const entry = { path: path46, content };
10648
+ if (!path47 || content == null) return null;
10649
+ const entry = { path: path47, content };
10695
10650
  if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
10696
10651
  return entry;
10697
10652
  }).filter((m2) => m2 !== null);
@@ -10727,8 +10682,8 @@ function attachmentDeferredToolsText(a) {
10727
10682
  function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
10728
10683
  if (backupFileName === null) return null;
10729
10684
  try {
10730
- return import_node_fs7.default.readFileSync(
10731
- import_node_path8.default.join(fileHistoryRoot, toolSessionId, backupFileName),
10685
+ return import_node_fs8.default.readFileSync(
10686
+ import_node_path9.default.join(fileHistoryRoot, toolSessionId, backupFileName),
10732
10687
  "utf8"
10733
10688
  );
10734
10689
  } catch {
@@ -10737,19 +10692,19 @@ function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
10737
10692
  }
10738
10693
  function readCurrentContent(filePath) {
10739
10694
  try {
10740
- return import_node_fs7.default.readFileSync(filePath, "utf8");
10695
+ return import_node_fs8.default.readFileSync(filePath, "utf8");
10741
10696
  } catch (err) {
10742
10697
  if (err.code === "ENOENT") return null;
10743
10698
  return null;
10744
10699
  }
10745
10700
  }
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;
10701
+ 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
10702
  var init_claude_history = __esm({
10748
10703
  "src/tools/claude-history.ts"() {
10749
10704
  "use strict";
10750
- import_node_fs7 = __toESM(require("fs"), 1);
10705
+ import_node_fs8 = __toESM(require("fs"), 1);
10751
10706
  import_node_os3 = __toESM(require("os"), 1);
10752
- import_node_path8 = __toESM(require("path"), 1);
10707
+ import_node_path9 = __toESM(require("path"), 1);
10753
10708
  init_lib();
10754
10709
  init_tool_result_extra();
10755
10710
  TASK_NOTIFICATION_RE = /<task-notification\b[\s\S]*?<\/task-notification>/i;
@@ -10773,14 +10728,14 @@ var init_claude_history = __esm({
10773
10728
  // 每次 user 提交前 trackEdit 拷一份,作为 rewind 回退目标
10774
10729
  fileHistoryRoot;
10775
10730
  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");
10731
+ const base = opts.baseDir ?? import_node_path9.default.join(import_node_os3.default.homedir(), ".claude");
10732
+ this.projectsRoot = import_node_path9.default.join(base, "projects");
10733
+ this.fileHistoryRoot = import_node_path9.default.join(base, "file-history");
10779
10734
  }
10780
10735
  async listProjects() {
10781
10736
  let entries;
10782
10737
  try {
10783
- entries = import_node_fs7.default.readdirSync(this.projectsRoot, { withFileTypes: true });
10738
+ entries = import_node_fs8.default.readdirSync(this.projectsRoot, { withFileTypes: true });
10784
10739
  } catch (err) {
10785
10740
  if (err.code === "ENOENT") return [];
10786
10741
  throw err;
@@ -10788,9 +10743,9 @@ var init_claude_history = __esm({
10788
10743
  const out = [];
10789
10744
  for (const ent of entries) {
10790
10745
  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);
10746
+ const dir = import_node_path9.default.join(this.projectsRoot, ent.name);
10747
+ const files = import_node_fs8.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
10748
+ const updatedAtMs = files.reduce((m2, f) => Math.max(m2, safeStatMtime(import_node_path9.default.join(dir, f))), 0);
10794
10749
  out.push({
10795
10750
  projectPath: hashDirToCwd(ent.name),
10796
10751
  hashDir: ent.name,
@@ -10802,17 +10757,17 @@ var init_claude_history = __esm({
10802
10757
  return out;
10803
10758
  }
10804
10759
  async listSessions(args) {
10805
- const dir = import_node_path8.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
10760
+ const dir = import_node_path9.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
10806
10761
  let files;
10807
10762
  try {
10808
- files = import_node_fs7.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
10763
+ files = import_node_fs8.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
10809
10764
  } catch (err) {
10810
10765
  if (err.code === "ENOENT") return [];
10811
10766
  throw err;
10812
10767
  }
10813
10768
  const out = [];
10814
10769
  for (const f of files) {
10815
- const full = import_node_path8.default.join(dir, f);
10770
+ const full = import_node_path9.default.join(dir, f);
10816
10771
  const toolSessionId = f.slice(0, -".jsonl".length);
10817
10772
  const lines = readJsonlLines(full);
10818
10773
  let summary = "";
@@ -10867,7 +10822,7 @@ var init_claude_history = __esm({
10867
10822
  return out;
10868
10823
  }
10869
10824
  async read(args) {
10870
- const file = import_node_path8.default.join(
10825
+ const file = import_node_path9.default.join(
10871
10826
  this.projectsRoot,
10872
10827
  cwdToHashDir(args.cwd),
10873
10828
  `${args.toolSessionId}.jsonl`
@@ -10900,7 +10855,7 @@ var init_claude_history = __esm({
10900
10855
  // 独立目录路径:<projectsRoot>/<cwdHash>/<toolSessionId>/subagents/*.jsonl
10901
10856
  // 返回 null 表示目录不存在(调用方回退旧实现);返回空数组表示目录存在但无 jsonl
10902
10857
  listSubagentsFromDirectory(cwd, toolSessionId) {
10903
- const dir = import_node_path8.default.join(
10858
+ const dir = import_node_path9.default.join(
10904
10859
  this.projectsRoot,
10905
10860
  cwdToHashDir(cwd),
10906
10861
  toolSessionId,
@@ -10908,7 +10863,7 @@ var init_claude_history = __esm({
10908
10863
  );
10909
10864
  let entries;
10910
10865
  try {
10911
- entries = import_node_fs7.default.readdirSync(dir, { withFileTypes: true });
10866
+ entries = import_node_fs8.default.readdirSync(dir, { withFileTypes: true });
10912
10867
  } catch (err) {
10913
10868
  if (err.code === "ENOENT") return null;
10914
10869
  return null;
@@ -10918,7 +10873,7 @@ var init_claude_history = __esm({
10918
10873
  if (!e.isFile()) continue;
10919
10874
  if (!e.name.startsWith("agent-") || !e.name.endsWith(".jsonl")) continue;
10920
10875
  const subagentId = e.name.slice("agent-".length, -".jsonl".length);
10921
- const filePath = import_node_path8.default.join(dir, e.name);
10876
+ const filePath = import_node_path9.default.join(dir, e.name);
10922
10877
  const lines = readJsonlLines(filePath);
10923
10878
  let firstText = "";
10924
10879
  let messageCount = 0;
@@ -10935,7 +10890,7 @@ var init_claude_history = __esm({
10935
10890
  return out;
10936
10891
  }
10937
10892
  listSubagentsFromMainJsonl(cwd, toolSessionId) {
10938
- const file = import_node_path8.default.join(
10893
+ const file = import_node_path9.default.join(
10939
10894
  this.projectsRoot,
10940
10895
  cwdToHashDir(cwd),
10941
10896
  `${toolSessionId}.jsonl`
@@ -10970,7 +10925,7 @@ var init_claude_history = __esm({
10970
10925
  }
10971
10926
  // 独立文件路径:agent-<subagentId>.jsonl;文件不存在返回 null 让调用方回退旧实现
10972
10927
  readSubagentFromFile(cwd, toolSessionId, subagentId) {
10973
- const file = import_node_path8.default.join(
10928
+ const file = import_node_path9.default.join(
10974
10929
  this.projectsRoot,
10975
10930
  cwdToHashDir(cwd),
10976
10931
  toolSessionId,
@@ -10979,7 +10934,7 @@ var init_claude_history = __esm({
10979
10934
  );
10980
10935
  let exists = false;
10981
10936
  try {
10982
- exists = import_node_fs7.default.statSync(file).isFile();
10937
+ exists = import_node_fs8.default.statSync(file).isFile();
10983
10938
  } catch {
10984
10939
  return null;
10985
10940
  }
@@ -10998,7 +10953,7 @@ var init_claude_history = __esm({
10998
10953
  * "那一刻每个 tracked 文件对应的 backup 文件名"
10999
10954
  */
11000
10955
  readFileHistorySnapshots(args) {
11001
- const file = import_node_path8.default.join(
10956
+ const file = import_node_path9.default.join(
11002
10957
  this.projectsRoot,
11003
10958
  cwdToHashDir(args.cwd),
11004
10959
  `${args.toolSessionId}.jsonl`
@@ -11043,7 +10998,7 @@ var init_claude_history = __esm({
11043
10998
  for (const [anchorId, target] of snapshots) {
11044
10999
  let hasAny = false;
11045
11000
  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);
11001
+ const absPath = import_node_path9.default.isAbsolute(rawPath) ? rawPath : import_node_path9.default.join(args.cwd, rawPath);
11047
11002
  const backupContent = readBackupContent(
11048
11003
  this.fileHistoryRoot,
11049
11004
  args.toolSessionId,
@@ -11083,7 +11038,7 @@ var init_claude_history = __esm({
11083
11038
  let totalInsertions = 0;
11084
11039
  let totalDeletions = 0;
11085
11040
  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);
11041
+ const absPath = import_node_path9.default.isAbsolute(rawPath) ? rawPath : import_node_path9.default.join(args.cwd, rawPath);
11087
11042
  const backupContent = readBackupContent(
11088
11043
  this.fileHistoryRoot,
11089
11044
  args.toolSessionId,
@@ -11130,7 +11085,7 @@ var init_claude_history = __esm({
11130
11085
  };
11131
11086
  }
11132
11087
  readSubagentFromMainJsonl(cwd, toolSessionId, subagentId) {
11133
- const file = import_node_path8.default.join(
11088
+ const file = import_node_path9.default.join(
11134
11089
  this.projectsRoot,
11135
11090
  cwdToHashDir(cwd),
11136
11091
  `${toolSessionId}.jsonl`
@@ -11154,48 +11109,48 @@ var init_claude_history = __esm({
11154
11109
  // src/tools/sandbox.ts
11155
11110
  function shouldSandbox(cwd, personaRoot) {
11156
11111
  if (!personaRoot) return false;
11157
- const sep3 = personaRoot.endsWith(path12.sep) ? "" : path12.sep;
11112
+ const sep3 = personaRoot.endsWith(path13.sep) ? "" : path13.sep;
11158
11113
  return cwd.startsWith(personaRoot + sep3) && cwd !== personaRoot;
11159
11114
  }
11160
11115
  function inferSandboxSettingsPath(cwd, personaRoot) {
11161
11116
  if (!shouldSandbox(cwd, personaRoot)) return null;
11162
- const rel = path12.relative(personaRoot, cwd);
11163
- const personaId = rel.split(path12.sep)[0];
11117
+ const rel = path13.relative(personaRoot, cwd);
11118
+ const personaId = rel.split(path13.sep)[0];
11164
11119
  if (!personaId) return null;
11165
- return path12.join(personaRoot, personaId, ".clawd", "sandbox-settings.json");
11120
+ return path13.join(personaRoot, personaId, ".clawd", "sandbox-settings.json");
11166
11121
  }
11167
- var path12;
11122
+ var path13;
11168
11123
  var init_sandbox = __esm({
11169
11124
  "src/tools/sandbox.ts"() {
11170
11125
  "use strict";
11171
- path12 = __toESM(require("path"), 1);
11126
+ path13 = __toESM(require("path"), 1);
11172
11127
  }
11173
11128
  });
11174
11129
 
11175
11130
  // src/tools/claude.ts
11176
11131
  function macOSDesktopCandidates(home) {
11177
11132
  return [
11178
- import_node_path9.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
11133
+ import_node_path10.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
11179
11134
  "/Applications/Claude.app/Contents/Resources/app.asar.unpacked/node_modules/@anthropic-ai/claude-code/cli.js"
11180
11135
  ];
11181
11136
  }
11182
11137
  function probeViaWhich() {
11183
11138
  try {
11184
11139
  const out = (0, import_node_child_process2.execFileSync)("which", ["claude"], { encoding: "utf8" }).trim();
11185
- if (out && import_node_fs8.default.existsSync(out)) return out;
11140
+ if (out && import_node_fs9.default.existsSync(out)) return out;
11186
11141
  } catch {
11187
11142
  }
11188
11143
  return null;
11189
11144
  }
11190
11145
  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)) {
11146
+ if (env.CLAUDE_BIN && import_node_fs9.default.existsSync(env.CLAUDE_BIN)) {
11192
11147
  return { available: true, path: env.CLAUDE_BIN };
11193
11148
  }
11194
11149
  const w2 = probeViaWhich();
11195
11150
  if (w2) return { available: true, path: w2 };
11196
11151
  if (process.platform === "darwin") {
11197
11152
  for (const candidate of macOSDesktopCandidates(home)) {
11198
- if (import_node_fs8.default.existsSync(candidate)) {
11153
+ if (import_node_fs9.default.existsSync(candidate)) {
11199
11154
  return { available: true, path: candidate };
11200
11155
  }
11201
11156
  }
@@ -11517,10 +11472,10 @@ function parseAttachment(obj) {
11517
11472
  const memories = raw.map((m2) => {
11518
11473
  if (!m2 || typeof m2 !== "object") return null;
11519
11474
  const rec = m2;
11520
- const path46 = typeof rec.path === "string" ? rec.path : null;
11475
+ const path47 = typeof rec.path === "string" ? rec.path : null;
11521
11476
  const content = typeof rec.content === "string" ? rec.content : null;
11522
- if (!path46 || content == null) return null;
11523
- const out = { path: path46, content };
11477
+ if (!path47 || content == null) return null;
11478
+ const out = { path: path47, content };
11524
11479
  if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
11525
11480
  return out;
11526
11481
  }).filter((m2) => m2 !== null);
@@ -11624,15 +11579,15 @@ function encodeClaudeStdin(text) {
11624
11579
  };
11625
11580
  return JSON.stringify(frame) + "\n";
11626
11581
  }
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;
11582
+ 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
11583
  var init_claude = __esm({
11629
11584
  "src/tools/claude.ts"() {
11630
11585
  "use strict";
11631
11586
  import_node_child_process = require("child_process");
11632
11587
  import_node_child_process2 = require("child_process");
11633
- import_node_fs8 = __toESM(require("fs"), 1);
11588
+ import_node_fs9 = __toESM(require("fs"), 1);
11634
11589
  import_node_os4 = __toESM(require("os"), 1);
11635
- import_node_path9 = __toESM(require("path"), 1);
11590
+ import_node_path10 = __toESM(require("path"), 1);
11636
11591
  init_protocol();
11637
11592
  init_claude_history();
11638
11593
  init_tool_result_extra();
@@ -20435,7 +20390,7 @@ var require_websocket_server = __commonJS({
20435
20390
  // src/run-case/recorder.ts
20436
20391
  function startRunCaseRecorder(opts) {
20437
20392
  const now = opts.now ?? Date.now;
20438
- const dir = import_node_path32.default.dirname(opts.recordPath);
20393
+ const dir = import_node_path33.default.dirname(opts.recordPath);
20439
20394
  let stream = null;
20440
20395
  let closing = false;
20441
20396
  let closedSettled = false;
@@ -20449,8 +20404,8 @@ function startRunCaseRecorder(opts) {
20449
20404
  });
20450
20405
  const ensureStream = () => {
20451
20406
  if (stream) return stream;
20452
- import_node_fs29.default.mkdirSync(dir, { recursive: true });
20453
- stream = import_node_fs29.default.createWriteStream(opts.recordPath, { flags: "a" });
20407
+ import_node_fs30.default.mkdirSync(dir, { recursive: true });
20408
+ stream = import_node_fs30.default.createWriteStream(opts.recordPath, { flags: "a" });
20454
20409
  stream.on("close", () => closedResolve());
20455
20410
  return stream;
20456
20411
  };
@@ -20475,12 +20430,12 @@ function startRunCaseRecorder(opts) {
20475
20430
  };
20476
20431
  return { tap, close, closed };
20477
20432
  }
20478
- var import_node_fs29, import_node_path32;
20433
+ var import_node_fs30, import_node_path33;
20479
20434
  var init_recorder = __esm({
20480
20435
  "src/run-case/recorder.ts"() {
20481
20436
  "use strict";
20482
- import_node_fs29 = __toESM(require("fs"), 1);
20483
- import_node_path32 = __toESM(require("path"), 1);
20437
+ import_node_fs30 = __toESM(require("fs"), 1);
20438
+ import_node_path33 = __toESM(require("path"), 1);
20484
20439
  }
20485
20440
  });
20486
20441
 
@@ -20523,7 +20478,7 @@ var init_wire = __esm({
20523
20478
  // src/run-case/controller.ts
20524
20479
  async function runController(opts) {
20525
20480
  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-"));
20481
+ const cwd = opts.cwd ?? (0, import_node_fs31.mkdtempSync)(import_node_path34.default.join(import_node_os15.default.tmpdir(), "clawd-runcase-"));
20527
20482
  const ownsCwd = opts.cwd === void 0;
20528
20483
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
20529
20484
  const spawnCtx = { cwd };
@@ -20684,19 +20639,19 @@ async function runController(opts) {
20684
20639
  if (sigintHandler) process.off("SIGINT", sigintHandler);
20685
20640
  if (ownsCwd) {
20686
20641
  try {
20687
- (0, import_node_fs30.rmSync)(cwd, { recursive: true, force: true });
20642
+ (0, import_node_fs31.rmSync)(cwd, { recursive: true, force: true });
20688
20643
  } catch {
20689
20644
  }
20690
20645
  }
20691
20646
  return exitCode ?? 0;
20692
20647
  }
20693
- var import_node_fs30, import_node_os15, import_node_path33;
20648
+ var import_node_fs31, import_node_os15, import_node_path34;
20694
20649
  var init_controller = __esm({
20695
20650
  "src/run-case/controller.ts"() {
20696
20651
  "use strict";
20697
- import_node_fs30 = require("fs");
20652
+ import_node_fs31 = require("fs");
20698
20653
  import_node_os15 = __toESM(require("os"), 1);
20699
- import_node_path33 = __toESM(require("path"), 1);
20654
+ import_node_path34 = __toESM(require("path"), 1);
20700
20655
  init_claude();
20701
20656
  init_stdout_splitter();
20702
20657
  init_permission_stdio();
@@ -20928,8 +20883,8 @@ Env (advanced):
20928
20883
  `;
20929
20884
 
20930
20885
  // src/index.ts
20931
- var import_node_path31 = __toESM(require("path"), 1);
20932
- var import_node_fs28 = __toESM(require("fs"), 1);
20886
+ var import_node_path32 = __toESM(require("path"), 1);
20887
+ var import_node_fs29 = __toESM(require("fs"), 1);
20933
20888
 
20934
20889
  // src/logger.ts
20935
20890
  var import_node_fs2 = __toESM(require("fs"), 1);
@@ -21153,8 +21108,8 @@ var SessionStoreFactory = class {
21153
21108
  };
21154
21109
 
21155
21110
  // src/session/manager.ts
21156
- var import_node_fs5 = __toESM(require("fs"), 1);
21157
- var import_node_path6 = __toESM(require("path"), 1);
21111
+ var import_node_fs6 = __toESM(require("fs"), 1);
21112
+ var import_node_path7 = __toESM(require("path"), 1);
21158
21113
 
21159
21114
  // ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
21160
21115
  var byteToHex = [];
@@ -22398,6 +22353,62 @@ function extractEditPath(input) {
22398
22353
  return candidate || null;
22399
22354
  }
22400
22355
 
22356
+ // src/debug/pty-probe.ts
22357
+ var import_node_fs5 = __toESM(require("fs"), 1);
22358
+ var import_node_path6 = __toESM(require("path"), 1);
22359
+ var PROBE_DIR = "/tmp/clawd-probe";
22360
+ var EVENTS_FILE = import_node_path6.default.join(PROBE_DIR, "events.jsonl");
22361
+ var inited = false;
22362
+ function ensureDir() {
22363
+ if (inited) return true;
22364
+ try {
22365
+ import_node_fs5.default.mkdirSync(PROBE_DIR, { recursive: true });
22366
+ inited = true;
22367
+ return true;
22368
+ } catch {
22369
+ return false;
22370
+ }
22371
+ }
22372
+ function probeEvent(event, data = {}) {
22373
+ try {
22374
+ if (!ensureDir()) return;
22375
+ const line = JSON.stringify({ ts: Date.now(), event, ...data }) + "\n";
22376
+ import_node_fs5.default.appendFileSync(EVENTS_FILE, line);
22377
+ } catch {
22378
+ }
22379
+ }
22380
+ function probeDumpReplay(sessionId, payload) {
22381
+ try {
22382
+ if (!ensureDir()) return "";
22383
+ const file = import_node_path6.default.join(PROBE_DIR, `replay-${sessionId}-${Date.now()}.ans`);
22384
+ import_node_fs5.default.writeFileSync(file, payload, "utf8");
22385
+ return file;
22386
+ } catch {
22387
+ return "";
22388
+ }
22389
+ }
22390
+ var _throttle = /* @__PURE__ */ new Map();
22391
+ function probePtyDataThrottled(tsid, len, tail) {
22392
+ const now = Date.now();
22393
+ let s = _throttle.get(tsid);
22394
+ if (!s) {
22395
+ s = { last: 0, bytes: 0, chunks: 0 };
22396
+ _throttle.set(tsid, s);
22397
+ }
22398
+ s.bytes += len;
22399
+ s.chunks += 1;
22400
+ if (now - s.last >= 1e3) {
22401
+ probeEvent("pty.data", {
22402
+ tsid,
22403
+ chunks: s.chunks,
22404
+ accumBytes: s.bytes,
22405
+ lastChunkLen: len,
22406
+ tailHex: tail.subarray(Math.max(0, tail.length - 32)).toString("hex")
22407
+ });
22408
+ s.last = now;
22409
+ }
22410
+ }
22411
+
22401
22412
  // src/session/manager.ts
22402
22413
  function compressFrameForWire(frame) {
22403
22414
  if (frame.type !== "session:status") return frame;
@@ -22461,7 +22472,7 @@ function derivePersonaSpawnCwd(file, personaRoot) {
22461
22472
  `derivePersonaSpawnCwd: personaRoot missing for owner session ${file.sessionId} (ownerPersonaId=${personaId})`
22462
22473
  );
22463
22474
  }
22464
- return import_node_path6.default.join(personaRoot, safeFileName(personaId));
22475
+ return import_node_path7.default.join(personaRoot, safeFileName(personaId));
22465
22476
  }
22466
22477
  function makeInitialState(file, subSessionMeta) {
22467
22478
  return {
@@ -22575,10 +22586,10 @@ var SessionManager = class {
22575
22586
  // <dataDir>/sessions/ 列子目录 (排除 'default').
22576
22587
  listPersonaIdsOnDisk() {
22577
22588
  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");
22589
+ const root = this.deps.storeFactory ? import_node_path7.default.join(this.deps.dataDir, "personas") : import_node_path7.default.join(this.deps.dataDir, "sessions");
22579
22590
  let entries;
22580
22591
  try {
22581
- entries = import_node_fs5.default.readdirSync(root, { withFileTypes: true });
22592
+ entries = import_node_fs6.default.readdirSync(root, { withFileTypes: true });
22582
22593
  } catch (err) {
22583
22594
  const code = err?.code;
22584
22595
  if (code === "ENOENT") return [];
@@ -22591,7 +22602,7 @@ var SessionManager = class {
22591
22602
  // 只在 storeFactory 注入 (新布局) 下生效, 老布局无 guest 目录.
22592
22603
  listGuestCapIdsForPersona(personaId) {
22593
22604
  if (!this.deps.dataDir || !this.deps.storeFactory) return [];
22594
- const root = import_node_path6.default.join(
22605
+ const root = import_node_path7.default.join(
22595
22606
  this.deps.dataDir,
22596
22607
  "personas",
22597
22608
  personaId,
@@ -22601,7 +22612,7 @@ var SessionManager = class {
22601
22612
  );
22602
22613
  let entries;
22603
22614
  try {
22604
- entries = import_node_fs5.default.readdirSync(root, { withFileTypes: true });
22615
+ entries = import_node_fs6.default.readdirSync(root, { withFileTypes: true });
22605
22616
  } catch (err) {
22606
22617
  const code = err?.code;
22607
22618
  if (code === "ENOENT") return [];
@@ -22838,7 +22849,7 @@ var SessionManager = class {
22838
22849
  throw new ClawdError(ERROR_CODES.INVALID_CWD, "cwd required when ownerPersonaId is absent");
22839
22850
  }
22840
22851
  try {
22841
- const stat = import_node_fs5.default.statSync(cwd);
22852
+ const stat = import_node_fs6.default.statSync(cwd);
22842
22853
  if (!stat.isDirectory()) throw new Error("not dir");
22843
22854
  } catch {
22844
22855
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `cwd not a directory: ${cwd}`);
@@ -22929,30 +22940,6 @@ var SessionManager = class {
22929
22940
  const file = this.getFile(args.sessionId);
22930
22941
  return { response: file, broadcast: [] };
22931
22942
  }
22932
- // mirror peer sessions (2026-05-26):把来自朋友 daemon 的 SessionFile(originOwnerPrincipalId
22933
- // 非空)持久化到本机 default store。dumb write,**不广播 push 帧**——UI 是写入唯一源,
22934
- // 双写完成后通过 cache.setData 同步 sidebar 本地 state。
22935
- //
22936
- // 强制走 deps.store(即 default scope),不走 scopeForFile:mirror 物理落 default 即可。
22937
- // 远端 creator / origin 字段原值保留(不被本机 ctx 派生覆写)。
22938
- //
22939
- // strip 远端 personaId:mirror SessionFile 上的 ownerPersonaId 是朋友 daemon 的 persona
22940
- // 目录 id,本机不持有对应 persona。留着会让按 ownerPersonaId 反查的本机消费者
22941
- // (MyPersonasSection 等)把 mirror 误聚到同 id persona 下。写入前清掉。
22942
- //
22943
- // 与 manager.create / manager.update 区别:
22944
- // - 不走 newRunner / attachObserver / cwd 校验(mirror 是纯 metadata 层)
22945
- // - 不发 session:info 帧(manager.create / .update 通过 reducer/wireCollector 发 push)
22946
- mirrorUpsert(file) {
22947
- const { ownerPersonaId: _stripped, ...rest } = file;
22948
- return this.deps.store.write(rest);
22949
- }
22950
- // mirror peer sessions:删本机 mirror SessionFile。mirror 一律落 default(mirrorUpsert
22951
- // 强制走 deps.store + strip ownerPersonaId),删也只删 default。idempotent:找不到
22952
- // 不 throw(store.delete 内部 ENOENT 兜底返 false 不 throw)。**不广播 session:deleted**。
22953
- mirrorRemove(sessionId) {
22954
- this.deps.store.delete(sessionId);
22955
- }
22956
22943
  // observer 上报"jsonl 写入了一条 user 行"时调用:在 buffer 里找到与之对应的、
22957
22944
  // 还没建立映射的最早一条 synth user_text,记下 synth → real 映射。
22958
22945
  // 找不到匹配的 synth(runner 不存在 / buffer 已被 /clear 清空 / 真 uuid 来自纯 history
@@ -23374,7 +23361,7 @@ var SessionManager = class {
23374
23361
  */
23375
23362
  createForScope(args) {
23376
23363
  try {
23377
- const stat = import_node_fs5.default.statSync(args.cwd);
23364
+ const stat = import_node_fs6.default.statSync(args.cwd);
23378
23365
  if (!stat.isDirectory()) throw new Error("not dir");
23379
23366
  } catch {
23380
23367
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `cwd not a directory: ${args.cwd}`);
@@ -23709,15 +23696,27 @@ var SessionManager = class {
23709
23696
  }
23710
23697
  /** spawn 进程 exit 时调用,清理映射防止后续 input 写到已死 pty + 释放 replay 闭包 */
23711
23698
  unregisterPty(toolSessionId) {
23699
+ const hadReplay = this.ptyReplaysByToolSid.has(toolSessionId);
23712
23700
  this.ptyTransports.delete(toolSessionId);
23713
23701
  this.ptyReplaysByToolSid.delete(toolSessionId);
23702
+ probeEvent("pty.unregister", {
23703
+ tsid: toolSessionId,
23704
+ hadReplay,
23705
+ replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
23706
+ });
23714
23707
  }
23715
23708
  /**
23716
23709
  * ClaudeTuiAdapter.spawn 创建 detector 后调用,注册当前屏幕快照闭包。
23717
23710
  * 同一 toolSessionId 重 spawn 会覆盖;unregisterPty 时一并删除。
23718
23711
  */
23719
23712
  registerPtyReplay(toolSessionId, replay) {
23713
+ const overwrite = this.ptyReplaysByToolSid.has(toolSessionId);
23720
23714
  this.ptyReplaysByToolSid.set(toolSessionId, replay);
23715
+ probeEvent("pty.register", {
23716
+ tsid: toolSessionId,
23717
+ overwrite,
23718
+ replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
23719
+ });
23721
23720
  }
23722
23721
  /**
23723
23722
  * 新 client subscribe 时拉当前屏幕快照。返回 null 表示无可重放数据:
@@ -23726,14 +23725,47 @@ var SessionManager = class {
23726
23725
  * 调用方(onSubscribe hook)按返回值非空时构造 session:pty + session:control 帧定向回放
23727
23726
  */
23728
23727
  getPtyReplay(sessionId) {
23729
- if (this.deps.mode !== "tui") return null;
23728
+ if (this.deps.mode !== "tui") {
23729
+ probeEvent("replay.request", { sid: sessionId, result: "not-tui-mode" });
23730
+ return null;
23731
+ }
23730
23732
  const runner = this.runners.get(sessionId);
23731
- if (!runner) return null;
23733
+ if (!runner) {
23734
+ probeEvent("replay.request", {
23735
+ sid: sessionId,
23736
+ result: "no-runner",
23737
+ runnerKeys: Array.from(this.runners.keys())
23738
+ });
23739
+ return null;
23740
+ }
23732
23741
  const tsid = runner.getState().file.toolSessionId;
23733
- if (!tsid) return null;
23742
+ if (!tsid) {
23743
+ probeEvent("replay.request", { sid: sessionId, result: "no-tsid" });
23744
+ return null;
23745
+ }
23734
23746
  const replay = this.ptyReplaysByToolSid.get(tsid);
23735
- if (!replay) return null;
23736
- return replay();
23747
+ if (!replay) {
23748
+ probeEvent("replay.request", {
23749
+ sid: sessionId,
23750
+ tsid,
23751
+ result: "no-replay-closure",
23752
+ replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
23753
+ });
23754
+ return null;
23755
+ }
23756
+ const snap = replay();
23757
+ const dumpFile = probeDumpReplay(sessionId, snap.data);
23758
+ probeEvent("replay.dump", {
23759
+ sid: sessionId,
23760
+ tsid,
23761
+ bytes: snap.data.length,
23762
+ popupKind: snap.popupKind,
23763
+ headHex: Buffer.from(snap.data, "utf8").subarray(0, 32).toString("hex"),
23764
+ dumpFile,
23765
+ runnerKeys: Array.from(this.runners.keys()),
23766
+ replayMapKeys: Array.from(this.ptyReplaysByToolSid.keys())
23767
+ });
23768
+ return snap;
23737
23769
  }
23738
23770
  /**
23739
23771
  * handler tui:pty:input / tui:pty:resize 入口:传 wire 层 sessionId(16 字符),
@@ -23796,8 +23828,8 @@ var SessionManager = class {
23796
23828
  };
23797
23829
 
23798
23830
  // src/persona/store.ts
23799
- var fs6 = __toESM(require("fs"), 1);
23800
- var path8 = __toESM(require("path"), 1);
23831
+ var fs7 = __toESM(require("fs"), 1);
23832
+ var path9 = __toESM(require("path"), 1);
23801
23833
  init_protocol();
23802
23834
  var DEFAULT_SETTINGS = {
23803
23835
  permissions: {
@@ -23822,17 +23854,17 @@ var DEFAULT_SETTINGS = {
23822
23854
  var PersonaStore = class {
23823
23855
  constructor(root) {
23824
23856
  this.root = root;
23825
- fs6.mkdirSync(root, { recursive: true });
23857
+ fs7.mkdirSync(root, { recursive: true });
23826
23858
  }
23827
23859
  root;
23828
23860
  personaDir(personaId) {
23829
- return path8.join(this.root, safeFileName(personaId));
23861
+ return path9.join(this.root, safeFileName(personaId));
23830
23862
  }
23831
23863
  metaPath(personaId) {
23832
- return path8.join(this.personaDir(personaId), ".clawd", "persona.json");
23864
+ return path9.join(this.personaDir(personaId), ".clawd", "persona.json");
23833
23865
  }
23834
23866
  claudeMdPath(personaId) {
23835
- return path8.join(this.personaDir(personaId), "CLAUDE.md");
23867
+ return path9.join(this.personaDir(personaId), "CLAUDE.md");
23836
23868
  }
23837
23869
  /**
23838
23870
  * Sandbox settings 落盘路径 —— 故意放在 `.clawd/` 而不是 `.claude/`,让 CC 的
@@ -23842,11 +23874,11 @@ var PersonaStore = class {
23842
23874
  * 加载 persona 人格,只有 listener 多一层 OS sandbox。
23843
23875
  */
23844
23876
  sandboxSettingsPath(personaId) {
23845
- return path8.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
23877
+ return path9.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
23846
23878
  }
23847
23879
  write(persona, personality) {
23848
23880
  const dir = this.personaDir(persona.personaId);
23849
- fs6.mkdirSync(path8.join(dir, ".clawd"), { recursive: true });
23881
+ fs7.mkdirSync(path9.join(dir, ".clawd"), { recursive: true });
23850
23882
  this.atomicWrite(this.claudeMdPath(persona.personaId), personality);
23851
23883
  this.atomicWrite(
23852
23884
  this.sandboxSettingsPath(persona.personaId),
@@ -23862,8 +23894,8 @@ var PersonaStore = class {
23862
23894
  }
23863
23895
  read(personaId) {
23864
23896
  const p2 = this.metaPath(personaId);
23865
- if (!fs6.existsSync(p2)) return null;
23866
- const raw = JSON.parse(fs6.readFileSync(p2, "utf8"));
23897
+ if (!fs7.existsSync(p2)) return null;
23898
+ const raw = JSON.parse(fs7.readFileSync(p2, "utf8"));
23867
23899
  if (raw && typeof raw === "object" && "tokenMap" in raw) {
23868
23900
  delete raw.tokenMap;
23869
23901
  this.atomicWrite(p2, JSON.stringify(raw, null, 2));
@@ -23871,12 +23903,12 @@ var PersonaStore = class {
23871
23903
  return PersonaFileSchema.parse(raw);
23872
23904
  }
23873
23905
  has(personaId) {
23874
- return fs6.existsSync(this.metaPath(personaId));
23906
+ return fs7.existsSync(this.metaPath(personaId));
23875
23907
  }
23876
23908
  readPersonality(personaId) {
23877
23909
  const p2 = this.claudeMdPath(personaId);
23878
- if (!fs6.existsSync(p2)) return null;
23879
- return fs6.readFileSync(p2, "utf8");
23910
+ if (!fs7.existsSync(p2)) return null;
23911
+ return fs7.readFileSync(p2, "utf8");
23880
23912
  }
23881
23913
  /**
23882
23914
  * 读 sandbox-settings.json 当前内容;文件不存在 / JSON 解析失败均返回 null。
@@ -23884,23 +23916,23 @@ var PersonaStore = class {
23884
23916
  */
23885
23917
  readSandboxSettings(personaId) {
23886
23918
  const p2 = this.sandboxSettingsPath(personaId);
23887
- if (!fs6.existsSync(p2)) return null;
23919
+ if (!fs7.existsSync(p2)) return null;
23888
23920
  try {
23889
- return JSON.parse(fs6.readFileSync(p2, "utf8"));
23921
+ return JSON.parse(fs7.readFileSync(p2, "utf8"));
23890
23922
  } catch {
23891
23923
  return null;
23892
23924
  }
23893
23925
  }
23894
23926
  /** Persona 私有 skills 目录路径:<personaDir>/.claude/skills */
23895
23927
  skillsDir(personaId) {
23896
- return path8.join(this.personaDir(personaId), ".claude", "skills");
23928
+ return path9.join(this.personaDir(personaId), ".claude", "skills");
23897
23929
  }
23898
23930
  /**
23899
23931
  * Claude Code 项目级 settings 路径:`<personaDir>/.claude/settings.json`。
23900
23932
  * 这里只读 `enabledPlugins` 字段,由 owner 通过 CC `/plugin` 之类命令维护,daemon 不写。
23901
23933
  */
23902
23934
  claudeSettingsPath(personaId) {
23903
- return path8.join(this.personaDir(personaId), ".claude", "settings.json");
23935
+ return path9.join(this.personaDir(personaId), ".claude", "settings.json");
23904
23936
  }
23905
23937
  /**
23906
23938
  * 读取 persona 的 `.claude/settings.json` 中 `enabledPlugins` map,把 value === true
@@ -23915,10 +23947,10 @@ var PersonaStore = class {
23915
23947
  */
23916
23948
  readEnabledPlugins(personaId) {
23917
23949
  const p2 = this.claudeSettingsPath(personaId);
23918
- if (!fs6.existsSync(p2)) return [];
23950
+ if (!fs7.existsSync(p2)) return [];
23919
23951
  let raw;
23920
23952
  try {
23921
- raw = JSON.parse(fs6.readFileSync(p2, "utf8"));
23953
+ raw = JSON.parse(fs7.readFileSync(p2, "utf8"));
23922
23954
  } catch {
23923
23955
  return [];
23924
23956
  }
@@ -23932,22 +23964,22 @@ var PersonaStore = class {
23932
23964
  return out;
23933
23965
  }
23934
23966
  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"));
23967
+ if (!fs7.existsSync(this.root)) return [];
23968
+ return fs7.readdirSync(this.root).filter((name) => {
23969
+ return fs7.existsSync(path9.join(this.root, name, ".clawd", "persona.json"));
23938
23970
  });
23939
23971
  }
23940
23972
  remove(personaId) {
23941
23973
  const dir = this.personaDir(personaId);
23942
- if (fs6.existsSync(dir)) fs6.rmSync(dir, { recursive: true, force: true });
23974
+ if (fs7.existsSync(dir)) fs7.rmSync(dir, { recursive: true, force: true });
23943
23975
  }
23944
23976
  personaDirPath(personaId) {
23945
23977
  return this.personaDir(personaId);
23946
23978
  }
23947
23979
  atomicWrite(file, content) {
23948
23980
  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);
23981
+ fs7.writeFileSync(tmp, content, { mode: 384 });
23982
+ fs7.renameSync(tmp, file);
23951
23983
  }
23952
23984
  };
23953
23985
 
@@ -23993,9 +24025,9 @@ var PersonaRegistry = class {
23993
24025
  var import_node_crypto3 = __toESM(require("crypto"), 1);
23994
24026
 
23995
24027
  // src/skills/scanner.ts
23996
- var import_node_fs6 = __toESM(require("fs"), 1);
24028
+ var import_node_fs7 = __toESM(require("fs"), 1);
23997
24029
  var import_node_os2 = __toESM(require("os"), 1);
23998
- var import_node_path7 = __toESM(require("path"), 1);
24030
+ var import_node_path8 = __toESM(require("path"), 1);
23999
24031
 
24000
24032
  // src/skills/frontmatter.ts
24001
24033
  var STRIP_QUOTES = /^["']|["']$/g;
@@ -24104,7 +24136,7 @@ function parseDescription(content) {
24104
24136
  }
24105
24137
  function isDirLikeSync(p2) {
24106
24138
  try {
24107
- return import_node_fs6.default.statSync(p2).isDirectory();
24139
+ return import_node_fs7.default.statSync(p2).isDirectory();
24108
24140
  } catch {
24109
24141
  return false;
24110
24142
  }
@@ -24112,19 +24144,19 @@ function isDirLikeSync(p2) {
24112
24144
  function scanSkillDir(dir, source, seen, out, pluginName) {
24113
24145
  let entries;
24114
24146
  try {
24115
- entries = import_node_fs6.default.readdirSync(dir, { withFileTypes: true });
24147
+ entries = import_node_fs7.default.readdirSync(dir, { withFileTypes: true });
24116
24148
  } catch {
24117
24149
  return;
24118
24150
  }
24119
24151
  for (const ent of entries) {
24120
- const entryPath = import_node_path7.default.join(dir, ent.name);
24152
+ const entryPath = import_node_path8.default.join(dir, ent.name);
24121
24153
  if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
24122
24154
  let content;
24123
24155
  try {
24124
- content = import_node_fs6.default.readFileSync(import_node_path7.default.join(entryPath, "SKILL.md"), "utf8");
24156
+ content = import_node_fs7.default.readFileSync(import_node_path8.default.join(entryPath, "SKILL.md"), "utf8");
24125
24157
  } catch {
24126
24158
  try {
24127
- content = import_node_fs6.default.readFileSync(import_node_path7.default.join(entryPath, "skill.md"), "utf8");
24159
+ content = import_node_fs7.default.readFileSync(import_node_path8.default.join(entryPath, "skill.md"), "utf8");
24128
24160
  } catch {
24129
24161
  continue;
24130
24162
  }
@@ -24148,26 +24180,26 @@ function listSkillsForDir(dir, source) {
24148
24180
  function scanCommandDir(dir, source, seen, out, pluginName) {
24149
24181
  let entries;
24150
24182
  try {
24151
- entries = import_node_fs6.default.readdirSync(dir, { withFileTypes: true });
24183
+ entries = import_node_fs7.default.readdirSync(dir, { withFileTypes: true });
24152
24184
  } catch {
24153
24185
  return;
24154
24186
  }
24155
24187
  for (const ent of entries) {
24156
- const entryPath = import_node_path7.default.join(dir, ent.name);
24188
+ const entryPath = import_node_path8.default.join(dir, ent.name);
24157
24189
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
24158
24190
  const ns = ent.name;
24159
24191
  let subEntries;
24160
24192
  try {
24161
- subEntries = import_node_fs6.default.readdirSync(entryPath, { withFileTypes: true });
24193
+ subEntries = import_node_fs7.default.readdirSync(entryPath, { withFileTypes: true });
24162
24194
  } catch {
24163
24195
  continue;
24164
24196
  }
24165
24197
  for (const se of subEntries) {
24166
24198
  if (!se.name.endsWith(".md")) continue;
24167
- const sePath = import_node_path7.default.join(entryPath, se.name);
24199
+ const sePath = import_node_path8.default.join(entryPath, se.name);
24168
24200
  let content;
24169
24201
  try {
24170
- content = import_node_fs6.default.readFileSync(sePath, "utf8");
24202
+ content = import_node_fs7.default.readFileSync(sePath, "utf8");
24171
24203
  } catch {
24172
24204
  continue;
24173
24205
  }
@@ -24184,7 +24216,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
24184
24216
  } else if (ent.name.endsWith(".md")) {
24185
24217
  let content;
24186
24218
  try {
24187
- content = import_node_fs6.default.readFileSync(entryPath, "utf8");
24219
+ content = import_node_fs7.default.readFileSync(entryPath, "utf8");
24188
24220
  } catch {
24189
24221
  continue;
24190
24222
  }
@@ -24200,10 +24232,10 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
24200
24232
  }
24201
24233
  }
24202
24234
  function readInstalledPlugins(home) {
24203
- const file = import_node_path7.default.join(home, ".claude", "plugins", "installed_plugins.json");
24235
+ const file = import_node_path8.default.join(home, ".claude", "plugins", "installed_plugins.json");
24204
24236
  let raw;
24205
24237
  try {
24206
- raw = import_node_fs6.default.readFileSync(file, "utf8");
24238
+ raw = import_node_fs7.default.readFileSync(file, "utf8");
24207
24239
  } catch {
24208
24240
  return [];
24209
24241
  }
@@ -24251,14 +24283,14 @@ var SkillsScanner = class {
24251
24283
  });
24252
24284
  }
24253
24285
  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);
24286
+ scanSkillDir(import_node_path8.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
24287
+ scanCommandDir(import_node_path8.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
24288
+ scanSkillDir(import_node_path8.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
24289
+ scanCommandDir(import_node_path8.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
24258
24290
  const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
24259
24291
  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);
24292
+ scanSkillDir(import_node_path8.default.join(root, "skills"), "plugin", seen, fsBlock, name);
24293
+ scanCommandDir(import_node_path8.default.join(root, "commands"), "plugin", seen, fsBlock, name);
24262
24294
  }
24263
24295
  fsBlock.sort((a, b2) => a.name < b2.name ? -1 : a.name > b2.name ? 1 : 0);
24264
24296
  return [...builtinBlock, ...fsBlock];
@@ -24363,8 +24395,8 @@ var PersonaManager = class {
24363
24395
  };
24364
24396
 
24365
24397
  // src/persona/seed.ts
24366
- var fs8 = __toESM(require("fs"), 1);
24367
- var path10 = __toESM(require("path"), 1);
24398
+ var fs9 = __toESM(require("fs"), 1);
24399
+ var path11 = __toESM(require("path"), 1);
24368
24400
  var import_node_url = require("url");
24369
24401
  var import_meta = {};
24370
24402
  var DEFAULT_PERSONAS = [
@@ -24400,18 +24432,18 @@ var DEFAULT_PERSONAS = [
24400
24432
  function findDefaultsRoot() {
24401
24433
  const candidates = [];
24402
24434
  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"));
24435
+ const here = path11.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
24436
+ candidates.push(path11.resolve(here, "defaults"));
24437
+ candidates.push(path11.resolve(here, "persona-defaults"));
24406
24438
  } catch {
24407
24439
  }
24408
24440
  if (process.argv[1]) {
24409
- const argvDir = path10.dirname(process.argv[1]);
24410
- candidates.push(path10.resolve(argvDir, "persona-defaults"));
24441
+ const argvDir = path11.dirname(process.argv[1]);
24442
+ candidates.push(path11.resolve(argvDir, "persona-defaults"));
24411
24443
  }
24412
24444
  for (const c of candidates) {
24413
24445
  try {
24414
- if (fs8.statSync(c).isDirectory()) return c;
24446
+ if (fs9.statSync(c).isDirectory()) return c;
24415
24447
  } catch {
24416
24448
  }
24417
24449
  }
@@ -24424,8 +24456,8 @@ function seedDefaultPersonas(args) {
24424
24456
  args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
24425
24457
  continue;
24426
24458
  }
24427
- const bundleDir = path10.join(args.defaultsRoot, entry.personaId);
24428
- if (!fs8.existsSync(bundleDir)) {
24459
+ const bundleDir = path11.join(args.defaultsRoot, entry.personaId);
24460
+ if (!fs9.existsSync(bundleDir)) {
24429
24461
  args.logger.warn("persona.seed.skip", {
24430
24462
  personaId: entry.personaId,
24431
24463
  reason: "bundle-missing",
@@ -24433,8 +24465,8 @@ function seedDefaultPersonas(args) {
24433
24465
  });
24434
24466
  continue;
24435
24467
  }
24436
- const claudeMdPath = path10.join(bundleDir, "CLAUDE.md");
24437
- if (!fs8.existsSync(claudeMdPath)) {
24468
+ const claudeMdPath = path11.join(bundleDir, "CLAUDE.md");
24469
+ if (!fs9.existsSync(claudeMdPath)) {
24438
24470
  args.logger.warn("persona.seed.skip", {
24439
24471
  personaId: entry.personaId,
24440
24472
  reason: "no-CLAUDE.md",
@@ -24442,7 +24474,7 @@ function seedDefaultPersonas(args) {
24442
24474
  });
24443
24475
  continue;
24444
24476
  }
24445
- const personality = fs8.readFileSync(claudeMdPath, "utf8");
24477
+ const personality = fs9.readFileSync(claudeMdPath, "utf8");
24446
24478
  const now = Date.now();
24447
24479
  const persona = {
24448
24480
  personaId: entry.personaId,
@@ -24459,14 +24491,14 @@ function seedDefaultPersonas(args) {
24459
24491
  }
24460
24492
  }
24461
24493
  function copyBundleExtras(srcDir, dstDir) {
24462
- for (const entry of fs8.readdirSync(srcDir, { withFileTypes: true })) {
24494
+ for (const entry of fs9.readdirSync(srcDir, { withFileTypes: true })) {
24463
24495
  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);
24496
+ const srcPath = path11.join(srcDir, entry.name);
24497
+ const dstPath = path11.join(dstDir, entry.name);
24466
24498
  if (entry.isDirectory()) {
24467
- fs8.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
24499
+ fs9.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
24468
24500
  } else if (entry.isFile()) {
24469
- fs8.copyFileSync(srcPath, dstPath);
24501
+ fs9.copyFileSync(srcPath, dstPath);
24470
24502
  }
24471
24503
  }
24472
24504
  }
@@ -24475,9 +24507,9 @@ function copyBundleExtras(srcDir, dstDir) {
24475
24507
  init_claude();
24476
24508
 
24477
24509
  // src/tools/claude-tui.ts
24478
- var import_node_fs9 = __toESM(require("fs"), 1);
24510
+ var import_node_fs10 = __toESM(require("fs"), 1);
24479
24511
  var import_node_os5 = __toESM(require("os"), 1);
24480
- var import_node_path10 = __toESM(require("path"), 1);
24512
+ var import_node_path11 = __toESM(require("path"), 1);
24481
24513
  var import_headless = __toESM(require_xterm_headless(), 1);
24482
24514
 
24483
24515
  // ../node_modules/.pnpm/@xterm+addon-serialize@0.14.0/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs
@@ -25197,6 +25229,11 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
25197
25229
  cwd: ctx.cwd,
25198
25230
  toolSessionId: ctx.toolSessionId
25199
25231
  });
25232
+ probeEvent("pty.spawn", {
25233
+ tsid: ctx.toolSessionId,
25234
+ isResume: jsonlExistsForCtx(ctx),
25235
+ cwd: ctx.cwd
25236
+ });
25200
25237
  const pty = spawnPty({
25201
25238
  command: cmd,
25202
25239
  args,
@@ -25238,8 +25275,12 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
25238
25275
  this.tuiOpts.onPtyData(ctx.toolSessionId, data.toString("base64"));
25239
25276
  }
25240
25277
  void detector.writeBytes(data.toString("utf8"));
25278
+ if (ctx.toolSessionId) {
25279
+ probePtyDataThrottled(ctx.toolSessionId, data.length, data);
25280
+ }
25241
25281
  });
25242
25282
  ptyChild.on("exit", () => {
25283
+ probeEvent("pty.exit", { tsid: ctx.toolSessionId });
25243
25284
  if (ctx.toolSessionId && this.tuiOpts.onPtyUnregister) {
25244
25285
  this.tuiOpts.onPtyUnregister(ctx.toolSessionId);
25245
25286
  }
@@ -25312,9 +25353,9 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
25312
25353
  function jsonlExistsForCtx(ctx) {
25313
25354
  if (!ctx.toolSessionId) return false;
25314
25355
  const home = import_node_os5.default.homedir();
25315
- const file = import_node_path10.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
25356
+ const file = import_node_path11.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
25316
25357
  try {
25317
- return import_node_fs9.default.statSync(file).isFile();
25358
+ return import_node_fs10.default.statSync(file).isFile();
25318
25359
  } catch {
25319
25360
  return false;
25320
25361
  }
@@ -25324,23 +25365,23 @@ function jsonlExistsForCtx(ctx) {
25324
25365
  init_claude_history();
25325
25366
 
25326
25367
  // src/workspace/browser.ts
25327
- var import_node_fs10 = __toESM(require("fs"), 1);
25368
+ var import_node_fs11 = __toESM(require("fs"), 1);
25328
25369
  var import_node_os6 = __toESM(require("os"), 1);
25329
- var import_node_path11 = __toESM(require("path"), 1);
25370
+ var import_node_path12 = __toESM(require("path"), 1);
25330
25371
  init_protocol();
25331
25372
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
25332
25373
  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)) {
25374
+ const absCwd = import_node_path12.default.resolve(cwd);
25375
+ const joined = import_node_path12.default.resolve(absCwd, subpath ?? ".");
25376
+ const rel = import_node_path12.default.relative(absCwd, joined);
25377
+ if (rel.startsWith("..") || import_node_path12.default.isAbsolute(rel)) {
25337
25378
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
25338
25379
  }
25339
25380
  return joined;
25340
25381
  }
25341
25382
  function ensureCwd(cwd) {
25342
25383
  try {
25343
- const stat = import_node_fs10.default.statSync(cwd);
25384
+ const stat = import_node_fs11.default.statSync(cwd);
25344
25385
  if (!stat.isDirectory()) {
25345
25386
  throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
25346
25387
  }
@@ -25354,7 +25395,7 @@ var WorkspaceBrowser = class {
25354
25395
  const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os6.default.homedir();
25355
25396
  ensureCwd(cwd);
25356
25397
  const full = resolveInsideCwd(cwd, args.path);
25357
- const dirents = import_node_fs10.default.readdirSync(full, { withFileTypes: true });
25398
+ const dirents = import_node_fs11.default.readdirSync(full, { withFileTypes: true });
25358
25399
  const entries = [];
25359
25400
  for (const d of dirents) {
25360
25401
  if (!args.showHidden && d.name.startsWith(".")) continue;
@@ -25364,7 +25405,7 @@ var WorkspaceBrowser = class {
25364
25405
  mtime: ""
25365
25406
  };
25366
25407
  try {
25367
- const st = import_node_fs10.default.statSync(import_node_path11.default.join(full, d.name));
25408
+ const st = import_node_fs11.default.statSync(import_node_path12.default.join(full, d.name));
25368
25409
  entry.mtime = new Date(st.mtimeMs).toISOString();
25369
25410
  if (d.isFile()) entry.size = st.size;
25370
25411
  } catch {
@@ -25380,14 +25421,14 @@ var WorkspaceBrowser = class {
25380
25421
  read(args) {
25381
25422
  ensureCwd(args.cwd);
25382
25423
  const full = resolveInsideCwd(args.cwd, args.path);
25383
- const st = import_node_fs10.default.statSync(full);
25424
+ const st = import_node_fs11.default.statSync(full);
25384
25425
  if (!st.isFile()) {
25385
25426
  throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
25386
25427
  }
25387
25428
  if (st.size > MAX_FILE_BYTES) {
25388
25429
  throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
25389
25430
  }
25390
- const buf = import_node_fs10.default.readFileSync(full);
25431
+ const buf = import_node_fs11.default.readFileSync(full);
25391
25432
  const isBinary = buf.includes(0);
25392
25433
  if (isBinary) {
25393
25434
  return {
@@ -25409,20 +25450,20 @@ var WorkspaceBrowser = class {
25409
25450
  };
25410
25451
 
25411
25452
  // src/skills/agents-scanner.ts
25412
- var import_node_fs11 = __toESM(require("fs"), 1);
25453
+ var import_node_fs12 = __toESM(require("fs"), 1);
25413
25454
  var import_node_os7 = __toESM(require("os"), 1);
25414
- var import_node_path12 = __toESM(require("path"), 1);
25455
+ var import_node_path13 = __toESM(require("path"), 1);
25415
25456
  var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
25416
25457
  function isDirLikeSync2(p2) {
25417
25458
  try {
25418
- return import_node_fs11.default.statSync(p2).isDirectory();
25459
+ return import_node_fs12.default.statSync(p2).isDirectory();
25419
25460
  } catch {
25420
25461
  return false;
25421
25462
  }
25422
25463
  }
25423
25464
  function fileExistsSync(p2) {
25424
25465
  try {
25425
- return import_node_fs11.default.statSync(p2).isFile();
25466
+ return import_node_fs12.default.statSync(p2).isFile();
25426
25467
  } catch {
25427
25468
  return false;
25428
25469
  }
@@ -25430,7 +25471,7 @@ function fileExistsSync(p2) {
25430
25471
  function parseAgentFile(filePath) {
25431
25472
  let content;
25432
25473
  try {
25433
- content = import_node_fs11.default.readFileSync(filePath, "utf8");
25474
+ content = import_node_fs12.default.readFileSync(filePath, "utf8");
25434
25475
  } catch {
25435
25476
  return {};
25436
25477
  }
@@ -25443,16 +25484,16 @@ function parseAgentFile(filePath) {
25443
25484
  function scanAgentsDir(dir, source, seen, out) {
25444
25485
  let entries;
25445
25486
  try {
25446
- entries = import_node_fs11.default.readdirSync(dir, { withFileTypes: true });
25487
+ entries = import_node_fs12.default.readdirSync(dir, { withFileTypes: true });
25447
25488
  } catch {
25448
25489
  return;
25449
25490
  }
25450
25491
  for (const ent of entries) {
25451
25492
  if (!ent.name.endsWith(".md")) continue;
25452
- if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path12.default.join(dir, ent.name)))) {
25493
+ if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path13.default.join(dir, ent.name)))) {
25453
25494
  continue;
25454
25495
  }
25455
- const filePath = import_node_path12.default.join(dir, ent.name);
25496
+ const filePath = import_node_path13.default.join(dir, ent.name);
25456
25497
  const baseName = ent.name.replace(/\.md$/, "");
25457
25498
  if (seen.has(baseName)) continue;
25458
25499
  seen.add(baseName);
@@ -25470,12 +25511,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
25470
25511
  function walk(dir, namespaces) {
25471
25512
  let entries;
25472
25513
  try {
25473
- entries = import_node_fs11.default.readdirSync(dir, { withFileTypes: true });
25514
+ entries = import_node_fs12.default.readdirSync(dir, { withFileTypes: true });
25474
25515
  } catch {
25475
25516
  return;
25476
25517
  }
25477
25518
  for (const ent of entries) {
25478
- const childPath = import_node_path12.default.join(dir, ent.name);
25519
+ const childPath = import_node_path13.default.join(dir, ent.name);
25479
25520
  if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
25480
25521
  walk(childPath, [...namespaces, ent.name]);
25481
25522
  continue;
@@ -25500,13 +25541,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
25500
25541
  walk(root, []);
25501
25542
  }
25502
25543
  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");
25544
+ const pluginsDir = import_node_path13.default.join(home, ".claude", "plugins");
25545
+ const v2 = import_node_path13.default.join(pluginsDir, "installed_plugins_v2.json");
25546
+ const v1 = import_node_path13.default.join(pluginsDir, "installed_plugins.json");
25506
25547
  let raw = null;
25507
25548
  for (const candidate of [v2, v1]) {
25508
25549
  try {
25509
- raw = import_node_fs11.default.readFileSync(candidate, "utf8");
25550
+ raw = import_node_fs12.default.readFileSync(candidate, "utf8");
25510
25551
  break;
25511
25552
  } catch {
25512
25553
  }
@@ -25531,19 +25572,19 @@ function readInstalledPlugins2(home) {
25531
25572
  return out;
25532
25573
  }
25533
25574
  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;
25575
+ let cur = import_node_path13.default.resolve(startCwd);
25576
+ const fsRoot = import_node_path13.default.parse(cur).root;
25536
25577
  while (true) {
25537
- scanAgentsDir(import_node_path12.default.join(cur, ".claude", "agents"), "project", seen, out);
25578
+ scanAgentsDir(import_node_path13.default.join(cur, ".claude", "agents"), "project", seen, out);
25538
25579
  let hasGit = false;
25539
25580
  try {
25540
- hasGit = import_node_fs11.default.existsSync(import_node_path12.default.join(cur, ".git"));
25581
+ hasGit = import_node_fs12.default.existsSync(import_node_path13.default.join(cur, ".git"));
25541
25582
  } catch {
25542
25583
  }
25543
25584
  if (hasGit) return;
25544
25585
  if (cur === home) return;
25545
25586
  if (cur === fsRoot) return;
25546
- const parent = import_node_path12.default.dirname(cur);
25587
+ const parent = import_node_path13.default.dirname(cur);
25547
25588
  if (parent === cur) return;
25548
25589
  cur = parent;
25549
25590
  }
@@ -25578,7 +25619,7 @@ var AgentsScanner = class {
25578
25619
  }
25579
25620
  const fsBlock = [];
25580
25621
  scanAgentsDir(
25581
- import_node_path12.default.join(this.home, ".claude", "agents"),
25622
+ import_node_path13.default.join(this.home, ".claude", "agents"),
25582
25623
  "global",
25583
25624
  seen,
25584
25625
  fsBlock
@@ -25592,7 +25633,7 @@ var AgentsScanner = class {
25592
25633
  ...this.extraPluginRoots
25593
25634
  ];
25594
25635
  for (const { name, root } of plugins) {
25595
- const agentsRoot = import_node_path12.default.join(root, "agents");
25636
+ const agentsRoot = import_node_path13.default.join(root, "agents");
25596
25637
  scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
25597
25638
  }
25598
25639
  return [...builtinBlock, ...fsBlock];
@@ -25600,15 +25641,15 @@ var AgentsScanner = class {
25600
25641
  };
25601
25642
 
25602
25643
  // src/observer/session-observer.ts
25603
- var import_node_fs13 = __toESM(require("fs"), 1);
25644
+ var import_node_fs14 = __toESM(require("fs"), 1);
25604
25645
  var import_node_os9 = __toESM(require("os"), 1);
25605
- var import_node_path14 = __toESM(require("path"), 1);
25646
+ var import_node_path15 = __toESM(require("path"), 1);
25606
25647
  init_claude_history();
25607
25648
 
25608
25649
  // src/observer/subagent-meta-observer.ts
25609
- var import_node_fs12 = __toESM(require("fs"), 1);
25650
+ var import_node_fs13 = __toESM(require("fs"), 1);
25610
25651
  var import_node_os8 = __toESM(require("os"), 1);
25611
- var import_node_path13 = __toESM(require("path"), 1);
25652
+ var import_node_path14 = __toESM(require("path"), 1);
25612
25653
  init_claude_history();
25613
25654
  var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
25614
25655
  var SubagentMetaObserver = class {
@@ -25621,7 +25662,7 @@ var SubagentMetaObserver = class {
25621
25662
  watches = /* @__PURE__ */ new Map();
25622
25663
  // public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
25623
25664
  resolveSubagentDir(cwd, toolSessionId) {
25624
- return import_node_path13.default.join(
25665
+ return import_node_path14.default.join(
25625
25666
  this.home,
25626
25667
  ".claude",
25627
25668
  "projects",
@@ -25651,7 +25692,7 @@ var SubagentMetaObserver = class {
25651
25692
  attachWatcher(w2) {
25652
25693
  if (w2.watcher) return;
25653
25694
  try {
25654
- w2.watcher = import_node_fs12.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
25695
+ w2.watcher = import_node_fs13.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
25655
25696
  if (!name) return;
25656
25697
  const m2 = META_RE.exec(String(name));
25657
25698
  if (!m2) return;
@@ -25663,7 +25704,7 @@ var SubagentMetaObserver = class {
25663
25704
  scan(w2) {
25664
25705
  let entries;
25665
25706
  try {
25666
- entries = import_node_fs12.default.readdirSync(w2.dirPath);
25707
+ entries = import_node_fs13.default.readdirSync(w2.dirPath);
25667
25708
  } catch {
25668
25709
  return;
25669
25710
  }
@@ -25677,10 +25718,10 @@ var SubagentMetaObserver = class {
25677
25718
  if (!m2) return;
25678
25719
  const agentId = m2[1];
25679
25720
  if (w2.emitted.has(agentId)) return;
25680
- const file = import_node_path13.default.join(w2.dirPath, name);
25721
+ const file = import_node_path14.default.join(w2.dirPath, name);
25681
25722
  let raw;
25682
25723
  try {
25683
- raw = import_node_fs12.default.readFileSync(file, "utf8");
25724
+ raw = import_node_fs13.default.readFileSync(file, "utf8");
25684
25725
  } catch {
25685
25726
  return;
25686
25727
  }
@@ -25737,14 +25778,14 @@ var SessionObserver = class {
25737
25778
  metaObserver;
25738
25779
  resolveJsonlPath(cwd, toolSessionId, override) {
25739
25780
  if (override) return override;
25740
- return import_node_path14.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
25781
+ return import_node_path15.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
25741
25782
  }
25742
25783
  start(args) {
25743
25784
  this.stop(args.sessionId);
25744
25785
  const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
25745
25786
  let size = 0;
25746
25787
  try {
25747
- size = import_node_fs13.default.statSync(filePath).size;
25788
+ size = import_node_fs14.default.statSync(filePath).size;
25748
25789
  } catch {
25749
25790
  }
25750
25791
  const w2 = {
@@ -25757,10 +25798,10 @@ var SessionObserver = class {
25757
25798
  adapter: args.adapter
25758
25799
  };
25759
25800
  try {
25760
- import_node_fs13.default.mkdirSync(import_node_path14.default.dirname(filePath), { recursive: true });
25801
+ import_node_fs14.default.mkdirSync(import_node_path15.default.dirname(filePath), { recursive: true });
25761
25802
  } catch {
25762
25803
  }
25763
- w2.watcher = import_node_fs13.default.watch(import_node_path14.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
25804
+ w2.watcher = import_node_fs14.default.watch(import_node_path15.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
25764
25805
  if (!changedName || !filePath.endsWith(changedName)) return;
25765
25806
  this.poll(w2);
25766
25807
  });
@@ -25783,7 +25824,7 @@ var SessionObserver = class {
25783
25824
  // 异常静默吞,不阻塞 watcher 启动
25784
25825
  hydrateMetaTail(w2, maxLines = 200) {
25785
25826
  try {
25786
- const raw = import_node_fs13.default.readFileSync(w2.filePath, "utf8");
25827
+ const raw = import_node_fs14.default.readFileSync(w2.filePath, "utf8");
25787
25828
  if (!raw) return;
25788
25829
  const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
25789
25830
  if (allLines.length === 0) return;
@@ -25807,7 +25848,7 @@ var SessionObserver = class {
25807
25848
  poll(w2) {
25808
25849
  let size = 0;
25809
25850
  try {
25810
- size = import_node_fs13.default.statSync(w2.filePath).size;
25851
+ size = import_node_fs14.default.statSync(w2.filePath).size;
25811
25852
  } catch {
25812
25853
  return;
25813
25854
  }
@@ -25816,11 +25857,11 @@ var SessionObserver = class {
25816
25857
  w2.buf = "";
25817
25858
  }
25818
25859
  if (size === w2.lastSize) return;
25819
- const fd = import_node_fs13.default.openSync(w2.filePath, "r");
25860
+ const fd = import_node_fs14.default.openSync(w2.filePath, "r");
25820
25861
  try {
25821
25862
  const len = size - w2.lastSize;
25822
25863
  const buf = Buffer.alloc(len);
25823
- import_node_fs13.default.readSync(fd, buf, 0, len, w2.lastSize);
25864
+ import_node_fs14.default.readSync(fd, buf, 0, len, w2.lastSize);
25824
25865
  w2.lastSize = size;
25825
25866
  w2.buf += buf.toString("utf8");
25826
25867
  let newlineIndex;
@@ -25834,7 +25875,7 @@ var SessionObserver = class {
25834
25875
  }
25835
25876
  }
25836
25877
  } finally {
25837
- import_node_fs13.default.closeSync(fd);
25878
+ import_node_fs14.default.closeSync(fd);
25838
25879
  }
25839
25880
  }
25840
25881
  // 解析 JSONL 单行:仅当是主链 user 文本行(非 sidechain / 非 sub-agent / message.role='user'
@@ -26494,14 +26535,14 @@ function authenticate(token, deps) {
26494
26535
  }
26495
26536
 
26496
26537
  // src/permission/capability-store.ts
26497
- var fs16 = __toESM(require("fs"), 1);
26498
- var path19 = __toESM(require("path"), 1);
26538
+ var fs17 = __toESM(require("fs"), 1);
26539
+ var path20 = __toESM(require("path"), 1);
26499
26540
  var CAPABILITIES_FILE_NAME = "capabilities.json";
26500
26541
  var FILE_VERSION = 1;
26501
26542
  var CapabilityStore = class {
26502
26543
  constructor(dataDir) {
26503
26544
  this.dataDir = dataDir;
26504
- fs16.mkdirSync(dataDir, { recursive: true });
26545
+ fs17.mkdirSync(dataDir, { recursive: true });
26505
26546
  this.cache = this.readFromDisk();
26506
26547
  }
26507
26548
  dataDir;
@@ -26525,13 +26566,13 @@ var CapabilityStore = class {
26525
26566
  this.flush();
26526
26567
  }
26527
26568
  filePath() {
26528
- return path19.join(this.dataDir, CAPABILITIES_FILE_NAME);
26569
+ return path20.join(this.dataDir, CAPABILITIES_FILE_NAME);
26529
26570
  }
26530
26571
  readFromDisk() {
26531
26572
  const file = this.filePath();
26532
26573
  let raw;
26533
26574
  try {
26534
- raw = fs16.readFileSync(file, "utf8");
26575
+ raw = fs17.readFileSync(file, "utf8");
26535
26576
  } catch (err) {
26536
26577
  if (err?.code === "ENOENT") return [];
26537
26578
  return [];
@@ -26559,10 +26600,10 @@ var CapabilityStore = class {
26559
26600
  }
26560
26601
  atomicWrite(file, content) {
26561
26602
  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);
26603
+ fs17.writeFileSync(tmp, content, { mode: 384 });
26604
+ fs17.renameSync(tmp, file);
26564
26605
  try {
26565
- fs16.chmodSync(file, 384);
26606
+ fs17.chmodSync(file, 384);
26566
26607
  } catch {
26567
26608
  }
26568
26609
  }
@@ -26655,14 +26696,14 @@ var CapabilityManager = class {
26655
26696
  };
26656
26697
 
26657
26698
  // src/permission/cleanup.ts
26658
- var fs17 = __toESM(require("fs"), 1);
26699
+ var fs18 = __toESM(require("fs"), 1);
26659
26700
  function cleanupGuestSessionsForCapability(cap, factory) {
26660
26701
  const removed = [];
26661
26702
  for (const g2 of cap.grants) {
26662
26703
  if (g2.resource.type !== "persona") continue;
26663
26704
  const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
26664
26705
  try {
26665
- fs17.rmSync(dir, { recursive: true, force: true });
26706
+ fs18.rmSync(dir, { recursive: true, force: true });
26666
26707
  removed.push(dir);
26667
26708
  } catch {
26668
26709
  }
@@ -26671,13 +26712,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
26671
26712
  }
26672
26713
 
26673
26714
  // src/permission/personal-capability.ts
26674
- var import_node_fs14 = __toESM(require("fs"), 1);
26675
- var import_node_path15 = __toESM(require("path"), 1);
26715
+ var import_node_fs15 = __toESM(require("fs"), 1);
26716
+ var import_node_path16 = __toESM(require("path"), 1);
26676
26717
  var import_node_crypto4 = __toESM(require("crypto"), 1);
26677
26718
  var PERSONAL_CAP_FILE_NAME = "personal-capability.json";
26678
26719
  var PERSONAL_CAP_DISPLAY_NAME = "personal";
26679
26720
  function personalCapFilePath(dataDir) {
26680
- return import_node_path15.default.join(dataDir, PERSONAL_CAP_FILE_NAME);
26721
+ return import_node_path16.default.join(dataDir, PERSONAL_CAP_FILE_NAME);
26681
26722
  }
26682
26723
  function loadOrCreatePersonalCapability(opts) {
26683
26724
  const file = personalCapFilePath(opts.dataDir);
@@ -26707,7 +26748,7 @@ function loadOrCreatePersonalCapability(opts) {
26707
26748
  function readFile(file) {
26708
26749
  let raw;
26709
26750
  try {
26710
- raw = import_node_fs14.default.readFileSync(file, "utf8");
26751
+ raw = import_node_fs15.default.readFileSync(file, "utf8");
26711
26752
  } catch (err) {
26712
26753
  const code = err?.code;
26713
26754
  if (code === "ENOENT") return null;
@@ -26728,10 +26769,10 @@ function readFile(file) {
26728
26769
  return { token: obj.token, capability: capParsed.data };
26729
26770
  }
26730
26771
  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 });
26772
+ import_node_fs15.default.mkdirSync(import_node_path16.default.dirname(file), { recursive: true });
26773
+ import_node_fs15.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
26733
26774
  try {
26734
- import_node_fs14.default.chmodSync(file, 384);
26775
+ import_node_fs15.default.chmodSync(file, 384);
26735
26776
  } catch {
26736
26777
  }
26737
26778
  }
@@ -26746,13 +26787,13 @@ function sha256Hex2(s) {
26746
26787
  }
26747
26788
 
26748
26789
  // src/inbox/inbox-store.ts
26749
- var fs19 = __toESM(require("fs"), 1);
26750
- var path21 = __toESM(require("path"), 1);
26790
+ var fs20 = __toESM(require("fs"), 1);
26791
+ var path22 = __toESM(require("path"), 1);
26751
26792
  var INBOX_SUBDIR = "inbox";
26752
26793
  var InboxStore = class {
26753
26794
  constructor(dataDir) {
26754
26795
  this.dataDir = dataDir;
26755
- fs19.mkdirSync(this.dirPath(), { recursive: true });
26796
+ fs20.mkdirSync(this.dirPath(), { recursive: true });
26756
26797
  }
26757
26798
  dataDir;
26758
26799
  /**
@@ -26764,7 +26805,7 @@ var InboxStore = class {
26764
26805
  const file = this.filePath(peerOwnerId);
26765
26806
  let raw;
26766
26807
  try {
26767
- raw = fs19.readFileSync(file, "utf8");
26808
+ raw = fs20.readFileSync(file, "utf8");
26768
26809
  } catch (err) {
26769
26810
  if (err?.code === "ENOENT") return [];
26770
26811
  return [];
@@ -26780,7 +26821,7 @@ var InboxStore = class {
26780
26821
  const dir = this.dirPath();
26781
26822
  let entries;
26782
26823
  try {
26783
- entries = fs19.readdirSync(dir);
26824
+ entries = fs20.readdirSync(dir);
26784
26825
  } catch (err) {
26785
26826
  if (err?.code === "ENOENT") return [];
26786
26827
  return [];
@@ -26796,9 +26837,9 @@ var InboxStore = class {
26796
26837
  if (existing.some((m2) => m2.id === message.id)) return;
26797
26838
  const file = this.filePath(message.peerOwnerId);
26798
26839
  const line = JSON.stringify(message) + "\n";
26799
- fs19.appendFileSync(file, line, { mode: 384 });
26840
+ fs20.appendFileSync(file, line, { mode: 384 });
26800
26841
  try {
26801
- fs19.chmodSync(file, 384);
26842
+ fs20.chmodSync(file, 384);
26802
26843
  } catch {
26803
26844
  }
26804
26845
  }
@@ -26828,7 +26869,7 @@ var InboxStore = class {
26828
26869
  removeByPeerOwnerId(peerOwnerId) {
26829
26870
  const file = this.filePath(peerOwnerId);
26830
26871
  try {
26831
- fs19.unlinkSync(file);
26872
+ fs20.unlinkSync(file);
26832
26873
  } catch (err) {
26833
26874
  if (err?.code === "ENOENT") return;
26834
26875
  }
@@ -26837,18 +26878,18 @@ var InboxStore = class {
26837
26878
  const file = this.filePath(peerOwnerId);
26838
26879
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
26839
26880
  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);
26881
+ fs20.writeFileSync(tmp, content, { mode: 384 });
26882
+ fs20.renameSync(tmp, file);
26842
26883
  try {
26843
- fs19.chmodSync(file, 384);
26884
+ fs20.chmodSync(file, 384);
26844
26885
  } catch {
26845
26886
  }
26846
26887
  }
26847
26888
  dirPath() {
26848
- return path21.join(this.dataDir, INBOX_SUBDIR);
26889
+ return path22.join(this.dataDir, INBOX_SUBDIR);
26849
26890
  }
26850
26891
  filePath(peerOwnerId) {
26851
- return path21.join(this.dirPath(), `${peerOwnerId}.jsonl`);
26892
+ return path22.join(this.dirPath(), `${peerOwnerId}.jsonl`);
26852
26893
  }
26853
26894
  };
26854
26895
  function parseAllLines(raw) {
@@ -26935,8 +26976,8 @@ var InboxManager = class {
26935
26976
  };
26936
26977
 
26937
26978
  // src/state/received-capability-store.ts
26938
- var fs20 = __toESM(require("fs"), 1);
26939
- var path22 = __toESM(require("path"), 1);
26979
+ var fs21 = __toESM(require("fs"), 1);
26980
+ var path23 = __toESM(require("path"), 1);
26940
26981
  var FILE_NAME = "received-capabilities.json";
26941
26982
  var ReceivedCapabilityStore = class {
26942
26983
  constructor(dataDir) {
@@ -26946,10 +26987,10 @@ var ReceivedCapabilityStore = class {
26946
26987
  caps = /* @__PURE__ */ new Map();
26947
26988
  load() {
26948
26989
  this.caps.clear();
26949
- const file = path22.join(this.dataDir, FILE_NAME);
26990
+ const file = path23.join(this.dataDir, FILE_NAME);
26950
26991
  let raw;
26951
26992
  try {
26952
- raw = fs20.readFileSync(file, "utf8");
26993
+ raw = fs21.readFileSync(file, "utf8");
26953
26994
  } catch (err) {
26954
26995
  if (err?.code !== "ENOENT") this.renameBak(file);
26955
26996
  return;
@@ -26986,20 +27027,20 @@ var ReceivedCapabilityStore = class {
26986
27027
  this.flush();
26987
27028
  }
26988
27029
  flush() {
26989
- const file = path22.join(this.dataDir, FILE_NAME);
27030
+ const file = path23.join(this.dataDir, FILE_NAME);
26990
27031
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
26991
27032
  const content = JSON.stringify(
26992
27033
  { receivedCaps: Array.from(this.caps.values()) },
26993
27034
  null,
26994
27035
  2
26995
27036
  );
26996
- fs20.mkdirSync(this.dataDir, { recursive: true });
26997
- fs20.writeFileSync(tmp, content, { mode: 384 });
26998
- fs20.renameSync(tmp, file);
27037
+ fs21.mkdirSync(this.dataDir, { recursive: true });
27038
+ fs21.writeFileSync(tmp, content, { mode: 384 });
27039
+ fs21.renameSync(tmp, file);
26999
27040
  }
27000
27041
  renameBak(file) {
27001
27042
  try {
27002
- fs20.renameSync(file, `${file}.bak`);
27043
+ fs21.renameSync(file, `${file}.bak`);
27003
27044
  } catch {
27004
27045
  }
27005
27046
  }
@@ -27097,61 +27138,61 @@ async function connectRemote(args) {
27097
27138
  }
27098
27139
 
27099
27140
  // src/migrations/2026-05-20-flatten-sessions.ts
27100
- var fs21 = __toESM(require("fs"), 1);
27101
- var path23 = __toESM(require("path"), 1);
27141
+ var fs22 = __toESM(require("fs"), 1);
27142
+ var path24 = __toESM(require("path"), 1);
27102
27143
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
27103
27144
  function migrateFlattenSessions(opts) {
27104
27145
  const dataDir = opts.dataDir;
27105
27146
  const now = opts.now ?? Date.now;
27106
- const sessionsDir = path23.join(dataDir, "sessions");
27107
- const flagPath = path23.join(sessionsDir, MIGRATION_FLAG_NAME);
27147
+ const sessionsDir = path24.join(dataDir, "sessions");
27148
+ const flagPath = path24.join(sessionsDir, MIGRATION_FLAG_NAME);
27108
27149
  if (existsSync3(flagPath)) {
27109
27150
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
27110
27151
  }
27111
27152
  let movedBare = 0;
27112
27153
  let movedVmOwner = 0;
27113
27154
  let archivedListener = 0;
27114
- const defaultDir = path23.join(sessionsDir, "default");
27155
+ const defaultDir = path24.join(sessionsDir, "default");
27115
27156
  if (existsSync3(defaultDir)) {
27116
27157
  for (const entry of readdirSafe(defaultDir)) {
27117
27158
  if (!entry.endsWith(".json")) continue;
27118
- const src = path23.join(defaultDir, entry);
27119
- const dst = path23.join(sessionsDir, entry);
27120
- fs21.renameSync(src, dst);
27159
+ const src = path24.join(defaultDir, entry);
27160
+ const dst = path24.join(sessionsDir, entry);
27161
+ fs22.renameSync(src, dst);
27121
27162
  movedBare += 1;
27122
27163
  }
27123
27164
  rmdirIfEmpty(defaultDir);
27124
27165
  }
27125
27166
  for (const pid of readdirSafe(sessionsDir)) {
27126
- const personaDir = path23.join(sessionsDir, pid);
27167
+ const personaDir = path24.join(sessionsDir, pid);
27127
27168
  if (!isDir(personaDir)) continue;
27128
27169
  if (pid === "default") continue;
27129
- const ownerSrc = path23.join(personaDir, "owner");
27170
+ const ownerSrc = path24.join(personaDir, "owner");
27130
27171
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
27131
- const ownerDst = path23.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
27132
- fs21.mkdirSync(ownerDst, { recursive: true });
27172
+ const ownerDst = path24.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
27173
+ fs22.mkdirSync(ownerDst, { recursive: true });
27133
27174
  for (const file of readdirSafe(ownerSrc)) {
27134
27175
  if (!file.endsWith(".json")) continue;
27135
- fs21.renameSync(path23.join(ownerSrc, file), path23.join(ownerDst, file));
27176
+ fs22.renameSync(path24.join(ownerSrc, file), path24.join(ownerDst, file));
27136
27177
  movedVmOwner += 1;
27137
27178
  }
27138
27179
  rmdirIfEmpty(ownerSrc);
27139
27180
  }
27140
- const listenerSrc = path23.join(personaDir, "listener");
27181
+ const listenerSrc = path24.join(personaDir, "listener");
27141
27182
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
27142
- const archiveDst = path23.join(dataDir, ".legacy", `listener-${pid}`);
27143
- fs21.mkdirSync(archiveDst, { recursive: true });
27183
+ const archiveDst = path24.join(dataDir, ".legacy", `listener-${pid}`);
27184
+ fs22.mkdirSync(archiveDst, { recursive: true });
27144
27185
  for (const file of readdirSafe(listenerSrc)) {
27145
27186
  if (!file.endsWith(".json")) continue;
27146
- fs21.renameSync(path23.join(listenerSrc, file), path23.join(archiveDst, file));
27187
+ fs22.renameSync(path24.join(listenerSrc, file), path24.join(archiveDst, file));
27147
27188
  archivedListener += 1;
27148
27189
  }
27149
27190
  rmdirIfEmpty(listenerSrc);
27150
27191
  }
27151
27192
  rmdirIfEmpty(personaDir);
27152
27193
  }
27153
- fs21.mkdirSync(sessionsDir, { recursive: true });
27154
- fs21.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
27194
+ fs22.mkdirSync(sessionsDir, { recursive: true });
27195
+ fs22.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
27155
27196
  return {
27156
27197
  skipped: false,
27157
27198
  flagWritten: true,
@@ -27162,7 +27203,7 @@ function migrateFlattenSessions(opts) {
27162
27203
  }
27163
27204
  function existsSync3(p2) {
27164
27205
  try {
27165
- fs21.statSync(p2);
27206
+ fs22.statSync(p2);
27166
27207
  return true;
27167
27208
  } catch {
27168
27209
  return false;
@@ -27170,31 +27211,31 @@ function existsSync3(p2) {
27170
27211
  }
27171
27212
  function isDir(p2) {
27172
27213
  try {
27173
- return fs21.statSync(p2).isDirectory();
27214
+ return fs22.statSync(p2).isDirectory();
27174
27215
  } catch {
27175
27216
  return false;
27176
27217
  }
27177
27218
  }
27178
27219
  function readdirSafe(p2) {
27179
27220
  try {
27180
- return fs21.readdirSync(p2);
27221
+ return fs22.readdirSync(p2);
27181
27222
  } catch {
27182
27223
  return [];
27183
27224
  }
27184
27225
  }
27185
27226
  function rmdirIfEmpty(p2) {
27186
27227
  try {
27187
- fs21.rmdirSync(p2);
27228
+ fs22.rmdirSync(p2);
27188
27229
  } catch {
27189
27230
  }
27190
27231
  }
27191
27232
 
27192
27233
  // src/transport/http-router.ts
27193
- var import_node_fs16 = __toESM(require("fs"), 1);
27194
- var import_node_path18 = __toESM(require("path"), 1);
27234
+ var import_node_fs17 = __toESM(require("fs"), 1);
27235
+ var import_node_path19 = __toESM(require("path"), 1);
27195
27236
 
27196
27237
  // src/attachment/mime.ts
27197
- var import_node_path16 = __toESM(require("path"), 1);
27238
+ var import_node_path17 = __toESM(require("path"), 1);
27198
27239
  var TEXT_PLAIN = "text/plain; charset=utf-8";
27199
27240
  var EXT_TO_NATIVE_MIME = {
27200
27241
  // 图片
@@ -27301,7 +27342,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
27301
27342
  ".mk"
27302
27343
  ]);
27303
27344
  function lookupMime(filePathOrName) {
27304
- const ext = import_node_path16.default.extname(filePathOrName).toLowerCase();
27345
+ const ext = import_node_path17.default.extname(filePathOrName).toLowerCase();
27305
27346
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
27306
27347
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
27307
27348
  return "application/octet-stream";
@@ -27370,8 +27411,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
27370
27411
  }
27371
27412
 
27372
27413
  // src/attachment/upload.ts
27373
- var import_node_fs15 = __toESM(require("fs"), 1);
27374
- var import_node_path17 = __toESM(require("path"), 1);
27414
+ var import_node_fs16 = __toESM(require("fs"), 1);
27415
+ var import_node_path18 = __toESM(require("path"), 1);
27375
27416
  var import_node_crypto6 = __toESM(require("crypto"), 1);
27376
27417
  var import_promises = require("stream/promises");
27377
27418
  var UploadError = class extends Error {
@@ -27383,22 +27424,22 @@ var UploadError = class extends Error {
27383
27424
  code;
27384
27425
  };
27385
27426
  function assertValidFileName(fileName) {
27386
- if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path17.default.basename(fileName)) {
27427
+ if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path18.default.basename(fileName)) {
27387
27428
  throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
27388
27429
  }
27389
27430
  }
27390
27431
  var HASH_PREFIX_LEN = 16;
27391
27432
  async function writeUploadedAttachment(args) {
27392
27433
  assertValidFileName(args.fileName);
27393
- const attachmentsRoot = import_node_path17.default.join(args.sessionDir, ".attachments");
27434
+ const attachmentsRoot = import_node_path18.default.join(args.sessionDir, ".attachments");
27394
27435
  try {
27395
- import_node_fs15.default.mkdirSync(attachmentsRoot, { recursive: true });
27436
+ import_node_fs16.default.mkdirSync(attachmentsRoot, { recursive: true });
27396
27437
  } catch (err) {
27397
27438
  throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
27398
27439
  }
27399
27440
  const hasher = import_node_crypto6.default.createHash("sha256");
27400
27441
  let actualSize = 0;
27401
- const tmpPath = import_node_path17.default.join(
27442
+ const tmpPath = import_node_path18.default.join(
27402
27443
  attachmentsRoot,
27403
27444
  `.upload-${process.pid}-${Date.now()}-${import_node_crypto6.default.randomBytes(4).toString("hex")}`
27404
27445
  );
@@ -27413,18 +27454,18 @@ async function writeUploadedAttachment(args) {
27413
27454
  yield buf;
27414
27455
  }
27415
27456
  },
27416
- import_node_fs15.default.createWriteStream(tmpPath, { mode: 384 })
27457
+ import_node_fs16.default.createWriteStream(tmpPath, { mode: 384 })
27417
27458
  );
27418
27459
  } catch (err) {
27419
27460
  try {
27420
- import_node_fs15.default.unlinkSync(tmpPath);
27461
+ import_node_fs16.default.unlinkSync(tmpPath);
27421
27462
  } catch {
27422
27463
  }
27423
27464
  throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
27424
27465
  }
27425
27466
  if (actualSize !== args.contentLength) {
27426
27467
  try {
27427
- import_node_fs15.default.unlinkSync(tmpPath);
27468
+ import_node_fs16.default.unlinkSync(tmpPath);
27428
27469
  } catch {
27429
27470
  }
27430
27471
  throw new UploadError(
@@ -27433,35 +27474,35 @@ async function writeUploadedAttachment(args) {
27433
27474
  );
27434
27475
  }
27435
27476
  const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
27436
- const hashDir = import_node_path17.default.join(attachmentsRoot, attachmentId);
27477
+ const hashDir = import_node_path18.default.join(attachmentsRoot, attachmentId);
27437
27478
  let finalFileName;
27438
27479
  let hashDirExists = false;
27439
27480
  try {
27440
- hashDirExists = import_node_fs15.default.statSync(hashDir).isDirectory();
27481
+ hashDirExists = import_node_fs16.default.statSync(hashDir).isDirectory();
27441
27482
  } catch {
27442
27483
  }
27443
27484
  if (hashDirExists) {
27444
- const existing = import_node_fs15.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
27485
+ const existing = import_node_fs16.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
27445
27486
  finalFileName = existing[0] ?? args.fileName;
27446
27487
  try {
27447
- import_node_fs15.default.unlinkSync(tmpPath);
27488
+ import_node_fs16.default.unlinkSync(tmpPath);
27448
27489
  } catch {
27449
27490
  }
27450
27491
  } else {
27451
27492
  try {
27452
- import_node_fs15.default.mkdirSync(hashDir, { recursive: true });
27493
+ import_node_fs16.default.mkdirSync(hashDir, { recursive: true });
27453
27494
  finalFileName = args.fileName;
27454
- import_node_fs15.default.renameSync(tmpPath, import_node_path17.default.join(hashDir, finalFileName));
27495
+ import_node_fs16.default.renameSync(tmpPath, import_node_path18.default.join(hashDir, finalFileName));
27455
27496
  } catch (err) {
27456
27497
  try {
27457
- import_node_fs15.default.unlinkSync(tmpPath);
27498
+ import_node_fs16.default.unlinkSync(tmpPath);
27458
27499
  } catch {
27459
27500
  }
27460
27501
  throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
27461
27502
  }
27462
27503
  }
27463
- const absPath = import_node_path17.default.join(hashDir, finalFileName);
27464
- const relPath = import_node_path17.default.relative(args.sessionDir, absPath);
27504
+ const absPath = import_node_path18.default.join(hashDir, finalFileName);
27505
+ const relPath = import_node_path18.default.relative(args.sessionDir, absPath);
27465
27506
  args.groupFileStore.upsert(args.scope, args.sessionId, {
27466
27507
  relPath: absPath,
27467
27508
  // 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
@@ -27498,7 +27539,7 @@ function isValidUploadFileName(fileName) {
27498
27539
  if (fileName === "." || fileName === "..") return false;
27499
27540
  if (fileName.startsWith(".")) return false;
27500
27541
  if (fileName.includes("/") || fileName.includes("\\")) return false;
27501
- return fileName === import_node_path18.default.basename(fileName);
27542
+ return fileName === import_node_path19.default.basename(fileName);
27502
27543
  }
27503
27544
  function createHttpRouter(deps) {
27504
27545
  return async (req, res) => {
@@ -27668,7 +27709,7 @@ function createHttpRouter(deps) {
27668
27709
  return true;
27669
27710
  }
27670
27711
  let absPath;
27671
- if (import_node_path18.default.isAbsolute(pathParam)) {
27712
+ if (import_node_path19.default.isAbsolute(pathParam)) {
27672
27713
  absPath = pathParam;
27673
27714
  } else if (deps.sessionStore) {
27674
27715
  const file = deps.sessionStore.read(sid);
@@ -27676,7 +27717,7 @@ function createHttpRouter(deps) {
27676
27717
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
27677
27718
  return true;
27678
27719
  }
27679
- absPath = import_node_path18.default.join(file.cwd, pathParam);
27720
+ absPath = import_node_path19.default.join(file.cwd, pathParam);
27680
27721
  } else {
27681
27722
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
27682
27723
  return true;
@@ -27709,7 +27750,7 @@ function withCtx(ctx, body) {
27709
27750
  function streamFile(res, absPath, logger) {
27710
27751
  let stat;
27711
27752
  try {
27712
- stat = import_node_fs16.default.statSync(absPath);
27753
+ stat = import_node_fs17.default.statSync(absPath);
27713
27754
  } catch (err) {
27714
27755
  const code = err?.code;
27715
27756
  if (code === "ENOENT") {
@@ -27724,7 +27765,7 @@ function streamFile(res, absPath, logger) {
27724
27765
  return;
27725
27766
  }
27726
27767
  const mime = lookupMime(absPath);
27727
- const basename = import_node_path18.default.basename(absPath);
27768
+ const basename = import_node_path19.default.basename(absPath);
27728
27769
  res.writeHead(200, {
27729
27770
  "Content-Type": mime,
27730
27771
  "Content-Length": String(stat.size),
@@ -27732,7 +27773,7 @@ function streamFile(res, absPath, logger) {
27732
27773
  // 防止浏览器把任意 mime 当 html 渲染
27733
27774
  "X-Content-Type-Options": "nosniff"
27734
27775
  });
27735
- const stream = import_node_fs16.default.createReadStream(absPath);
27776
+ const stream = import_node_fs17.default.createReadStream(absPath);
27736
27777
  stream.on("error", (err) => {
27737
27778
  logger?.warn("streamFile read error", { absPath, err: err.message });
27738
27779
  res.destroy();
@@ -27741,8 +27782,8 @@ function streamFile(res, absPath, logger) {
27741
27782
  }
27742
27783
 
27743
27784
  // src/attachment/gc.ts
27744
- var import_node_fs17 = __toESM(require("fs"), 1);
27745
- var import_node_path19 = __toESM(require("path"), 1);
27785
+ var import_node_fs18 = __toESM(require("fs"), 1);
27786
+ var import_node_path20 = __toESM(require("path"), 1);
27746
27787
  var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
27747
27788
  function runAttachmentGc(args) {
27748
27789
  const now = (args.now ?? Date.now)();
@@ -27751,38 +27792,38 @@ function runAttachmentGc(args) {
27751
27792
  for (const { scope, sessionId } of args.sessionScopes) {
27752
27793
  for (const entry of args.groupFileStore.list(scope, sessionId)) {
27753
27794
  if (entry.stale) continue;
27754
- if (import_node_path19.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
27795
+ if (import_node_path20.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
27755
27796
  }
27756
27797
  }
27757
27798
  for (const { scope, sessionId } of args.sessionScopes) {
27758
- const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path19.default.join(
27799
+ const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path20.default.join(
27759
27800
  args.dataDir,
27760
27801
  "sessions",
27761
27802
  ...scopeSubPath(scope).map(safeFileName),
27762
27803
  safeFileName(sessionId)
27763
27804
  );
27764
- const attRoot = import_node_path19.default.join(sessionDir, ".attachments");
27805
+ const attRoot = import_node_path20.default.join(sessionDir, ".attachments");
27765
27806
  let hashDirs;
27766
27807
  try {
27767
- hashDirs = import_node_fs17.default.readdirSync(attRoot);
27808
+ hashDirs = import_node_fs18.default.readdirSync(attRoot);
27768
27809
  } catch (err) {
27769
27810
  if (err.code === "ENOENT") continue;
27770
27811
  args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
27771
27812
  continue;
27772
27813
  }
27773
27814
  for (const hashDir of hashDirs) {
27774
- const hashDirAbs = import_node_path19.default.join(attRoot, hashDir);
27815
+ const hashDirAbs = import_node_path20.default.join(attRoot, hashDir);
27775
27816
  let files;
27776
27817
  try {
27777
- files = import_node_fs17.default.readdirSync(hashDirAbs);
27818
+ files = import_node_fs18.default.readdirSync(hashDirAbs);
27778
27819
  } catch {
27779
27820
  continue;
27780
27821
  }
27781
27822
  for (const name of files) {
27782
- const file = import_node_path19.default.join(hashDirAbs, name);
27823
+ const file = import_node_path20.default.join(hashDirAbs, name);
27783
27824
  let stat;
27784
27825
  try {
27785
- stat = import_node_fs17.default.statSync(file);
27826
+ stat = import_node_fs18.default.statSync(file);
27786
27827
  } catch {
27787
27828
  continue;
27788
27829
  }
@@ -27791,26 +27832,26 @@ function runAttachmentGc(args) {
27791
27832
  if (age < ttlMs) continue;
27792
27833
  if (liveAbs.has(file)) continue;
27793
27834
  try {
27794
- import_node_fs17.default.unlinkSync(file);
27835
+ import_node_fs18.default.unlinkSync(file);
27795
27836
  } catch (err) {
27796
27837
  args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
27797
27838
  }
27798
27839
  }
27799
27840
  try {
27800
- if (import_node_fs17.default.readdirSync(hashDirAbs).length === 0) import_node_fs17.default.rmdirSync(hashDirAbs);
27841
+ if (import_node_fs18.default.readdirSync(hashDirAbs).length === 0) import_node_fs18.default.rmdirSync(hashDirAbs);
27801
27842
  } catch {
27802
27843
  }
27803
27844
  }
27804
27845
  try {
27805
- if (import_node_fs17.default.readdirSync(attRoot).length === 0) import_node_fs17.default.rmdirSync(attRoot);
27846
+ if (import_node_fs18.default.readdirSync(attRoot).length === 0) import_node_fs18.default.rmdirSync(attRoot);
27806
27847
  } catch {
27807
27848
  }
27808
27849
  }
27809
27850
  }
27810
27851
 
27811
27852
  // src/attachment/group.ts
27812
- var import_node_fs18 = __toESM(require("fs"), 1);
27813
- var import_node_path20 = __toESM(require("path"), 1);
27853
+ var import_node_fs19 = __toESM(require("fs"), 1);
27854
+ var import_node_path21 = __toESM(require("path"), 1);
27814
27855
  var import_node_crypto7 = __toESM(require("crypto"), 1);
27815
27856
  init_protocol();
27816
27857
  var GroupFileStore = class {
@@ -27822,11 +27863,11 @@ var GroupFileStore = class {
27822
27863
  this.logger = opts.logger;
27823
27864
  }
27824
27865
  rootForScope(scope) {
27825
- return import_node_path20.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
27866
+ return import_node_path21.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
27826
27867
  }
27827
27868
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
27828
27869
  filePath(scope, sessionId) {
27829
- return import_node_path20.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
27870
+ return import_node_path21.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
27830
27871
  }
27831
27872
  cacheKey(scope, sessionId) {
27832
27873
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -27835,7 +27876,7 @@ var GroupFileStore = class {
27835
27876
  readFile(scope, sessionId) {
27836
27877
  const file = this.filePath(scope, sessionId);
27837
27878
  try {
27838
- const raw = import_node_fs18.default.readFileSync(file, "utf8");
27879
+ const raw = import_node_fs19.default.readFileSync(file, "utf8");
27839
27880
  const parsed = JSON.parse(raw);
27840
27881
  if (!Array.isArray(parsed)) {
27841
27882
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -27861,10 +27902,10 @@ var GroupFileStore = class {
27861
27902
  }
27862
27903
  writeFile(scope, sessionId, entries) {
27863
27904
  const file = this.filePath(scope, sessionId);
27864
- import_node_fs18.default.mkdirSync(import_node_path20.default.dirname(file), { recursive: true });
27905
+ import_node_fs19.default.mkdirSync(import_node_path21.default.dirname(file), { recursive: true });
27865
27906
  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);
27907
+ import_node_fs19.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
27908
+ import_node_fs19.default.renameSync(tmp, file);
27868
27909
  }
27869
27910
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
27870
27911
  list(scope, sessionId) {
@@ -27950,10 +27991,10 @@ var GroupFileStore = class {
27950
27991
  };
27951
27992
 
27952
27993
  // src/discovery/state-file.ts
27953
- var import_node_fs19 = __toESM(require("fs"), 1);
27954
- var import_node_path21 = __toESM(require("path"), 1);
27994
+ var import_node_fs20 = __toESM(require("fs"), 1);
27995
+ var import_node_path22 = __toESM(require("path"), 1);
27955
27996
  function defaultStateFilePath(dataDir) {
27956
- return import_node_path21.default.join(dataDir, "state.json");
27997
+ return import_node_path22.default.join(dataDir, "state.json");
27957
27998
  }
27958
27999
  function isPidAlive(pid) {
27959
28000
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -27975,7 +28016,7 @@ var StateFileManager = class {
27975
28016
  }
27976
28017
  read() {
27977
28018
  try {
27978
- const raw = import_node_fs19.default.readFileSync(this.file, "utf8");
28019
+ const raw = import_node_fs20.default.readFileSync(this.file, "utf8");
27979
28020
  const parsed = JSON.parse(raw);
27980
28021
  return parsed;
27981
28022
  } catch {
@@ -27989,34 +28030,34 @@ var StateFileManager = class {
27989
28030
  return { status: "stale", existing };
27990
28031
  }
27991
28032
  write(state) {
27992
- import_node_fs19.default.mkdirSync(import_node_path21.default.dirname(this.file), { recursive: true });
28033
+ import_node_fs20.default.mkdirSync(import_node_path22.default.dirname(this.file), { recursive: true });
27993
28034
  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);
28035
+ import_node_fs20.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
28036
+ import_node_fs20.default.renameSync(tmp, this.file);
27996
28037
  if (process.platform !== "win32") {
27997
28038
  try {
27998
- import_node_fs19.default.chmodSync(this.file, 384);
28039
+ import_node_fs20.default.chmodSync(this.file, 384);
27999
28040
  } catch {
28000
28041
  }
28001
28042
  }
28002
28043
  }
28003
28044
  delete() {
28004
28045
  try {
28005
- import_node_fs19.default.unlinkSync(this.file);
28046
+ import_node_fs20.default.unlinkSync(this.file);
28006
28047
  } catch {
28007
28048
  }
28008
28049
  }
28009
28050
  };
28010
28051
 
28011
28052
  // src/tunnel/tunnel-manager.ts
28012
- var import_node_fs23 = __toESM(require("fs"), 1);
28013
- var import_node_path25 = __toESM(require("path"), 1);
28053
+ var import_node_fs24 = __toESM(require("fs"), 1);
28054
+ var import_node_path26 = __toESM(require("path"), 1);
28014
28055
  var import_node_crypto8 = __toESM(require("crypto"), 1);
28015
28056
  var import_node_child_process5 = require("child_process");
28016
28057
 
28017
28058
  // src/tunnel/tunnel-store.ts
28018
- var import_node_fs20 = __toESM(require("fs"), 1);
28019
- var import_node_path22 = __toESM(require("path"), 1);
28059
+ var import_node_fs21 = __toESM(require("fs"), 1);
28060
+ var import_node_path23 = __toESM(require("path"), 1);
28020
28061
  var TunnelStore = class {
28021
28062
  constructor(filePath) {
28022
28063
  this.filePath = filePath;
@@ -28024,7 +28065,7 @@ var TunnelStore = class {
28024
28065
  filePath;
28025
28066
  async get() {
28026
28067
  try {
28027
- const raw = await import_node_fs20.default.promises.readFile(this.filePath, "utf8");
28068
+ const raw = await import_node_fs21.default.promises.readFile(this.filePath, "utf8");
28028
28069
  const obj = JSON.parse(raw);
28029
28070
  if (!isPersistedTunnel(obj)) return null;
28030
28071
  return obj;
@@ -28035,22 +28076,22 @@ var TunnelStore = class {
28035
28076
  }
28036
28077
  }
28037
28078
  async set(v2) {
28038
- const dir = import_node_path22.default.dirname(this.filePath);
28039
- await import_node_fs20.default.promises.mkdir(dir, { recursive: true });
28079
+ const dir = import_node_path23.default.dirname(this.filePath);
28080
+ await import_node_fs21.default.promises.mkdir(dir, { recursive: true });
28040
28081
  const data = JSON.stringify(v2, null, 2);
28041
28082
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
28042
- await import_node_fs20.default.promises.writeFile(tmp, data, { mode: 384 });
28083
+ await import_node_fs21.default.promises.writeFile(tmp, data, { mode: 384 });
28043
28084
  if (process.platform !== "win32") {
28044
28085
  try {
28045
- await import_node_fs20.default.promises.chmod(tmp, 384);
28086
+ await import_node_fs21.default.promises.chmod(tmp, 384);
28046
28087
  } catch {
28047
28088
  }
28048
28089
  }
28049
- await import_node_fs20.default.promises.rename(tmp, this.filePath);
28090
+ await import_node_fs21.default.promises.rename(tmp, this.filePath);
28050
28091
  }
28051
28092
  async clear() {
28052
28093
  try {
28053
- await import_node_fs20.default.promises.unlink(this.filePath);
28094
+ await import_node_fs21.default.promises.unlink(this.filePath);
28054
28095
  } catch (err) {
28055
28096
  const code = err?.code;
28056
28097
  if (code !== "ENOENT") throw err;
@@ -28145,9 +28186,9 @@ function escape(v2) {
28145
28186
  }
28146
28187
 
28147
28188
  // src/tunnel/frpc-binary.ts
28148
- var import_node_fs21 = __toESM(require("fs"), 1);
28189
+ var import_node_fs22 = __toESM(require("fs"), 1);
28149
28190
  var import_node_os10 = __toESM(require("os"), 1);
28150
- var import_node_path23 = __toESM(require("path"), 1);
28191
+ var import_node_path24 = __toESM(require("path"), 1);
28151
28192
  var import_node_child_process3 = require("child_process");
28152
28193
  var import_node_stream2 = require("stream");
28153
28194
  var import_promises2 = require("stream/promises");
@@ -28179,20 +28220,20 @@ function frpcDownloadUrl(version2, p2) {
28179
28220
  }
28180
28221
  async function ensureFrpcBinary(opts) {
28181
28222
  if (opts.override) {
28182
- if (!import_node_fs21.default.existsSync(opts.override)) {
28223
+ if (!import_node_fs22.default.existsSync(opts.override)) {
28183
28224
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
28184
28225
  }
28185
28226
  return opts.override;
28186
28227
  }
28187
28228
  const version2 = opts.version ?? FRPC_VERSION;
28188
28229
  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 });
28230
+ const binDir = import_node_path24.default.join(opts.dataDir, "bin");
28231
+ import_node_fs22.default.mkdirSync(binDir, { recursive: true });
28191
28232
  cleanupStaleArtifacts(binDir);
28192
- const stableBin = import_node_path23.default.join(binDir, "frpc");
28193
- if (import_node_fs21.default.existsSync(stableBin)) return stableBin;
28233
+ const stableBin = import_node_path24.default.join(binDir, "frpc");
28234
+ if (import_node_fs22.default.existsSync(stableBin)) return stableBin;
28194
28235
  const partialBin = `${stableBin}.partial`;
28195
- const tarballPath = import_node_path23.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
28236
+ const tarballPath = import_node_path24.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
28196
28237
  try {
28197
28238
  const url = frpcDownloadUrl(version2, platform);
28198
28239
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -28201,8 +28242,8 @@ async function ensureFrpcBinary(opts) {
28201
28242
  } else {
28202
28243
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
28203
28244
  }
28204
- import_node_fs21.default.chmodSync(partialBin, 493);
28205
- import_node_fs21.default.renameSync(partialBin, stableBin);
28245
+ import_node_fs22.default.chmodSync(partialBin, 493);
28246
+ import_node_fs22.default.renameSync(partialBin, stableBin);
28206
28247
  } finally {
28207
28248
  safeUnlink(tarballPath);
28208
28249
  safeUnlink(partialBin);
@@ -28212,15 +28253,15 @@ async function ensureFrpcBinary(opts) {
28212
28253
  function cleanupStaleArtifacts(binDir) {
28213
28254
  let entries;
28214
28255
  try {
28215
- entries = import_node_fs21.default.readdirSync(binDir);
28256
+ entries = import_node_fs22.default.readdirSync(binDir);
28216
28257
  } catch {
28217
28258
  return;
28218
28259
  }
28219
28260
  for (const name of entries) {
28220
28261
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
28221
- const full = import_node_path23.default.join(binDir, name);
28262
+ const full = import_node_path24.default.join(binDir, name);
28222
28263
  try {
28223
- import_node_fs21.default.rmSync(full, { recursive: true, force: true });
28264
+ import_node_fs22.default.rmSync(full, { recursive: true, force: true });
28224
28265
  } catch {
28225
28266
  }
28226
28267
  }
@@ -28228,7 +28269,7 @@ function cleanupStaleArtifacts(binDir) {
28228
28269
  }
28229
28270
  function safeUnlink(p2) {
28230
28271
  try {
28231
- import_node_fs21.default.unlinkSync(p2);
28272
+ import_node_fs22.default.unlinkSync(p2);
28232
28273
  } catch {
28233
28274
  }
28234
28275
  }
@@ -28239,13 +28280,13 @@ async function downloadToFile(url, dest, fetchImpl) {
28239
28280
  if (!res.ok || !res.body) {
28240
28281
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
28241
28282
  }
28242
- const out = import_node_fs21.default.createWriteStream(dest);
28283
+ const out = import_node_fs22.default.createWriteStream(dest);
28243
28284
  const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
28244
28285
  await (0, import_promises2.pipeline)(nodeStream, out);
28245
28286
  }
28246
28287
  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 });
28288
+ const work = import_node_path24.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
28289
+ import_node_fs22.default.mkdirSync(work, { recursive: true });
28249
28290
  try {
28250
28291
  await new Promise((resolve6, reject) => {
28251
28292
  const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -28253,32 +28294,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
28253
28294
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
28254
28295
  });
28255
28296
  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)) {
28297
+ const src = import_node_path24.default.join(work, dirName, "frpc");
28298
+ if (!import_node_fs22.default.existsSync(src)) {
28258
28299
  throw new Error(`frpc not found inside tarball at ${src}`);
28259
28300
  }
28260
- import_node_fs21.default.copyFileSync(src, destBin);
28301
+ import_node_fs22.default.copyFileSync(src, destBin);
28261
28302
  } finally {
28262
- import_node_fs21.default.rmSync(work, { recursive: true, force: true });
28303
+ import_node_fs22.default.rmSync(work, { recursive: true, force: true });
28263
28304
  }
28264
28305
  }
28265
28306
 
28266
28307
  // src/tunnel/frpc-process.ts
28267
- var import_node_fs22 = __toESM(require("fs"), 1);
28268
- var import_node_path24 = __toESM(require("path"), 1);
28308
+ var import_node_fs23 = __toESM(require("fs"), 1);
28309
+ var import_node_path25 = __toESM(require("path"), 1);
28269
28310
  var import_node_child_process4 = require("child_process");
28270
28311
  function frpcPidFilePath(dataDir) {
28271
- return import_node_path24.default.join(dataDir, "frpc.pid");
28312
+ return import_node_path25.default.join(dataDir, "frpc.pid");
28272
28313
  }
28273
28314
  function writeFrpcPid(dataDir, pid) {
28274
28315
  try {
28275
- import_node_fs22.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
28316
+ import_node_fs23.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
28276
28317
  } catch {
28277
28318
  }
28278
28319
  }
28279
28320
  function clearFrpcPid(dataDir) {
28280
28321
  try {
28281
- import_node_fs22.default.unlinkSync(frpcPidFilePath(dataDir));
28322
+ import_node_fs23.default.unlinkSync(frpcPidFilePath(dataDir));
28282
28323
  } catch {
28283
28324
  }
28284
28325
  }
@@ -28294,7 +28335,7 @@ function defaultIsPidAlive(pid) {
28294
28335
  }
28295
28336
  function defaultReadPidFile(file) {
28296
28337
  try {
28297
- return import_node_fs22.default.readFileSync(file, "utf8");
28338
+ return import_node_fs23.default.readFileSync(file, "utf8");
28298
28339
  } catch {
28299
28340
  return null;
28300
28341
  }
@@ -28310,7 +28351,7 @@ function defaultSleep(ms) {
28310
28351
  }
28311
28352
  async function killStaleFrpc(deps) {
28312
28353
  const pidFile = frpcPidFilePath(deps.dataDir);
28313
- const tomlPath = import_node_path24.default.join(deps.dataDir, "frpc.toml");
28354
+ const tomlPath = import_node_path25.default.join(deps.dataDir, "frpc.toml");
28314
28355
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
28315
28356
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
28316
28357
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -28334,7 +28375,7 @@ async function killStaleFrpc(deps) {
28334
28375
  }
28335
28376
  if (victims.size === 0) {
28336
28377
  try {
28337
- import_node_fs22.default.unlinkSync(pidFile);
28378
+ import_node_fs23.default.unlinkSync(pidFile);
28338
28379
  } catch {
28339
28380
  }
28340
28381
  return;
@@ -28345,7 +28386,7 @@ async function killStaleFrpc(deps) {
28345
28386
  }
28346
28387
  await sleep(deps.reapWaitMs ?? 300);
28347
28388
  try {
28348
- import_node_fs22.default.unlinkSync(pidFile);
28389
+ import_node_fs23.default.unlinkSync(pidFile);
28349
28390
  } catch {
28350
28391
  }
28351
28392
  }
@@ -28382,7 +28423,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
28382
28423
  var TunnelManager = class {
28383
28424
  constructor(deps) {
28384
28425
  this.deps = deps;
28385
- this.store = deps.store ?? new TunnelStore(import_node_path25.default.join(deps.dataDir, "tunnel.json"));
28426
+ this.store = deps.store ?? new TunnelStore(import_node_path26.default.join(deps.dataDir, "tunnel.json"));
28386
28427
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
28387
28428
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
28388
28429
  }
@@ -28509,7 +28550,7 @@ var TunnelManager = class {
28509
28550
  dataDir: this.deps.dataDir,
28510
28551
  override: this.deps.frpcBinaryOverride ?? void 0
28511
28552
  });
28512
- const tomlPath = import_node_path25.default.join(this.deps.dataDir, "frpc.toml");
28553
+ const tomlPath = import_node_path26.default.join(this.deps.dataDir, "frpc.toml");
28513
28554
  const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto8.default.randomBytes(3).toString("hex")}`;
28514
28555
  const toml = buildFrpcToml({
28515
28556
  serverAddr: t.frpsHost,
@@ -28520,12 +28561,12 @@ var TunnelManager = class {
28520
28561
  localPort,
28521
28562
  logLevel: "info"
28522
28563
  });
28523
- await import_node_fs23.default.promises.writeFile(tomlPath, toml, { mode: 384 });
28564
+ await import_node_fs24.default.promises.writeFile(tomlPath, toml, { mode: 384 });
28524
28565
  const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
28525
28566
  stdio: ["ignore", "pipe", "pipe"]
28526
28567
  });
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 });
28568
+ const logFilePath = import_node_path26.default.join(this.deps.dataDir, "frpc.log");
28569
+ const logStream = import_node_fs24.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
28529
28570
  logStream.on("error", () => {
28530
28571
  });
28531
28572
  const tee = (chunk) => {
@@ -28618,12 +28659,12 @@ function deriveStableDeviceKey(opts = {}) {
28618
28659
  }
28619
28660
 
28620
28661
  // src/auth-store.ts
28621
- var import_node_fs24 = __toESM(require("fs"), 1);
28622
- var import_node_path26 = __toESM(require("path"), 1);
28662
+ var import_node_fs25 = __toESM(require("fs"), 1);
28663
+ var import_node_path27 = __toESM(require("path"), 1);
28623
28664
  var import_node_crypto10 = __toESM(require("crypto"), 1);
28624
28665
  var AUTH_FILE_NAME = "auth.json";
28625
28666
  function authFilePath(dataDir) {
28626
- return import_node_path26.default.join(dataDir, AUTH_FILE_NAME);
28667
+ return import_node_path27.default.join(dataDir, AUTH_FILE_NAME);
28627
28668
  }
28628
28669
  function loadOrCreateAuthFile(opts) {
28629
28670
  const file = authFilePath(opts.dataDir);
@@ -28655,7 +28696,7 @@ function defaultGenerateOwnerPrincipalId() {
28655
28696
  }
28656
28697
  function readAuthFile(file) {
28657
28698
  try {
28658
- const raw = import_node_fs24.default.readFileSync(file, "utf8");
28699
+ const raw = import_node_fs25.default.readFileSync(file, "utf8");
28659
28700
  const parsed = JSON.parse(raw);
28660
28701
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
28661
28702
  return null;
@@ -28673,25 +28714,25 @@ function readAuthFile(file) {
28673
28714
  }
28674
28715
  }
28675
28716
  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 });
28717
+ import_node_fs25.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
28718
+ import_node_fs25.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
28678
28719
  try {
28679
- import_node_fs24.default.chmodSync(file, 384);
28720
+ import_node_fs25.default.chmodSync(file, 384);
28680
28721
  } catch {
28681
28722
  }
28682
28723
  }
28683
28724
 
28684
28725
  // src/owner-profile.ts
28685
- var import_node_fs25 = __toESM(require("fs"), 1);
28726
+ var import_node_fs26 = __toESM(require("fs"), 1);
28686
28727
  var import_node_os12 = __toESM(require("os"), 1);
28687
- var import_node_path27 = __toESM(require("path"), 1);
28728
+ var import_node_path28 = __toESM(require("path"), 1);
28688
28729
  var PROFILE_FILENAME = "profile.json";
28689
28730
  function loadOwnerDisplayName(dataDir) {
28690
28731
  const fallback = import_node_os12.default.userInfo().username;
28691
- const profilePath = import_node_path27.default.join(dataDir, PROFILE_FILENAME);
28732
+ const profilePath = import_node_path28.default.join(dataDir, PROFILE_FILENAME);
28692
28733
  let raw;
28693
28734
  try {
28694
- raw = import_node_fs25.default.readFileSync(profilePath, "utf8");
28735
+ raw = import_node_fs26.default.readFileSync(profilePath, "utf8");
28695
28736
  } catch {
28696
28737
  return fallback;
28697
28738
  }
@@ -28720,12 +28761,12 @@ init_protocol();
28720
28761
  init_protocol();
28721
28762
 
28722
28763
  // src/session/fork.ts
28723
- var import_node_fs26 = __toESM(require("fs"), 1);
28764
+ var import_node_fs27 = __toESM(require("fs"), 1);
28724
28765
  var import_node_os13 = __toESM(require("os"), 1);
28725
- var import_node_path28 = __toESM(require("path"), 1);
28766
+ var import_node_path29 = __toESM(require("path"), 1);
28726
28767
  init_claude_history();
28727
28768
  function readJsonlEntries(file) {
28728
- const raw = import_node_fs26.default.readFileSync(file, "utf8");
28769
+ const raw = import_node_fs27.default.readFileSync(file, "utf8");
28729
28770
  const out = [];
28730
28771
  for (const line of raw.split("\n")) {
28731
28772
  const t = line.trim();
@@ -28738,10 +28779,10 @@ function readJsonlEntries(file) {
28738
28779
  return out;
28739
28780
  }
28740
28781
  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)) {
28782
+ const baseDir = input.baseDir ?? import_node_path29.default.join(import_node_os13.default.homedir(), ".claude");
28783
+ const projectDir = import_node_path29.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
28784
+ const sourceFile = import_node_path29.default.join(projectDir, `${input.toolSessionId}.jsonl`);
28785
+ if (!import_node_fs27.default.existsSync(sourceFile)) {
28745
28786
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
28746
28787
  }
28747
28788
  const entries = readJsonlEntries(sourceFile);
@@ -28771,9 +28812,9 @@ function forkSession(input) {
28771
28812
  }
28772
28813
  forkedLines.push(JSON.stringify(forked));
28773
28814
  }
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 });
28815
+ const forkedFilePath = import_node_path29.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
28816
+ import_node_fs27.default.mkdirSync(projectDir, { recursive: true });
28817
+ import_node_fs27.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
28777
28818
  return { forkedToolSessionId, forkedFilePath };
28778
28819
  }
28779
28820
 
@@ -29061,28 +29102,6 @@ function buildSessionHandlers(deps) {
29061
29102
  }
29062
29103
  };
29063
29104
  };
29064
- const peerSessionUpsert = async (frame, _client, ctx) => {
29065
- if (ctx && ctx.principal.kind !== "owner") {
29066
- throw new ClawdError(
29067
- ERROR_CODES.UNAUTHORIZED,
29068
- `principal ${ctx.principal.kind}:${ctx.principal.id} cannot peerSession:upsert`
29069
- );
29070
- }
29071
- const file = PeerSessionUpsertArgs.parse(frame);
29072
- manager.mirrorUpsert(file);
29073
- return { response: { type: "peerSession:upsert:ok" }, broadcast: [] };
29074
- };
29075
- const peerSessionRemove = async (frame, _client, ctx) => {
29076
- if (ctx && ctx.principal.kind !== "owner") {
29077
- throw new ClawdError(
29078
- ERROR_CODES.UNAUTHORIZED,
29079
- `principal ${ctx.principal.kind}:${ctx.principal.id} cannot peerSession:remove`
29080
- );
29081
- }
29082
- const args = PeerSessionRemoveArgs.parse(frame);
29083
- manager.mirrorRemove(args.sessionId);
29084
- return { response: { type: "peerSession:remove:ok" }, broadcast: [] };
29085
- };
29086
29105
  return {
29087
29106
  "session:create": create,
29088
29107
  "session:list": list,
@@ -29108,9 +29127,7 @@ function buildSessionHandlers(deps) {
29108
29127
  "session:cancelQuestion": cancelQuestion,
29109
29128
  "session:pty:input": ptyInput,
29110
29129
  "session:pty:resize": ptyResize,
29111
- "session:pty:snapshot": ptySnapshot,
29112
- "peerSession:upsert": peerSessionUpsert,
29113
- "peerSession:remove": peerSessionRemove
29130
+ "session:pty:snapshot": ptySnapshot
29114
29131
  };
29115
29132
  }
29116
29133
 
@@ -29129,7 +29146,7 @@ function buildPermissionHandlers(deps) {
29129
29146
  }
29130
29147
 
29131
29148
  // src/handlers/history.ts
29132
- var path38 = __toESM(require("path"), 1);
29149
+ var path39 = __toESM(require("path"), 1);
29133
29150
  init_protocol();
29134
29151
 
29135
29152
  // src/session/recent-dirs.ts
@@ -29147,7 +29164,7 @@ function listRecentDirs(store, limit = 50) {
29147
29164
  }
29148
29165
 
29149
29166
  // src/permission/persona-paths.ts
29150
- var path37 = __toESM(require("path"), 1);
29167
+ var path38 = __toESM(require("path"), 1);
29151
29168
  function getAllowedPersonaIds(grants, action) {
29152
29169
  const ids = /* @__PURE__ */ new Set();
29153
29170
  for (const g2 of grants) {
@@ -29160,26 +29177,26 @@ function getAllowedPersonaIds(grants, action) {
29160
29177
  return ids;
29161
29178
  }
29162
29179
  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;
29180
+ const root = path38.resolve(personaRoot);
29181
+ const target = path38.resolve(absPath);
29182
+ const sep3 = root.endsWith(path38.sep) ? "" : path38.sep;
29166
29183
  if (!target.startsWith(root + sep3)) return false;
29167
- const rel = path37.relative(root, target);
29184
+ const rel = path38.relative(root, target);
29168
29185
  if (!rel || rel.startsWith("..")) return false;
29169
- const personaId = rel.split(path37.sep)[0];
29186
+ const personaId = rel.split(path38.sep)[0];
29170
29187
  if (!personaId) return false;
29171
29188
  const allowed = getAllowedPersonaIds(grants, action);
29172
29189
  if (allowed === "*") return true;
29173
29190
  return allowed.has(personaId);
29174
29191
  }
29175
29192
  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;
29193
+ const root = path38.resolve(personaRoot);
29194
+ const target = path38.resolve(absPath);
29195
+ const sep3 = root.endsWith(path38.sep) ? "" : path38.sep;
29179
29196
  if (!target.startsWith(root + sep3)) return null;
29180
- const rel = path37.relative(root, target);
29197
+ const rel = path38.relative(root, target);
29181
29198
  if (!rel || rel.startsWith("..")) return null;
29182
- const id = rel.split(path37.sep)[0];
29199
+ const id = rel.split(path38.sep)[0];
29183
29200
  return id || null;
29184
29201
  }
29185
29202
 
@@ -29204,7 +29221,7 @@ function buildHistoryHandlers(deps) {
29204
29221
  if (!pid) return false;
29205
29222
  return isGuestPathAllowed(
29206
29223
  ctx.grants,
29207
- path38.join(personaRoot, pid),
29224
+ path39.join(personaRoot, pid),
29208
29225
  personaRoot,
29209
29226
  "read"
29210
29227
  );
@@ -29215,7 +29232,7 @@ function buildHistoryHandlers(deps) {
29215
29232
  };
29216
29233
  const list = async (frame, _client, ctx) => {
29217
29234
  const args = HistoryListArgs.parse(frame);
29218
- assertGuestPath(ctx, path38.resolve(args.projectPath), personaRoot, "history:list");
29235
+ assertGuestPath(ctx, path39.resolve(args.projectPath), personaRoot, "history:list");
29219
29236
  const sessions = await history.listSessions(args);
29220
29237
  return { response: { type: "history:list", sessions } };
29221
29238
  };
@@ -29247,13 +29264,13 @@ function buildHistoryHandlers(deps) {
29247
29264
  };
29248
29265
  const subagents = async (frame, _client, ctx) => {
29249
29266
  const args = HistorySubagentsArgs.parse(frame);
29250
- assertGuestPath(ctx, path38.resolve(args.cwd), personaRoot, "history:subagents");
29267
+ assertGuestPath(ctx, path39.resolve(args.cwd), personaRoot, "history:subagents");
29251
29268
  const subs = await history.listSubagents(args);
29252
29269
  return { response: { type: "history:subagents", subagents: subs } };
29253
29270
  };
29254
29271
  const subagentRead = async (frame, _client, ctx) => {
29255
29272
  const args = HistorySubagentReadArgs.parse(frame);
29256
- assertGuestPath(ctx, path38.resolve(args.cwd), personaRoot, "history:subagent-read");
29273
+ assertGuestPath(ctx, path39.resolve(args.cwd), personaRoot, "history:subagent-read");
29257
29274
  const res = await history.readSubagent(args);
29258
29275
  return { response: { type: "history:subagent-read", ...res } };
29259
29276
  };
@@ -29261,7 +29278,7 @@ function buildHistoryHandlers(deps) {
29261
29278
  const dirs = listRecentDirs(store);
29262
29279
  if (ctx?.principal.kind === "guest" && personaRoot) {
29263
29280
  const filtered = dirs.filter(
29264
- (d) => isGuestPathAllowed(ctx.grants, path38.resolve(d.cwd), personaRoot, "read")
29281
+ (d) => isGuestPathAllowed(ctx.grants, path39.resolve(d.cwd), personaRoot, "read")
29265
29282
  );
29266
29283
  return { response: { type: "history:recentDirs", dirs: filtered } };
29267
29284
  }
@@ -29278,7 +29295,7 @@ function buildHistoryHandlers(deps) {
29278
29295
  }
29279
29296
 
29280
29297
  // src/handlers/workspace.ts
29281
- var path39 = __toESM(require("path"), 1);
29298
+ var path40 = __toESM(require("path"), 1);
29282
29299
  var os14 = __toESM(require("os"), 1);
29283
29300
  init_protocol();
29284
29301
  init_protocol();
@@ -29319,22 +29336,22 @@ function buildWorkspaceHandlers(deps) {
29319
29336
  const args = WorkspaceListArgs.parse(frame);
29320
29337
  const isGuest = ctx?.principal.kind === "guest";
29321
29338
  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;
29339
+ const resolvedCwd = path40.resolve(args.cwd ?? fallbackCwd);
29340
+ const target = args.path ? path40.resolve(resolvedCwd, args.path) : resolvedCwd;
29324
29341
  assertGuestPath2(ctx, target, personaRoot, "workspace:list");
29325
29342
  const res = workspace.list({ ...args, cwd: resolvedCwd });
29326
29343
  return { response: { type: "workspace:list", ...res } };
29327
29344
  };
29328
29345
  const read = async (frame, _client, ctx) => {
29329
29346
  const args = WorkspaceReadArgs.parse(frame);
29330
- const target = path39.isAbsolute(args.path) ? path39.resolve(args.path) : path39.resolve(args.cwd, args.path);
29347
+ const target = path40.isAbsolute(args.path) ? path40.resolve(args.path) : path40.resolve(args.cwd, args.path);
29331
29348
  assertGuestPath2(ctx, target, personaRoot, "workspace:read");
29332
29349
  const res = workspace.read(args);
29333
29350
  return { response: { type: "workspace:read", ...res } };
29334
29351
  };
29335
29352
  const skillsList = async (frame, _client, ctx) => {
29336
29353
  const args = SkillsListArgs.parse(frame);
29337
- const cwdAbs = path39.resolve(args.cwd);
29354
+ const cwdAbs = path40.resolve(args.cwd);
29338
29355
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
29339
29356
  const list2 = skills.list(args);
29340
29357
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -29346,7 +29363,7 @@ function buildWorkspaceHandlers(deps) {
29346
29363
  };
29347
29364
  const agentsList = async (frame, _client, ctx) => {
29348
29365
  const args = AgentsListArgs.parse(frame);
29349
- const cwdAbs = path39.resolve(args.cwd);
29366
+ const cwdAbs = path40.resolve(args.cwd);
29350
29367
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
29351
29368
  const list2 = agents.list(args);
29352
29369
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -29365,20 +29382,20 @@ function buildWorkspaceHandlers(deps) {
29365
29382
  }
29366
29383
 
29367
29384
  // src/handlers/git.ts
29368
- var path41 = __toESM(require("path"), 1);
29385
+ var path42 = __toESM(require("path"), 1);
29369
29386
  init_protocol();
29370
29387
  init_protocol();
29371
29388
 
29372
29389
  // src/workspace/git.ts
29373
29390
  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);
29391
+ var import_node_fs28 = __toESM(require("fs"), 1);
29392
+ var import_node_path30 = __toESM(require("path"), 1);
29376
29393
  var import_node_util = require("util");
29377
29394
  var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
29378
29395
  function normalizePath(p2) {
29379
- const resolved = import_node_path29.default.resolve(p2);
29396
+ const resolved = import_node_path30.default.resolve(p2);
29380
29397
  try {
29381
- return import_node_fs27.default.realpathSync(resolved);
29398
+ return import_node_fs28.default.realpathSync(resolved);
29382
29399
  } catch {
29383
29400
  return resolved;
29384
29401
  }
@@ -29451,7 +29468,7 @@ async function listGitBranches(cwd) {
29451
29468
  // src/handlers/git.ts
29452
29469
  function assertGuestCwd(ctx, cwd, personaRoot, method) {
29453
29470
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
29454
- if (!isGuestPathAllowed(ctx.grants, path41.resolve(cwd), personaRoot, "read")) {
29471
+ if (!isGuestPathAllowed(ctx.grants, path42.resolve(cwd), personaRoot, "read")) {
29455
29472
  throw new ClawdError(
29456
29473
  ERROR_CODES.UNAUTHORIZED,
29457
29474
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -29938,7 +29955,7 @@ function buildPersonaHandlers(deps) {
29938
29955
  }
29939
29956
 
29940
29957
  // src/handlers/attachment.ts
29941
- var import_node_path30 = __toESM(require("path"), 1);
29958
+ var import_node_path31 = __toESM(require("path"), 1);
29942
29959
  init_protocol();
29943
29960
  init_protocol();
29944
29961
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -29992,12 +30009,12 @@ function buildAttachmentHandlers(deps) {
29992
30009
  `session ${args.sessionId} scope unresolved`
29993
30010
  );
29994
30011
  }
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);
30012
+ const cwdAbs = import_node_path31.default.resolve(sessionFile.cwd);
30013
+ 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
30014
  assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
29998
30015
  const entries = deps.groupFileStore.list(scope, args.sessionId);
29999
30016
  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);
30017
+ 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
30018
  return storedAbs === candidateAbs && !e.stale;
30002
30019
  });
30003
30020
  if (!entry) {
@@ -30021,7 +30038,7 @@ function buildAttachmentHandlers(deps) {
30021
30038
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
30022
30039
  const f = deps.sessionStore.read(sessionId);
30023
30040
  if (!f) return;
30024
- assertGuestAttachmentPath(ctx, import_node_path30.default.resolve(f.cwd), deps.personaRoot, method);
30041
+ assertGuestAttachmentPath(ctx, import_node_path31.default.resolve(f.cwd), deps.personaRoot, method);
30025
30042
  }
30026
30043
  const groupAdd = async (frame, _client, ctx) => {
30027
30044
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -30188,11 +30205,6 @@ var METHOD_GRANT_MAP = {
30188
30205
  "session:pin": CAPABILITY_SCOPED,
30189
30206
  "session:reorderPins": ADMIN_ANY,
30190
30207
  // owner 全局操作,无 personaId 维度
30191
- // mirror peer sessions (2026-05-26):owner-only — guest 不应能写/删本机 mirror SessionFile
30192
- // (会绕过 #739 隔离规则把伪造身份的 SessionFile 写进 default store)。handler 端内部 ctx
30193
- // 校验,dispatcher 层一刀切 admin 也兜底。
30194
- "peerSession:upsert": ADMIN_ANY,
30195
- "peerSession:remove": ADMIN_ANY,
30196
30208
  "permission:respond": CAPABILITY_SCOPED,
30197
30209
  "session:answerQuestion": CAPABILITY_SCOPED,
30198
30210
  "session:cancelQuestion": CAPABILITY_SCOPED,
@@ -30263,7 +30275,7 @@ function computeGrantForFrame(method, frame) {
30263
30275
  async function startDaemon(config) {
30264
30276
  const logger = createLogger({
30265
30277
  level: config.logLevel,
30266
- file: import_node_path31.default.join(config.dataDir, "clawd.log")
30278
+ file: import_node_path32.default.join(config.dataDir, "clawd.log")
30267
30279
  });
30268
30280
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
30269
30281
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -30350,7 +30362,7 @@ async function startDaemon(config) {
30350
30362
  const agents = new AgentsScanner();
30351
30363
  const history = new ClaudeHistoryReader();
30352
30364
  let transport = null;
30353
- const personaStore = new PersonaStore(import_node_path31.default.join(config.dataDir, "personas"));
30365
+ const personaStore = new PersonaStore(import_node_path32.default.join(config.dataDir, "personas"));
30354
30366
  const defaultsRoot = findDefaultsRoot();
30355
30367
  if (defaultsRoot) {
30356
30368
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -30367,7 +30379,7 @@ async function startDaemon(config) {
30367
30379
  getAdapter,
30368
30380
  historyReader: history,
30369
30381
  dataDir: config.dataDir,
30370
- personaRoot: import_node_path31.default.join(config.dataDir, "personas"),
30382
+ personaRoot: import_node_path32.default.join(config.dataDir, "personas"),
30371
30383
  personaStore,
30372
30384
  ownerDisplayName,
30373
30385
  ownerPrincipalId,
@@ -30391,10 +30403,10 @@ async function startDaemon(config) {
30391
30403
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
30392
30404
  attachmentGroup: {
30393
30405
  onFileEdit: (input) => {
30394
- const absPath = import_node_path31.default.isAbsolute(input.relPath) ? input.relPath : import_node_path31.default.join(input.cwd, input.relPath);
30406
+ const absPath = import_node_path32.default.isAbsolute(input.relPath) ? input.relPath : import_node_path32.default.join(input.cwd, input.relPath);
30395
30407
  let size = 0;
30396
30408
  try {
30397
- size = import_node_fs28.default.statSync(absPath).size;
30409
+ size = import_node_fs29.default.statSync(absPath).size;
30398
30410
  } catch (err) {
30399
30411
  logger.warn("attachment.onFileEdit stat failed", {
30400
30412
  sessionId: input.sessionId,
@@ -30512,10 +30524,10 @@ async function startDaemon(config) {
30512
30524
  // 'persona/<pid>/owner',default 走 'default'。
30513
30525
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
30514
30526
  // guest path guard:candidate 必须在 personaRoot 子树下
30515
- personaRoot: import_node_path31.default.join(config.dataDir, "personas")
30527
+ personaRoot: import_node_path32.default.join(config.dataDir, "personas")
30516
30528
  },
30517
30529
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
30518
- personaRoot: import_node_path31.default.join(config.dataDir, "personas"),
30530
+ personaRoot: import_node_path32.default.join(config.dataDir, "personas"),
30519
30531
  // capability:list / delete handler 依赖
30520
30532
  capabilityManager,
30521
30533
  // personal-cap:get 返回的 shareBaseUrl 用此 base URL:
@@ -30608,6 +30620,7 @@ async function startDaemon(config) {
30608
30620
  // 形状与 reducer permission_request 分支构造的 session:question 帧一致;UI 不区分
30609
30621
  // 首播 vs 重放(last-write-wins,详见 protocol/events.ts JSDoc)。
30610
30622
  onSubscribe: (client, sessionId) => {
30623
+ probeEvent("subscribe", { sid: sessionId });
30611
30624
  const runner = manager.getActive(sessionId);
30612
30625
  if (!runner) return;
30613
30626
  const pendingQuestions = runner.getState().pendingQuestions ?? {};
@@ -30728,8 +30741,8 @@ async function startDaemon(config) {
30728
30741
  const lines = [
30729
30742
  `Tunnel: ${r.url}`,
30730
30743
  ...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")}`
30744
+ `Frpc config: ${import_node_path32.default.join(config.dataDir, "frpc.toml")}`,
30745
+ `Frpc log: ${import_node_path32.default.join(config.dataDir, "frpc.log")}`
30733
30746
  ];
30734
30747
  const width = Math.max(...lines.map((l) => l.length));
30735
30748
  const bar = "\u2550".repeat(width + 4);
@@ -30742,8 +30755,8 @@ ${bar}
30742
30755
 
30743
30756
  `);
30744
30757
  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 });
30758
+ const connectPath = import_node_path32.default.join(config.dataDir, "connect.txt");
30759
+ import_node_fs29.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
30747
30760
  } catch {
30748
30761
  }
30749
30762
  } catch (err) {
@@ -30808,9 +30821,9 @@ ${bar}
30808
30821
  };
30809
30822
  }
30810
30823
  function migrateDropPersonsDir(dataDir) {
30811
- const dir = import_node_path31.default.join(dataDir, "persons");
30824
+ const dir = import_node_path32.default.join(dataDir, "persons");
30812
30825
  try {
30813
- import_node_fs28.default.rmSync(dir, { recursive: true, force: true });
30826
+ import_node_fs29.default.rmSync(dir, { recursive: true, force: true });
30814
30827
  } catch {
30815
30828
  }
30816
30829
  }