@clawos-dev/clawd 0.2.71-beta.125.4951782 → 0.2.71-beta.126.06f4cfa

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 +435 -133
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -121,11 +121,18 @@ var init_methods = __esm({
121
121
  "capability:issue",
122
122
  "capability:list",
123
123
  "capability:revoke",
124
- // ---- inbox:* (capability platform Phase 3 跨用户通知) ----
125
- // owner 接 guest 的 cross-principal 消息事件. 当前 Phase 3 仅 owner 调 (admin-only),
126
- // Phase 4 DM 真接通后 guest 也能调 inbox:postMessage (本批次不加 postMessage).
124
+ // ---- inbox:* (capability platform Phase 3 跨用户通知 + Phase 4 DM) ----
125
+ // owner 接 guest 的 cross-principal 消息事件 + DM 双向私聊.
126
+ // inbox:list / markRead: admin-only (Phase 3); inbox:postMessage: DM 自带能力,
127
+ // 任何 principal (owner/guest) 可调 (Phase 4).
127
128
  "inbox:list",
128
129
  "inbox:markRead",
130
+ "inbox:postMessage",
131
+ // ---- remote-persona:* (Phase 4 远程 persona, v1 仅本地存储, 不接 outgoing WS) ----
132
+ // owner 添加 / 列出 / 删除远程 persona 入口. admin-only.
133
+ "remote-persona:add",
134
+ "remote-persona:list",
135
+ "remote-persona:remove",
129
136
  "info",
130
137
  "ping"
131
138
  ];
@@ -617,8 +624,8 @@ var init_parseUtil = __esm({
617
624
  init_errors2();
618
625
  init_en();
619
626
  makeIssue = (params) => {
620
- const { data, path: path36, errorMaps, issueData } = params;
621
- const fullPath = [...path36, ...issueData.path || []];
627
+ const { data, path: path37, errorMaps, issueData } = params;
628
+ const fullPath = [...path37, ...issueData.path || []];
622
629
  const fullIssue = {
623
630
  ...issueData,
624
631
  path: fullPath
@@ -929,11 +936,11 @@ var init_types = __esm({
929
936
  init_parseUtil();
930
937
  init_util();
931
938
  ParseInputLazyPath = class {
932
- constructor(parent, value, path36, key) {
939
+ constructor(parent, value, path37, key) {
933
940
  this._cachedPath = [];
934
941
  this.parent = parent;
935
942
  this.data = value;
936
- this._path = path36;
943
+ this._path = path37;
937
944
  this._key = key;
938
945
  }
939
946
  get path() {
@@ -5118,7 +5125,7 @@ var init_capability = __esm({
5118
5125
  });
5119
5126
 
5120
5127
  // ../protocol/src/inbox.ts
5121
- var INBOX_EVENT_KIND_VALUES, InboxEventKindSchema, INBOX_PREVIEW_MAX_LENGTH, InboxEventSchema, InboxListArgsSchema, InboxMarkReadArgsSchema;
5128
+ var INBOX_EVENT_KIND_VALUES, InboxEventKindSchema, INBOX_PREVIEW_MAX_LENGTH, InboxEventSchema, InboxListArgsSchema, InboxMarkReadArgsSchema, InboxPostMessageArgsSchema;
5122
5129
  var init_inbox = __esm({
5123
5130
  "../protocol/src/inbox.ts"() {
5124
5131
  "use strict";
@@ -5148,6 +5155,45 @@ var init_inbox = __esm({
5148
5155
  InboxMarkReadArgsSchema = external_exports.object({
5149
5156
  eventId: external_exports.string().min(1)
5150
5157
  }).strict();
5158
+ InboxPostMessageArgsSchema = external_exports.object({
5159
+ peerPrincipalId: external_exports.string().min(1),
5160
+ text: external_exports.string().min(1).max(INBOX_PREVIEW_MAX_LENGTH)
5161
+ }).strict();
5162
+ }
5163
+ });
5164
+
5165
+ // ../protocol/src/remote-persona.ts
5166
+ function stripRemotePersonaSecret(rp) {
5167
+ const { capabilityToken: _t, ...wire } = rp;
5168
+ return wire;
5169
+ }
5170
+ var RemotePersonaSchema, RemotePersonaWireSchema, RemotePersonaAddArgsSchema, RemotePersonaRemoveArgsSchema;
5171
+ var init_remote_persona = __esm({
5172
+ "../protocol/src/remote-persona.ts"() {
5173
+ "use strict";
5174
+ init_zod();
5175
+ RemotePersonaSchema = external_exports.object({
5176
+ alias: external_exports.string().min(1),
5177
+ remoteUrl: external_exports.string().min(1),
5178
+ capabilityToken: external_exports.string().min(1),
5179
+ remotePersonaId: external_exports.string().min(1),
5180
+ remoteDisplayName: external_exports.string(),
5181
+ ownerDisplayName: external_exports.string().optional(),
5182
+ addedAt: external_exports.number().int().nonnegative(),
5183
+ lastConnectedAt: external_exports.number().int().positive().optional()
5184
+ }).strict();
5185
+ RemotePersonaWireSchema = RemotePersonaSchema.omit({ capabilityToken: true });
5186
+ RemotePersonaAddArgsSchema = external_exports.object({
5187
+ alias: external_exports.string().min(1),
5188
+ remoteUrl: external_exports.string().min(1),
5189
+ capabilityToken: external_exports.string().min(1),
5190
+ remotePersonaId: external_exports.string().min(1),
5191
+ remoteDisplayName: external_exports.string(),
5192
+ ownerDisplayName: external_exports.string().optional()
5193
+ }).strict();
5194
+ RemotePersonaRemoveArgsSchema = external_exports.object({
5195
+ alias: external_exports.string().min(1)
5196
+ }).strict();
5151
5197
  }
5152
5198
  });
5153
5199
 
@@ -5166,6 +5212,7 @@ var init_runtime = __esm({
5166
5212
  init_principal();
5167
5213
  init_capability();
5168
5214
  init_inbox();
5215
+ init_remote_persona();
5169
5216
  }
5170
5217
  });
5171
5218
 
@@ -5440,8 +5487,8 @@ var require_req = __commonJS({
5440
5487
  if (req.originalUrl) {
5441
5488
  _req.url = req.originalUrl;
5442
5489
  } else {
5443
- const path36 = req.path;
5444
- _req.url = typeof path36 === "string" ? path36 : req.url ? req.url.path || req.url : void 0;
5490
+ const path37 = req.path;
5491
+ _req.url = typeof path37 === "string" ? path37 : req.url ? req.url.path || req.url : void 0;
5445
5492
  }
5446
5493
  if (req.query) {
5447
5494
  _req.query = req.query;
@@ -5606,14 +5653,14 @@ var require_redact = __commonJS({
5606
5653
  }
5607
5654
  return obj;
5608
5655
  }
5609
- function parsePath(path36) {
5656
+ function parsePath(path37) {
5610
5657
  const parts = [];
5611
5658
  let current = "";
5612
5659
  let inBrackets = false;
5613
5660
  let inQuotes = false;
5614
5661
  let quoteChar = "";
5615
- for (let i = 0; i < path36.length; i++) {
5616
- const char = path36[i];
5662
+ for (let i = 0; i < path37.length; i++) {
5663
+ const char = path37[i];
5617
5664
  if (!inBrackets && char === ".") {
5618
5665
  if (current) {
5619
5666
  parts.push(current);
@@ -5744,10 +5791,10 @@ var require_redact = __commonJS({
5744
5791
  return current;
5745
5792
  }
5746
5793
  function redactPaths(obj, paths, censor, remove = false) {
5747
- for (const path36 of paths) {
5748
- const parts = parsePath(path36);
5794
+ for (const path37 of paths) {
5795
+ const parts = parsePath(path37);
5749
5796
  if (parts.includes("*")) {
5750
- redactWildcardPath(obj, parts, censor, path36, remove);
5797
+ redactWildcardPath(obj, parts, censor, path37, remove);
5751
5798
  } else {
5752
5799
  if (remove) {
5753
5800
  removeKey(obj, parts);
@@ -5832,8 +5879,8 @@ var require_redact = __commonJS({
5832
5879
  }
5833
5880
  } else {
5834
5881
  if (afterWildcard.includes("*")) {
5835
- const wrappedCensor = typeof censor === "function" ? (value, path36) => {
5836
- const fullPath = [...pathArray.slice(0, pathLength), ...path36];
5882
+ const wrappedCensor = typeof censor === "function" ? (value, path37) => {
5883
+ const fullPath = [...pathArray.slice(0, pathLength), ...path37];
5837
5884
  return censor(value, fullPath);
5838
5885
  } : censor;
5839
5886
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -5868,8 +5915,8 @@ var require_redact = __commonJS({
5868
5915
  return null;
5869
5916
  }
5870
5917
  const pathStructure = /* @__PURE__ */ new Map();
5871
- for (const path36 of pathsToClone) {
5872
- const parts = parsePath(path36);
5918
+ for (const path37 of pathsToClone) {
5919
+ const parts = parsePath(path37);
5873
5920
  let current = pathStructure;
5874
5921
  for (let i = 0; i < parts.length; i++) {
5875
5922
  const part = parts[i];
@@ -5921,24 +5968,24 @@ var require_redact = __commonJS({
5921
5968
  }
5922
5969
  return cloneSelectively(obj, pathStructure);
5923
5970
  }
5924
- function validatePath(path36) {
5925
- if (typeof path36 !== "string") {
5971
+ function validatePath(path37) {
5972
+ if (typeof path37 !== "string") {
5926
5973
  throw new Error("Paths must be (non-empty) strings");
5927
5974
  }
5928
- if (path36 === "") {
5975
+ if (path37 === "") {
5929
5976
  throw new Error("Invalid redaction path ()");
5930
5977
  }
5931
- if (path36.includes("..")) {
5932
- throw new Error(`Invalid redaction path (${path36})`);
5978
+ if (path37.includes("..")) {
5979
+ throw new Error(`Invalid redaction path (${path37})`);
5933
5980
  }
5934
- if (path36.includes(",")) {
5935
- throw new Error(`Invalid redaction path (${path36})`);
5981
+ if (path37.includes(",")) {
5982
+ throw new Error(`Invalid redaction path (${path37})`);
5936
5983
  }
5937
5984
  let bracketCount = 0;
5938
5985
  let inQuotes = false;
5939
5986
  let quoteChar = "";
5940
- for (let i = 0; i < path36.length; i++) {
5941
- const char = path36[i];
5987
+ for (let i = 0; i < path37.length; i++) {
5988
+ const char = path37[i];
5942
5989
  if ((char === '"' || char === "'") && bracketCount > 0) {
5943
5990
  if (!inQuotes) {
5944
5991
  inQuotes = true;
@@ -5952,20 +5999,20 @@ var require_redact = __commonJS({
5952
5999
  } else if (char === "]" && !inQuotes) {
5953
6000
  bracketCount--;
5954
6001
  if (bracketCount < 0) {
5955
- throw new Error(`Invalid redaction path (${path36})`);
6002
+ throw new Error(`Invalid redaction path (${path37})`);
5956
6003
  }
5957
6004
  }
5958
6005
  }
5959
6006
  if (bracketCount !== 0) {
5960
- throw new Error(`Invalid redaction path (${path36})`);
6007
+ throw new Error(`Invalid redaction path (${path37})`);
5961
6008
  }
5962
6009
  }
5963
6010
  function validatePaths(paths) {
5964
6011
  if (!Array.isArray(paths)) {
5965
6012
  throw new TypeError("paths must be an array");
5966
6013
  }
5967
- for (const path36 of paths) {
5968
- validatePath(path36);
6014
+ for (const path37 of paths) {
6015
+ validatePath(path37);
5969
6016
  }
5970
6017
  }
5971
6018
  function slowRedact(options = {}) {
@@ -6133,8 +6180,8 @@ var require_redaction = __commonJS({
6133
6180
  if (shape[k2] === null) {
6134
6181
  o[k2] = (value) => topCensor(value, [k2]);
6135
6182
  } else {
6136
- const wrappedCensor = typeof censor === "function" ? (value, path36) => {
6137
- return censor(value, [k2, ...path36]);
6183
+ const wrappedCensor = typeof censor === "function" ? (value, path37) => {
6184
+ return censor(value, [k2, ...path37]);
6138
6185
  } : censor;
6139
6186
  o[k2] = Redact({
6140
6187
  paths: shape[k2],
@@ -6352,10 +6399,10 @@ var require_atomic_sleep = __commonJS({
6352
6399
  var require_sonic_boom = __commonJS({
6353
6400
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
6354
6401
  "use strict";
6355
- var fs32 = require("fs");
6402
+ var fs33 = require("fs");
6356
6403
  var EventEmitter2 = require("events");
6357
6404
  var inherits = require("util").inherits;
6358
- var path36 = require("path");
6405
+ var path37 = require("path");
6359
6406
  var sleep = require_atomic_sleep();
6360
6407
  var assert = require("assert");
6361
6408
  var BUSY_WRITE_TIMEOUT = 100;
@@ -6409,20 +6456,20 @@ var require_sonic_boom = __commonJS({
6409
6456
  const mode = sonic.mode;
6410
6457
  if (sonic.sync) {
6411
6458
  try {
6412
- if (sonic.mkdir) fs32.mkdirSync(path36.dirname(file), { recursive: true });
6413
- const fd = fs32.openSync(file, flags, mode);
6459
+ if (sonic.mkdir) fs33.mkdirSync(path37.dirname(file), { recursive: true });
6460
+ const fd = fs33.openSync(file, flags, mode);
6414
6461
  fileOpened(null, fd);
6415
6462
  } catch (err) {
6416
6463
  fileOpened(err);
6417
6464
  throw err;
6418
6465
  }
6419
6466
  } else if (sonic.mkdir) {
6420
- fs32.mkdir(path36.dirname(file), { recursive: true }, (err) => {
6467
+ fs33.mkdir(path37.dirname(file), { recursive: true }, (err) => {
6421
6468
  if (err) return fileOpened(err);
6422
- fs32.open(file, flags, mode, fileOpened);
6469
+ fs33.open(file, flags, mode, fileOpened);
6423
6470
  });
6424
6471
  } else {
6425
- fs32.open(file, flags, mode, fileOpened);
6472
+ fs33.open(file, flags, mode, fileOpened);
6426
6473
  }
6427
6474
  }
6428
6475
  function SonicBoom(opts) {
@@ -6463,8 +6510,8 @@ var require_sonic_boom = __commonJS({
6463
6510
  this.flush = flushBuffer;
6464
6511
  this.flushSync = flushBufferSync;
6465
6512
  this._actualWrite = actualWriteBuffer;
6466
- fsWriteSync = () => fs32.writeSync(this.fd, this._writingBuf);
6467
- fsWrite = () => fs32.write(this.fd, this._writingBuf, this.release);
6513
+ fsWriteSync = () => fs33.writeSync(this.fd, this._writingBuf);
6514
+ fsWrite = () => fs33.write(this.fd, this._writingBuf, this.release);
6468
6515
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
6469
6516
  this._writingBuf = "";
6470
6517
  this.write = write;
@@ -6473,15 +6520,15 @@ var require_sonic_boom = __commonJS({
6473
6520
  this._actualWrite = actualWrite;
6474
6521
  fsWriteSync = () => {
6475
6522
  if (Buffer.isBuffer(this._writingBuf)) {
6476
- return fs32.writeSync(this.fd, this._writingBuf);
6523
+ return fs33.writeSync(this.fd, this._writingBuf);
6477
6524
  }
6478
- return fs32.writeSync(this.fd, this._writingBuf, "utf8");
6525
+ return fs33.writeSync(this.fd, this._writingBuf, "utf8");
6479
6526
  };
6480
6527
  fsWrite = () => {
6481
6528
  if (Buffer.isBuffer(this._writingBuf)) {
6482
- return fs32.write(this.fd, this._writingBuf, this.release);
6529
+ return fs33.write(this.fd, this._writingBuf, this.release);
6483
6530
  }
6484
- return fs32.write(this.fd, this._writingBuf, "utf8", this.release);
6531
+ return fs33.write(this.fd, this._writingBuf, "utf8", this.release);
6485
6532
  };
6486
6533
  } else {
6487
6534
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -6538,7 +6585,7 @@ var require_sonic_boom = __commonJS({
6538
6585
  }
6539
6586
  }
6540
6587
  if (this._fsync) {
6541
- fs32.fsyncSync(this.fd);
6588
+ fs33.fsyncSync(this.fd);
6542
6589
  }
6543
6590
  const len = this._len;
6544
6591
  if (this._reopening) {
@@ -6652,7 +6699,7 @@ var require_sonic_boom = __commonJS({
6652
6699
  const onDrain = () => {
6653
6700
  if (!this._fsync) {
6654
6701
  try {
6655
- fs32.fsync(this.fd, (err) => {
6702
+ fs33.fsync(this.fd, (err) => {
6656
6703
  this._flushPending = false;
6657
6704
  cb(err);
6658
6705
  });
@@ -6754,7 +6801,7 @@ var require_sonic_boom = __commonJS({
6754
6801
  const fd = this.fd;
6755
6802
  this.once("ready", () => {
6756
6803
  if (fd !== this.fd) {
6757
- fs32.close(fd, (err) => {
6804
+ fs33.close(fd, (err) => {
6758
6805
  if (err) {
6759
6806
  return this.emit("error", err);
6760
6807
  }
@@ -6803,7 +6850,7 @@ var require_sonic_boom = __commonJS({
6803
6850
  buf = this._bufs[0];
6804
6851
  }
6805
6852
  try {
6806
- const n = Buffer.isBuffer(buf) ? fs32.writeSync(this.fd, buf) : fs32.writeSync(this.fd, buf, "utf8");
6853
+ const n = Buffer.isBuffer(buf) ? fs33.writeSync(this.fd, buf) : fs33.writeSync(this.fd, buf, "utf8");
6807
6854
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
6808
6855
  buf = releasedBufObj.writingBuf;
6809
6856
  this._len = releasedBufObj.len;
@@ -6819,7 +6866,7 @@ var require_sonic_boom = __commonJS({
6819
6866
  }
6820
6867
  }
6821
6868
  try {
6822
- fs32.fsyncSync(this.fd);
6869
+ fs33.fsyncSync(this.fd);
6823
6870
  } catch {
6824
6871
  }
6825
6872
  }
@@ -6840,7 +6887,7 @@ var require_sonic_boom = __commonJS({
6840
6887
  buf = mergeBuf(this._bufs[0], this._lens[0]);
6841
6888
  }
6842
6889
  try {
6843
- const n = fs32.writeSync(this.fd, buf);
6890
+ const n = fs33.writeSync(this.fd, buf);
6844
6891
  buf = buf.subarray(n);
6845
6892
  this._len = Math.max(this._len - n, 0);
6846
6893
  if (buf.length <= 0) {
@@ -6868,13 +6915,13 @@ var require_sonic_boom = __commonJS({
6868
6915
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
6869
6916
  if (this.sync) {
6870
6917
  try {
6871
- const written = Buffer.isBuffer(this._writingBuf) ? fs32.writeSync(this.fd, this._writingBuf) : fs32.writeSync(this.fd, this._writingBuf, "utf8");
6918
+ const written = Buffer.isBuffer(this._writingBuf) ? fs33.writeSync(this.fd, this._writingBuf) : fs33.writeSync(this.fd, this._writingBuf, "utf8");
6872
6919
  release(null, written);
6873
6920
  } catch (err) {
6874
6921
  release(err);
6875
6922
  }
6876
6923
  } else {
6877
- fs32.write(this.fd, this._writingBuf, release);
6924
+ fs33.write(this.fd, this._writingBuf, release);
6878
6925
  }
6879
6926
  }
6880
6927
  function actualWriteBuffer() {
@@ -6883,7 +6930,7 @@ var require_sonic_boom = __commonJS({
6883
6930
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
6884
6931
  if (this.sync) {
6885
6932
  try {
6886
- const written = fs32.writeSync(this.fd, this._writingBuf);
6933
+ const written = fs33.writeSync(this.fd, this._writingBuf);
6887
6934
  release(null, written);
6888
6935
  } catch (err) {
6889
6936
  release(err);
@@ -6892,7 +6939,7 @@ var require_sonic_boom = __commonJS({
6892
6939
  if (kCopyBuffer) {
6893
6940
  this._writingBuf = Buffer.from(this._writingBuf);
6894
6941
  }
6895
- fs32.write(this.fd, this._writingBuf, release);
6942
+ fs33.write(this.fd, this._writingBuf, release);
6896
6943
  }
6897
6944
  }
6898
6945
  function actualClose(sonic) {
@@ -6908,12 +6955,12 @@ var require_sonic_boom = __commonJS({
6908
6955
  sonic._lens = [];
6909
6956
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
6910
6957
  try {
6911
- fs32.fsync(sonic.fd, closeWrapped);
6958
+ fs33.fsync(sonic.fd, closeWrapped);
6912
6959
  } catch {
6913
6960
  }
6914
6961
  function closeWrapped() {
6915
6962
  if (sonic.fd !== 1 && sonic.fd !== 2) {
6916
- fs32.close(sonic.fd, done);
6963
+ fs33.close(sonic.fd, done);
6917
6964
  } else {
6918
6965
  done();
6919
6966
  }
@@ -7170,7 +7217,7 @@ var require_thread_stream = __commonJS({
7170
7217
  var { version: version2 } = require_package();
7171
7218
  var { EventEmitter: EventEmitter2 } = require("events");
7172
7219
  var { Worker } = require("worker_threads");
7173
- var { join: join9 } = require("path");
7220
+ var { join: join10 } = require("path");
7174
7221
  var { pathToFileURL } = require("url");
7175
7222
  var { wait } = require_wait();
7176
7223
  var {
@@ -7206,7 +7253,7 @@ var require_thread_stream = __commonJS({
7206
7253
  function createWorker(stream, opts) {
7207
7254
  const { filename, workerData } = opts;
7208
7255
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
7209
- const toExecute = bundlerOverrides["thread-stream-worker"] || join9(__dirname, "lib", "worker.js");
7256
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join10(__dirname, "lib", "worker.js");
7210
7257
  const worker = new Worker(toExecute, {
7211
7258
  ...opts.workerOpts,
7212
7259
  trackUnmanagedFds: false,
@@ -7592,7 +7639,7 @@ var require_transport = __commonJS({
7592
7639
  "use strict";
7593
7640
  var { createRequire } = require("module");
7594
7641
  var getCallers = require_caller();
7595
- var { join: join9, isAbsolute, sep: sep2 } = require("path");
7642
+ var { join: join10, isAbsolute, sep: sep2 } = require("path");
7596
7643
  var sleep = require_atomic_sleep();
7597
7644
  var onExit = require_on_exit_leak_free();
7598
7645
  var ThreadStream = require_thread_stream();
@@ -7655,7 +7702,7 @@ var require_transport = __commonJS({
7655
7702
  throw new Error("only one of target or targets can be specified");
7656
7703
  }
7657
7704
  if (targets) {
7658
- target = bundlerOverrides["pino-worker"] || join9(__dirname, "worker.js");
7705
+ target = bundlerOverrides["pino-worker"] || join10(__dirname, "worker.js");
7659
7706
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
7660
7707
  return {
7661
7708
  ...dest,
@@ -7673,7 +7720,7 @@ var require_transport = __commonJS({
7673
7720
  });
7674
7721
  });
7675
7722
  } else if (pipeline2) {
7676
- target = bundlerOverrides["pino-worker"] || join9(__dirname, "worker.js");
7723
+ target = bundlerOverrides["pino-worker"] || join10(__dirname, "worker.js");
7677
7724
  options.pipelines = [pipeline2.map((dest) => {
7678
7725
  return {
7679
7726
  ...dest,
@@ -7695,7 +7742,7 @@ var require_transport = __commonJS({
7695
7742
  return origin;
7696
7743
  }
7697
7744
  if (origin === "pino/file") {
7698
- return join9(__dirname, "..", "file.js");
7745
+ return join10(__dirname, "..", "file.js");
7699
7746
  }
7700
7747
  let fixTarget2;
7701
7748
  for (const filePath of callers) {
@@ -8685,7 +8732,7 @@ var require_safe_stable_stringify = __commonJS({
8685
8732
  return circularValue;
8686
8733
  }
8687
8734
  let res = "";
8688
- let join9 = ",";
8735
+ let join10 = ",";
8689
8736
  const originalIndentation = indentation;
8690
8737
  if (Array.isArray(value)) {
8691
8738
  if (value.length === 0) {
@@ -8699,7 +8746,7 @@ var require_safe_stable_stringify = __commonJS({
8699
8746
  indentation += spacer;
8700
8747
  res += `
8701
8748
  ${indentation}`;
8702
- join9 = `,
8749
+ join10 = `,
8703
8750
  ${indentation}`;
8704
8751
  }
8705
8752
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -8707,13 +8754,13 @@ ${indentation}`;
8707
8754
  for (; i < maximumValuesToStringify - 1; i++) {
8708
8755
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
8709
8756
  res += tmp2 !== void 0 ? tmp2 : "null";
8710
- res += join9;
8757
+ res += join10;
8711
8758
  }
8712
8759
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
8713
8760
  res += tmp !== void 0 ? tmp : "null";
8714
8761
  if (value.length - 1 > maximumBreadth) {
8715
8762
  const removedKeys = value.length - maximumBreadth - 1;
8716
- res += `${join9}"... ${getItemCount(removedKeys)} not stringified"`;
8763
+ res += `${join10}"... ${getItemCount(removedKeys)} not stringified"`;
8717
8764
  }
8718
8765
  if (spacer !== "") {
8719
8766
  res += `
@@ -8734,7 +8781,7 @@ ${originalIndentation}`;
8734
8781
  let separator = "";
8735
8782
  if (spacer !== "") {
8736
8783
  indentation += spacer;
8737
- join9 = `,
8784
+ join10 = `,
8738
8785
  ${indentation}`;
8739
8786
  whitespace = " ";
8740
8787
  }
@@ -8748,13 +8795,13 @@ ${indentation}`;
8748
8795
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
8749
8796
  if (tmp !== void 0) {
8750
8797
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
8751
- separator = join9;
8798
+ separator = join10;
8752
8799
  }
8753
8800
  }
8754
8801
  if (keyLength > maximumBreadth) {
8755
8802
  const removedKeys = keyLength - maximumBreadth;
8756
8803
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
8757
- separator = join9;
8804
+ separator = join10;
8758
8805
  }
8759
8806
  if (spacer !== "" && separator.length > 1) {
8760
8807
  res = `
@@ -8795,7 +8842,7 @@ ${originalIndentation}`;
8795
8842
  }
8796
8843
  const originalIndentation = indentation;
8797
8844
  let res = "";
8798
- let join9 = ",";
8845
+ let join10 = ",";
8799
8846
  if (Array.isArray(value)) {
8800
8847
  if (value.length === 0) {
8801
8848
  return "[]";
@@ -8808,7 +8855,7 @@ ${originalIndentation}`;
8808
8855
  indentation += spacer;
8809
8856
  res += `
8810
8857
  ${indentation}`;
8811
- join9 = `,
8858
+ join10 = `,
8812
8859
  ${indentation}`;
8813
8860
  }
8814
8861
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -8816,13 +8863,13 @@ ${indentation}`;
8816
8863
  for (; i < maximumValuesToStringify - 1; i++) {
8817
8864
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
8818
8865
  res += tmp2 !== void 0 ? tmp2 : "null";
8819
- res += join9;
8866
+ res += join10;
8820
8867
  }
8821
8868
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
8822
8869
  res += tmp !== void 0 ? tmp : "null";
8823
8870
  if (value.length - 1 > maximumBreadth) {
8824
8871
  const removedKeys = value.length - maximumBreadth - 1;
8825
- res += `${join9}"... ${getItemCount(removedKeys)} not stringified"`;
8872
+ res += `${join10}"... ${getItemCount(removedKeys)} not stringified"`;
8826
8873
  }
8827
8874
  if (spacer !== "") {
8828
8875
  res += `
@@ -8835,7 +8882,7 @@ ${originalIndentation}`;
8835
8882
  let whitespace = "";
8836
8883
  if (spacer !== "") {
8837
8884
  indentation += spacer;
8838
- join9 = `,
8885
+ join10 = `,
8839
8886
  ${indentation}`;
8840
8887
  whitespace = " ";
8841
8888
  }
@@ -8844,7 +8891,7 @@ ${indentation}`;
8844
8891
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
8845
8892
  if (tmp !== void 0) {
8846
8893
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
8847
- separator = join9;
8894
+ separator = join10;
8848
8895
  }
8849
8896
  }
8850
8897
  if (spacer !== "" && separator.length > 1) {
@@ -8902,20 +8949,20 @@ ${originalIndentation}`;
8902
8949
  indentation += spacer;
8903
8950
  let res2 = `
8904
8951
  ${indentation}`;
8905
- const join10 = `,
8952
+ const join11 = `,
8906
8953
  ${indentation}`;
8907
8954
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
8908
8955
  let i = 0;
8909
8956
  for (; i < maximumValuesToStringify - 1; i++) {
8910
8957
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
8911
8958
  res2 += tmp2 !== void 0 ? tmp2 : "null";
8912
- res2 += join10;
8959
+ res2 += join11;
8913
8960
  }
8914
8961
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
8915
8962
  res2 += tmp !== void 0 ? tmp : "null";
8916
8963
  if (value.length - 1 > maximumBreadth) {
8917
8964
  const removedKeys = value.length - maximumBreadth - 1;
8918
- res2 += `${join10}"... ${getItemCount(removedKeys)} not stringified"`;
8965
+ res2 += `${join11}"... ${getItemCount(removedKeys)} not stringified"`;
8919
8966
  }
8920
8967
  res2 += `
8921
8968
  ${originalIndentation}`;
@@ -8931,16 +8978,16 @@ ${originalIndentation}`;
8931
8978
  return '"[Object]"';
8932
8979
  }
8933
8980
  indentation += spacer;
8934
- const join9 = `,
8981
+ const join10 = `,
8935
8982
  ${indentation}`;
8936
8983
  let res = "";
8937
8984
  let separator = "";
8938
8985
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
8939
8986
  if (isTypedArrayWithEntries(value)) {
8940
- res += stringifyTypedArray(value, join9, maximumBreadth);
8987
+ res += stringifyTypedArray(value, join10, maximumBreadth);
8941
8988
  keys = keys.slice(value.length);
8942
8989
  maximumPropertiesToStringify -= value.length;
8943
- separator = join9;
8990
+ separator = join10;
8944
8991
  }
8945
8992
  if (deterministic) {
8946
8993
  keys = sort(keys, comparator);
@@ -8951,13 +8998,13 @@ ${indentation}`;
8951
8998
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
8952
8999
  if (tmp !== void 0) {
8953
9000
  res += `${separator}${strEscape(key2)}: ${tmp}`;
8954
- separator = join9;
9001
+ separator = join10;
8955
9002
  }
8956
9003
  }
8957
9004
  if (keyLength > maximumBreadth) {
8958
9005
  const removedKeys = keyLength - maximumBreadth;
8959
9006
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
8960
- separator = join9;
9007
+ separator = join10;
8961
9008
  }
8962
9009
  if (separator !== "") {
8963
9010
  res = `
@@ -10048,11 +10095,11 @@ var init_lib = __esm({
10048
10095
  }
10049
10096
  }
10050
10097
  },
10051
- addToPath: function addToPath(path36, added, removed, oldPosInc, options) {
10052
- var last = path36.lastComponent;
10098
+ addToPath: function addToPath(path37, added, removed, oldPosInc, options) {
10099
+ var last = path37.lastComponent;
10053
10100
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
10054
10101
  return {
10055
- oldPos: path36.oldPos + oldPosInc,
10102
+ oldPos: path37.oldPos + oldPosInc,
10056
10103
  lastComponent: {
10057
10104
  count: last.count + 1,
10058
10105
  added,
@@ -10062,7 +10109,7 @@ var init_lib = __esm({
10062
10109
  };
10063
10110
  } else {
10064
10111
  return {
10065
- oldPos: path36.oldPos + oldPosInc,
10112
+ oldPos: path37.oldPos + oldPosInc,
10066
10113
  lastComponent: {
10067
10114
  count: 1,
10068
10115
  added,
@@ -10493,10 +10540,10 @@ function attachmentToHistoryMessage(o, ts) {
10493
10540
  const memories = raw.map((m2) => {
10494
10541
  if (!m2 || typeof m2 !== "object") return null;
10495
10542
  const rec = m2;
10496
- const path36 = typeof rec.path === "string" ? rec.path : null;
10543
+ const path37 = typeof rec.path === "string" ? rec.path : null;
10497
10544
  const content = typeof rec.content === "string" ? rec.content : null;
10498
- if (!path36 || content == null) return null;
10499
- const entry = { path: path36, content };
10545
+ if (!path37 || content == null) return null;
10546
+ const entry = { path: path37, content };
10500
10547
  if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
10501
10548
  return entry;
10502
10549
  }).filter((m2) => m2 !== null);
@@ -11322,10 +11369,10 @@ function parseAttachment(obj) {
11322
11369
  const memories = raw.map((m2) => {
11323
11370
  if (!m2 || typeof m2 !== "object") return null;
11324
11371
  const rec = m2;
11325
- const path36 = typeof rec.path === "string" ? rec.path : null;
11372
+ const path37 = typeof rec.path === "string" ? rec.path : null;
11326
11373
  const content = typeof rec.content === "string" ? rec.content : null;
11327
- if (!path36 || content == null) return null;
11328
- const out = { path: path36, content };
11374
+ if (!path37 || content == null) return null;
11375
+ const out = { path: path37, content };
11329
11376
  if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
11330
11377
  return out;
11331
11378
  }).filter((m2) => m2 !== null);
@@ -18824,7 +18871,7 @@ var require_websocket = __commonJS({
18824
18871
  var http2 = require("http");
18825
18872
  var net = require("net");
18826
18873
  var tls = require("tls");
18827
- var { randomBytes: randomBytes3, createHash: createHash3 } = require("crypto");
18874
+ var { randomBytes: randomBytes3, createHash: createHash4 } = require("crypto");
18828
18875
  var { Duplex, Readable: Readable3 } = require("stream");
18829
18876
  var { URL: URL2 } = require("url");
18830
18877
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -19484,7 +19531,7 @@ var require_websocket = __commonJS({
19484
19531
  abortHandshake(websocket, socket, "Invalid Upgrade header");
19485
19532
  return;
19486
19533
  }
19487
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
19534
+ const digest = createHash4("sha1").update(key + GUID).digest("base64");
19488
19535
  if (res.headers["sec-websocket-accept"] !== digest) {
19489
19536
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
19490
19537
  return;
@@ -19851,7 +19898,7 @@ var require_websocket_server = __commonJS({
19851
19898
  var EventEmitter2 = require("events");
19852
19899
  var http2 = require("http");
19853
19900
  var { Duplex } = require("stream");
19854
- var { createHash: createHash3 } = require("crypto");
19901
+ var { createHash: createHash4 } = require("crypto");
19855
19902
  var extension2 = require_extension();
19856
19903
  var PerMessageDeflate2 = require_permessage_deflate();
19857
19904
  var subprotocol2 = require_subprotocol();
@@ -20152,7 +20199,7 @@ var require_websocket_server = __commonJS({
20152
20199
  );
20153
20200
  }
20154
20201
  if (this._state > RUNNING) return abortHandshake(socket, 503);
20155
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
20202
+ const digest = createHash4("sha1").update(key + GUID).digest("base64");
20156
20203
  const headers = [
20157
20204
  "HTTP/1.1 101 Switching Protocols",
20158
20205
  "Upgrade: websocket",
@@ -25552,6 +25599,23 @@ var LocalWsServer = class {
25552
25599
  this.safeSend(c.ws, frame);
25553
25600
  }
25554
25601
  }
25602
+ // Phase 4 capability platform DM: 广播到指定 principal 的所有活跃 ws.
25603
+ // principalId === 'owner' → 同 broadcastToOwners (所有 owner ws)
25604
+ // principalId === 'cap_xxx' → 该 capability 的所有 guest ws (多端 / 多 tab)
25605
+ // 用于 DM inbox:event 路由: from + to 两侧各播一次, 让双方 UI 实时看到 thread 更新.
25606
+ broadcastToPrincipal(principalId, frame) {
25607
+ if (principalId === "owner") {
25608
+ this.broadcastToOwners(frame);
25609
+ return;
25610
+ }
25611
+ const set = this.capabilityIdToClients.get(principalId);
25612
+ if (!set) return;
25613
+ for (const id of set) {
25614
+ const c = this.clients.get(id);
25615
+ if (!c) continue;
25616
+ this.safeSend(c.ws, frame);
25617
+ }
25618
+ }
25555
25619
  firstSubscriber(sessionId) {
25556
25620
  for (const c of this.clients.values()) {
25557
25621
  if (c.handle.subscribedSessions.has(sessionId)) return c.handle;
@@ -26231,7 +26295,16 @@ function parseAllLines(raw) {
26231
26295
  }
26232
26296
 
26233
26297
  // src/inbox/inbox-manager.ts
26298
+ var crypto7 = __toESM(require("crypto"), 1);
26299
+
26300
+ // src/inbox/dm.ts
26234
26301
  var crypto6 = __toESM(require("crypto"), 1);
26302
+ function deriveDmThreadId(idA, idB) {
26303
+ const [low, high] = idA < idB ? [idA, idB] : [idB, idA];
26304
+ return crypto6.createHash("sha256").update(`${low}/${high}`).digest("hex");
26305
+ }
26306
+
26307
+ // src/inbox/inbox-manager.ts
26235
26308
  var InboxManager = class {
26236
26309
  constructor(store, broadcast, opts = {}) {
26237
26310
  this.store = store;
@@ -26263,6 +26336,30 @@ var InboxManager = class {
26263
26336
  this.broadcast({ type: "inbox:event", event: ev });
26264
26337
  return ev;
26265
26338
  }
26339
+ /**
26340
+ * Phase 4 Task 4.2: DM 私聊事件. 与 recordPersonaMention 区别:
26341
+ * - kind = 'direct-message' (不是 persona-mention)
26342
+ * - 不带 resource (DM 不挂某个 persona)
26343
+ * - threadId 由 from.id + to.id 派生 (sha256), 双向消息共享同一 thread
26344
+ * - 调用方 (handler) 已校验 sender = ctx.principal (防伪造)
26345
+ *
26346
+ * 返回值是 InboxEvent (含派生 threadId), daemon/index.ts 装配 broadcast 路由:
26347
+ * broadcastToPrincipal(from.id) + broadcastToPrincipal(to.id) (双侧 ws 都收).
26348
+ */
26349
+ recordDirectMessage(args) {
26350
+ const ev = {
26351
+ id: this.genId(),
26352
+ kind: "direct-message",
26353
+ fromPrincipal: args.from,
26354
+ toPrincipal: args.to,
26355
+ preview: truncatePreview(args.text),
26356
+ createdAt: this.now(),
26357
+ threadId: deriveDmThreadId(args.from.id, args.to.id)
26358
+ };
26359
+ this.store.append(ev);
26360
+ this.broadcast({ type: "inbox:event", event: ev });
26361
+ return ev;
26362
+ }
26266
26363
  list(opts = {}) {
26267
26364
  const all = this.store.list();
26268
26365
  if (opts.includeRead) return all;
@@ -26277,65 +26374,165 @@ function truncatePreview(s) {
26277
26374
  return s.slice(0, INBOX_PREVIEW_MAX_LENGTH);
26278
26375
  }
26279
26376
  function defaultGenId() {
26280
- return "inb_" + crypto6.randomBytes(6).toString("base64url");
26377
+ return "inb_" + crypto7.randomBytes(6).toString("base64url");
26281
26378
  }
26282
26379
 
26283
- // src/migrations/2026-05-20-flatten-sessions.ts
26380
+ // src/remote-persona/store.ts
26284
26381
  var fs18 = __toESM(require("fs"), 1);
26285
26382
  var path20 = __toESM(require("path"), 1);
26383
+ var REMOTE_PERSONAS_DIR = "remote-personas";
26384
+ var RemotePersonaStore = class {
26385
+ constructor(dataDir) {
26386
+ this.dataDir = dataDir;
26387
+ fs18.mkdirSync(this.rootDir(), { recursive: true });
26388
+ }
26389
+ dataDir;
26390
+ list() {
26391
+ let entries;
26392
+ try {
26393
+ entries = fs18.readdirSync(this.rootDir());
26394
+ } catch (err) {
26395
+ if (err?.code === "ENOENT") return [];
26396
+ return [];
26397
+ }
26398
+ const out = [];
26399
+ for (const name of entries) {
26400
+ if (!name.endsWith(".json")) continue;
26401
+ if (name.includes(".tmp-")) continue;
26402
+ const file = path20.join(this.rootDir(), name);
26403
+ let raw;
26404
+ try {
26405
+ raw = fs18.readFileSync(file, "utf8");
26406
+ } catch {
26407
+ continue;
26408
+ }
26409
+ let parsed;
26410
+ try {
26411
+ parsed = JSON.parse(raw);
26412
+ } catch {
26413
+ continue;
26414
+ }
26415
+ const r = RemotePersonaSchema.safeParse(parsed);
26416
+ if (r.success) out.push(r.data);
26417
+ }
26418
+ return out.sort((a, b2) => a.addedAt > b2.addedAt ? -1 : a.addedAt < b2.addedAt ? 1 : 0);
26419
+ }
26420
+ get(alias) {
26421
+ const file = this.filePath(alias);
26422
+ let raw;
26423
+ try {
26424
+ raw = fs18.readFileSync(file, "utf8");
26425
+ } catch {
26426
+ return null;
26427
+ }
26428
+ try {
26429
+ const parsed = JSON.parse(raw);
26430
+ const r = RemotePersonaSchema.safeParse(parsed);
26431
+ return r.success ? r.data : null;
26432
+ } catch {
26433
+ return null;
26434
+ }
26435
+ }
26436
+ add(rp) {
26437
+ const file = this.filePath(rp.alias);
26438
+ if (fs18.existsSync(file)) {
26439
+ throw new Error(`RemotePersonaStore.add: alias already exists: ${rp.alias}`);
26440
+ }
26441
+ this.atomicWrite(file, rp);
26442
+ }
26443
+ remove(alias) {
26444
+ const file = this.filePath(alias);
26445
+ try {
26446
+ fs18.unlinkSync(file);
26447
+ return true;
26448
+ } catch (err) {
26449
+ if (err?.code === "ENOENT") return false;
26450
+ throw err;
26451
+ }
26452
+ }
26453
+ /**
26454
+ * patch lastConnectedAt (v2 outgoing client 连上时更新). 其他字段不动.
26455
+ * 不存在 alias → no-op.
26456
+ */
26457
+ updateLastConnectedAt(alias, at) {
26458
+ const cur = this.get(alias);
26459
+ if (!cur) return;
26460
+ this.atomicWrite(this.filePath(alias), { ...cur, lastConnectedAt: at });
26461
+ }
26462
+ rootDir() {
26463
+ return path20.join(this.dataDir, REMOTE_PERSONAS_DIR);
26464
+ }
26465
+ filePath(alias) {
26466
+ return path20.join(this.rootDir(), `${safeFileName(alias)}.json`);
26467
+ }
26468
+ atomicWrite(file, content) {
26469
+ fs18.mkdirSync(this.rootDir(), { recursive: true });
26470
+ const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
26471
+ fs18.writeFileSync(tmp, JSON.stringify(content, null, 2), { mode: 384 });
26472
+ fs18.renameSync(tmp, file);
26473
+ try {
26474
+ fs18.chmodSync(file, 384);
26475
+ } catch {
26476
+ }
26477
+ }
26478
+ };
26479
+
26480
+ // src/migrations/2026-05-20-flatten-sessions.ts
26481
+ var fs19 = __toESM(require("fs"), 1);
26482
+ var path21 = __toESM(require("path"), 1);
26286
26483
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
26287
26484
  function migrateFlattenSessions(opts) {
26288
26485
  const dataDir = opts.dataDir;
26289
26486
  const now = opts.now ?? Date.now;
26290
- const sessionsDir = path20.join(dataDir, "sessions");
26291
- const flagPath = path20.join(sessionsDir, MIGRATION_FLAG_NAME);
26292
- if (existsSync3(flagPath)) {
26487
+ const sessionsDir = path21.join(dataDir, "sessions");
26488
+ const flagPath = path21.join(sessionsDir, MIGRATION_FLAG_NAME);
26489
+ if (existsSync4(flagPath)) {
26293
26490
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
26294
26491
  }
26295
26492
  let movedBare = 0;
26296
26493
  let movedVmOwner = 0;
26297
26494
  let archivedListener = 0;
26298
- const defaultDir = path20.join(sessionsDir, "default");
26299
- if (existsSync3(defaultDir)) {
26495
+ const defaultDir = path21.join(sessionsDir, "default");
26496
+ if (existsSync4(defaultDir)) {
26300
26497
  for (const entry of readdirSafe(defaultDir)) {
26301
26498
  if (!entry.endsWith(".json")) continue;
26302
- const src = path20.join(defaultDir, entry);
26303
- const dst = path20.join(sessionsDir, entry);
26304
- fs18.renameSync(src, dst);
26499
+ const src = path21.join(defaultDir, entry);
26500
+ const dst = path21.join(sessionsDir, entry);
26501
+ fs19.renameSync(src, dst);
26305
26502
  movedBare += 1;
26306
26503
  }
26307
26504
  rmdirIfEmpty(defaultDir);
26308
26505
  }
26309
26506
  for (const pid of readdirSafe(sessionsDir)) {
26310
- const personaDir = path20.join(sessionsDir, pid);
26507
+ const personaDir = path21.join(sessionsDir, pid);
26311
26508
  if (!isDir(personaDir)) continue;
26312
26509
  if (pid === "default") continue;
26313
- const ownerSrc = path20.join(personaDir, "owner");
26314
- if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
26315
- const ownerDst = path20.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
26316
- fs18.mkdirSync(ownerDst, { recursive: true });
26510
+ const ownerSrc = path21.join(personaDir, "owner");
26511
+ if (existsSync4(ownerSrc) && isDir(ownerSrc)) {
26512
+ const ownerDst = path21.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
26513
+ fs19.mkdirSync(ownerDst, { recursive: true });
26317
26514
  for (const file of readdirSafe(ownerSrc)) {
26318
26515
  if (!file.endsWith(".json")) continue;
26319
- fs18.renameSync(path20.join(ownerSrc, file), path20.join(ownerDst, file));
26516
+ fs19.renameSync(path21.join(ownerSrc, file), path21.join(ownerDst, file));
26320
26517
  movedVmOwner += 1;
26321
26518
  }
26322
26519
  rmdirIfEmpty(ownerSrc);
26323
26520
  }
26324
- const listenerSrc = path20.join(personaDir, "listener");
26325
- if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
26326
- const archiveDst = path20.join(dataDir, ".legacy", `listener-${pid}`);
26327
- fs18.mkdirSync(archiveDst, { recursive: true });
26521
+ const listenerSrc = path21.join(personaDir, "listener");
26522
+ if (existsSync4(listenerSrc) && isDir(listenerSrc)) {
26523
+ const archiveDst = path21.join(dataDir, ".legacy", `listener-${pid}`);
26524
+ fs19.mkdirSync(archiveDst, { recursive: true });
26328
26525
  for (const file of readdirSafe(listenerSrc)) {
26329
26526
  if (!file.endsWith(".json")) continue;
26330
- fs18.renameSync(path20.join(listenerSrc, file), path20.join(archiveDst, file));
26527
+ fs19.renameSync(path21.join(listenerSrc, file), path21.join(archiveDst, file));
26331
26528
  archivedListener += 1;
26332
26529
  }
26333
26530
  rmdirIfEmpty(listenerSrc);
26334
26531
  }
26335
26532
  rmdirIfEmpty(personaDir);
26336
26533
  }
26337
- fs18.mkdirSync(sessionsDir, { recursive: true });
26338
- fs18.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
26534
+ fs19.mkdirSync(sessionsDir, { recursive: true });
26535
+ fs19.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
26339
26536
  return {
26340
26537
  skipped: false,
26341
26538
  flagWritten: true,
@@ -26344,9 +26541,9 @@ function migrateFlattenSessions(opts) {
26344
26541
  archivedListener
26345
26542
  };
26346
26543
  }
26347
- function existsSync3(p2) {
26544
+ function existsSync4(p2) {
26348
26545
  try {
26349
- fs18.statSync(p2);
26546
+ fs19.statSync(p2);
26350
26547
  return true;
26351
26548
  } catch {
26352
26549
  return false;
@@ -26354,21 +26551,21 @@ function existsSync3(p2) {
26354
26551
  }
26355
26552
  function isDir(p2) {
26356
26553
  try {
26357
- return fs18.statSync(p2).isDirectory();
26554
+ return fs19.statSync(p2).isDirectory();
26358
26555
  } catch {
26359
26556
  return false;
26360
26557
  }
26361
26558
  }
26362
26559
  function readdirSafe(p2) {
26363
26560
  try {
26364
- return fs18.readdirSync(p2);
26561
+ return fs19.readdirSync(p2);
26365
26562
  } catch {
26366
26563
  return [];
26367
26564
  }
26368
26565
  }
26369
26566
  function rmdirIfEmpty(p2) {
26370
26567
  try {
26371
- fs18.rmdirSync(p2);
26568
+ fs19.rmdirSync(p2);
26372
26569
  } catch {
26373
26570
  }
26374
26571
  }
@@ -28220,8 +28417,22 @@ function buildCapabilityHandlers(deps) {
28220
28417
  }
28221
28418
 
28222
28419
  // src/handlers/inbox.ts
28420
+ init_protocol();
28223
28421
  function buildInboxHandlers(deps) {
28224
- const { manager } = deps;
28422
+ const { manager, capabilityRegistry } = deps;
28423
+ function resolvePeerPrincipal(peerId) {
28424
+ if (peerId === "owner") {
28425
+ return { id: "owner", kind: "owner", displayName: "owner" };
28426
+ }
28427
+ const cap = capabilityRegistry.findById(peerId);
28428
+ if (!cap) {
28429
+ throw new ClawdError(
28430
+ ERROR_CODES.VALIDATION_ERROR,
28431
+ `peer principal not found: ${peerId}`
28432
+ );
28433
+ }
28434
+ return { id: cap.id, kind: "guest", displayName: cap.displayName };
28435
+ }
28225
28436
  const list = async (frame) => {
28226
28437
  const { type: _t, requestId: _r, ...rest } = frame;
28227
28438
  const args = InboxListArgsSchema.parse(rest);
@@ -28238,9 +28449,77 @@ function buildInboxHandlers(deps) {
28238
28449
  response: { type: "inbox:markRead:ok", eventId: args.eventId }
28239
28450
  };
28240
28451
  };
28452
+ const postMessage = async (frame, _client, ctx) => {
28453
+ const { type: _t, requestId: _r, ...rest } = frame;
28454
+ const args = InboxPostMessageArgsSchema.parse(rest);
28455
+ if (!ctx) {
28456
+ throw new ClawdError(ERROR_CODES.INTERNAL, "inbox:postMessage: missing ConnectionContext");
28457
+ }
28458
+ const peer = resolvePeerPrincipal(args.peerPrincipalId);
28459
+ const ev = manager.recordDirectMessage({
28460
+ from: ctx.principal,
28461
+ to: peer,
28462
+ text: args.text
28463
+ });
28464
+ return {
28465
+ response: { type: "inbox:postMessage:ok", event: ev }
28466
+ };
28467
+ };
28241
28468
  return {
28242
28469
  "inbox:list": list,
28243
- "inbox:markRead": markRead
28470
+ "inbox:markRead": markRead,
28471
+ "inbox:postMessage": postMessage
28472
+ };
28473
+ }
28474
+
28475
+ // src/handlers/remote-persona.ts
28476
+ init_protocol();
28477
+ function buildRemotePersonaHandlers(deps) {
28478
+ const { store } = deps;
28479
+ const now = deps.now ?? Date.now;
28480
+ const add = async (frame) => {
28481
+ const { type: _t, requestId: _r, ...rest } = frame;
28482
+ const args = RemotePersonaAddArgsSchema.parse(rest);
28483
+ const rp = {
28484
+ ...args,
28485
+ addedAt: now()
28486
+ };
28487
+ try {
28488
+ store.add(rp);
28489
+ } catch (err) {
28490
+ if (err.message?.includes("alias already exists")) {
28491
+ throw new ClawdError(
28492
+ ERROR_CODES.VALIDATION_ERROR,
28493
+ `remote-persona alias already exists: ${args.alias}`
28494
+ );
28495
+ }
28496
+ throw err;
28497
+ }
28498
+ return {
28499
+ response: { type: "remote-persona:add:ok", remotePersona: stripRemotePersonaSecret(rp) }
28500
+ };
28501
+ };
28502
+ const list = async () => {
28503
+ const all = store.list();
28504
+ return {
28505
+ response: {
28506
+ type: "remote-persona:list",
28507
+ remotePersonas: all.map(stripRemotePersonaSecret)
28508
+ }
28509
+ };
28510
+ };
28511
+ const remove = async (frame) => {
28512
+ const { type: _t, requestId: _r, ...rest } = frame;
28513
+ const args = RemotePersonaRemoveArgsSchema.parse(rest);
28514
+ const removed = store.remove(args.alias);
28515
+ return {
28516
+ response: { type: "remote-persona:remove:ok", alias: args.alias, removed }
28517
+ };
28518
+ };
28519
+ return {
28520
+ "remote-persona:add": add,
28521
+ "remote-persona:list": list,
28522
+ "remote-persona:remove": remove
28244
28523
  };
28245
28524
  }
28246
28525
 
@@ -28496,7 +28775,11 @@ function buildMethodHandlers(deps) {
28496
28775
  personaRegistry: deps.personaRegistry
28497
28776
  }),
28498
28777
  ...buildCapabilityHandlers({ manager: deps.capabilityManager }),
28499
- ...buildInboxHandlers({ manager: deps.inboxManager }),
28778
+ ...buildInboxHandlers({
28779
+ manager: deps.inboxManager,
28780
+ capabilityRegistry: deps.capabilityRegistry
28781
+ }),
28782
+ ...buildRemotePersonaHandlers({ store: deps.remotePersonaStore }),
28500
28783
  ...deps.attachment ? buildAttachmentHandlers(deps.attachment) : {}
28501
28784
  };
28502
28785
  }
@@ -28518,6 +28801,13 @@ var METHOD_GRANT_MAP = {
28518
28801
  // ---- inbox 跨用户通知 (Phase 3 admin-only, owner 调; Phase 4 加 postMessage) ----
28519
28802
  "inbox:list": ADMIN_ANY,
28520
28803
  "inbox:markRead": ADMIN_ANY,
28804
+ // Phase 4 Task 4.2: DM 是 capability 自带能力 (plan §2),
28805
+ // 任何 principal (owner / guest) 可调, 不通过 grant 表达.
28806
+ "inbox:postMessage": { kind: "public" },
28807
+ // Phase 4 Task 4.3: 远程 persona 仅 owner 管理 (admin-only)
28808
+ "remote-persona:add": ADMIN_ANY,
28809
+ "remote-persona:list": ADMIN_ANY,
28810
+ "remote-persona:remove": ADMIN_ANY,
28521
28811
  // ---- 业务方法:Phase 1 全 admin-only(owner 自动通过;guest 无法调用) ----
28522
28812
  "session:create": ADMIN_ANY,
28523
28813
  "session:list": ADMIN_ANY,
@@ -28649,7 +28939,15 @@ async function startDaemon(config) {
28649
28939
  }
28650
28940
  });
28651
28941
  const inboxStore = new InboxStore(config.dataDir);
28942
+ const remotePersonaStore = new RemotePersonaStore(config.dataDir);
28652
28943
  const inboxManager = new InboxManager(inboxStore, (frame) => {
28944
+ if (frame.event.kind === "direct-message") {
28945
+ const fromId = frame.event.fromPrincipal.id;
28946
+ const toId = frame.event.toPrincipal.id;
28947
+ wsServer?.broadcastToPrincipal(fromId, frame);
28948
+ if (toId !== fromId) wsServer?.broadcastToPrincipal(toId, frame);
28949
+ return;
28950
+ }
28653
28951
  wsServer?.broadcastToOwners(frame);
28654
28952
  });
28655
28953
  let wsServer = null;
@@ -28842,8 +29140,12 @@ async function startDaemon(config) {
28842
29140
  },
28843
29141
  // Task 1.9: capability:issue/list/revoke handler 依赖
28844
29142
  capabilityManager,
29143
+ // Phase 4 Task 4.2: inbox:postMessage 要查 capabilityRegistry 解析 peer Principal
29144
+ capabilityRegistry,
28845
29145
  // Phase 3 Task 3.4: inbox:list/markRead handler 依赖
28846
- inboxManager
29146
+ inboxManager,
29147
+ // Phase 4 Task 4.3: remote-persona:* handler 依赖 (本地存储, v1 不接 outgoing WS)
29148
+ remotePersonaStore
28847
29149
  });
28848
29150
  const authResolver = new AuthContextResolver({
28849
29151
  ownerToken: resolvedAuthToken,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.71-beta.125.4951782",
3
+ "version": "0.2.71-beta.126.06f4cfa",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",