@clawos-dev/clawd 0.2.81-beta.152.ab64214 → 0.2.82-beta.153.5114ee6

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 +419 -459
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -119,18 +119,15 @@ var init_methods = __esm({
119
119
  "attachment.groupRemove",
120
120
  "attachment.groupList",
121
121
  // ---- capability:* (capability platform 鉴权底座) ----
122
- // owner 颁发 / 列出 / 删除给 guest capability。三者均需 admin 权限(METHOD_GRANT_MAP
123
- // daemon 端固定为 `{ resource: '*', action: 'admin' }`,owner 自动满足)。
124
- // 颁发后 daemon 推 'capability:tokenIssued' 帧;删除推 'capability:tokenDeleted' 帧。
125
- // 删除是 hard delete:CapabilityStore 物理移除 + 关该 cap 的所有活跃 ws + rm
126
- // personas/<pid>/.clawd/sessions/guests/<capId>/ guest sessions 目录。
127
- "capability:issue",
122
+ // global personal token 模型 (2026-05-25): UI 不再调 capability:issue —— daemon 启动时
123
+ // loadOrCreatePersonalCapability 自动创建 1 fixed-grants personal capability,
124
+ // 所有联系人共用 personal token。capability:list / capability:delete 保留 (供调试 /
125
+ // 老板手动清旧 cap);capability:issue / capability:bindPeer 已下线。
128
126
  "capability:list",
129
127
  "capability:delete",
130
- // bidirectional cap 视角 B 2026-05-23: owner 主动告诉 daemon "我颁的某 cap 给了谁"
131
- // (UI accept dialog 4 步流程里调; 等价于 recordPeerHello 但不经 ws auth path).
132
- // 否则 B 端颁回的 cap 因为 A 不连 B → peerOwnerId 永不回写 → useContacts 派生 pending.
133
- "capability:bindPeer",
128
+ // global personal token (2026-05-25): UI invite/accept dialog 挂载即调,拿 personal
129
+ // token + capability + shareBaseUrl 用于拼 inviteUrl / autoAttach 反向推。owner-only。
130
+ "personal-cap:get",
134
131
  // ---- inbox:* (capability platform Phase 3 跨用户通知 + Phase 4 DM) ----
135
132
  // owner 接 guest 的 cross-principal 消息事件 + DM 双向私聊.
136
133
  // inbox:list / markRead: admin-only (Phase 3); inbox:postMessage: DM 自带能力,
@@ -646,8 +643,8 @@ var init_parseUtil = __esm({
646
643
  init_errors2();
647
644
  init_en();
648
645
  makeIssue = (params) => {
649
- const { data, path: path42, errorMaps, issueData } = params;
650
- const fullPath = [...path42, ...issueData.path || []];
646
+ const { data, path: path43, errorMaps, issueData } = params;
647
+ const fullPath = [...path43, ...issueData.path || []];
651
648
  const fullIssue = {
652
649
  ...issueData,
653
650
  path: fullPath
@@ -958,11 +955,11 @@ var init_types = __esm({
958
955
  init_parseUtil();
959
956
  init_util();
960
957
  ParseInputLazyPath = class {
961
- constructor(parent, value, path42, key) {
958
+ constructor(parent, value, path43, key) {
962
959
  this._cachedPath = [];
963
960
  this.parent = parent;
964
961
  this.data = value;
965
- this._path = path42;
962
+ this._path = path43;
966
963
  this._key = key;
967
964
  }
968
965
  get path() {
@@ -5109,7 +5106,7 @@ function stripSecretHash(cap) {
5109
5106
  const { secretHash: _hash, ...wire } = cap;
5110
5107
  return wire;
5111
5108
  }
5112
- var ResourceSchema, ActionSchema, GrantSchema, CapabilitySchema, CapabilityWireSchema, CapabilityErrorCodeSchema, WhoamiResponseSchema, CapabilityIssueArgsSchema, CapabilityBindPeerArgsSchema;
5109
+ var ResourceSchema, ActionSchema, GrantSchema, CapabilitySchema, CapabilityWireSchema, CapabilityErrorCodeSchema, WhoamiResponseSchema, PERSONAL_CAP_GRANTS, PersonalCapGetResponseSchema;
5113
5110
  var init_capability = __esm({
5114
5111
  "../protocol/src/capability.ts"() {
5115
5112
  "use strict";
@@ -5171,16 +5168,18 @@ var init_capability = __esm({
5171
5168
  }).strict()
5172
5169
  )
5173
5170
  }).strict();
5174
- CapabilityIssueArgsSchema = external_exports.object({
5175
- displayName: external_exports.string().min(1),
5176
- grants: external_exports.array(GrantSchema),
5177
- expiresAt: external_exports.number().int().positive().optional(),
5178
- maxUses: external_exports.number().int().positive().optional()
5179
- }).strict();
5180
- CapabilityBindPeerArgsSchema = external_exports.object({
5181
- capabilityId: external_exports.string().min(1),
5182
- peerOwnerId: external_exports.string().min(1),
5183
- peerDisplayName: external_exports.string()
5171
+ PERSONAL_CAP_GRANTS = Object.freeze([
5172
+ Object.freeze({
5173
+ resource: Object.freeze({ type: "persona", id: "*" }),
5174
+ actions: Object.freeze(["read", "send"])
5175
+ })
5176
+ ]);
5177
+ PersonalCapGetResponseSchema = external_exports.object({
5178
+ type: external_exports.literal("personal-cap:get:ok"),
5179
+ token: external_exports.string().min(1),
5180
+ capability: CapabilityWireSchema,
5181
+ /** ws/wss base URL,UI deriveInviteBase 用来拼 inviteUrl(tunnel 优先 / 否则本机 ws) */
5182
+ shareBaseUrl: external_exports.string().min(1)
5184
5183
  }).strict();
5185
5184
  }
5186
5185
  });
@@ -5564,8 +5563,8 @@ var require_req = __commonJS({
5564
5563
  if (req.originalUrl) {
5565
5564
  _req.url = req.originalUrl;
5566
5565
  } else {
5567
- const path42 = req.path;
5568
- _req.url = typeof path42 === "string" ? path42 : req.url ? req.url.path || req.url : void 0;
5566
+ const path43 = req.path;
5567
+ _req.url = typeof path43 === "string" ? path43 : req.url ? req.url.path || req.url : void 0;
5569
5568
  }
5570
5569
  if (req.query) {
5571
5570
  _req.query = req.query;
@@ -5730,14 +5729,14 @@ var require_redact = __commonJS({
5730
5729
  }
5731
5730
  return obj;
5732
5731
  }
5733
- function parsePath(path42) {
5732
+ function parsePath(path43) {
5734
5733
  const parts = [];
5735
5734
  let current = "";
5736
5735
  let inBrackets = false;
5737
5736
  let inQuotes = false;
5738
5737
  let quoteChar = "";
5739
- for (let i = 0; i < path42.length; i++) {
5740
- const char = path42[i];
5738
+ for (let i = 0; i < path43.length; i++) {
5739
+ const char = path43[i];
5741
5740
  if (!inBrackets && char === ".") {
5742
5741
  if (current) {
5743
5742
  parts.push(current);
@@ -5868,10 +5867,10 @@ var require_redact = __commonJS({
5868
5867
  return current;
5869
5868
  }
5870
5869
  function redactPaths(obj, paths, censor, remove = false) {
5871
- for (const path42 of paths) {
5872
- const parts = parsePath(path42);
5870
+ for (const path43 of paths) {
5871
+ const parts = parsePath(path43);
5873
5872
  if (parts.includes("*")) {
5874
- redactWildcardPath(obj, parts, censor, path42, remove);
5873
+ redactWildcardPath(obj, parts, censor, path43, remove);
5875
5874
  } else {
5876
5875
  if (remove) {
5877
5876
  removeKey(obj, parts);
@@ -5956,8 +5955,8 @@ var require_redact = __commonJS({
5956
5955
  }
5957
5956
  } else {
5958
5957
  if (afterWildcard.includes("*")) {
5959
- const wrappedCensor = typeof censor === "function" ? (value, path42) => {
5960
- const fullPath = [...pathArray.slice(0, pathLength), ...path42];
5958
+ const wrappedCensor = typeof censor === "function" ? (value, path43) => {
5959
+ const fullPath = [...pathArray.slice(0, pathLength), ...path43];
5961
5960
  return censor(value, fullPath);
5962
5961
  } : censor;
5963
5962
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -5992,8 +5991,8 @@ var require_redact = __commonJS({
5992
5991
  return null;
5993
5992
  }
5994
5993
  const pathStructure = /* @__PURE__ */ new Map();
5995
- for (const path42 of pathsToClone) {
5996
- const parts = parsePath(path42);
5994
+ for (const path43 of pathsToClone) {
5995
+ const parts = parsePath(path43);
5997
5996
  let current = pathStructure;
5998
5997
  for (let i = 0; i < parts.length; i++) {
5999
5998
  const part = parts[i];
@@ -6045,24 +6044,24 @@ var require_redact = __commonJS({
6045
6044
  }
6046
6045
  return cloneSelectively(obj, pathStructure);
6047
6046
  }
6048
- function validatePath(path42) {
6049
- if (typeof path42 !== "string") {
6047
+ function validatePath(path43) {
6048
+ if (typeof path43 !== "string") {
6050
6049
  throw new Error("Paths must be (non-empty) strings");
6051
6050
  }
6052
- if (path42 === "") {
6051
+ if (path43 === "") {
6053
6052
  throw new Error("Invalid redaction path ()");
6054
6053
  }
6055
- if (path42.includes("..")) {
6056
- throw new Error(`Invalid redaction path (${path42})`);
6054
+ if (path43.includes("..")) {
6055
+ throw new Error(`Invalid redaction path (${path43})`);
6057
6056
  }
6058
- if (path42.includes(",")) {
6059
- throw new Error(`Invalid redaction path (${path42})`);
6057
+ if (path43.includes(",")) {
6058
+ throw new Error(`Invalid redaction path (${path43})`);
6060
6059
  }
6061
6060
  let bracketCount = 0;
6062
6061
  let inQuotes = false;
6063
6062
  let quoteChar = "";
6064
- for (let i = 0; i < path42.length; i++) {
6065
- const char = path42[i];
6063
+ for (let i = 0; i < path43.length; i++) {
6064
+ const char = path43[i];
6066
6065
  if ((char === '"' || char === "'") && bracketCount > 0) {
6067
6066
  if (!inQuotes) {
6068
6067
  inQuotes = true;
@@ -6076,20 +6075,20 @@ var require_redact = __commonJS({
6076
6075
  } else if (char === "]" && !inQuotes) {
6077
6076
  bracketCount--;
6078
6077
  if (bracketCount < 0) {
6079
- throw new Error(`Invalid redaction path (${path42})`);
6078
+ throw new Error(`Invalid redaction path (${path43})`);
6080
6079
  }
6081
6080
  }
6082
6081
  }
6083
6082
  if (bracketCount !== 0) {
6084
- throw new Error(`Invalid redaction path (${path42})`);
6083
+ throw new Error(`Invalid redaction path (${path43})`);
6085
6084
  }
6086
6085
  }
6087
6086
  function validatePaths(paths) {
6088
6087
  if (!Array.isArray(paths)) {
6089
6088
  throw new TypeError("paths must be an array");
6090
6089
  }
6091
- for (const path42 of paths) {
6092
- validatePath(path42);
6090
+ for (const path43 of paths) {
6091
+ validatePath(path43);
6093
6092
  }
6094
6093
  }
6095
6094
  function slowRedact(options = {}) {
@@ -6257,8 +6256,8 @@ var require_redaction = __commonJS({
6257
6256
  if (shape[k2] === null) {
6258
6257
  o[k2] = (value) => topCensor(value, [k2]);
6259
6258
  } else {
6260
- const wrappedCensor = typeof censor === "function" ? (value, path42) => {
6261
- return censor(value, [k2, ...path42]);
6259
+ const wrappedCensor = typeof censor === "function" ? (value, path43) => {
6260
+ return censor(value, [k2, ...path43]);
6262
6261
  } : censor;
6263
6262
  o[k2] = Redact({
6264
6263
  paths: shape[k2],
@@ -6476,10 +6475,10 @@ var require_atomic_sleep = __commonJS({
6476
6475
  var require_sonic_boom = __commonJS({
6477
6476
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
6478
6477
  "use strict";
6479
- var fs33 = require("fs");
6478
+ var fs34 = require("fs");
6480
6479
  var EventEmitter2 = require("events");
6481
6480
  var inherits = require("util").inherits;
6482
- var path42 = require("path");
6481
+ var path43 = require("path");
6483
6482
  var sleep = require_atomic_sleep();
6484
6483
  var assert = require("assert");
6485
6484
  var BUSY_WRITE_TIMEOUT = 100;
@@ -6533,20 +6532,20 @@ var require_sonic_boom = __commonJS({
6533
6532
  const mode = sonic.mode;
6534
6533
  if (sonic.sync) {
6535
6534
  try {
6536
- if (sonic.mkdir) fs33.mkdirSync(path42.dirname(file), { recursive: true });
6537
- const fd = fs33.openSync(file, flags, mode);
6535
+ if (sonic.mkdir) fs34.mkdirSync(path43.dirname(file), { recursive: true });
6536
+ const fd = fs34.openSync(file, flags, mode);
6538
6537
  fileOpened(null, fd);
6539
6538
  } catch (err) {
6540
6539
  fileOpened(err);
6541
6540
  throw err;
6542
6541
  }
6543
6542
  } else if (sonic.mkdir) {
6544
- fs33.mkdir(path42.dirname(file), { recursive: true }, (err) => {
6543
+ fs34.mkdir(path43.dirname(file), { recursive: true }, (err) => {
6545
6544
  if (err) return fileOpened(err);
6546
- fs33.open(file, flags, mode, fileOpened);
6545
+ fs34.open(file, flags, mode, fileOpened);
6547
6546
  });
6548
6547
  } else {
6549
- fs33.open(file, flags, mode, fileOpened);
6548
+ fs34.open(file, flags, mode, fileOpened);
6550
6549
  }
6551
6550
  }
6552
6551
  function SonicBoom(opts) {
@@ -6587,8 +6586,8 @@ var require_sonic_boom = __commonJS({
6587
6586
  this.flush = flushBuffer;
6588
6587
  this.flushSync = flushBufferSync;
6589
6588
  this._actualWrite = actualWriteBuffer;
6590
- fsWriteSync = () => fs33.writeSync(this.fd, this._writingBuf);
6591
- fsWrite = () => fs33.write(this.fd, this._writingBuf, this.release);
6589
+ fsWriteSync = () => fs34.writeSync(this.fd, this._writingBuf);
6590
+ fsWrite = () => fs34.write(this.fd, this._writingBuf, this.release);
6592
6591
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
6593
6592
  this._writingBuf = "";
6594
6593
  this.write = write;
@@ -6597,15 +6596,15 @@ var require_sonic_boom = __commonJS({
6597
6596
  this._actualWrite = actualWrite;
6598
6597
  fsWriteSync = () => {
6599
6598
  if (Buffer.isBuffer(this._writingBuf)) {
6600
- return fs33.writeSync(this.fd, this._writingBuf);
6599
+ return fs34.writeSync(this.fd, this._writingBuf);
6601
6600
  }
6602
- return fs33.writeSync(this.fd, this._writingBuf, "utf8");
6601
+ return fs34.writeSync(this.fd, this._writingBuf, "utf8");
6603
6602
  };
6604
6603
  fsWrite = () => {
6605
6604
  if (Buffer.isBuffer(this._writingBuf)) {
6606
- return fs33.write(this.fd, this._writingBuf, this.release);
6605
+ return fs34.write(this.fd, this._writingBuf, this.release);
6607
6606
  }
6608
- return fs33.write(this.fd, this._writingBuf, "utf8", this.release);
6607
+ return fs34.write(this.fd, this._writingBuf, "utf8", this.release);
6609
6608
  };
6610
6609
  } else {
6611
6610
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -6662,7 +6661,7 @@ var require_sonic_boom = __commonJS({
6662
6661
  }
6663
6662
  }
6664
6663
  if (this._fsync) {
6665
- fs33.fsyncSync(this.fd);
6664
+ fs34.fsyncSync(this.fd);
6666
6665
  }
6667
6666
  const len = this._len;
6668
6667
  if (this._reopening) {
@@ -6776,7 +6775,7 @@ var require_sonic_boom = __commonJS({
6776
6775
  const onDrain = () => {
6777
6776
  if (!this._fsync) {
6778
6777
  try {
6779
- fs33.fsync(this.fd, (err) => {
6778
+ fs34.fsync(this.fd, (err) => {
6780
6779
  this._flushPending = false;
6781
6780
  cb(err);
6782
6781
  });
@@ -6878,7 +6877,7 @@ var require_sonic_boom = __commonJS({
6878
6877
  const fd = this.fd;
6879
6878
  this.once("ready", () => {
6880
6879
  if (fd !== this.fd) {
6881
- fs33.close(fd, (err) => {
6880
+ fs34.close(fd, (err) => {
6882
6881
  if (err) {
6883
6882
  return this.emit("error", err);
6884
6883
  }
@@ -6927,7 +6926,7 @@ var require_sonic_boom = __commonJS({
6927
6926
  buf = this._bufs[0];
6928
6927
  }
6929
6928
  try {
6930
- const n = Buffer.isBuffer(buf) ? fs33.writeSync(this.fd, buf) : fs33.writeSync(this.fd, buf, "utf8");
6929
+ const n = Buffer.isBuffer(buf) ? fs34.writeSync(this.fd, buf) : fs34.writeSync(this.fd, buf, "utf8");
6931
6930
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
6932
6931
  buf = releasedBufObj.writingBuf;
6933
6932
  this._len = releasedBufObj.len;
@@ -6943,7 +6942,7 @@ var require_sonic_boom = __commonJS({
6943
6942
  }
6944
6943
  }
6945
6944
  try {
6946
- fs33.fsyncSync(this.fd);
6945
+ fs34.fsyncSync(this.fd);
6947
6946
  } catch {
6948
6947
  }
6949
6948
  }
@@ -6964,7 +6963,7 @@ var require_sonic_boom = __commonJS({
6964
6963
  buf = mergeBuf(this._bufs[0], this._lens[0]);
6965
6964
  }
6966
6965
  try {
6967
- const n = fs33.writeSync(this.fd, buf);
6966
+ const n = fs34.writeSync(this.fd, buf);
6968
6967
  buf = buf.subarray(n);
6969
6968
  this._len = Math.max(this._len - n, 0);
6970
6969
  if (buf.length <= 0) {
@@ -6992,13 +6991,13 @@ var require_sonic_boom = __commonJS({
6992
6991
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
6993
6992
  if (this.sync) {
6994
6993
  try {
6995
- const written = Buffer.isBuffer(this._writingBuf) ? fs33.writeSync(this.fd, this._writingBuf) : fs33.writeSync(this.fd, this._writingBuf, "utf8");
6994
+ const written = Buffer.isBuffer(this._writingBuf) ? fs34.writeSync(this.fd, this._writingBuf) : fs34.writeSync(this.fd, this._writingBuf, "utf8");
6996
6995
  release(null, written);
6997
6996
  } catch (err) {
6998
6997
  release(err);
6999
6998
  }
7000
6999
  } else {
7001
- fs33.write(this.fd, this._writingBuf, release);
7000
+ fs34.write(this.fd, this._writingBuf, release);
7002
7001
  }
7003
7002
  }
7004
7003
  function actualWriteBuffer() {
@@ -7007,7 +7006,7 @@ var require_sonic_boom = __commonJS({
7007
7006
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
7008
7007
  if (this.sync) {
7009
7008
  try {
7010
- const written = fs33.writeSync(this.fd, this._writingBuf);
7009
+ const written = fs34.writeSync(this.fd, this._writingBuf);
7011
7010
  release(null, written);
7012
7011
  } catch (err) {
7013
7012
  release(err);
@@ -7016,7 +7015,7 @@ var require_sonic_boom = __commonJS({
7016
7015
  if (kCopyBuffer) {
7017
7016
  this._writingBuf = Buffer.from(this._writingBuf);
7018
7017
  }
7019
- fs33.write(this.fd, this._writingBuf, release);
7018
+ fs34.write(this.fd, this._writingBuf, release);
7020
7019
  }
7021
7020
  }
7022
7021
  function actualClose(sonic) {
@@ -7032,12 +7031,12 @@ var require_sonic_boom = __commonJS({
7032
7031
  sonic._lens = [];
7033
7032
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
7034
7033
  try {
7035
- fs33.fsync(sonic.fd, closeWrapped);
7034
+ fs34.fsync(sonic.fd, closeWrapped);
7036
7035
  } catch {
7037
7036
  }
7038
7037
  function closeWrapped() {
7039
7038
  if (sonic.fd !== 1 && sonic.fd !== 2) {
7040
- fs33.close(sonic.fd, done);
7039
+ fs34.close(sonic.fd, done);
7041
7040
  } else {
7042
7041
  done();
7043
7042
  }
@@ -10172,11 +10171,11 @@ var init_lib = __esm({
10172
10171
  }
10173
10172
  }
10174
10173
  },
10175
- addToPath: function addToPath(path42, added, removed, oldPosInc, options) {
10176
- var last = path42.lastComponent;
10174
+ addToPath: function addToPath(path43, added, removed, oldPosInc, options) {
10175
+ var last = path43.lastComponent;
10177
10176
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
10178
10177
  return {
10179
- oldPos: path42.oldPos + oldPosInc,
10178
+ oldPos: path43.oldPos + oldPosInc,
10180
10179
  lastComponent: {
10181
10180
  count: last.count + 1,
10182
10181
  added,
@@ -10186,7 +10185,7 @@ var init_lib = __esm({
10186
10185
  };
10187
10186
  } else {
10188
10187
  return {
10189
- oldPos: path42.oldPos + oldPosInc,
10188
+ oldPos: path43.oldPos + oldPosInc,
10190
10189
  lastComponent: {
10191
10190
  count: 1,
10192
10191
  added,
@@ -10617,10 +10616,10 @@ function attachmentToHistoryMessage(o, ts) {
10617
10616
  const memories = raw.map((m2) => {
10618
10617
  if (!m2 || typeof m2 !== "object") return null;
10619
10618
  const rec = m2;
10620
- const path42 = typeof rec.path === "string" ? rec.path : null;
10619
+ const path43 = typeof rec.path === "string" ? rec.path : null;
10621
10620
  const content = typeof rec.content === "string" ? rec.content : null;
10622
- if (!path42 || content == null) return null;
10623
- const entry = { path: path42, content };
10621
+ if (!path43 || content == null) return null;
10622
+ const entry = { path: path43, content };
10624
10623
  if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
10625
10624
  return entry;
10626
10625
  }).filter((m2) => m2 !== null);
@@ -11446,10 +11445,10 @@ function parseAttachment(obj) {
11446
11445
  const memories = raw.map((m2) => {
11447
11446
  if (!m2 || typeof m2 !== "object") return null;
11448
11447
  const rec = m2;
11449
- const path42 = typeof rec.path === "string" ? rec.path : null;
11448
+ const path43 = typeof rec.path === "string" ? rec.path : null;
11450
11449
  const content = typeof rec.content === "string" ? rec.content : null;
11451
- if (!path42 || content == null) return null;
11452
- const out = { path: path42, content };
11450
+ if (!path43 || content == null) return null;
11451
+ const out = { path: path43, content };
11453
11452
  if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
11454
11453
  return out;
11455
11454
  }).filter((m2) => m2 !== null);
@@ -18948,7 +18947,7 @@ var require_websocket = __commonJS({
18948
18947
  var http2 = require("http");
18949
18948
  var net = require("net");
18950
18949
  var tls = require("tls");
18951
- var { randomBytes: randomBytes2, createHash: createHash3 } = require("crypto");
18950
+ var { randomBytes, createHash: createHash2 } = require("crypto");
18952
18951
  var { Duplex, Readable: Readable3 } = require("stream");
18953
18952
  var { URL: URL2 } = require("url");
18954
18953
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -19478,7 +19477,7 @@ var require_websocket = __commonJS({
19478
19477
  }
19479
19478
  }
19480
19479
  const defaultPort = isSecure ? 443 : 80;
19481
- const key = randomBytes2(16).toString("base64");
19480
+ const key = randomBytes(16).toString("base64");
19482
19481
  const request = isSecure ? https.request : http2.request;
19483
19482
  const protocolSet = /* @__PURE__ */ new Set();
19484
19483
  let perMessageDeflate;
@@ -19608,7 +19607,7 @@ var require_websocket = __commonJS({
19608
19607
  abortHandshake(websocket, socket, "Invalid Upgrade header");
19609
19608
  return;
19610
19609
  }
19611
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
19610
+ const digest = createHash2("sha1").update(key + GUID).digest("base64");
19612
19611
  if (res.headers["sec-websocket-accept"] !== digest) {
19613
19612
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
19614
19613
  return;
@@ -19975,7 +19974,7 @@ var require_websocket_server = __commonJS({
19975
19974
  var EventEmitter2 = require("events");
19976
19975
  var http2 = require("http");
19977
19976
  var { Duplex } = require("stream");
19978
- var { createHash: createHash3 } = require("crypto");
19977
+ var { createHash: createHash2 } = require("crypto");
19979
19978
  var extension2 = require_extension();
19980
19979
  var PerMessageDeflate2 = require_permessage_deflate();
19981
19980
  var subprotocol2 = require_subprotocol();
@@ -20276,7 +20275,7 @@ var require_websocket_server = __commonJS({
20276
20275
  );
20277
20276
  }
20278
20277
  if (this._state > RUNNING) return abortHandshake(socket, 503);
20279
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
20278
+ const digest = createHash2("sha1").update(key + GUID).digest("base64");
20280
20279
  const headers = [
20281
20280
  "HTTP/1.1 101 Switching Protocols",
20282
20281
  "Upgrade: websocket",
@@ -20364,7 +20363,7 @@ var require_websocket_server = __commonJS({
20364
20363
  // src/run-case/recorder.ts
20365
20364
  function startRunCaseRecorder(opts) {
20366
20365
  const now = opts.now ?? Date.now;
20367
- const dir = import_node_path28.default.dirname(opts.recordPath);
20366
+ const dir = import_node_path29.default.dirname(opts.recordPath);
20368
20367
  let stream = null;
20369
20368
  let closing = false;
20370
20369
  let closedSettled = false;
@@ -20378,8 +20377,8 @@ function startRunCaseRecorder(opts) {
20378
20377
  });
20379
20378
  const ensureStream = () => {
20380
20379
  if (stream) return stream;
20381
- import_node_fs25.default.mkdirSync(dir, { recursive: true });
20382
- stream = import_node_fs25.default.createWriteStream(opts.recordPath, { flags: "a" });
20380
+ import_node_fs26.default.mkdirSync(dir, { recursive: true });
20381
+ stream = import_node_fs26.default.createWriteStream(opts.recordPath, { flags: "a" });
20383
20382
  stream.on("close", () => closedResolve());
20384
20383
  return stream;
20385
20384
  };
@@ -20404,12 +20403,12 @@ function startRunCaseRecorder(opts) {
20404
20403
  };
20405
20404
  return { tap, close, closed };
20406
20405
  }
20407
- var import_node_fs25, import_node_path28;
20406
+ var import_node_fs26, import_node_path29;
20408
20407
  var init_recorder = __esm({
20409
20408
  "src/run-case/recorder.ts"() {
20410
20409
  "use strict";
20411
- import_node_fs25 = __toESM(require("fs"), 1);
20412
- import_node_path28 = __toESM(require("path"), 1);
20410
+ import_node_fs26 = __toESM(require("fs"), 1);
20411
+ import_node_path29 = __toESM(require("path"), 1);
20413
20412
  }
20414
20413
  });
20415
20414
 
@@ -20452,7 +20451,7 @@ var init_wire = __esm({
20452
20451
  // src/run-case/controller.ts
20453
20452
  async function runController(opts) {
20454
20453
  const now = opts.now ?? Date.now;
20455
- const cwd = opts.cwd ?? (0, import_node_fs26.mkdtempSync)(import_node_path29.default.join(import_node_os14.default.tmpdir(), "clawd-runcase-"));
20454
+ const cwd = opts.cwd ?? (0, import_node_fs27.mkdtempSync)(import_node_path30.default.join(import_node_os14.default.tmpdir(), "clawd-runcase-"));
20456
20455
  const ownsCwd = opts.cwd === void 0;
20457
20456
  const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
20458
20457
  const spawnCtx = { cwd };
@@ -20613,19 +20612,19 @@ async function runController(opts) {
20613
20612
  if (sigintHandler) process.off("SIGINT", sigintHandler);
20614
20613
  if (ownsCwd) {
20615
20614
  try {
20616
- (0, import_node_fs26.rmSync)(cwd, { recursive: true, force: true });
20615
+ (0, import_node_fs27.rmSync)(cwd, { recursive: true, force: true });
20617
20616
  } catch {
20618
20617
  }
20619
20618
  }
20620
20619
  return exitCode ?? 0;
20621
20620
  }
20622
- var import_node_fs26, import_node_os14, import_node_path29;
20621
+ var import_node_fs27, import_node_os14, import_node_path30;
20623
20622
  var init_controller = __esm({
20624
20623
  "src/run-case/controller.ts"() {
20625
20624
  "use strict";
20626
- import_node_fs26 = require("fs");
20625
+ import_node_fs27 = require("fs");
20627
20626
  import_node_os14 = __toESM(require("os"), 1);
20628
- import_node_path29 = __toESM(require("path"), 1);
20627
+ import_node_path30 = __toESM(require("path"), 1);
20629
20628
  init_claude();
20630
20629
  init_stdout_splitter();
20631
20630
  init_permission_stdio();
@@ -20857,8 +20856,8 @@ Env (advanced):
20857
20856
  `;
20858
20857
 
20859
20858
  // src/index.ts
20860
- var import_node_path27 = __toESM(require("path"), 1);
20861
- var import_node_fs24 = __toESM(require("fs"), 1);
20859
+ var import_node_path28 = __toESM(require("path"), 1);
20860
+ var import_node_fs25 = __toESM(require("fs"), 1);
20862
20861
 
20863
20862
  // src/logger.ts
20864
20863
  var import_node_fs2 = __toESM(require("fs"), 1);
@@ -26233,11 +26232,12 @@ function ownerContext(ownerPrincipalId, displayName) {
26233
26232
  grants: [{ resource: { type: "*" }, actions: ["admin"] }]
26234
26233
  };
26235
26234
  }
26236
- function guestContext(cap) {
26235
+ function guestContext(cap, peerOwnerPrincipalId) {
26237
26236
  return {
26238
26237
  principal: { id: cap.id, kind: "guest", displayName: cap.displayName },
26239
26238
  grants: cap.grants,
26240
- capabilityId: cap.id
26239
+ capabilityId: cap.id,
26240
+ ...peerOwnerPrincipalId ? { peerOwnerPrincipalId } : {}
26241
26241
  };
26242
26242
  }
26243
26243
  function authenticate(token, deps) {
@@ -26251,17 +26251,7 @@ function authenticate(token, deps) {
26251
26251
  if (v2.code === "TOKEN_INVALID") return { ok: false, code: "BAD_TOKEN" };
26252
26252
  return { ok: false, code: v2.code };
26253
26253
  }
26254
- if (deps.selfPrincipalId && deps.selfDisplayName && deps.onGuestHello) {
26255
- try {
26256
- deps.onGuestHello(v2.capability.id, deps.selfPrincipalId, deps.selfDisplayName);
26257
- } catch (e) {
26258
- if (e.message === "TOKEN_SHARED_LEAK") {
26259
- return { ok: false, code: "TOKEN_REVOKED" };
26260
- }
26261
- throw e;
26262
- }
26263
- }
26264
- return { ok: true, context: guestContext(v2.capability) };
26254
+ return { ok: true, context: guestContext(v2.capability, deps.selfPrincipalId) };
26265
26255
  }
26266
26256
 
26267
26257
  // src/permission/capability-store.ts
@@ -26397,7 +26387,6 @@ function sha256Hex(s) {
26397
26387
  }
26398
26388
 
26399
26389
  // src/permission/capability-manager.ts
26400
- var crypto5 = __toESM(require("crypto"), 1);
26401
26390
  var CapabilityManager = class {
26402
26391
  constructor(registry2, hooks = {}) {
26403
26392
  this.registry = registry2;
@@ -26413,54 +26402,6 @@ var CapabilityManager = class {
26413
26402
  findById(id) {
26414
26403
  return this.registry.findById(id);
26415
26404
  }
26416
- issue(args) {
26417
- if (!args.displayName.trim()) {
26418
- throw new Error("CapabilityManager.issue: displayName must be non-empty");
26419
- }
26420
- const token = (this.hooks.generateToken ?? defaultGenerateToken)();
26421
- const id = (this.hooks.generateId ?? defaultGenerateId)();
26422
- const now = (this.hooks.now ?? Date.now)();
26423
- const cap = {
26424
- id,
26425
- secretHash: sha256Hex2(token),
26426
- displayName: args.displayName,
26427
- grants: args.grants,
26428
- issuedAt: now,
26429
- usedCount: 0,
26430
- ...args.expiresAt !== void 0 ? { expiresAt: args.expiresAt } : {},
26431
- ...args.maxUses !== void 0 ? { maxUses: args.maxUses } : {}
26432
- };
26433
- this.registry.upsertCapability(cap);
26434
- this.hooks.onIssued?.(cap, token);
26435
- return { token, capability: cap };
26436
- }
26437
- /**
26438
- * guest 端 auth 帧捎带 selfPrincipalId/selfDisplayName 时,AuthGate.authenticate
26439
- * 校验 cap token 通过后调本方法把 peer 字段写回 cap:
26440
- * - 首次(cap.firstUsedByPeerAt 未设)→ 写盘 + 触发 onIssued 复用 push 频道
26441
- * 让 owner UI 通过 capability:updated 实时拿到 peer 字段
26442
- * - 重复(同 peerOwnerId)→ noop
26443
- * - 冲突(不同 peerOwnerId)→ throw TOKEN_SHARED_LEAK,AuthGate 转 close 4401
26444
- */
26445
- recordPeerHello(capId, args) {
26446
- const cap = this.registry.findById(capId);
26447
- if (!cap) return { changed: false };
26448
- if (cap.firstUsedByPeerAt != null) {
26449
- if (cap.peerOwnerId !== args.ownerPrincipalId) {
26450
- throw new Error("TOKEN_SHARED_LEAK");
26451
- }
26452
- return { changed: false };
26453
- }
26454
- const updated = {
26455
- ...cap,
26456
- peerOwnerId: args.ownerPrincipalId,
26457
- firstUsedByPeerAt: args.now,
26458
- peerDisplayName: args.displayName
26459
- };
26460
- this.registry.upsertCapability(updated);
26461
- this.hooks.onIssued?.(updated, "__peer_hello__");
26462
- return { changed: true };
26463
- }
26464
26405
  /**
26465
26406
  * Hard delete:从 registry / store 物理移除 capability。
26466
26407
  * idempotent:不存在 → null(handler 翻译成 VALIDATION_ERROR)
@@ -26473,15 +26414,6 @@ var CapabilityManager = class {
26473
26414
  return { capability: removed };
26474
26415
  }
26475
26416
  };
26476
- function defaultGenerateToken() {
26477
- return crypto5.randomBytes(24).toString("base64url");
26478
- }
26479
- function defaultGenerateId() {
26480
- return "cap_" + crypto5.randomBytes(6).toString("base64url");
26481
- }
26482
- function sha256Hex2(s) {
26483
- return crypto5.createHash("sha256").update(s).digest("hex");
26484
- }
26485
26417
 
26486
26418
  // src/permission/cleanup.ts
26487
26419
  var fs16 = __toESM(require("fs"), 1);
@@ -26499,14 +26431,89 @@ function cleanupGuestSessionsForCapability(cap, factory) {
26499
26431
  return { removed };
26500
26432
  }
26501
26433
 
26434
+ // src/permission/personal-capability.ts
26435
+ var import_node_fs13 = __toESM(require("fs"), 1);
26436
+ var import_node_path14 = __toESM(require("path"), 1);
26437
+ var import_node_crypto4 = __toESM(require("crypto"), 1);
26438
+ var PERSONAL_CAP_FILE_NAME = "personal-capability.json";
26439
+ var PERSONAL_CAP_DISPLAY_NAME = "personal";
26440
+ function personalCapFilePath(dataDir) {
26441
+ return import_node_path14.default.join(dataDir, PERSONAL_CAP_FILE_NAME);
26442
+ }
26443
+ function loadOrCreatePersonalCapability(opts) {
26444
+ const file = personalCapFilePath(opts.dataDir);
26445
+ const generateToken = opts.generateToken ?? defaultGenerateToken;
26446
+ const generateId = opts.generateId ?? defaultGenerateId;
26447
+ const now = opts.now ?? Date.now;
26448
+ const existing = readFile(file);
26449
+ if (existing) return existing;
26450
+ const token = generateToken();
26451
+ const id = generateId();
26452
+ const capability = {
26453
+ id,
26454
+ secretHash: sha256Hex2(token),
26455
+ displayName: PERSONAL_CAP_DISPLAY_NAME,
26456
+ // CapabilitySchema 期待 mutable Grant[],protocol 常量是 readonly,落盘前拷一份
26457
+ grants: PERSONAL_CAP_GRANTS.map((g2) => ({
26458
+ resource: { ...g2.resource },
26459
+ actions: [...g2.actions]
26460
+ })),
26461
+ issuedAt: now(),
26462
+ usedCount: 0
26463
+ };
26464
+ const content = { token, capability };
26465
+ writeFile(file, content);
26466
+ return content;
26467
+ }
26468
+ function readFile(file) {
26469
+ let raw;
26470
+ try {
26471
+ raw = import_node_fs13.default.readFileSync(file, "utf8");
26472
+ } catch (err) {
26473
+ const code = err?.code;
26474
+ if (code === "ENOENT") return null;
26475
+ return null;
26476
+ }
26477
+ let parsed;
26478
+ try {
26479
+ parsed = JSON.parse(raw);
26480
+ } catch {
26481
+ return null;
26482
+ }
26483
+ if (!parsed || typeof parsed !== "object") return null;
26484
+ const obj = parsed;
26485
+ if (typeof obj.token !== "string" || obj.token.length === 0) return null;
26486
+ const capParsed = CapabilitySchema.safeParse(obj.capability);
26487
+ if (!capParsed.success) return null;
26488
+ if (sha256Hex2(obj.token) !== capParsed.data.secretHash) return null;
26489
+ return { token: obj.token, capability: capParsed.data };
26490
+ }
26491
+ function writeFile(file, content) {
26492
+ import_node_fs13.default.mkdirSync(import_node_path14.default.dirname(file), { recursive: true });
26493
+ import_node_fs13.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
26494
+ try {
26495
+ import_node_fs13.default.chmodSync(file, 384);
26496
+ } catch {
26497
+ }
26498
+ }
26499
+ function defaultGenerateToken() {
26500
+ return import_node_crypto4.default.randomBytes(24).toString("base64url");
26501
+ }
26502
+ function defaultGenerateId() {
26503
+ return "personal_" + import_node_crypto4.default.randomBytes(6).toString("base64url");
26504
+ }
26505
+ function sha256Hex2(s) {
26506
+ return import_node_crypto4.default.createHash("sha256").update(s).digest("hex");
26507
+ }
26508
+
26502
26509
  // src/inbox/inbox-store.ts
26503
- var fs17 = __toESM(require("fs"), 1);
26504
- var path19 = __toESM(require("path"), 1);
26510
+ var fs18 = __toESM(require("fs"), 1);
26511
+ var path20 = __toESM(require("path"), 1);
26505
26512
  var INBOX_SUBDIR = "inbox";
26506
26513
  var InboxStore = class {
26507
26514
  constructor(dataDir) {
26508
26515
  this.dataDir = dataDir;
26509
- fs17.mkdirSync(this.dirPath(), { recursive: true });
26516
+ fs18.mkdirSync(this.dirPath(), { recursive: true });
26510
26517
  }
26511
26518
  dataDir;
26512
26519
  /**
@@ -26518,7 +26525,7 @@ var InboxStore = class {
26518
26525
  const file = this.filePath(peerOwnerId);
26519
26526
  let raw;
26520
26527
  try {
26521
- raw = fs17.readFileSync(file, "utf8");
26528
+ raw = fs18.readFileSync(file, "utf8");
26522
26529
  } catch (err) {
26523
26530
  if (err?.code === "ENOENT") return [];
26524
26531
  return [];
@@ -26534,7 +26541,7 @@ var InboxStore = class {
26534
26541
  const dir = this.dirPath();
26535
26542
  let entries;
26536
26543
  try {
26537
- entries = fs17.readdirSync(dir);
26544
+ entries = fs18.readdirSync(dir);
26538
26545
  } catch (err) {
26539
26546
  if (err?.code === "ENOENT") return [];
26540
26547
  return [];
@@ -26550,9 +26557,9 @@ var InboxStore = class {
26550
26557
  if (existing.some((m2) => m2.id === message.id)) return;
26551
26558
  const file = this.filePath(message.peerOwnerId);
26552
26559
  const line = JSON.stringify(message) + "\n";
26553
- fs17.appendFileSync(file, line, { mode: 384 });
26560
+ fs18.appendFileSync(file, line, { mode: 384 });
26554
26561
  try {
26555
- fs17.chmodSync(file, 384);
26562
+ fs18.chmodSync(file, 384);
26556
26563
  } catch {
26557
26564
  }
26558
26565
  }
@@ -26582,7 +26589,7 @@ var InboxStore = class {
26582
26589
  removeByPeerOwnerId(peerOwnerId) {
26583
26590
  const file = this.filePath(peerOwnerId);
26584
26591
  try {
26585
- fs17.unlinkSync(file);
26592
+ fs18.unlinkSync(file);
26586
26593
  } catch (err) {
26587
26594
  if (err?.code === "ENOENT") return;
26588
26595
  }
@@ -26591,18 +26598,18 @@ var InboxStore = class {
26591
26598
  const file = this.filePath(peerOwnerId);
26592
26599
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
26593
26600
  const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
26594
- fs17.writeFileSync(tmp, content, { mode: 384 });
26595
- fs17.renameSync(tmp, file);
26601
+ fs18.writeFileSync(tmp, content, { mode: 384 });
26602
+ fs18.renameSync(tmp, file);
26596
26603
  try {
26597
- fs17.chmodSync(file, 384);
26604
+ fs18.chmodSync(file, 384);
26598
26605
  } catch {
26599
26606
  }
26600
26607
  }
26601
26608
  dirPath() {
26602
- return path19.join(this.dataDir, INBOX_SUBDIR);
26609
+ return path20.join(this.dataDir, INBOX_SUBDIR);
26603
26610
  }
26604
26611
  filePath(peerOwnerId) {
26605
- return path19.join(this.dirPath(), `${peerOwnerId}.jsonl`);
26612
+ return path20.join(this.dirPath(), `${peerOwnerId}.jsonl`);
26606
26613
  }
26607
26614
  };
26608
26615
  function parseAllLines(raw) {
@@ -26689,8 +26696,8 @@ var InboxManager = class {
26689
26696
  };
26690
26697
 
26691
26698
  // src/state/received-capability-store.ts
26692
- var fs18 = __toESM(require("fs"), 1);
26693
- var path20 = __toESM(require("path"), 1);
26699
+ var fs19 = __toESM(require("fs"), 1);
26700
+ var path21 = __toESM(require("path"), 1);
26694
26701
  var FILE_NAME = "received-capabilities.json";
26695
26702
  var ReceivedCapabilityStore = class {
26696
26703
  constructor(dataDir) {
@@ -26700,10 +26707,10 @@ var ReceivedCapabilityStore = class {
26700
26707
  caps = /* @__PURE__ */ new Map();
26701
26708
  load() {
26702
26709
  this.caps.clear();
26703
- const file = path20.join(this.dataDir, FILE_NAME);
26710
+ const file = path21.join(this.dataDir, FILE_NAME);
26704
26711
  let raw;
26705
26712
  try {
26706
- raw = fs18.readFileSync(file, "utf8");
26713
+ raw = fs19.readFileSync(file, "utf8");
26707
26714
  } catch (err) {
26708
26715
  if (err?.code !== "ENOENT") this.renameBak(file);
26709
26716
  return;
@@ -26740,20 +26747,20 @@ var ReceivedCapabilityStore = class {
26740
26747
  this.flush();
26741
26748
  }
26742
26749
  flush() {
26743
- const file = path20.join(this.dataDir, FILE_NAME);
26750
+ const file = path21.join(this.dataDir, FILE_NAME);
26744
26751
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
26745
26752
  const content = JSON.stringify(
26746
26753
  { receivedCaps: Array.from(this.caps.values()) },
26747
26754
  null,
26748
26755
  2
26749
26756
  );
26750
- fs18.mkdirSync(this.dataDir, { recursive: true });
26751
- fs18.writeFileSync(tmp, content, { mode: 384 });
26752
- fs18.renameSync(tmp, file);
26757
+ fs19.mkdirSync(this.dataDir, { recursive: true });
26758
+ fs19.writeFileSync(tmp, content, { mode: 384 });
26759
+ fs19.renameSync(tmp, file);
26753
26760
  }
26754
26761
  renameBak(file) {
26755
26762
  try {
26756
- fs18.renameSync(file, `${file}.bak`);
26763
+ fs19.renameSync(file, `${file}.bak`);
26757
26764
  } catch {
26758
26765
  }
26759
26766
  }
@@ -26851,61 +26858,61 @@ async function connectRemote(args) {
26851
26858
  }
26852
26859
 
26853
26860
  // src/migrations/2026-05-20-flatten-sessions.ts
26854
- var fs19 = __toESM(require("fs"), 1);
26855
- var path21 = __toESM(require("path"), 1);
26861
+ var fs20 = __toESM(require("fs"), 1);
26862
+ var path22 = __toESM(require("path"), 1);
26856
26863
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
26857
26864
  function migrateFlattenSessions(opts) {
26858
26865
  const dataDir = opts.dataDir;
26859
26866
  const now = opts.now ?? Date.now;
26860
- const sessionsDir = path21.join(dataDir, "sessions");
26861
- const flagPath = path21.join(sessionsDir, MIGRATION_FLAG_NAME);
26867
+ const sessionsDir = path22.join(dataDir, "sessions");
26868
+ const flagPath = path22.join(sessionsDir, MIGRATION_FLAG_NAME);
26862
26869
  if (existsSync3(flagPath)) {
26863
26870
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
26864
26871
  }
26865
26872
  let movedBare = 0;
26866
26873
  let movedVmOwner = 0;
26867
26874
  let archivedListener = 0;
26868
- const defaultDir = path21.join(sessionsDir, "default");
26875
+ const defaultDir = path22.join(sessionsDir, "default");
26869
26876
  if (existsSync3(defaultDir)) {
26870
26877
  for (const entry of readdirSafe(defaultDir)) {
26871
26878
  if (!entry.endsWith(".json")) continue;
26872
- const src = path21.join(defaultDir, entry);
26873
- const dst = path21.join(sessionsDir, entry);
26874
- fs19.renameSync(src, dst);
26879
+ const src = path22.join(defaultDir, entry);
26880
+ const dst = path22.join(sessionsDir, entry);
26881
+ fs20.renameSync(src, dst);
26875
26882
  movedBare += 1;
26876
26883
  }
26877
26884
  rmdirIfEmpty(defaultDir);
26878
26885
  }
26879
26886
  for (const pid of readdirSafe(sessionsDir)) {
26880
- const personaDir = path21.join(sessionsDir, pid);
26887
+ const personaDir = path22.join(sessionsDir, pid);
26881
26888
  if (!isDir(personaDir)) continue;
26882
26889
  if (pid === "default") continue;
26883
- const ownerSrc = path21.join(personaDir, "owner");
26890
+ const ownerSrc = path22.join(personaDir, "owner");
26884
26891
  if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
26885
- const ownerDst = path21.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
26886
- fs19.mkdirSync(ownerDst, { recursive: true });
26892
+ const ownerDst = path22.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
26893
+ fs20.mkdirSync(ownerDst, { recursive: true });
26887
26894
  for (const file of readdirSafe(ownerSrc)) {
26888
26895
  if (!file.endsWith(".json")) continue;
26889
- fs19.renameSync(path21.join(ownerSrc, file), path21.join(ownerDst, file));
26896
+ fs20.renameSync(path22.join(ownerSrc, file), path22.join(ownerDst, file));
26890
26897
  movedVmOwner += 1;
26891
26898
  }
26892
26899
  rmdirIfEmpty(ownerSrc);
26893
26900
  }
26894
- const listenerSrc = path21.join(personaDir, "listener");
26901
+ const listenerSrc = path22.join(personaDir, "listener");
26895
26902
  if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
26896
- const archiveDst = path21.join(dataDir, ".legacy", `listener-${pid}`);
26897
- fs19.mkdirSync(archiveDst, { recursive: true });
26903
+ const archiveDst = path22.join(dataDir, ".legacy", `listener-${pid}`);
26904
+ fs20.mkdirSync(archiveDst, { recursive: true });
26898
26905
  for (const file of readdirSafe(listenerSrc)) {
26899
26906
  if (!file.endsWith(".json")) continue;
26900
- fs19.renameSync(path21.join(listenerSrc, file), path21.join(archiveDst, file));
26907
+ fs20.renameSync(path22.join(listenerSrc, file), path22.join(archiveDst, file));
26901
26908
  archivedListener += 1;
26902
26909
  }
26903
26910
  rmdirIfEmpty(listenerSrc);
26904
26911
  }
26905
26912
  rmdirIfEmpty(personaDir);
26906
26913
  }
26907
- fs19.mkdirSync(sessionsDir, { recursive: true });
26908
- fs19.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
26914
+ fs20.mkdirSync(sessionsDir, { recursive: true });
26915
+ fs20.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
26909
26916
  return {
26910
26917
  skipped: false,
26911
26918
  flagWritten: true,
@@ -26916,7 +26923,7 @@ function migrateFlattenSessions(opts) {
26916
26923
  }
26917
26924
  function existsSync3(p2) {
26918
26925
  try {
26919
- fs19.statSync(p2);
26926
+ fs20.statSync(p2);
26920
26927
  return true;
26921
26928
  } catch {
26922
26929
  return false;
@@ -26924,31 +26931,31 @@ function existsSync3(p2) {
26924
26931
  }
26925
26932
  function isDir(p2) {
26926
26933
  try {
26927
- return fs19.statSync(p2).isDirectory();
26934
+ return fs20.statSync(p2).isDirectory();
26928
26935
  } catch {
26929
26936
  return false;
26930
26937
  }
26931
26938
  }
26932
26939
  function readdirSafe(p2) {
26933
26940
  try {
26934
- return fs19.readdirSync(p2);
26941
+ return fs20.readdirSync(p2);
26935
26942
  } catch {
26936
26943
  return [];
26937
26944
  }
26938
26945
  }
26939
26946
  function rmdirIfEmpty(p2) {
26940
26947
  try {
26941
- fs19.rmdirSync(p2);
26948
+ fs20.rmdirSync(p2);
26942
26949
  } catch {
26943
26950
  }
26944
26951
  }
26945
26952
 
26946
26953
  // src/transport/http-router.ts
26947
- var import_node_fs13 = __toESM(require("fs"), 1);
26948
- var import_node_path15 = __toESM(require("path"), 1);
26954
+ var import_node_fs14 = __toESM(require("fs"), 1);
26955
+ var import_node_path16 = __toESM(require("path"), 1);
26949
26956
 
26950
26957
  // src/attachment/mime.ts
26951
- var import_node_path14 = __toESM(require("path"), 1);
26958
+ var import_node_path15 = __toESM(require("path"), 1);
26952
26959
  var TEXT_PLAIN = "text/plain; charset=utf-8";
26953
26960
  var EXT_TO_NATIVE_MIME = {
26954
26961
  // 图片
@@ -27055,14 +27062,14 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
27055
27062
  ".mk"
27056
27063
  ]);
27057
27064
  function lookupMime(filePathOrName) {
27058
- const ext = import_node_path14.default.extname(filePathOrName).toLowerCase();
27065
+ const ext = import_node_path15.default.extname(filePathOrName).toLowerCase();
27059
27066
  if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
27060
27067
  if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
27061
27068
  return "application/octet-stream";
27062
27069
  }
27063
27070
 
27064
27071
  // src/attachment/sign-url.ts
27065
- var import_node_crypto4 = __toESM(require("crypto"), 1);
27072
+ var import_node_crypto5 = __toESM(require("crypto"), 1);
27066
27073
  var HMAC_ALGO = "sha256";
27067
27074
  function base64urlEncode(buf) {
27068
27075
  const b2 = typeof buf === "string" ? Buffer.from(buf, "utf8") : buf;
@@ -27079,7 +27086,7 @@ function decodeAbsPathFromUrl(encoded) {
27079
27086
  }
27080
27087
  function computeSig(secret, absPath, e) {
27081
27088
  const msg = e === null ? absPath : `${absPath}|${e}`;
27082
- return import_node_crypto4.default.createHmac(HMAC_ALGO, secret).update(msg).digest();
27089
+ return import_node_crypto5.default.createHmac(HMAC_ALGO, secret).update(msg).digest();
27083
27090
  }
27084
27091
  function signUrlParts(secret, absPath, ttlSeconds, now = Date.now) {
27085
27092
  const e = ttlSeconds === null ? null : Math.floor(now() / 1e3) + ttlSeconds;
@@ -27114,7 +27121,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
27114
27121
  if (provided.length !== expected.length) {
27115
27122
  return { ok: false, code: "BAD_SIG" };
27116
27123
  }
27117
- if (!import_node_crypto4.default.timingSafeEqual(provided, expected)) {
27124
+ if (!import_node_crypto5.default.timingSafeEqual(provided, expected)) {
27118
27125
  return { ok: false, code: "BAD_SIG" };
27119
27126
  }
27120
27127
  if (e !== null && now() / 1e3 > e) {
@@ -27132,9 +27139,7 @@ function createHttpRouter(deps) {
27132
27139
  return true;
27133
27140
  }
27134
27141
  if (url.pathname === "/healthz" && req.method === "GET") {
27135
- sendJson(res, 200, { ok: true, version: deps.daemonVersion }, {
27136
- "Access-Control-Allow-Origin": "*"
27137
- });
27142
+ sendJson(res, 200, { ok: true, version: deps.daemonVersion });
27138
27143
  return true;
27139
27144
  }
27140
27145
  if (!url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/")) {
@@ -27186,7 +27191,7 @@ function createHttpRouter(deps) {
27186
27191
  return true;
27187
27192
  }
27188
27193
  let absPath;
27189
- if (import_node_path15.default.isAbsolute(pathParam)) {
27194
+ if (import_node_path16.default.isAbsolute(pathParam)) {
27190
27195
  absPath = pathParam;
27191
27196
  } else if (deps.sessionStore) {
27192
27197
  const file = deps.sessionStore.read(sid);
@@ -27194,7 +27199,7 @@ function createHttpRouter(deps) {
27194
27199
  sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
27195
27200
  return true;
27196
27201
  }
27197
- absPath = import_node_path15.default.join(file.cwd, pathParam);
27202
+ absPath = import_node_path16.default.join(file.cwd, pathParam);
27198
27203
  } else {
27199
27204
  sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
27200
27205
  return true;
@@ -27214,11 +27219,8 @@ function parseUrl(rawUrl) {
27214
27219
  return null;
27215
27220
  }
27216
27221
  }
27217
- function sendJson(res, status, body, extraHeaders) {
27218
- res.writeHead(status, {
27219
- "Content-Type": "application/json; charset=utf-8",
27220
- ...extraHeaders ?? {}
27221
- });
27222
+ function sendJson(res, status, body) {
27223
+ res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
27222
27224
  res.end(JSON.stringify(body));
27223
27225
  }
27224
27226
  function withCtx(ctx, body) {
@@ -27227,7 +27229,7 @@ function withCtx(ctx, body) {
27227
27229
  function streamFile(res, absPath, logger) {
27228
27230
  let stat;
27229
27231
  try {
27230
- stat = import_node_fs13.default.statSync(absPath);
27232
+ stat = import_node_fs14.default.statSync(absPath);
27231
27233
  } catch (err) {
27232
27234
  const code = err?.code;
27233
27235
  if (code === "ENOENT") {
@@ -27242,7 +27244,7 @@ function streamFile(res, absPath, logger) {
27242
27244
  return;
27243
27245
  }
27244
27246
  const mime = lookupMime(absPath);
27245
- const basename = import_node_path15.default.basename(absPath);
27247
+ const basename = import_node_path16.default.basename(absPath);
27246
27248
  res.writeHead(200, {
27247
27249
  "Content-Type": mime,
27248
27250
  "Content-Length": String(stat.size),
@@ -27250,7 +27252,7 @@ function streamFile(res, absPath, logger) {
27250
27252
  // 防止浏览器把任意 mime 当 html 渲染
27251
27253
  "X-Content-Type-Options": "nosniff"
27252
27254
  });
27253
- const stream = import_node_fs13.default.createReadStream(absPath);
27255
+ const stream = import_node_fs14.default.createReadStream(absPath);
27254
27256
  stream.on("error", (err) => {
27255
27257
  logger?.warn("streamFile read error", { absPath, err: err.message });
27256
27258
  res.destroy();
@@ -27259,9 +27261,9 @@ function streamFile(res, absPath, logger) {
27259
27261
  }
27260
27262
 
27261
27263
  // src/attachment/group.ts
27262
- var import_node_fs14 = __toESM(require("fs"), 1);
27263
- var import_node_path16 = __toESM(require("path"), 1);
27264
- var import_node_crypto5 = __toESM(require("crypto"), 1);
27264
+ var import_node_fs15 = __toESM(require("fs"), 1);
27265
+ var import_node_path17 = __toESM(require("path"), 1);
27266
+ var import_node_crypto6 = __toESM(require("crypto"), 1);
27265
27267
  init_protocol();
27266
27268
  var GroupFileStore = class {
27267
27269
  dataDir;
@@ -27272,11 +27274,11 @@ var GroupFileStore = class {
27272
27274
  this.logger = opts.logger;
27273
27275
  }
27274
27276
  rootForScope(scope) {
27275
- return import_node_path16.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
27277
+ return import_node_path17.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
27276
27278
  }
27277
27279
  /** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
27278
27280
  filePath(scope, sessionId) {
27279
- return import_node_path16.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
27281
+ return import_node_path17.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
27280
27282
  }
27281
27283
  cacheKey(scope, sessionId) {
27282
27284
  return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
@@ -27285,7 +27287,7 @@ var GroupFileStore = class {
27285
27287
  readFile(scope, sessionId) {
27286
27288
  const file = this.filePath(scope, sessionId);
27287
27289
  try {
27288
- const raw = import_node_fs14.default.readFileSync(file, "utf8");
27290
+ const raw = import_node_fs15.default.readFileSync(file, "utf8");
27289
27291
  const parsed = JSON.parse(raw);
27290
27292
  if (!Array.isArray(parsed)) {
27291
27293
  this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
@@ -27311,10 +27313,10 @@ var GroupFileStore = class {
27311
27313
  }
27312
27314
  writeFile(scope, sessionId, entries) {
27313
27315
  const file = this.filePath(scope, sessionId);
27314
- import_node_fs14.default.mkdirSync(import_node_path16.default.dirname(file), { recursive: true });
27316
+ import_node_fs15.default.mkdirSync(import_node_path17.default.dirname(file), { recursive: true });
27315
27317
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
27316
- import_node_fs14.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
27317
- import_node_fs14.default.renameSync(tmp, file);
27318
+ import_node_fs15.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
27319
+ import_node_fs15.default.renameSync(tmp, file);
27318
27320
  }
27319
27321
  /** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
27320
27322
  list(scope, sessionId) {
@@ -27350,7 +27352,7 @@ var GroupFileStore = class {
27350
27352
  entries[idx] = next;
27351
27353
  } else {
27352
27354
  next = {
27353
- id: `gf-${import_node_crypto5.default.randomBytes(6).toString("base64url")}`,
27355
+ id: `gf-${import_node_crypto6.default.randomBytes(6).toString("base64url")}`,
27354
27356
  relPath: input.relPath,
27355
27357
  from: input.from,
27356
27358
  label: input.label,
@@ -27400,10 +27402,10 @@ var GroupFileStore = class {
27400
27402
  };
27401
27403
 
27402
27404
  // src/discovery/state-file.ts
27403
- var import_node_fs15 = __toESM(require("fs"), 1);
27404
- var import_node_path17 = __toESM(require("path"), 1);
27405
+ var import_node_fs16 = __toESM(require("fs"), 1);
27406
+ var import_node_path18 = __toESM(require("path"), 1);
27405
27407
  function defaultStateFilePath(dataDir) {
27406
- return import_node_path17.default.join(dataDir, "state.json");
27408
+ return import_node_path18.default.join(dataDir, "state.json");
27407
27409
  }
27408
27410
  function isPidAlive(pid) {
27409
27411
  if (!Number.isFinite(pid) || pid <= 0) return false;
@@ -27425,7 +27427,7 @@ var StateFileManager = class {
27425
27427
  }
27426
27428
  read() {
27427
27429
  try {
27428
- const raw = import_node_fs15.default.readFileSync(this.file, "utf8");
27430
+ const raw = import_node_fs16.default.readFileSync(this.file, "utf8");
27429
27431
  const parsed = JSON.parse(raw);
27430
27432
  return parsed;
27431
27433
  } catch {
@@ -27439,34 +27441,34 @@ var StateFileManager = class {
27439
27441
  return { status: "stale", existing };
27440
27442
  }
27441
27443
  write(state) {
27442
- import_node_fs15.default.mkdirSync(import_node_path17.default.dirname(this.file), { recursive: true });
27444
+ import_node_fs16.default.mkdirSync(import_node_path18.default.dirname(this.file), { recursive: true });
27443
27445
  const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
27444
- import_node_fs15.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
27445
- import_node_fs15.default.renameSync(tmp, this.file);
27446
+ import_node_fs16.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
27447
+ import_node_fs16.default.renameSync(tmp, this.file);
27446
27448
  if (process.platform !== "win32") {
27447
27449
  try {
27448
- import_node_fs15.default.chmodSync(this.file, 384);
27450
+ import_node_fs16.default.chmodSync(this.file, 384);
27449
27451
  } catch {
27450
27452
  }
27451
27453
  }
27452
27454
  }
27453
27455
  delete() {
27454
27456
  try {
27455
- import_node_fs15.default.unlinkSync(this.file);
27457
+ import_node_fs16.default.unlinkSync(this.file);
27456
27458
  } catch {
27457
27459
  }
27458
27460
  }
27459
27461
  };
27460
27462
 
27461
27463
  // src/tunnel/tunnel-manager.ts
27462
- var import_node_fs19 = __toESM(require("fs"), 1);
27463
- var import_node_path21 = __toESM(require("path"), 1);
27464
- var import_node_crypto6 = __toESM(require("crypto"), 1);
27464
+ var import_node_fs20 = __toESM(require("fs"), 1);
27465
+ var import_node_path22 = __toESM(require("path"), 1);
27466
+ var import_node_crypto7 = __toESM(require("crypto"), 1);
27465
27467
  var import_node_child_process5 = require("child_process");
27466
27468
 
27467
27469
  // src/tunnel/tunnel-store.ts
27468
- var import_node_fs16 = __toESM(require("fs"), 1);
27469
- var import_node_path18 = __toESM(require("path"), 1);
27470
+ var import_node_fs17 = __toESM(require("fs"), 1);
27471
+ var import_node_path19 = __toESM(require("path"), 1);
27470
27472
  var TunnelStore = class {
27471
27473
  constructor(filePath) {
27472
27474
  this.filePath = filePath;
@@ -27474,7 +27476,7 @@ var TunnelStore = class {
27474
27476
  filePath;
27475
27477
  async get() {
27476
27478
  try {
27477
- const raw = await import_node_fs16.default.promises.readFile(this.filePath, "utf8");
27479
+ const raw = await import_node_fs17.default.promises.readFile(this.filePath, "utf8");
27478
27480
  const obj = JSON.parse(raw);
27479
27481
  if (!isPersistedTunnel(obj)) return null;
27480
27482
  return obj;
@@ -27485,22 +27487,22 @@ var TunnelStore = class {
27485
27487
  }
27486
27488
  }
27487
27489
  async set(v2) {
27488
- const dir = import_node_path18.default.dirname(this.filePath);
27489
- await import_node_fs16.default.promises.mkdir(dir, { recursive: true });
27490
+ const dir = import_node_path19.default.dirname(this.filePath);
27491
+ await import_node_fs17.default.promises.mkdir(dir, { recursive: true });
27490
27492
  const data = JSON.stringify(v2, null, 2);
27491
27493
  const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
27492
- await import_node_fs16.default.promises.writeFile(tmp, data, { mode: 384 });
27494
+ await import_node_fs17.default.promises.writeFile(tmp, data, { mode: 384 });
27493
27495
  if (process.platform !== "win32") {
27494
27496
  try {
27495
- await import_node_fs16.default.promises.chmod(tmp, 384);
27497
+ await import_node_fs17.default.promises.chmod(tmp, 384);
27496
27498
  } catch {
27497
27499
  }
27498
27500
  }
27499
- await import_node_fs16.default.promises.rename(tmp, this.filePath);
27501
+ await import_node_fs17.default.promises.rename(tmp, this.filePath);
27500
27502
  }
27501
27503
  async clear() {
27502
27504
  try {
27503
- await import_node_fs16.default.promises.unlink(this.filePath);
27505
+ await import_node_fs17.default.promises.unlink(this.filePath);
27504
27506
  } catch (err) {
27505
27507
  const code = err?.code;
27506
27508
  if (code !== "ENOENT") throw err;
@@ -27595,9 +27597,9 @@ function escape(v2) {
27595
27597
  }
27596
27598
 
27597
27599
  // src/tunnel/frpc-binary.ts
27598
- var import_node_fs17 = __toESM(require("fs"), 1);
27600
+ var import_node_fs18 = __toESM(require("fs"), 1);
27599
27601
  var import_node_os9 = __toESM(require("os"), 1);
27600
- var import_node_path19 = __toESM(require("path"), 1);
27602
+ var import_node_path20 = __toESM(require("path"), 1);
27601
27603
  var import_node_child_process3 = require("child_process");
27602
27604
  var import_node_stream2 = require("stream");
27603
27605
  var import_promises = require("stream/promises");
@@ -27629,20 +27631,20 @@ function frpcDownloadUrl(version2, p2) {
27629
27631
  }
27630
27632
  async function ensureFrpcBinary(opts) {
27631
27633
  if (opts.override) {
27632
- if (!import_node_fs17.default.existsSync(opts.override)) {
27634
+ if (!import_node_fs18.default.existsSync(opts.override)) {
27633
27635
  throw new Error(`frpc binary not found at override path: ${opts.override}`);
27634
27636
  }
27635
27637
  return opts.override;
27636
27638
  }
27637
27639
  const version2 = opts.version ?? FRPC_VERSION;
27638
27640
  const platform = opts.platform ?? detectPlatform();
27639
- const binDir = import_node_path19.default.join(opts.dataDir, "bin");
27640
- import_node_fs17.default.mkdirSync(binDir, { recursive: true });
27641
+ const binDir = import_node_path20.default.join(opts.dataDir, "bin");
27642
+ import_node_fs18.default.mkdirSync(binDir, { recursive: true });
27641
27643
  cleanupStaleArtifacts(binDir);
27642
- const stableBin = import_node_path19.default.join(binDir, "frpc");
27643
- if (import_node_fs17.default.existsSync(stableBin)) return stableBin;
27644
+ const stableBin = import_node_path20.default.join(binDir, "frpc");
27645
+ if (import_node_fs18.default.existsSync(stableBin)) return stableBin;
27644
27646
  const partialBin = `${stableBin}.partial`;
27645
- const tarballPath = import_node_path19.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
27647
+ const tarballPath = import_node_path20.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
27646
27648
  try {
27647
27649
  const url = frpcDownloadUrl(version2, platform);
27648
27650
  await downloadToFile(url, tarballPath, opts.fetchImpl);
@@ -27651,8 +27653,8 @@ async function ensureFrpcBinary(opts) {
27651
27653
  } else {
27652
27654
  await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
27653
27655
  }
27654
- import_node_fs17.default.chmodSync(partialBin, 493);
27655
- import_node_fs17.default.renameSync(partialBin, stableBin);
27656
+ import_node_fs18.default.chmodSync(partialBin, 493);
27657
+ import_node_fs18.default.renameSync(partialBin, stableBin);
27656
27658
  } finally {
27657
27659
  safeUnlink(tarballPath);
27658
27660
  safeUnlink(partialBin);
@@ -27662,15 +27664,15 @@ async function ensureFrpcBinary(opts) {
27662
27664
  function cleanupStaleArtifacts(binDir) {
27663
27665
  let entries;
27664
27666
  try {
27665
- entries = import_node_fs17.default.readdirSync(binDir);
27667
+ entries = import_node_fs18.default.readdirSync(binDir);
27666
27668
  } catch {
27667
27669
  return;
27668
27670
  }
27669
27671
  for (const name of entries) {
27670
27672
  if (name.endsWith(".partial") || name.startsWith("extract-")) {
27671
- const full = import_node_path19.default.join(binDir, name);
27673
+ const full = import_node_path20.default.join(binDir, name);
27672
27674
  try {
27673
- import_node_fs17.default.rmSync(full, { recursive: true, force: true });
27675
+ import_node_fs18.default.rmSync(full, { recursive: true, force: true });
27674
27676
  } catch {
27675
27677
  }
27676
27678
  }
@@ -27678,7 +27680,7 @@ function cleanupStaleArtifacts(binDir) {
27678
27680
  }
27679
27681
  function safeUnlink(p2) {
27680
27682
  try {
27681
- import_node_fs17.default.unlinkSync(p2);
27683
+ import_node_fs18.default.unlinkSync(p2);
27682
27684
  } catch {
27683
27685
  }
27684
27686
  }
@@ -27689,13 +27691,13 @@ async function downloadToFile(url, dest, fetchImpl) {
27689
27691
  if (!res.ok || !res.body) {
27690
27692
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
27691
27693
  }
27692
- const out = import_node_fs17.default.createWriteStream(dest);
27694
+ const out = import_node_fs18.default.createWriteStream(dest);
27693
27695
  const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
27694
27696
  await (0, import_promises.pipeline)(nodeStream, out);
27695
27697
  }
27696
27698
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
27697
- const work = import_node_path19.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
27698
- import_node_fs17.default.mkdirSync(work, { recursive: true });
27699
+ const work = import_node_path20.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
27700
+ import_node_fs18.default.mkdirSync(work, { recursive: true });
27699
27701
  try {
27700
27702
  await new Promise((resolve6, reject) => {
27701
27703
  const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
@@ -27703,32 +27705,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
27703
27705
  proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
27704
27706
  });
27705
27707
  const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
27706
- const src = import_node_path19.default.join(work, dirName, "frpc");
27707
- if (!import_node_fs17.default.existsSync(src)) {
27708
+ const src = import_node_path20.default.join(work, dirName, "frpc");
27709
+ if (!import_node_fs18.default.existsSync(src)) {
27708
27710
  throw new Error(`frpc not found inside tarball at ${src}`);
27709
27711
  }
27710
- import_node_fs17.default.copyFileSync(src, destBin);
27712
+ import_node_fs18.default.copyFileSync(src, destBin);
27711
27713
  } finally {
27712
- import_node_fs17.default.rmSync(work, { recursive: true, force: true });
27714
+ import_node_fs18.default.rmSync(work, { recursive: true, force: true });
27713
27715
  }
27714
27716
  }
27715
27717
 
27716
27718
  // src/tunnel/frpc-process.ts
27717
- var import_node_fs18 = __toESM(require("fs"), 1);
27718
- var import_node_path20 = __toESM(require("path"), 1);
27719
+ var import_node_fs19 = __toESM(require("fs"), 1);
27720
+ var import_node_path21 = __toESM(require("path"), 1);
27719
27721
  var import_node_child_process4 = require("child_process");
27720
27722
  function frpcPidFilePath(dataDir) {
27721
- return import_node_path20.default.join(dataDir, "frpc.pid");
27723
+ return import_node_path21.default.join(dataDir, "frpc.pid");
27722
27724
  }
27723
27725
  function writeFrpcPid(dataDir, pid) {
27724
27726
  try {
27725
- import_node_fs18.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
27727
+ import_node_fs19.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
27726
27728
  } catch {
27727
27729
  }
27728
27730
  }
27729
27731
  function clearFrpcPid(dataDir) {
27730
27732
  try {
27731
- import_node_fs18.default.unlinkSync(frpcPidFilePath(dataDir));
27733
+ import_node_fs19.default.unlinkSync(frpcPidFilePath(dataDir));
27732
27734
  } catch {
27733
27735
  }
27734
27736
  }
@@ -27744,7 +27746,7 @@ function defaultIsPidAlive(pid) {
27744
27746
  }
27745
27747
  function defaultReadPidFile(file) {
27746
27748
  try {
27747
- return import_node_fs18.default.readFileSync(file, "utf8");
27749
+ return import_node_fs19.default.readFileSync(file, "utf8");
27748
27750
  } catch {
27749
27751
  return null;
27750
27752
  }
@@ -27760,7 +27762,7 @@ function defaultSleep(ms) {
27760
27762
  }
27761
27763
  async function killStaleFrpc(deps) {
27762
27764
  const pidFile = frpcPidFilePath(deps.dataDir);
27763
- const tomlPath = import_node_path20.default.join(deps.dataDir, "frpc.toml");
27765
+ const tomlPath = import_node_path21.default.join(deps.dataDir, "frpc.toml");
27764
27766
  const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
27765
27767
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
27766
27768
  const killPid = deps.killPidImpl ?? defaultKillPid;
@@ -27784,7 +27786,7 @@ async function killStaleFrpc(deps) {
27784
27786
  }
27785
27787
  if (victims.size === 0) {
27786
27788
  try {
27787
- import_node_fs18.default.unlinkSync(pidFile);
27789
+ import_node_fs19.default.unlinkSync(pidFile);
27788
27790
  } catch {
27789
27791
  }
27790
27792
  return;
@@ -27795,7 +27797,7 @@ async function killStaleFrpc(deps) {
27795
27797
  }
27796
27798
  await sleep(deps.reapWaitMs ?? 300);
27797
27799
  try {
27798
- import_node_fs18.default.unlinkSync(pidFile);
27800
+ import_node_fs19.default.unlinkSync(pidFile);
27799
27801
  } catch {
27800
27802
  }
27801
27803
  }
@@ -27832,7 +27834,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
27832
27834
  var TunnelManager = class {
27833
27835
  constructor(deps) {
27834
27836
  this.deps = deps;
27835
- this.store = deps.store ?? new TunnelStore(import_node_path21.default.join(deps.dataDir, "tunnel.json"));
27837
+ this.store = deps.store ?? new TunnelStore(import_node_path22.default.join(deps.dataDir, "tunnel.json"));
27836
27838
  this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
27837
27839
  this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
27838
27840
  }
@@ -27959,8 +27961,8 @@ var TunnelManager = class {
27959
27961
  dataDir: this.deps.dataDir,
27960
27962
  override: this.deps.frpcBinaryOverride ?? void 0
27961
27963
  });
27962
- const tomlPath = import_node_path21.default.join(this.deps.dataDir, "frpc.toml");
27963
- const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto6.default.randomBytes(3).toString("hex")}`;
27964
+ const tomlPath = import_node_path22.default.join(this.deps.dataDir, "frpc.toml");
27965
+ const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
27964
27966
  const toml = buildFrpcToml({
27965
27967
  serverAddr: t.frpsHost,
27966
27968
  serverPort: t.frpsPort,
@@ -27970,12 +27972,12 @@ var TunnelManager = class {
27970
27972
  localPort,
27971
27973
  logLevel: "info"
27972
27974
  });
27973
- await import_node_fs19.default.promises.writeFile(tomlPath, toml, { mode: 384 });
27975
+ await import_node_fs20.default.promises.writeFile(tomlPath, toml, { mode: 384 });
27974
27976
  const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
27975
27977
  stdio: ["ignore", "pipe", "pipe"]
27976
27978
  });
27977
- const logFilePath = import_node_path21.default.join(this.deps.dataDir, "frpc.log");
27978
- const logStream = import_node_fs19.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
27979
+ const logFilePath = import_node_path22.default.join(this.deps.dataDir, "frpc.log");
27980
+ const logStream = import_node_fs20.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
27979
27981
  logStream.on("error", () => {
27980
27982
  });
27981
27983
  const tee = (chunk) => {
@@ -28058,22 +28060,22 @@ async function waitForFrpcReady(proc, timeoutMs) {
28058
28060
 
28059
28061
  // src/tunnel/device-key.ts
28060
28062
  var import_node_os10 = __toESM(require("os"), 1);
28061
- var import_node_crypto7 = __toESM(require("crypto"), 1);
28063
+ var import_node_crypto8 = __toESM(require("crypto"), 1);
28062
28064
  var DERIVE_SALT = "clawd-tunnel-device-v1";
28063
28065
  function deriveStableDeviceKey(opts = {}) {
28064
28066
  const hostname = opts.hostname ?? import_node_os10.default.hostname();
28065
28067
  const uid = opts.uid ?? (typeof import_node_os10.default.userInfo === "function" ? import_node_os10.default.userInfo().uid : 0);
28066
28068
  const input = `${hostname}::${uid}`;
28067
- return import_node_crypto7.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
28069
+ return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
28068
28070
  }
28069
28071
 
28070
28072
  // src/auth-store.ts
28071
- var import_node_fs20 = __toESM(require("fs"), 1);
28072
- var import_node_path22 = __toESM(require("path"), 1);
28073
- var import_node_crypto8 = __toESM(require("crypto"), 1);
28073
+ var import_node_fs21 = __toESM(require("fs"), 1);
28074
+ var import_node_path23 = __toESM(require("path"), 1);
28075
+ var import_node_crypto9 = __toESM(require("crypto"), 1);
28074
28076
  var AUTH_FILE_NAME = "auth.json";
28075
28077
  function authFilePath(dataDir) {
28076
- return import_node_path22.default.join(dataDir, AUTH_FILE_NAME);
28078
+ return import_node_path23.default.join(dataDir, AUTH_FILE_NAME);
28077
28079
  }
28078
28080
  function loadOrCreateAuthFile(opts) {
28079
28081
  const file = authFilePath(opts.dataDir);
@@ -28098,14 +28100,14 @@ function loadOrCreateAuthFile(opts) {
28098
28100
  return next;
28099
28101
  }
28100
28102
  function defaultGenerateToken2() {
28101
- return import_node_crypto8.default.randomBytes(32).toString("base64url");
28103
+ return import_node_crypto9.default.randomBytes(32).toString("base64url");
28102
28104
  }
28103
28105
  function defaultGenerateOwnerPrincipalId() {
28104
- return `owner-${import_node_crypto8.default.randomUUID()}`;
28106
+ return `owner-${import_node_crypto9.default.randomUUID()}`;
28105
28107
  }
28106
28108
  function readAuthFile(file) {
28107
28109
  try {
28108
- const raw = import_node_fs20.default.readFileSync(file, "utf8");
28110
+ const raw = import_node_fs21.default.readFileSync(file, "utf8");
28109
28111
  const parsed = JSON.parse(raw);
28110
28112
  if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
28111
28113
  return null;
@@ -28123,25 +28125,25 @@ function readAuthFile(file) {
28123
28125
  }
28124
28126
  }
28125
28127
  function writeAuthFile(file, content) {
28126
- import_node_fs20.default.mkdirSync(import_node_path22.default.dirname(file), { recursive: true });
28127
- import_node_fs20.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
28128
+ import_node_fs21.default.mkdirSync(import_node_path23.default.dirname(file), { recursive: true });
28129
+ import_node_fs21.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
28128
28130
  try {
28129
- import_node_fs20.default.chmodSync(file, 384);
28131
+ import_node_fs21.default.chmodSync(file, 384);
28130
28132
  } catch {
28131
28133
  }
28132
28134
  }
28133
28135
 
28134
28136
  // src/owner-profile.ts
28135
- var import_node_fs21 = __toESM(require("fs"), 1);
28137
+ var import_node_fs22 = __toESM(require("fs"), 1);
28136
28138
  var import_node_os11 = __toESM(require("os"), 1);
28137
- var import_node_path23 = __toESM(require("path"), 1);
28139
+ var import_node_path24 = __toESM(require("path"), 1);
28138
28140
  var PROFILE_FILENAME = "profile.json";
28139
28141
  function loadOwnerDisplayName(dataDir) {
28140
28142
  const fallback = import_node_os11.default.userInfo().username;
28141
- const profilePath = import_node_path23.default.join(dataDir, PROFILE_FILENAME);
28143
+ const profilePath = import_node_path24.default.join(dataDir, PROFILE_FILENAME);
28142
28144
  let raw;
28143
28145
  try {
28144
- raw = import_node_fs21.default.readFileSync(profilePath, "utf8");
28146
+ raw = import_node_fs22.default.readFileSync(profilePath, "utf8");
28145
28147
  } catch {
28146
28148
  return fallback;
28147
28149
  }
@@ -28170,12 +28172,12 @@ init_protocol();
28170
28172
  init_protocol();
28171
28173
 
28172
28174
  // src/session/fork.ts
28173
- var import_node_fs22 = __toESM(require("fs"), 1);
28175
+ var import_node_fs23 = __toESM(require("fs"), 1);
28174
28176
  var import_node_os12 = __toESM(require("os"), 1);
28175
- var import_node_path24 = __toESM(require("path"), 1);
28177
+ var import_node_path25 = __toESM(require("path"), 1);
28176
28178
  init_claude_history();
28177
28179
  function readJsonlEntries(file) {
28178
- const raw = import_node_fs22.default.readFileSync(file, "utf8");
28180
+ const raw = import_node_fs23.default.readFileSync(file, "utf8");
28179
28181
  const out = [];
28180
28182
  for (const line of raw.split("\n")) {
28181
28183
  const t = line.trim();
@@ -28188,10 +28190,10 @@ function readJsonlEntries(file) {
28188
28190
  return out;
28189
28191
  }
28190
28192
  function forkSession(input) {
28191
- const baseDir = input.baseDir ?? import_node_path24.default.join(import_node_os12.default.homedir(), ".claude");
28192
- const projectDir = import_node_path24.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
28193
- const sourceFile = import_node_path24.default.join(projectDir, `${input.toolSessionId}.jsonl`);
28194
- if (!import_node_fs22.default.existsSync(sourceFile)) {
28193
+ const baseDir = input.baseDir ?? import_node_path25.default.join(import_node_os12.default.homedir(), ".claude");
28194
+ const projectDir = import_node_path25.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
28195
+ const sourceFile = import_node_path25.default.join(projectDir, `${input.toolSessionId}.jsonl`);
28196
+ if (!import_node_fs23.default.existsSync(sourceFile)) {
28195
28197
  throw new Error(`fork: source transcript not found: ${sourceFile}`);
28196
28198
  }
28197
28199
  const entries = readJsonlEntries(sourceFile);
@@ -28221,9 +28223,9 @@ function forkSession(input) {
28221
28223
  }
28222
28224
  forkedLines.push(JSON.stringify(forked));
28223
28225
  }
28224
- const forkedFilePath = import_node_path24.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
28225
- import_node_fs22.default.mkdirSync(projectDir, { recursive: true });
28226
- import_node_fs22.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
28226
+ const forkedFilePath = import_node_path25.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
28227
+ import_node_fs23.default.mkdirSync(projectDir, { recursive: true });
28228
+ import_node_fs23.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
28227
28229
  return { forkedToolSessionId, forkedFilePath };
28228
28230
  }
28229
28231
 
@@ -28544,7 +28546,7 @@ function buildPermissionHandlers(deps) {
28544
28546
  }
28545
28547
 
28546
28548
  // src/handlers/history.ts
28547
- var path34 = __toESM(require("path"), 1);
28549
+ var path35 = __toESM(require("path"), 1);
28548
28550
  init_protocol();
28549
28551
 
28550
28552
  // src/session/recent-dirs.ts
@@ -28562,7 +28564,7 @@ function listRecentDirs(store, limit = 50) {
28562
28564
  }
28563
28565
 
28564
28566
  // src/permission/persona-paths.ts
28565
- var path33 = __toESM(require("path"), 1);
28567
+ var path34 = __toESM(require("path"), 1);
28566
28568
  function getAllowedPersonaIds(grants, action) {
28567
28569
  const ids = /* @__PURE__ */ new Set();
28568
28570
  for (const g2 of grants) {
@@ -28575,26 +28577,26 @@ function getAllowedPersonaIds(grants, action) {
28575
28577
  return ids;
28576
28578
  }
28577
28579
  function isGuestPathAllowed(grants, absPath, personaRoot, action = "read") {
28578
- const root = path33.resolve(personaRoot);
28579
- const target = path33.resolve(absPath);
28580
- const sep3 = root.endsWith(path33.sep) ? "" : path33.sep;
28580
+ const root = path34.resolve(personaRoot);
28581
+ const target = path34.resolve(absPath);
28582
+ const sep3 = root.endsWith(path34.sep) ? "" : path34.sep;
28581
28583
  if (!target.startsWith(root + sep3)) return false;
28582
- const rel = path33.relative(root, target);
28584
+ const rel = path34.relative(root, target);
28583
28585
  if (!rel || rel.startsWith("..")) return false;
28584
- const personaId = rel.split(path33.sep)[0];
28586
+ const personaId = rel.split(path34.sep)[0];
28585
28587
  if (!personaId) return false;
28586
28588
  const allowed = getAllowedPersonaIds(grants, action);
28587
28589
  if (allowed === "*") return true;
28588
28590
  return allowed.has(personaId);
28589
28591
  }
28590
28592
  function personaIdFromPath(absPath, personaRoot) {
28591
- const root = path33.resolve(personaRoot);
28592
- const target = path33.resolve(absPath);
28593
- const sep3 = root.endsWith(path33.sep) ? "" : path33.sep;
28593
+ const root = path34.resolve(personaRoot);
28594
+ const target = path34.resolve(absPath);
28595
+ const sep3 = root.endsWith(path34.sep) ? "" : path34.sep;
28594
28596
  if (!target.startsWith(root + sep3)) return null;
28595
- const rel = path33.relative(root, target);
28597
+ const rel = path34.relative(root, target);
28596
28598
  if (!rel || rel.startsWith("..")) return null;
28597
- const id = rel.split(path33.sep)[0];
28599
+ const id = rel.split(path34.sep)[0];
28598
28600
  return id || null;
28599
28601
  }
28600
28602
 
@@ -28619,7 +28621,7 @@ function buildHistoryHandlers(deps) {
28619
28621
  if (!pid) return false;
28620
28622
  return isGuestPathAllowed(
28621
28623
  ctx.grants,
28622
- path34.join(personaRoot, pid),
28624
+ path35.join(personaRoot, pid),
28623
28625
  personaRoot,
28624
28626
  "read"
28625
28627
  );
@@ -28630,7 +28632,7 @@ function buildHistoryHandlers(deps) {
28630
28632
  };
28631
28633
  const list = async (frame, _client, ctx) => {
28632
28634
  const args = HistoryListArgs.parse(frame);
28633
- assertGuestPath(ctx, path34.resolve(args.projectPath), personaRoot, "history:list");
28635
+ assertGuestPath(ctx, path35.resolve(args.projectPath), personaRoot, "history:list");
28634
28636
  const sessions = await history.listSessions(args);
28635
28637
  return { response: { type: "history:list", sessions } };
28636
28638
  };
@@ -28662,13 +28664,13 @@ function buildHistoryHandlers(deps) {
28662
28664
  };
28663
28665
  const subagents = async (frame, _client, ctx) => {
28664
28666
  const args = HistorySubagentsArgs.parse(frame);
28665
- assertGuestPath(ctx, path34.resolve(args.cwd), personaRoot, "history:subagents");
28667
+ assertGuestPath(ctx, path35.resolve(args.cwd), personaRoot, "history:subagents");
28666
28668
  const subs = await history.listSubagents(args);
28667
28669
  return { response: { type: "history:subagents", subagents: subs } };
28668
28670
  };
28669
28671
  const subagentRead = async (frame, _client, ctx) => {
28670
28672
  const args = HistorySubagentReadArgs.parse(frame);
28671
- assertGuestPath(ctx, path34.resolve(args.cwd), personaRoot, "history:subagent-read");
28673
+ assertGuestPath(ctx, path35.resolve(args.cwd), personaRoot, "history:subagent-read");
28672
28674
  const res = await history.readSubagent(args);
28673
28675
  return { response: { type: "history:subagent-read", ...res } };
28674
28676
  };
@@ -28676,7 +28678,7 @@ function buildHistoryHandlers(deps) {
28676
28678
  const dirs = listRecentDirs(store);
28677
28679
  if (ctx?.principal.kind === "guest" && personaRoot) {
28678
28680
  const filtered = dirs.filter(
28679
- (d) => isGuestPathAllowed(ctx.grants, path34.resolve(d.cwd), personaRoot, "read")
28681
+ (d) => isGuestPathAllowed(ctx.grants, path35.resolve(d.cwd), personaRoot, "read")
28680
28682
  );
28681
28683
  return { response: { type: "history:recentDirs", dirs: filtered } };
28682
28684
  }
@@ -28693,7 +28695,7 @@ function buildHistoryHandlers(deps) {
28693
28695
  }
28694
28696
 
28695
28697
  // src/handlers/workspace.ts
28696
- var path35 = __toESM(require("path"), 1);
28698
+ var path36 = __toESM(require("path"), 1);
28697
28699
  var os13 = __toESM(require("os"), 1);
28698
28700
  init_protocol();
28699
28701
  init_protocol();
@@ -28734,22 +28736,22 @@ function buildWorkspaceHandlers(deps) {
28734
28736
  const args = WorkspaceListArgs.parse(frame);
28735
28737
  const isGuest = ctx?.principal.kind === "guest";
28736
28738
  const fallbackCwd = isGuest && personaRoot ? personaRoot : os13.homedir();
28737
- const resolvedCwd = path35.resolve(args.cwd ?? fallbackCwd);
28738
- const target = args.path ? path35.resolve(resolvedCwd, args.path) : resolvedCwd;
28739
+ const resolvedCwd = path36.resolve(args.cwd ?? fallbackCwd);
28740
+ const target = args.path ? path36.resolve(resolvedCwd, args.path) : resolvedCwd;
28739
28741
  assertGuestPath2(ctx, target, personaRoot, "workspace:list");
28740
28742
  const res = workspace.list({ ...args, cwd: resolvedCwd });
28741
28743
  return { response: { type: "workspace:list", ...res } };
28742
28744
  };
28743
28745
  const read = async (frame, _client, ctx) => {
28744
28746
  const args = WorkspaceReadArgs.parse(frame);
28745
- const target = path35.isAbsolute(args.path) ? path35.resolve(args.path) : path35.resolve(args.cwd, args.path);
28747
+ const target = path36.isAbsolute(args.path) ? path36.resolve(args.path) : path36.resolve(args.cwd, args.path);
28746
28748
  assertGuestPath2(ctx, target, personaRoot, "workspace:read");
28747
28749
  const res = workspace.read(args);
28748
28750
  return { response: { type: "workspace:read", ...res } };
28749
28751
  };
28750
28752
  const skillsList = async (frame, _client, ctx) => {
28751
28753
  const args = SkillsListArgs.parse(frame);
28752
- const cwdAbs = path35.resolve(args.cwd);
28754
+ const cwdAbs = path36.resolve(args.cwd);
28753
28755
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
28754
28756
  const list2 = skills.list(args);
28755
28757
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -28761,7 +28763,7 @@ function buildWorkspaceHandlers(deps) {
28761
28763
  };
28762
28764
  const agentsList = async (frame, _client, ctx) => {
28763
28765
  const args = AgentsListArgs.parse(frame);
28764
- const cwdAbs = path35.resolve(args.cwd);
28766
+ const cwdAbs = path36.resolve(args.cwd);
28765
28767
  assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
28766
28768
  const list2 = agents.list(args);
28767
28769
  if (ctx?.principal.kind === "guest" && personaRoot) {
@@ -28780,20 +28782,20 @@ function buildWorkspaceHandlers(deps) {
28780
28782
  }
28781
28783
 
28782
28784
  // src/handlers/git.ts
28783
- var path37 = __toESM(require("path"), 1);
28785
+ var path38 = __toESM(require("path"), 1);
28784
28786
  init_protocol();
28785
28787
  init_protocol();
28786
28788
 
28787
28789
  // src/workspace/git.ts
28788
28790
  var import_node_child_process6 = require("child_process");
28789
- var import_node_fs23 = __toESM(require("fs"), 1);
28790
- var import_node_path25 = __toESM(require("path"), 1);
28791
+ var import_node_fs24 = __toESM(require("fs"), 1);
28792
+ var import_node_path26 = __toESM(require("path"), 1);
28791
28793
  var import_node_util = require("util");
28792
28794
  var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
28793
28795
  function normalizePath(p2) {
28794
- const resolved = import_node_path25.default.resolve(p2);
28796
+ const resolved = import_node_path26.default.resolve(p2);
28795
28797
  try {
28796
- return import_node_fs23.default.realpathSync(resolved);
28798
+ return import_node_fs24.default.realpathSync(resolved);
28797
28799
  } catch {
28798
28800
  return resolved;
28799
28801
  }
@@ -28866,7 +28868,7 @@ async function listGitBranches(cwd) {
28866
28868
  // src/handlers/git.ts
28867
28869
  function assertGuestCwd(ctx, cwd, personaRoot, method) {
28868
28870
  if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
28869
- if (!isGuestPathAllowed(ctx.grants, path37.resolve(cwd), personaRoot, "read")) {
28871
+ if (!isGuestPathAllowed(ctx.grants, path38.resolve(cwd), personaRoot, "read")) {
28870
28872
  throw new ClawdError(
28871
28873
  ERROR_CODES.UNAUTHORIZED,
28872
28874
  `guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
@@ -28921,27 +28923,7 @@ var DeleteArgsSchema = external_exports.object({
28921
28923
  capabilityId: external_exports.string().min(1)
28922
28924
  }).strict();
28923
28925
  function buildCapabilityHandlers(deps) {
28924
- const { manager, getShareBaseUrl } = deps;
28925
- const issue = async (frame) => {
28926
- const { type: _type, requestId: _requestId, ...rest } = frame;
28927
- const args = CapabilityIssueArgsSchema.parse(rest);
28928
- const { token, capability } = manager.issue({
28929
- displayName: args.displayName,
28930
- grants: args.grants,
28931
- ...args.expiresAt !== void 0 ? { expiresAt: args.expiresAt } : {},
28932
- ...args.maxUses !== void 0 ? { maxUses: args.maxUses } : {}
28933
- });
28934
- const base = getShareBaseUrl().replace(/\/$/, "");
28935
- const shareUrl = `${base}/?token=${encodeURIComponent(token)}`;
28936
- return {
28937
- response: {
28938
- type: "capability:issued",
28939
- token,
28940
- shareUrl,
28941
- capability: stripSecretHash(capability)
28942
- }
28943
- };
28944
- };
28926
+ const { manager, getShareBaseUrl, getPersonalCapability } = deps;
28945
28927
  const list = async () => {
28946
28928
  return {
28947
28929
  response: {
@@ -28967,30 +28949,21 @@ function buildCapabilityHandlers(deps) {
28967
28949
  }
28968
28950
  };
28969
28951
  };
28970
- const bindPeer = async (frame) => {
28971
- const { type: _type, requestId: _requestId, ...rest } = frame;
28972
- const args = CapabilityBindPeerArgsSchema.parse(rest);
28973
- try {
28974
- manager.recordPeerHello(args.capabilityId, {
28975
- ownerPrincipalId: args.peerOwnerId,
28976
- displayName: args.peerDisplayName,
28977
- now: Date.now()
28978
- });
28979
- } catch (e) {
28980
- throw new ClawdError(
28981
- ERROR_CODES.VALIDATION_ERROR,
28982
- `capability:bindPeer: ${e.message}`
28983
- );
28984
- }
28952
+ const personalCapGet = async () => {
28953
+ const { token, capability } = getPersonalCapability();
28985
28954
  return {
28986
- response: { type: "capability:bindPeer:ok", capabilityId: args.capabilityId }
28955
+ response: {
28956
+ type: "personal-cap:get:ok",
28957
+ token,
28958
+ capability: stripSecretHash(capability),
28959
+ shareBaseUrl: getShareBaseUrl()
28960
+ }
28987
28961
  };
28988
28962
  };
28989
28963
  return {
28990
- "capability:issue": issue,
28991
28964
  "capability:list": list,
28992
28965
  "capability:delete": del,
28993
- "capability:bindPeer": bindPeer
28966
+ "personal-cap:get": personalCapGet
28994
28967
  };
28995
28968
  }
28996
28969
 
@@ -29009,20 +28982,24 @@ function resolvePeerOwnerId(ctx, argsPeerOwnerId, capManager) {
29009
28982
  if (!ctx.capabilityId) {
29010
28983
  throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "inbox: guest ctx missing capabilityId");
29011
28984
  }
29012
- const cap = capManager.findById(ctx.capabilityId);
29013
- if (!cap?.peerOwnerId) {
28985
+ let resolved = ctx.peerOwnerPrincipalId;
28986
+ if (!resolved) {
28987
+ const cap = capManager.findById(ctx.capabilityId);
28988
+ resolved = cap?.peerOwnerId;
28989
+ }
28990
+ if (!resolved) {
29014
28991
  throw new ClawdError(
29015
28992
  ERROR_CODES.UNAUTHORIZED,
29016
- `inbox: guest cap ${ctx.capabilityId} has no peerOwnerId (recordPeerHello not yet)`
28993
+ `inbox: guest cap ${ctx.capabilityId} has no peerOwnerPrincipalId (auth frame missing selfPrincipalId)`
29017
28994
  );
29018
28995
  }
29019
- if (argsPeerOwnerId && argsPeerOwnerId !== cap.peerOwnerId) {
28996
+ if (argsPeerOwnerId && argsPeerOwnerId !== resolved) {
29020
28997
  throw new ClawdError(
29021
28998
  ERROR_CODES.UNAUTHORIZED,
29022
- `inbox: guest args.peerOwnerId mismatch (cap.peerOwnerId=${cap.peerOwnerId}, args=${argsPeerOwnerId})`
28999
+ `inbox: guest args.peerOwnerId mismatch (resolved=${resolved}, args=${argsPeerOwnerId})`
29023
29000
  );
29024
29001
  }
29025
- return cap.peerOwnerId;
29002
+ return resolved;
29026
29003
  }
29027
29004
  function buildInboxHandlers(deps) {
29028
29005
  const { manager, capManager } = deps;
@@ -29378,7 +29355,7 @@ function buildPersonaHandlers(deps) {
29378
29355
  }
29379
29356
 
29380
29357
  // src/handlers/attachment.ts
29381
- var import_node_path26 = __toESM(require("path"), 1);
29358
+ var import_node_path27 = __toESM(require("path"), 1);
29382
29359
  init_protocol();
29383
29360
  init_protocol();
29384
29361
  var DEFAULT_TTL_SECONDS = 24 * 3600;
@@ -29432,12 +29409,12 @@ function buildAttachmentHandlers(deps) {
29432
29409
  `session ${args.sessionId} scope unresolved`
29433
29410
  );
29434
29411
  }
29435
- const cwdAbs = import_node_path26.default.resolve(sessionFile.cwd);
29436
- const candidateAbs = import_node_path26.default.isAbsolute(args.relPath) ? import_node_path26.default.resolve(args.relPath) : import_node_path26.default.resolve(cwdAbs, args.relPath);
29412
+ const cwdAbs = import_node_path27.default.resolve(sessionFile.cwd);
29413
+ const candidateAbs = import_node_path27.default.isAbsolute(args.relPath) ? import_node_path27.default.resolve(args.relPath) : import_node_path27.default.resolve(cwdAbs, args.relPath);
29437
29414
  assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
29438
29415
  const entries = deps.groupFileStore.list(scope, args.sessionId);
29439
29416
  const entry = entries.find((e) => {
29440
- const storedAbs = import_node_path26.default.isAbsolute(e.relPath) ? import_node_path26.default.resolve(e.relPath) : import_node_path26.default.resolve(cwdAbs, e.relPath);
29417
+ const storedAbs = import_node_path27.default.isAbsolute(e.relPath) ? import_node_path27.default.resolve(e.relPath) : import_node_path27.default.resolve(cwdAbs, e.relPath);
29441
29418
  return storedAbs === candidateAbs && !e.stale;
29442
29419
  });
29443
29420
  if (!entry) {
@@ -29461,7 +29438,7 @@ function buildAttachmentHandlers(deps) {
29461
29438
  if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
29462
29439
  const f = deps.sessionStore.read(sessionId);
29463
29440
  if (!f) return;
29464
- assertGuestAttachmentPath(ctx, import_node_path26.default.resolve(f.cwd), deps.personaRoot, method);
29441
+ assertGuestAttachmentPath(ctx, import_node_path27.default.resolve(f.cwd), deps.personaRoot, method);
29465
29442
  }
29466
29443
  const groupAdd = async (frame, _client, ctx) => {
29467
29444
  if (!deps.groupFileStore || !deps.getSessionScope) {
@@ -29547,7 +29524,8 @@ function buildMethodHandlers(deps) {
29547
29524
  }),
29548
29525
  ...buildCapabilityHandlers({
29549
29526
  manager: deps.capabilityManager,
29550
- getShareBaseUrl: deps.getShareBaseUrl
29527
+ getShareBaseUrl: deps.getShareBaseUrl,
29528
+ getPersonalCapability: deps.getPersonalCapability
29551
29529
  }),
29552
29530
  ...buildInboxHandlers({
29553
29531
  manager: deps.inboxManager,
@@ -29585,11 +29563,12 @@ var METHOD_GRANT_MAP = {
29585
29563
  // handler 内部按 ctx.principal.kind 决定返回 "合成 owner self capability" 还是
29586
29564
  // "查 capabilityManager 拿 caller 的 guest capability"。
29587
29565
  "whoami": { kind: "public" },
29588
- // ---- capability platform(admin-only,本 PR 新增) ----
29589
- "capability:issue": ADMIN_ANY,
29566
+ // ---- capability platform(admin-only ----
29567
+ // global personal token (2026-05-25): capability:issue / bindPeer 已下线;
29568
+ // personal capability 由 daemon 启动时自动创建,personal-cap:get 是 owner-only 拿 token + shareBaseUrl
29590
29569
  "capability:list": ADMIN_ANY,
29591
29570
  "capability:delete": ADMIN_ANY,
29592
- "capability:bindPeer": ADMIN_ANY,
29571
+ "personal-cap:get": ADMIN_ANY,
29593
29572
  // ---- inbox: channel-based IM (capability platform v3) ----
29594
29573
  // 三条都 'public' — capability 本身就是授权凭证. handler 内额外校验
29595
29574
  // guest ctx.capabilityId === args.capabilityId, 防 guest 越权操作别的 channel.
@@ -29690,7 +29669,7 @@ function computeGrantForFrame(method, frame) {
29690
29669
  async function startDaemon(config) {
29691
29670
  const logger = createLogger({
29692
29671
  level: config.logLevel,
29693
- file: import_node_path27.default.join(config.dataDir, "clawd.log")
29672
+ file: import_node_path28.default.join(config.dataDir, "clawd.log")
29694
29673
  });
29695
29674
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
29696
29675
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -29719,14 +29698,9 @@ async function startDaemon(config) {
29719
29698
  receivedCapabilityStore.load();
29720
29699
  const capabilityStore = new CapabilityStore(config.dataDir);
29721
29700
  const capabilityRegistry = new CapabilityRegistry(capabilityStore);
29701
+ const personalCapability = loadOrCreatePersonalCapability({ dataDir: config.dataDir });
29702
+ capabilityRegistry.upsertCapability(personalCapability.capability);
29722
29703
  const capabilityManager = new CapabilityManager(capabilityRegistry, {
29723
- onIssued: (cap, token) => {
29724
- wsServer?.broadcastToOwners({
29725
- type: "capability:tokenIssued",
29726
- capability: stripSecretHash(cap),
29727
- token
29728
- });
29729
- },
29730
29704
  onDeleted: (cap) => {
29731
29705
  const deletedAt = Date.now();
29732
29706
  wsServer?.broadcastToOwners({
@@ -29758,14 +29732,7 @@ async function startDaemon(config) {
29758
29732
  ownerDisplayName,
29759
29733
  capabilityRegistry,
29760
29734
  selfPrincipalId,
29761
- selfDisplayName,
29762
- onGuestHello: (capId, ownerId, name) => {
29763
- capabilityManager.recordPeerHello(capId, {
29764
- ownerPrincipalId: ownerId,
29765
- displayName: name,
29766
- now: Date.now()
29767
- });
29768
- }
29735
+ selfDisplayName
29769
29736
  });
29770
29737
  },
29771
29738
  onAuthed: (h, ctx) => wsServer?.attachClientContext(h.id, ctx),
@@ -29789,7 +29756,7 @@ async function startDaemon(config) {
29789
29756
  const agents = new AgentsScanner();
29790
29757
  const history = new ClaudeHistoryReader();
29791
29758
  let transport = null;
29792
- const personaStore = new PersonaStore(import_node_path27.default.join(config.dataDir, "personas"));
29759
+ const personaStore = new PersonaStore(import_node_path28.default.join(config.dataDir, "personas"));
29793
29760
  const defaultsRoot = findDefaultsRoot();
29794
29761
  if (defaultsRoot) {
29795
29762
  seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
@@ -29806,7 +29773,7 @@ async function startDaemon(config) {
29806
29773
  getAdapter,
29807
29774
  historyReader: history,
29808
29775
  dataDir: config.dataDir,
29809
- personaRoot: import_node_path27.default.join(config.dataDir, "personas"),
29776
+ personaRoot: import_node_path28.default.join(config.dataDir, "personas"),
29810
29777
  personaStore,
29811
29778
  ownerDisplayName,
29812
29779
  ownerPrincipalId,
@@ -29830,10 +29797,10 @@ async function startDaemon(config) {
29830
29797
  // 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
29831
29798
  attachmentGroup: {
29832
29799
  onFileEdit: (input) => {
29833
- const absPath = import_node_path27.default.isAbsolute(input.relPath) ? input.relPath : import_node_path27.default.join(input.cwd, input.relPath);
29800
+ const absPath = import_node_path28.default.isAbsolute(input.relPath) ? input.relPath : import_node_path28.default.join(input.cwd, input.relPath);
29834
29801
  let size = 0;
29835
29802
  try {
29836
- size = import_node_fs24.default.statSync(absPath).size;
29803
+ size = import_node_fs25.default.statSync(absPath).size;
29837
29804
  } catch (err) {
29838
29805
  logger.warn("attachment.onFileEdit stat failed", {
29839
29806
  sessionId: input.sessionId,
@@ -29946,15 +29913,17 @@ async function startDaemon(config) {
29946
29913
  // 'persona/<pid>/owner',default 走 'default'。
29947
29914
  getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
29948
29915
  // guest path guard:candidate 必须在 personaRoot 子树下
29949
- personaRoot: import_node_path27.default.join(config.dataDir, "personas")
29916
+ personaRoot: import_node_path28.default.join(config.dataDir, "personas")
29950
29917
  },
29951
29918
  // workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
29952
- personaRoot: import_node_path27.default.join(config.dataDir, "personas"),
29953
- // Task 1.9: capability:issue/list/revoke handler 依赖
29919
+ personaRoot: import_node_path28.default.join(config.dataDir, "personas"),
29920
+ // capability:list / delete handler 依赖
29954
29921
  capabilityManager,
29955
- // v2 Phase 5: capability:issue 返回的 shareUrl 用此 base URL 拼接。
29922
+ // personal-cap:get 返回的 shareBaseUrl 用此 base URL
29956
29923
  // tunnel 拉起后切到反代 wss://... 地址;否则本机 ws://host:port。
29957
29924
  getShareBaseUrl: () => currentTunnelUrl ?? `ws://${config.host}:${config.port}`,
29925
+ // global personal token (2026-05-25): personal-cap:get handler 直接返回此 token + cap
29926
+ getPersonalCapability: () => personalCapability,
29958
29927
  // v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
29959
29928
  ownerDisplayName,
29960
29929
  // owner-id stabilization: whoami 用稳定 ownerPrincipalId 替代 'owner' 字面量
@@ -30010,23 +29979,14 @@ async function startDaemon(config) {
30010
29979
  // 用 cap token 连 noAuth daemon 时若无此 hook 会 fallback owner ctx, whoami 错返
30011
29980
  // capability.id = ownerPrincipalId, 导致 myCapabilityId 写错 → inbox channel 写错.
30012
29981
  // 命中 cap → attach guest ctx; 空 token / 未命中 → 保持 noAuth 行为 (handler fallback owner).
30013
- tryVerifyCapabilityToken: (token, selfPrincipalId, selfDisplayName) => {
29982
+ tryVerifyCapabilityToken: (token, selfPrincipalId, _selfDisplayName) => {
30014
29983
  const v2 = capabilityRegistry.verifyToken(token);
30015
29984
  if (!v2.ok) return null;
30016
- if (selfPrincipalId && selfDisplayName) {
30017
- try {
30018
- capabilityManager.recordPeerHello(v2.capability.id, {
30019
- ownerPrincipalId: selfPrincipalId,
30020
- displayName: selfDisplayName,
30021
- now: Date.now()
30022
- });
30023
- } catch {
30024
- }
30025
- }
30026
29985
  return {
30027
29986
  principal: { id: v2.capability.id, kind: "guest", displayName: v2.capability.displayName },
30028
29987
  grants: v2.capability.grants,
30029
- capabilityId: v2.capability.id
29988
+ capabilityId: v2.capability.id,
29989
+ ...selfPrincipalId ? { peerOwnerPrincipalId: selfPrincipalId } : {}
30030
29990
  };
30031
29991
  },
30032
29992
  // file-sharing HTTP 路由复用 daemon 同端口(spec §5 第 3 条);router 自己处理 auth + 404
@@ -30157,8 +30117,8 @@ async function startDaemon(config) {
30157
30117
  const lines = [
30158
30118
  `Tunnel: ${r.url}`,
30159
30119
  ...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
30160
- `Frpc config: ${import_node_path27.default.join(config.dataDir, "frpc.toml")}`,
30161
- `Frpc log: ${import_node_path27.default.join(config.dataDir, "frpc.log")}`
30120
+ `Frpc config: ${import_node_path28.default.join(config.dataDir, "frpc.toml")}`,
30121
+ `Frpc log: ${import_node_path28.default.join(config.dataDir, "frpc.log")}`
30162
30122
  ];
30163
30123
  const width = Math.max(...lines.map((l) => l.length));
30164
30124
  const bar = "\u2550".repeat(width + 4);
@@ -30171,8 +30131,8 @@ ${bar}
30171
30131
 
30172
30132
  `);
30173
30133
  try {
30174
- const connectPath = import_node_path27.default.join(config.dataDir, "connect.txt");
30175
- import_node_fs24.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
30134
+ const connectPath = import_node_path28.default.join(config.dataDir, "connect.txt");
30135
+ import_node_fs25.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
30176
30136
  } catch {
30177
30137
  }
30178
30138
  } catch (err) {
@@ -30216,9 +30176,9 @@ ${bar}
30216
30176
  };
30217
30177
  }
30218
30178
  function migrateDropPersonsDir(dataDir) {
30219
- const dir = import_node_path27.default.join(dataDir, "persons");
30179
+ const dir = import_node_path28.default.join(dataDir, "persons");
30220
30180
  try {
30221
- import_node_fs24.default.rmSync(dir, { recursive: true, force: true });
30181
+ import_node_fs25.default.rmSync(dir, { recursive: true, force: true });
30222
30182
  } catch {
30223
30183
  }
30224
30184
  }