@clawos-dev/clawd 0.2.71-beta.124.b09b0a0 → 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 +631 -126
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -121,6 +121,18 @@ var init_methods = __esm({
121
121
  "capability:issue",
122
122
  "capability:list",
123
123
  "capability:revoke",
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).
128
+ "inbox:list",
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",
124
136
  "info",
125
137
  "ping"
126
138
  ];
@@ -612,8 +624,8 @@ var init_parseUtil = __esm({
612
624
  init_errors2();
613
625
  init_en();
614
626
  makeIssue = (params) => {
615
- const { data, path: path35, errorMaps, issueData } = params;
616
- const fullPath = [...path35, ...issueData.path || []];
627
+ const { data, path: path37, errorMaps, issueData } = params;
628
+ const fullPath = [...path37, ...issueData.path || []];
617
629
  const fullIssue = {
618
630
  ...issueData,
619
631
  path: fullPath
@@ -924,11 +936,11 @@ var init_types = __esm({
924
936
  init_parseUtil();
925
937
  init_util();
926
938
  ParseInputLazyPath = class {
927
- constructor(parent, value, path35, key) {
939
+ constructor(parent, value, path37, key) {
928
940
  this._cachedPath = [];
929
941
  this.parent = parent;
930
942
  this.data = value;
931
- this._path = path35;
943
+ this._path = path37;
932
944
  this._key = key;
933
945
  }
934
946
  get path() {
@@ -5112,6 +5124,79 @@ var init_capability = __esm({
5112
5124
  }
5113
5125
  });
5114
5126
 
5127
+ // ../protocol/src/inbox.ts
5128
+ var INBOX_EVENT_KIND_VALUES, InboxEventKindSchema, INBOX_PREVIEW_MAX_LENGTH, InboxEventSchema, InboxListArgsSchema, InboxMarkReadArgsSchema, InboxPostMessageArgsSchema;
5129
+ var init_inbox = __esm({
5130
+ "../protocol/src/inbox.ts"() {
5131
+ "use strict";
5132
+ init_zod();
5133
+ init_principal();
5134
+ init_capability();
5135
+ INBOX_EVENT_KIND_VALUES = ["persona-mention", "direct-message"];
5136
+ InboxEventKindSchema = external_exports.enum(INBOX_EVENT_KIND_VALUES);
5137
+ INBOX_PREVIEW_MAX_LENGTH = 140;
5138
+ InboxEventSchema = external_exports.object({
5139
+ id: external_exports.string().min(1),
5140
+ kind: InboxEventKindSchema,
5141
+ fromPrincipal: PrincipalSchema,
5142
+ toPrincipal: PrincipalSchema,
5143
+ // persona-mention 才有, direct-message 不带
5144
+ resource: ResourceSchema.optional(),
5145
+ preview: external_exports.string().max(INBOX_PREVIEW_MAX_LENGTH),
5146
+ createdAt: external_exports.number().int().nonnegative(),
5147
+ readAt: external_exports.number().int().positive().optional(),
5148
+ // direct-message 才有, sha256 hex 64; 派生规则: sha256(min(A,B) + '/' + max(A,B))
5149
+ threadId: external_exports.string().regex(/^[a-f0-9]{64}$/).optional()
5150
+ }).strict();
5151
+ InboxListArgsSchema = external_exports.object({
5152
+ // false / 缺省 = 只返回未读; true = 含已读 (历史回溯用)
5153
+ includeRead: external_exports.boolean().optional()
5154
+ }).strict();
5155
+ InboxMarkReadArgsSchema = external_exports.object({
5156
+ eventId: external_exports.string().min(1)
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();
5197
+ }
5198
+ });
5199
+
5115
5200
  // ../protocol/src/runtime.ts
5116
5201
  var init_runtime = __esm({
5117
5202
  "../protocol/src/runtime.ts"() {
@@ -5126,6 +5211,8 @@ var init_runtime = __esm({
5126
5211
  init_attachment_schemas();
5127
5212
  init_principal();
5128
5213
  init_capability();
5214
+ init_inbox();
5215
+ init_remote_persona();
5129
5216
  }
5130
5217
  });
5131
5218
 
@@ -5400,8 +5487,8 @@ var require_req = __commonJS({
5400
5487
  if (req.originalUrl) {
5401
5488
  _req.url = req.originalUrl;
5402
5489
  } else {
5403
- const path35 = req.path;
5404
- _req.url = typeof path35 === "string" ? path35 : 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;
5405
5492
  }
5406
5493
  if (req.query) {
5407
5494
  _req.query = req.query;
@@ -5566,14 +5653,14 @@ var require_redact = __commonJS({
5566
5653
  }
5567
5654
  return obj;
5568
5655
  }
5569
- function parsePath(path35) {
5656
+ function parsePath(path37) {
5570
5657
  const parts = [];
5571
5658
  let current = "";
5572
5659
  let inBrackets = false;
5573
5660
  let inQuotes = false;
5574
5661
  let quoteChar = "";
5575
- for (let i = 0; i < path35.length; i++) {
5576
- const char = path35[i];
5662
+ for (let i = 0; i < path37.length; i++) {
5663
+ const char = path37[i];
5577
5664
  if (!inBrackets && char === ".") {
5578
5665
  if (current) {
5579
5666
  parts.push(current);
@@ -5704,10 +5791,10 @@ var require_redact = __commonJS({
5704
5791
  return current;
5705
5792
  }
5706
5793
  function redactPaths(obj, paths, censor, remove = false) {
5707
- for (const path35 of paths) {
5708
- const parts = parsePath(path35);
5794
+ for (const path37 of paths) {
5795
+ const parts = parsePath(path37);
5709
5796
  if (parts.includes("*")) {
5710
- redactWildcardPath(obj, parts, censor, path35, remove);
5797
+ redactWildcardPath(obj, parts, censor, path37, remove);
5711
5798
  } else {
5712
5799
  if (remove) {
5713
5800
  removeKey(obj, parts);
@@ -5792,8 +5879,8 @@ var require_redact = __commonJS({
5792
5879
  }
5793
5880
  } else {
5794
5881
  if (afterWildcard.includes("*")) {
5795
- const wrappedCensor = typeof censor === "function" ? (value, path35) => {
5796
- const fullPath = [...pathArray.slice(0, pathLength), ...path35];
5882
+ const wrappedCensor = typeof censor === "function" ? (value, path37) => {
5883
+ const fullPath = [...pathArray.slice(0, pathLength), ...path37];
5797
5884
  return censor(value, fullPath);
5798
5885
  } : censor;
5799
5886
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -5828,8 +5915,8 @@ var require_redact = __commonJS({
5828
5915
  return null;
5829
5916
  }
5830
5917
  const pathStructure = /* @__PURE__ */ new Map();
5831
- for (const path35 of pathsToClone) {
5832
- const parts = parsePath(path35);
5918
+ for (const path37 of pathsToClone) {
5919
+ const parts = parsePath(path37);
5833
5920
  let current = pathStructure;
5834
5921
  for (let i = 0; i < parts.length; i++) {
5835
5922
  const part = parts[i];
@@ -5881,24 +5968,24 @@ var require_redact = __commonJS({
5881
5968
  }
5882
5969
  return cloneSelectively(obj, pathStructure);
5883
5970
  }
5884
- function validatePath(path35) {
5885
- if (typeof path35 !== "string") {
5971
+ function validatePath(path37) {
5972
+ if (typeof path37 !== "string") {
5886
5973
  throw new Error("Paths must be (non-empty) strings");
5887
5974
  }
5888
- if (path35 === "") {
5975
+ if (path37 === "") {
5889
5976
  throw new Error("Invalid redaction path ()");
5890
5977
  }
5891
- if (path35.includes("..")) {
5892
- throw new Error(`Invalid redaction path (${path35})`);
5978
+ if (path37.includes("..")) {
5979
+ throw new Error(`Invalid redaction path (${path37})`);
5893
5980
  }
5894
- if (path35.includes(",")) {
5895
- throw new Error(`Invalid redaction path (${path35})`);
5981
+ if (path37.includes(",")) {
5982
+ throw new Error(`Invalid redaction path (${path37})`);
5896
5983
  }
5897
5984
  let bracketCount = 0;
5898
5985
  let inQuotes = false;
5899
5986
  let quoteChar = "";
5900
- for (let i = 0; i < path35.length; i++) {
5901
- const char = path35[i];
5987
+ for (let i = 0; i < path37.length; i++) {
5988
+ const char = path37[i];
5902
5989
  if ((char === '"' || char === "'") && bracketCount > 0) {
5903
5990
  if (!inQuotes) {
5904
5991
  inQuotes = true;
@@ -5912,20 +5999,20 @@ var require_redact = __commonJS({
5912
5999
  } else if (char === "]" && !inQuotes) {
5913
6000
  bracketCount--;
5914
6001
  if (bracketCount < 0) {
5915
- throw new Error(`Invalid redaction path (${path35})`);
6002
+ throw new Error(`Invalid redaction path (${path37})`);
5916
6003
  }
5917
6004
  }
5918
6005
  }
5919
6006
  if (bracketCount !== 0) {
5920
- throw new Error(`Invalid redaction path (${path35})`);
6007
+ throw new Error(`Invalid redaction path (${path37})`);
5921
6008
  }
5922
6009
  }
5923
6010
  function validatePaths(paths) {
5924
6011
  if (!Array.isArray(paths)) {
5925
6012
  throw new TypeError("paths must be an array");
5926
6013
  }
5927
- for (const path35 of paths) {
5928
- validatePath(path35);
6014
+ for (const path37 of paths) {
6015
+ validatePath(path37);
5929
6016
  }
5930
6017
  }
5931
6018
  function slowRedact(options = {}) {
@@ -6093,8 +6180,8 @@ var require_redaction = __commonJS({
6093
6180
  if (shape[k2] === null) {
6094
6181
  o[k2] = (value) => topCensor(value, [k2]);
6095
6182
  } else {
6096
- const wrappedCensor = typeof censor === "function" ? (value, path35) => {
6097
- return censor(value, [k2, ...path35]);
6183
+ const wrappedCensor = typeof censor === "function" ? (value, path37) => {
6184
+ return censor(value, [k2, ...path37]);
6098
6185
  } : censor;
6099
6186
  o[k2] = Redact({
6100
6187
  paths: shape[k2],
@@ -6312,10 +6399,10 @@ var require_atomic_sleep = __commonJS({
6312
6399
  var require_sonic_boom = __commonJS({
6313
6400
  "../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
6314
6401
  "use strict";
6315
- var fs31 = require("fs");
6402
+ var fs33 = require("fs");
6316
6403
  var EventEmitter2 = require("events");
6317
6404
  var inherits = require("util").inherits;
6318
- var path35 = require("path");
6405
+ var path37 = require("path");
6319
6406
  var sleep = require_atomic_sleep();
6320
6407
  var assert = require("assert");
6321
6408
  var BUSY_WRITE_TIMEOUT = 100;
@@ -6369,20 +6456,20 @@ var require_sonic_boom = __commonJS({
6369
6456
  const mode = sonic.mode;
6370
6457
  if (sonic.sync) {
6371
6458
  try {
6372
- if (sonic.mkdir) fs31.mkdirSync(path35.dirname(file), { recursive: true });
6373
- const fd = fs31.openSync(file, flags, mode);
6459
+ if (sonic.mkdir) fs33.mkdirSync(path37.dirname(file), { recursive: true });
6460
+ const fd = fs33.openSync(file, flags, mode);
6374
6461
  fileOpened(null, fd);
6375
6462
  } catch (err) {
6376
6463
  fileOpened(err);
6377
6464
  throw err;
6378
6465
  }
6379
6466
  } else if (sonic.mkdir) {
6380
- fs31.mkdir(path35.dirname(file), { recursive: true }, (err) => {
6467
+ fs33.mkdir(path37.dirname(file), { recursive: true }, (err) => {
6381
6468
  if (err) return fileOpened(err);
6382
- fs31.open(file, flags, mode, fileOpened);
6469
+ fs33.open(file, flags, mode, fileOpened);
6383
6470
  });
6384
6471
  } else {
6385
- fs31.open(file, flags, mode, fileOpened);
6472
+ fs33.open(file, flags, mode, fileOpened);
6386
6473
  }
6387
6474
  }
6388
6475
  function SonicBoom(opts) {
@@ -6423,8 +6510,8 @@ var require_sonic_boom = __commonJS({
6423
6510
  this.flush = flushBuffer;
6424
6511
  this.flushSync = flushBufferSync;
6425
6512
  this._actualWrite = actualWriteBuffer;
6426
- fsWriteSync = () => fs31.writeSync(this.fd, this._writingBuf);
6427
- fsWrite = () => fs31.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);
6428
6515
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
6429
6516
  this._writingBuf = "";
6430
6517
  this.write = write;
@@ -6433,15 +6520,15 @@ var require_sonic_boom = __commonJS({
6433
6520
  this._actualWrite = actualWrite;
6434
6521
  fsWriteSync = () => {
6435
6522
  if (Buffer.isBuffer(this._writingBuf)) {
6436
- return fs31.writeSync(this.fd, this._writingBuf);
6523
+ return fs33.writeSync(this.fd, this._writingBuf);
6437
6524
  }
6438
- return fs31.writeSync(this.fd, this._writingBuf, "utf8");
6525
+ return fs33.writeSync(this.fd, this._writingBuf, "utf8");
6439
6526
  };
6440
6527
  fsWrite = () => {
6441
6528
  if (Buffer.isBuffer(this._writingBuf)) {
6442
- return fs31.write(this.fd, this._writingBuf, this.release);
6529
+ return fs33.write(this.fd, this._writingBuf, this.release);
6443
6530
  }
6444
- return fs31.write(this.fd, this._writingBuf, "utf8", this.release);
6531
+ return fs33.write(this.fd, this._writingBuf, "utf8", this.release);
6445
6532
  };
6446
6533
  } else {
6447
6534
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -6498,7 +6585,7 @@ var require_sonic_boom = __commonJS({
6498
6585
  }
6499
6586
  }
6500
6587
  if (this._fsync) {
6501
- fs31.fsyncSync(this.fd);
6588
+ fs33.fsyncSync(this.fd);
6502
6589
  }
6503
6590
  const len = this._len;
6504
6591
  if (this._reopening) {
@@ -6612,7 +6699,7 @@ var require_sonic_boom = __commonJS({
6612
6699
  const onDrain = () => {
6613
6700
  if (!this._fsync) {
6614
6701
  try {
6615
- fs31.fsync(this.fd, (err) => {
6702
+ fs33.fsync(this.fd, (err) => {
6616
6703
  this._flushPending = false;
6617
6704
  cb(err);
6618
6705
  });
@@ -6714,7 +6801,7 @@ var require_sonic_boom = __commonJS({
6714
6801
  const fd = this.fd;
6715
6802
  this.once("ready", () => {
6716
6803
  if (fd !== this.fd) {
6717
- fs31.close(fd, (err) => {
6804
+ fs33.close(fd, (err) => {
6718
6805
  if (err) {
6719
6806
  return this.emit("error", err);
6720
6807
  }
@@ -6763,7 +6850,7 @@ var require_sonic_boom = __commonJS({
6763
6850
  buf = this._bufs[0];
6764
6851
  }
6765
6852
  try {
6766
- const n = Buffer.isBuffer(buf) ? fs31.writeSync(this.fd, buf) : fs31.writeSync(this.fd, buf, "utf8");
6853
+ const n = Buffer.isBuffer(buf) ? fs33.writeSync(this.fd, buf) : fs33.writeSync(this.fd, buf, "utf8");
6767
6854
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
6768
6855
  buf = releasedBufObj.writingBuf;
6769
6856
  this._len = releasedBufObj.len;
@@ -6779,7 +6866,7 @@ var require_sonic_boom = __commonJS({
6779
6866
  }
6780
6867
  }
6781
6868
  try {
6782
- fs31.fsyncSync(this.fd);
6869
+ fs33.fsyncSync(this.fd);
6783
6870
  } catch {
6784
6871
  }
6785
6872
  }
@@ -6800,7 +6887,7 @@ var require_sonic_boom = __commonJS({
6800
6887
  buf = mergeBuf(this._bufs[0], this._lens[0]);
6801
6888
  }
6802
6889
  try {
6803
- const n = fs31.writeSync(this.fd, buf);
6890
+ const n = fs33.writeSync(this.fd, buf);
6804
6891
  buf = buf.subarray(n);
6805
6892
  this._len = Math.max(this._len - n, 0);
6806
6893
  if (buf.length <= 0) {
@@ -6828,13 +6915,13 @@ var require_sonic_boom = __commonJS({
6828
6915
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
6829
6916
  if (this.sync) {
6830
6917
  try {
6831
- const written = Buffer.isBuffer(this._writingBuf) ? fs31.writeSync(this.fd, this._writingBuf) : fs31.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");
6832
6919
  release(null, written);
6833
6920
  } catch (err) {
6834
6921
  release(err);
6835
6922
  }
6836
6923
  } else {
6837
- fs31.write(this.fd, this._writingBuf, release);
6924
+ fs33.write(this.fd, this._writingBuf, release);
6838
6925
  }
6839
6926
  }
6840
6927
  function actualWriteBuffer() {
@@ -6843,7 +6930,7 @@ var require_sonic_boom = __commonJS({
6843
6930
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
6844
6931
  if (this.sync) {
6845
6932
  try {
6846
- const written = fs31.writeSync(this.fd, this._writingBuf);
6933
+ const written = fs33.writeSync(this.fd, this._writingBuf);
6847
6934
  release(null, written);
6848
6935
  } catch (err) {
6849
6936
  release(err);
@@ -6852,7 +6939,7 @@ var require_sonic_boom = __commonJS({
6852
6939
  if (kCopyBuffer) {
6853
6940
  this._writingBuf = Buffer.from(this._writingBuf);
6854
6941
  }
6855
- fs31.write(this.fd, this._writingBuf, release);
6942
+ fs33.write(this.fd, this._writingBuf, release);
6856
6943
  }
6857
6944
  }
6858
6945
  function actualClose(sonic) {
@@ -6868,12 +6955,12 @@ var require_sonic_boom = __commonJS({
6868
6955
  sonic._lens = [];
6869
6956
  assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
6870
6957
  try {
6871
- fs31.fsync(sonic.fd, closeWrapped);
6958
+ fs33.fsync(sonic.fd, closeWrapped);
6872
6959
  } catch {
6873
6960
  }
6874
6961
  function closeWrapped() {
6875
6962
  if (sonic.fd !== 1 && sonic.fd !== 2) {
6876
- fs31.close(sonic.fd, done);
6963
+ fs33.close(sonic.fd, done);
6877
6964
  } else {
6878
6965
  done();
6879
6966
  }
@@ -7130,7 +7217,7 @@ var require_thread_stream = __commonJS({
7130
7217
  var { version: version2 } = require_package();
7131
7218
  var { EventEmitter: EventEmitter2 } = require("events");
7132
7219
  var { Worker } = require("worker_threads");
7133
- var { join: join8 } = require("path");
7220
+ var { join: join10 } = require("path");
7134
7221
  var { pathToFileURL } = require("url");
7135
7222
  var { wait } = require_wait();
7136
7223
  var {
@@ -7166,7 +7253,7 @@ var require_thread_stream = __commonJS({
7166
7253
  function createWorker(stream, opts) {
7167
7254
  const { filename, workerData } = opts;
7168
7255
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
7169
- const toExecute = bundlerOverrides["thread-stream-worker"] || join8(__dirname, "lib", "worker.js");
7256
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join10(__dirname, "lib", "worker.js");
7170
7257
  const worker = new Worker(toExecute, {
7171
7258
  ...opts.workerOpts,
7172
7259
  trackUnmanagedFds: false,
@@ -7552,7 +7639,7 @@ var require_transport = __commonJS({
7552
7639
  "use strict";
7553
7640
  var { createRequire } = require("module");
7554
7641
  var getCallers = require_caller();
7555
- var { join: join8, isAbsolute, sep: sep2 } = require("path");
7642
+ var { join: join10, isAbsolute, sep: sep2 } = require("path");
7556
7643
  var sleep = require_atomic_sleep();
7557
7644
  var onExit = require_on_exit_leak_free();
7558
7645
  var ThreadStream = require_thread_stream();
@@ -7615,7 +7702,7 @@ var require_transport = __commonJS({
7615
7702
  throw new Error("only one of target or targets can be specified");
7616
7703
  }
7617
7704
  if (targets) {
7618
- target = bundlerOverrides["pino-worker"] || join8(__dirname, "worker.js");
7705
+ target = bundlerOverrides["pino-worker"] || join10(__dirname, "worker.js");
7619
7706
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
7620
7707
  return {
7621
7708
  ...dest,
@@ -7633,7 +7720,7 @@ var require_transport = __commonJS({
7633
7720
  });
7634
7721
  });
7635
7722
  } else if (pipeline2) {
7636
- target = bundlerOverrides["pino-worker"] || join8(__dirname, "worker.js");
7723
+ target = bundlerOverrides["pino-worker"] || join10(__dirname, "worker.js");
7637
7724
  options.pipelines = [pipeline2.map((dest) => {
7638
7725
  return {
7639
7726
  ...dest,
@@ -7655,7 +7742,7 @@ var require_transport = __commonJS({
7655
7742
  return origin;
7656
7743
  }
7657
7744
  if (origin === "pino/file") {
7658
- return join8(__dirname, "..", "file.js");
7745
+ return join10(__dirname, "..", "file.js");
7659
7746
  }
7660
7747
  let fixTarget2;
7661
7748
  for (const filePath of callers) {
@@ -8645,7 +8732,7 @@ var require_safe_stable_stringify = __commonJS({
8645
8732
  return circularValue;
8646
8733
  }
8647
8734
  let res = "";
8648
- let join8 = ",";
8735
+ let join10 = ",";
8649
8736
  const originalIndentation = indentation;
8650
8737
  if (Array.isArray(value)) {
8651
8738
  if (value.length === 0) {
@@ -8659,7 +8746,7 @@ var require_safe_stable_stringify = __commonJS({
8659
8746
  indentation += spacer;
8660
8747
  res += `
8661
8748
  ${indentation}`;
8662
- join8 = `,
8749
+ join10 = `,
8663
8750
  ${indentation}`;
8664
8751
  }
8665
8752
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -8667,13 +8754,13 @@ ${indentation}`;
8667
8754
  for (; i < maximumValuesToStringify - 1; i++) {
8668
8755
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
8669
8756
  res += tmp2 !== void 0 ? tmp2 : "null";
8670
- res += join8;
8757
+ res += join10;
8671
8758
  }
8672
8759
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
8673
8760
  res += tmp !== void 0 ? tmp : "null";
8674
8761
  if (value.length - 1 > maximumBreadth) {
8675
8762
  const removedKeys = value.length - maximumBreadth - 1;
8676
- res += `${join8}"... ${getItemCount(removedKeys)} not stringified"`;
8763
+ res += `${join10}"... ${getItemCount(removedKeys)} not stringified"`;
8677
8764
  }
8678
8765
  if (spacer !== "") {
8679
8766
  res += `
@@ -8694,7 +8781,7 @@ ${originalIndentation}`;
8694
8781
  let separator = "";
8695
8782
  if (spacer !== "") {
8696
8783
  indentation += spacer;
8697
- join8 = `,
8784
+ join10 = `,
8698
8785
  ${indentation}`;
8699
8786
  whitespace = " ";
8700
8787
  }
@@ -8708,13 +8795,13 @@ ${indentation}`;
8708
8795
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
8709
8796
  if (tmp !== void 0) {
8710
8797
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
8711
- separator = join8;
8798
+ separator = join10;
8712
8799
  }
8713
8800
  }
8714
8801
  if (keyLength > maximumBreadth) {
8715
8802
  const removedKeys = keyLength - maximumBreadth;
8716
8803
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
8717
- separator = join8;
8804
+ separator = join10;
8718
8805
  }
8719
8806
  if (spacer !== "" && separator.length > 1) {
8720
8807
  res = `
@@ -8755,7 +8842,7 @@ ${originalIndentation}`;
8755
8842
  }
8756
8843
  const originalIndentation = indentation;
8757
8844
  let res = "";
8758
- let join8 = ",";
8845
+ let join10 = ",";
8759
8846
  if (Array.isArray(value)) {
8760
8847
  if (value.length === 0) {
8761
8848
  return "[]";
@@ -8768,7 +8855,7 @@ ${originalIndentation}`;
8768
8855
  indentation += spacer;
8769
8856
  res += `
8770
8857
  ${indentation}`;
8771
- join8 = `,
8858
+ join10 = `,
8772
8859
  ${indentation}`;
8773
8860
  }
8774
8861
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -8776,13 +8863,13 @@ ${indentation}`;
8776
8863
  for (; i < maximumValuesToStringify - 1; i++) {
8777
8864
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
8778
8865
  res += tmp2 !== void 0 ? tmp2 : "null";
8779
- res += join8;
8866
+ res += join10;
8780
8867
  }
8781
8868
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
8782
8869
  res += tmp !== void 0 ? tmp : "null";
8783
8870
  if (value.length - 1 > maximumBreadth) {
8784
8871
  const removedKeys = value.length - maximumBreadth - 1;
8785
- res += `${join8}"... ${getItemCount(removedKeys)} not stringified"`;
8872
+ res += `${join10}"... ${getItemCount(removedKeys)} not stringified"`;
8786
8873
  }
8787
8874
  if (spacer !== "") {
8788
8875
  res += `
@@ -8795,7 +8882,7 @@ ${originalIndentation}`;
8795
8882
  let whitespace = "";
8796
8883
  if (spacer !== "") {
8797
8884
  indentation += spacer;
8798
- join8 = `,
8885
+ join10 = `,
8799
8886
  ${indentation}`;
8800
8887
  whitespace = " ";
8801
8888
  }
@@ -8804,7 +8891,7 @@ ${indentation}`;
8804
8891
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
8805
8892
  if (tmp !== void 0) {
8806
8893
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
8807
- separator = join8;
8894
+ separator = join10;
8808
8895
  }
8809
8896
  }
8810
8897
  if (spacer !== "" && separator.length > 1) {
@@ -8862,20 +8949,20 @@ ${originalIndentation}`;
8862
8949
  indentation += spacer;
8863
8950
  let res2 = `
8864
8951
  ${indentation}`;
8865
- const join9 = `,
8952
+ const join11 = `,
8866
8953
  ${indentation}`;
8867
8954
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
8868
8955
  let i = 0;
8869
8956
  for (; i < maximumValuesToStringify - 1; i++) {
8870
8957
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
8871
8958
  res2 += tmp2 !== void 0 ? tmp2 : "null";
8872
- res2 += join9;
8959
+ res2 += join11;
8873
8960
  }
8874
8961
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
8875
8962
  res2 += tmp !== void 0 ? tmp : "null";
8876
8963
  if (value.length - 1 > maximumBreadth) {
8877
8964
  const removedKeys = value.length - maximumBreadth - 1;
8878
- res2 += `${join9}"... ${getItemCount(removedKeys)} not stringified"`;
8965
+ res2 += `${join11}"... ${getItemCount(removedKeys)} not stringified"`;
8879
8966
  }
8880
8967
  res2 += `
8881
8968
  ${originalIndentation}`;
@@ -8891,16 +8978,16 @@ ${originalIndentation}`;
8891
8978
  return '"[Object]"';
8892
8979
  }
8893
8980
  indentation += spacer;
8894
- const join8 = `,
8981
+ const join10 = `,
8895
8982
  ${indentation}`;
8896
8983
  let res = "";
8897
8984
  let separator = "";
8898
8985
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
8899
8986
  if (isTypedArrayWithEntries(value)) {
8900
- res += stringifyTypedArray(value, join8, maximumBreadth);
8987
+ res += stringifyTypedArray(value, join10, maximumBreadth);
8901
8988
  keys = keys.slice(value.length);
8902
8989
  maximumPropertiesToStringify -= value.length;
8903
- separator = join8;
8990
+ separator = join10;
8904
8991
  }
8905
8992
  if (deterministic) {
8906
8993
  keys = sort(keys, comparator);
@@ -8911,13 +8998,13 @@ ${indentation}`;
8911
8998
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
8912
8999
  if (tmp !== void 0) {
8913
9000
  res += `${separator}${strEscape(key2)}: ${tmp}`;
8914
- separator = join8;
9001
+ separator = join10;
8915
9002
  }
8916
9003
  }
8917
9004
  if (keyLength > maximumBreadth) {
8918
9005
  const removedKeys = keyLength - maximumBreadth;
8919
9006
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
8920
- separator = join8;
9007
+ separator = join10;
8921
9008
  }
8922
9009
  if (separator !== "") {
8923
9010
  res = `
@@ -10008,11 +10095,11 @@ var init_lib = __esm({
10008
10095
  }
10009
10096
  }
10010
10097
  },
10011
- addToPath: function addToPath(path35, added, removed, oldPosInc, options) {
10012
- var last = path35.lastComponent;
10098
+ addToPath: function addToPath(path37, added, removed, oldPosInc, options) {
10099
+ var last = path37.lastComponent;
10013
10100
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
10014
10101
  return {
10015
- oldPos: path35.oldPos + oldPosInc,
10102
+ oldPos: path37.oldPos + oldPosInc,
10016
10103
  lastComponent: {
10017
10104
  count: last.count + 1,
10018
10105
  added,
@@ -10022,7 +10109,7 @@ var init_lib = __esm({
10022
10109
  };
10023
10110
  } else {
10024
10111
  return {
10025
- oldPos: path35.oldPos + oldPosInc,
10112
+ oldPos: path37.oldPos + oldPosInc,
10026
10113
  lastComponent: {
10027
10114
  count: 1,
10028
10115
  added,
@@ -10453,10 +10540,10 @@ function attachmentToHistoryMessage(o, ts) {
10453
10540
  const memories = raw.map((m2) => {
10454
10541
  if (!m2 || typeof m2 !== "object") return null;
10455
10542
  const rec = m2;
10456
- const path35 = typeof rec.path === "string" ? rec.path : null;
10543
+ const path37 = typeof rec.path === "string" ? rec.path : null;
10457
10544
  const content = typeof rec.content === "string" ? rec.content : null;
10458
- if (!path35 || content == null) return null;
10459
- const entry = { path: path35, content };
10545
+ if (!path37 || content == null) return null;
10546
+ const entry = { path: path37, content };
10460
10547
  if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
10461
10548
  return entry;
10462
10549
  }).filter((m2) => m2 !== null);
@@ -11282,10 +11369,10 @@ function parseAttachment(obj) {
11282
11369
  const memories = raw.map((m2) => {
11283
11370
  if (!m2 || typeof m2 !== "object") return null;
11284
11371
  const rec = m2;
11285
- const path35 = typeof rec.path === "string" ? rec.path : null;
11372
+ const path37 = typeof rec.path === "string" ? rec.path : null;
11286
11373
  const content = typeof rec.content === "string" ? rec.content : null;
11287
- if (!path35 || content == null) return null;
11288
- const out = { path: path35, content };
11374
+ if (!path37 || content == null) return null;
11375
+ const out = { path: path37, content };
11289
11376
  if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
11290
11377
  return out;
11291
11378
  }).filter((m2) => m2 !== null);
@@ -18784,7 +18871,7 @@ var require_websocket = __commonJS({
18784
18871
  var http2 = require("http");
18785
18872
  var net = require("net");
18786
18873
  var tls = require("tls");
18787
- var { randomBytes: randomBytes2, createHash: createHash3 } = require("crypto");
18874
+ var { randomBytes: randomBytes3, createHash: createHash4 } = require("crypto");
18788
18875
  var { Duplex, Readable: Readable3 } = require("stream");
18789
18876
  var { URL: URL2 } = require("url");
18790
18877
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -19314,7 +19401,7 @@ var require_websocket = __commonJS({
19314
19401
  }
19315
19402
  }
19316
19403
  const defaultPort = isSecure ? 443 : 80;
19317
- const key = randomBytes2(16).toString("base64");
19404
+ const key = randomBytes3(16).toString("base64");
19318
19405
  const request = isSecure ? https.request : http2.request;
19319
19406
  const protocolSet = /* @__PURE__ */ new Set();
19320
19407
  let perMessageDeflate;
@@ -19444,7 +19531,7 @@ var require_websocket = __commonJS({
19444
19531
  abortHandshake(websocket, socket, "Invalid Upgrade header");
19445
19532
  return;
19446
19533
  }
19447
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
19534
+ const digest = createHash4("sha1").update(key + GUID).digest("base64");
19448
19535
  if (res.headers["sec-websocket-accept"] !== digest) {
19449
19536
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
19450
19537
  return;
@@ -19811,7 +19898,7 @@ var require_websocket_server = __commonJS({
19811
19898
  var EventEmitter2 = require("events");
19812
19899
  var http2 = require("http");
19813
19900
  var { Duplex } = require("stream");
19814
- var { createHash: createHash3 } = require("crypto");
19901
+ var { createHash: createHash4 } = require("crypto");
19815
19902
  var extension2 = require_extension();
19816
19903
  var PerMessageDeflate2 = require_permessage_deflate();
19817
19904
  var subprotocol2 = require_subprotocol();
@@ -20112,7 +20199,7 @@ var require_websocket_server = __commonJS({
20112
20199
  );
20113
20200
  }
20114
20201
  if (this._state > RUNNING) return abortHandshake(socket, 503);
20115
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
20202
+ const digest = createHash4("sha1").update(key + GUID).digest("base64");
20116
20203
  const headers = [
20117
20204
  "HTTP/1.1 101 Switching Protocols",
20118
20205
  "Upgrade: websocket",
@@ -25512,6 +25599,23 @@ var LocalWsServer = class {
25512
25599
  this.safeSend(c.ws, frame);
25513
25600
  }
25514
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
+ }
25515
25619
  firstSubscriber(sessionId) {
25516
25620
  for (const c of this.clients.values()) {
25517
25621
  if (c.handle.subscribedSessions.has(sessionId)) return c.handle;
@@ -26112,62 +26216,323 @@ function cleanupGuestSessionsForCapability(cap, factory) {
26112
26216
  return { removed };
26113
26217
  }
26114
26218
 
26115
- // src/migrations/2026-05-20-flatten-sessions.ts
26219
+ // src/inbox/inbox-store.ts
26116
26220
  var fs17 = __toESM(require("fs"), 1);
26117
26221
  var path19 = __toESM(require("path"), 1);
26222
+ var INBOX_FILE_NAME = "inbox.jsonl";
26223
+ var InboxStore = class {
26224
+ constructor(dataDir) {
26225
+ this.dataDir = dataDir;
26226
+ fs17.mkdirSync(dataDir, { recursive: true });
26227
+ }
26228
+ dataDir;
26229
+ list() {
26230
+ const file = this.filePath();
26231
+ let raw;
26232
+ try {
26233
+ raw = fs17.readFileSync(file, "utf8");
26234
+ } catch (err) {
26235
+ if (err?.code === "ENOENT") return [];
26236
+ return [];
26237
+ }
26238
+ return parseAllLines(raw);
26239
+ }
26240
+ append(ev) {
26241
+ const file = this.filePath();
26242
+ const line = JSON.stringify(ev) + "\n";
26243
+ fs17.appendFileSync(file, line, { mode: 384 });
26244
+ try {
26245
+ fs17.chmodSync(file, 384);
26246
+ } catch {
26247
+ }
26248
+ }
26249
+ /**
26250
+ * 标记某条 event 为已读. 已有 readAt 时不覆盖 (idempotent: 第二次调用维持第一次时间).
26251
+ * 未知 id 静默 no-op (不抛, 不写文件).
26252
+ */
26253
+ markRead(id, at) {
26254
+ const events = this.list();
26255
+ let changed = false;
26256
+ const next = events.map((e) => {
26257
+ if (e.id !== id) return e;
26258
+ if (e.readAt !== void 0) return e;
26259
+ changed = true;
26260
+ return { ...e, readAt: at };
26261
+ });
26262
+ if (!changed) return;
26263
+ this.rewrite(next);
26264
+ }
26265
+ rewrite(events) {
26266
+ const file = this.filePath();
26267
+ const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
26268
+ const content = events.map((e) => JSON.stringify(e)).join("\n") + (events.length > 0 ? "\n" : "");
26269
+ fs17.writeFileSync(tmp, content, { mode: 384 });
26270
+ fs17.renameSync(tmp, file);
26271
+ try {
26272
+ fs17.chmodSync(file, 384);
26273
+ } catch {
26274
+ }
26275
+ }
26276
+ filePath() {
26277
+ return path19.join(this.dataDir, INBOX_FILE_NAME);
26278
+ }
26279
+ };
26280
+ function parseAllLines(raw) {
26281
+ const out = [];
26282
+ for (const line of raw.split("\n")) {
26283
+ const trimmed = line.trim();
26284
+ if (!trimmed) continue;
26285
+ let parsed;
26286
+ try {
26287
+ parsed = JSON.parse(trimmed);
26288
+ } catch {
26289
+ continue;
26290
+ }
26291
+ const r = InboxEventSchema.safeParse(parsed);
26292
+ if (r.success) out.push(r.data);
26293
+ }
26294
+ return out;
26295
+ }
26296
+
26297
+ // src/inbox/inbox-manager.ts
26298
+ var crypto7 = __toESM(require("crypto"), 1);
26299
+
26300
+ // src/inbox/dm.ts
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
26308
+ var InboxManager = class {
26309
+ constructor(store, broadcast, opts = {}) {
26310
+ this.store = store;
26311
+ this.broadcast = broadcast;
26312
+ this.now = opts.now ?? Date.now;
26313
+ this.genId = opts.genId ?? defaultGenId;
26314
+ }
26315
+ store;
26316
+ broadcast;
26317
+ now;
26318
+ genId;
26319
+ /**
26320
+ * persona VM 内某 sender 给 CC 发消息 → 跨 principal 时记 inbox event.
26321
+ * 返回 null = owner 自己 (no-op); 否则返回写入的 event (含派生 id / createdAt).
26322
+ */
26323
+ recordPersonaMention(args) {
26324
+ if (args.sender.kind === "owner") return null;
26325
+ const resource = { type: "persona", id: args.personaId };
26326
+ const ev = {
26327
+ id: this.genId(),
26328
+ kind: "persona-mention",
26329
+ fromPrincipal: args.sender,
26330
+ toPrincipal: OWNER_PRINCIPAL,
26331
+ resource,
26332
+ preview: truncatePreview(args.preview),
26333
+ createdAt: this.now()
26334
+ };
26335
+ this.store.append(ev);
26336
+ this.broadcast({ type: "inbox:event", event: ev });
26337
+ return ev;
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
+ }
26363
+ list(opts = {}) {
26364
+ const all = this.store.list();
26365
+ if (opts.includeRead) return all;
26366
+ return all.filter((e) => e.readAt === void 0);
26367
+ }
26368
+ markRead(eventId) {
26369
+ this.store.markRead(eventId, this.now());
26370
+ }
26371
+ };
26372
+ function truncatePreview(s) {
26373
+ if (s.length <= INBOX_PREVIEW_MAX_LENGTH) return s;
26374
+ return s.slice(0, INBOX_PREVIEW_MAX_LENGTH);
26375
+ }
26376
+ function defaultGenId() {
26377
+ return "inb_" + crypto7.randomBytes(6).toString("base64url");
26378
+ }
26379
+
26380
+ // src/remote-persona/store.ts
26381
+ var fs18 = __toESM(require("fs"), 1);
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);
26118
26483
  var MIGRATION_FLAG_NAME = ".migration.v1.done";
26119
26484
  function migrateFlattenSessions(opts) {
26120
26485
  const dataDir = opts.dataDir;
26121
26486
  const now = opts.now ?? Date.now;
26122
- const sessionsDir = path19.join(dataDir, "sessions");
26123
- const flagPath = path19.join(sessionsDir, MIGRATION_FLAG_NAME);
26124
- if (existsSync3(flagPath)) {
26487
+ const sessionsDir = path21.join(dataDir, "sessions");
26488
+ const flagPath = path21.join(sessionsDir, MIGRATION_FLAG_NAME);
26489
+ if (existsSync4(flagPath)) {
26125
26490
  return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
26126
26491
  }
26127
26492
  let movedBare = 0;
26128
26493
  let movedVmOwner = 0;
26129
26494
  let archivedListener = 0;
26130
- const defaultDir = path19.join(sessionsDir, "default");
26131
- if (existsSync3(defaultDir)) {
26495
+ const defaultDir = path21.join(sessionsDir, "default");
26496
+ if (existsSync4(defaultDir)) {
26132
26497
  for (const entry of readdirSafe(defaultDir)) {
26133
26498
  if (!entry.endsWith(".json")) continue;
26134
- const src = path19.join(defaultDir, entry);
26135
- const dst = path19.join(sessionsDir, entry);
26136
- fs17.renameSync(src, dst);
26499
+ const src = path21.join(defaultDir, entry);
26500
+ const dst = path21.join(sessionsDir, entry);
26501
+ fs19.renameSync(src, dst);
26137
26502
  movedBare += 1;
26138
26503
  }
26139
26504
  rmdirIfEmpty(defaultDir);
26140
26505
  }
26141
26506
  for (const pid of readdirSafe(sessionsDir)) {
26142
- const personaDir = path19.join(sessionsDir, pid);
26507
+ const personaDir = path21.join(sessionsDir, pid);
26143
26508
  if (!isDir(personaDir)) continue;
26144
26509
  if (pid === "default") continue;
26145
- const ownerSrc = path19.join(personaDir, "owner");
26146
- if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
26147
- const ownerDst = path19.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
26148
- fs17.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 });
26149
26514
  for (const file of readdirSafe(ownerSrc)) {
26150
26515
  if (!file.endsWith(".json")) continue;
26151
- fs17.renameSync(path19.join(ownerSrc, file), path19.join(ownerDst, file));
26516
+ fs19.renameSync(path21.join(ownerSrc, file), path21.join(ownerDst, file));
26152
26517
  movedVmOwner += 1;
26153
26518
  }
26154
26519
  rmdirIfEmpty(ownerSrc);
26155
26520
  }
26156
- const listenerSrc = path19.join(personaDir, "listener");
26157
- if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
26158
- const archiveDst = path19.join(dataDir, ".legacy", `listener-${pid}`);
26159
- fs17.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 });
26160
26525
  for (const file of readdirSafe(listenerSrc)) {
26161
26526
  if (!file.endsWith(".json")) continue;
26162
- fs17.renameSync(path19.join(listenerSrc, file), path19.join(archiveDst, file));
26527
+ fs19.renameSync(path21.join(listenerSrc, file), path21.join(archiveDst, file));
26163
26528
  archivedListener += 1;
26164
26529
  }
26165
26530
  rmdirIfEmpty(listenerSrc);
26166
26531
  }
26167
26532
  rmdirIfEmpty(personaDir);
26168
26533
  }
26169
- fs17.mkdirSync(sessionsDir, { recursive: true });
26170
- fs17.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
26534
+ fs19.mkdirSync(sessionsDir, { recursive: true });
26535
+ fs19.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
26171
26536
  return {
26172
26537
  skipped: false,
26173
26538
  flagWritten: true,
@@ -26176,9 +26541,9 @@ function migrateFlattenSessions(opts) {
26176
26541
  archivedListener
26177
26542
  };
26178
26543
  }
26179
- function existsSync3(p2) {
26544
+ function existsSync4(p2) {
26180
26545
  try {
26181
- fs17.statSync(p2);
26546
+ fs19.statSync(p2);
26182
26547
  return true;
26183
26548
  } catch {
26184
26549
  return false;
@@ -26186,21 +26551,21 @@ function existsSync3(p2) {
26186
26551
  }
26187
26552
  function isDir(p2) {
26188
26553
  try {
26189
- return fs17.statSync(p2).isDirectory();
26554
+ return fs19.statSync(p2).isDirectory();
26190
26555
  } catch {
26191
26556
  return false;
26192
26557
  }
26193
26558
  }
26194
26559
  function readdirSafe(p2) {
26195
26560
  try {
26196
- return fs17.readdirSync(p2);
26561
+ return fs19.readdirSync(p2);
26197
26562
  } catch {
26198
26563
  return [];
26199
26564
  }
26200
26565
  }
26201
26566
  function rmdirIfEmpty(p2) {
26202
26567
  try {
26203
- fs17.rmdirSync(p2);
26568
+ fs19.rmdirSync(p2);
26204
26569
  } catch {
26205
26570
  }
26206
26571
  }
@@ -28051,6 +28416,113 @@ function buildCapabilityHandlers(deps) {
28051
28416
  };
28052
28417
  }
28053
28418
 
28419
+ // src/handlers/inbox.ts
28420
+ init_protocol();
28421
+ function buildInboxHandlers(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
+ }
28436
+ const list = async (frame) => {
28437
+ const { type: _t, requestId: _r, ...rest } = frame;
28438
+ const args = InboxListArgsSchema.parse(rest);
28439
+ const events = manager.list({ includeRead: args.includeRead ?? false });
28440
+ return {
28441
+ response: { type: "inbox:list", events }
28442
+ };
28443
+ };
28444
+ const markRead = async (frame) => {
28445
+ const { type: _t, requestId: _r, ...rest } = frame;
28446
+ const args = InboxMarkReadArgsSchema.parse(rest);
28447
+ manager.markRead(args.eventId);
28448
+ return {
28449
+ response: { type: "inbox:markRead:ok", eventId: args.eventId }
28450
+ };
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
+ };
28468
+ return {
28469
+ "inbox:list": list,
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
28523
+ };
28524
+ }
28525
+
28054
28526
  // src/handlers/meta.ts
28055
28527
  var import_node_os13 = __toESM(require("os"), 1);
28056
28528
  init_protocol();
@@ -28303,6 +28775,11 @@ function buildMethodHandlers(deps) {
28303
28775
  personaRegistry: deps.personaRegistry
28304
28776
  }),
28305
28777
  ...buildCapabilityHandlers({ manager: deps.capabilityManager }),
28778
+ ...buildInboxHandlers({
28779
+ manager: deps.inboxManager,
28780
+ capabilityRegistry: deps.capabilityRegistry
28781
+ }),
28782
+ ...buildRemotePersonaHandlers({ store: deps.remotePersonaStore }),
28306
28783
  ...deps.attachment ? buildAttachmentHandlers(deps.attachment) : {}
28307
28784
  };
28308
28785
  }
@@ -28321,6 +28798,16 @@ var METHOD_GRANT_MAP = {
28321
28798
  "capability:issue": ADMIN_ANY,
28322
28799
  "capability:list": ADMIN_ANY,
28323
28800
  "capability:revoke": ADMIN_ANY,
28801
+ // ---- inbox 跨用户通知 (Phase 3 admin-only, owner 调; Phase 4 加 postMessage) ----
28802
+ "inbox:list": ADMIN_ANY,
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,
28324
28811
  // ---- 业务方法:Phase 1 全 admin-only(owner 自动通过;guest 无法调用) ----
28325
28812
  "session:create": ADMIN_ANY,
28326
28813
  "session:list": ADMIN_ANY,
@@ -28451,6 +28938,18 @@ async function startDaemon(config) {
28451
28938
  }
28452
28939
  }
28453
28940
  });
28941
+ const inboxStore = new InboxStore(config.dataDir);
28942
+ const remotePersonaStore = new RemotePersonaStore(config.dataDir);
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
+ }
28951
+ wsServer?.broadcastToOwners(frame);
28952
+ });
28454
28953
  let wsServer = null;
28455
28954
  const authGate = authMode === "first-message" ? new AuthGate({
28456
28955
  shouldEnforce: buildShouldEnforce({ tunnel: config.tunnel }),
@@ -28640,7 +29139,13 @@ async function startDaemon(config) {
28640
29139
  }
28641
29140
  },
28642
29141
  // Task 1.9: capability:issue/list/revoke handler 依赖
28643
- capabilityManager
29142
+ capabilityManager,
29143
+ // Phase 4 Task 4.2: inbox:postMessage 要查 capabilityRegistry 解析 peer Principal
29144
+ capabilityRegistry,
29145
+ // Phase 3 Task 3.4: inbox:list/markRead handler 依赖
29146
+ inboxManager,
29147
+ // Phase 4 Task 4.3: remote-persona:* handler 依赖 (本地存储, v1 不接 outgoing WS)
29148
+ remotePersonaStore
28644
29149
  });
28645
29150
  const authResolver = new AuthContextResolver({
28646
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.124.b09b0a0",
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",