@clawos-dev/clawd 0.2.71-beta.123.6a5ed6f → 0.2.71-beta.125.4951782
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.
- package/dist/cli.cjs +585 -134
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -121,6 +121,11 @@ 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).
|
|
127
|
+
"inbox:list",
|
|
128
|
+
"inbox:markRead",
|
|
124
129
|
"info",
|
|
125
130
|
"ping"
|
|
126
131
|
];
|
|
@@ -612,8 +617,8 @@ var init_parseUtil = __esm({
|
|
|
612
617
|
init_errors2();
|
|
613
618
|
init_en();
|
|
614
619
|
makeIssue = (params) => {
|
|
615
|
-
const { data, path:
|
|
616
|
-
const fullPath = [...
|
|
620
|
+
const { data, path: path36, errorMaps, issueData } = params;
|
|
621
|
+
const fullPath = [...path36, ...issueData.path || []];
|
|
617
622
|
const fullIssue = {
|
|
618
623
|
...issueData,
|
|
619
624
|
path: fullPath
|
|
@@ -924,11 +929,11 @@ var init_types = __esm({
|
|
|
924
929
|
init_parseUtil();
|
|
925
930
|
init_util();
|
|
926
931
|
ParseInputLazyPath = class {
|
|
927
|
-
constructor(parent, value,
|
|
932
|
+
constructor(parent, value, path36, key) {
|
|
928
933
|
this._cachedPath = [];
|
|
929
934
|
this.parent = parent;
|
|
930
935
|
this.data = value;
|
|
931
|
-
this._path =
|
|
936
|
+
this._path = path36;
|
|
932
937
|
this._key = key;
|
|
933
938
|
}
|
|
934
939
|
get path() {
|
|
@@ -5112,6 +5117,40 @@ var init_capability = __esm({
|
|
|
5112
5117
|
}
|
|
5113
5118
|
});
|
|
5114
5119
|
|
|
5120
|
+
// ../protocol/src/inbox.ts
|
|
5121
|
+
var INBOX_EVENT_KIND_VALUES, InboxEventKindSchema, INBOX_PREVIEW_MAX_LENGTH, InboxEventSchema, InboxListArgsSchema, InboxMarkReadArgsSchema;
|
|
5122
|
+
var init_inbox = __esm({
|
|
5123
|
+
"../protocol/src/inbox.ts"() {
|
|
5124
|
+
"use strict";
|
|
5125
|
+
init_zod();
|
|
5126
|
+
init_principal();
|
|
5127
|
+
init_capability();
|
|
5128
|
+
INBOX_EVENT_KIND_VALUES = ["persona-mention", "direct-message"];
|
|
5129
|
+
InboxEventKindSchema = external_exports.enum(INBOX_EVENT_KIND_VALUES);
|
|
5130
|
+
INBOX_PREVIEW_MAX_LENGTH = 140;
|
|
5131
|
+
InboxEventSchema = external_exports.object({
|
|
5132
|
+
id: external_exports.string().min(1),
|
|
5133
|
+
kind: InboxEventKindSchema,
|
|
5134
|
+
fromPrincipal: PrincipalSchema,
|
|
5135
|
+
toPrincipal: PrincipalSchema,
|
|
5136
|
+
// persona-mention 才有, direct-message 不带
|
|
5137
|
+
resource: ResourceSchema.optional(),
|
|
5138
|
+
preview: external_exports.string().max(INBOX_PREVIEW_MAX_LENGTH),
|
|
5139
|
+
createdAt: external_exports.number().int().nonnegative(),
|
|
5140
|
+
readAt: external_exports.number().int().positive().optional(),
|
|
5141
|
+
// direct-message 才有, sha256 hex 64; 派生规则: sha256(min(A,B) + '/' + max(A,B))
|
|
5142
|
+
threadId: external_exports.string().regex(/^[a-f0-9]{64}$/).optional()
|
|
5143
|
+
}).strict();
|
|
5144
|
+
InboxListArgsSchema = external_exports.object({
|
|
5145
|
+
// false / 缺省 = 只返回未读; true = 含已读 (历史回溯用)
|
|
5146
|
+
includeRead: external_exports.boolean().optional()
|
|
5147
|
+
}).strict();
|
|
5148
|
+
InboxMarkReadArgsSchema = external_exports.object({
|
|
5149
|
+
eventId: external_exports.string().min(1)
|
|
5150
|
+
}).strict();
|
|
5151
|
+
}
|
|
5152
|
+
});
|
|
5153
|
+
|
|
5115
5154
|
// ../protocol/src/runtime.ts
|
|
5116
5155
|
var init_runtime = __esm({
|
|
5117
5156
|
"../protocol/src/runtime.ts"() {
|
|
@@ -5126,6 +5165,7 @@ var init_runtime = __esm({
|
|
|
5126
5165
|
init_attachment_schemas();
|
|
5127
5166
|
init_principal();
|
|
5128
5167
|
init_capability();
|
|
5168
|
+
init_inbox();
|
|
5129
5169
|
}
|
|
5130
5170
|
});
|
|
5131
5171
|
|
|
@@ -5400,8 +5440,8 @@ var require_req = __commonJS({
|
|
|
5400
5440
|
if (req.originalUrl) {
|
|
5401
5441
|
_req.url = req.originalUrl;
|
|
5402
5442
|
} else {
|
|
5403
|
-
const
|
|
5404
|
-
_req.url = typeof
|
|
5443
|
+
const path36 = req.path;
|
|
5444
|
+
_req.url = typeof path36 === "string" ? path36 : req.url ? req.url.path || req.url : void 0;
|
|
5405
5445
|
}
|
|
5406
5446
|
if (req.query) {
|
|
5407
5447
|
_req.query = req.query;
|
|
@@ -5566,14 +5606,14 @@ var require_redact = __commonJS({
|
|
|
5566
5606
|
}
|
|
5567
5607
|
return obj;
|
|
5568
5608
|
}
|
|
5569
|
-
function parsePath(
|
|
5609
|
+
function parsePath(path36) {
|
|
5570
5610
|
const parts = [];
|
|
5571
5611
|
let current = "";
|
|
5572
5612
|
let inBrackets = false;
|
|
5573
5613
|
let inQuotes = false;
|
|
5574
5614
|
let quoteChar = "";
|
|
5575
|
-
for (let i = 0; i <
|
|
5576
|
-
const char =
|
|
5615
|
+
for (let i = 0; i < path36.length; i++) {
|
|
5616
|
+
const char = path36[i];
|
|
5577
5617
|
if (!inBrackets && char === ".") {
|
|
5578
5618
|
if (current) {
|
|
5579
5619
|
parts.push(current);
|
|
@@ -5704,10 +5744,10 @@ var require_redact = __commonJS({
|
|
|
5704
5744
|
return current;
|
|
5705
5745
|
}
|
|
5706
5746
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
5707
|
-
for (const
|
|
5708
|
-
const parts = parsePath(
|
|
5747
|
+
for (const path36 of paths) {
|
|
5748
|
+
const parts = parsePath(path36);
|
|
5709
5749
|
if (parts.includes("*")) {
|
|
5710
|
-
redactWildcardPath(obj, parts, censor,
|
|
5750
|
+
redactWildcardPath(obj, parts, censor, path36, remove);
|
|
5711
5751
|
} else {
|
|
5712
5752
|
if (remove) {
|
|
5713
5753
|
removeKey(obj, parts);
|
|
@@ -5792,8 +5832,8 @@ var require_redact = __commonJS({
|
|
|
5792
5832
|
}
|
|
5793
5833
|
} else {
|
|
5794
5834
|
if (afterWildcard.includes("*")) {
|
|
5795
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
5796
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
5835
|
+
const wrappedCensor = typeof censor === "function" ? (value, path36) => {
|
|
5836
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path36];
|
|
5797
5837
|
return censor(value, fullPath);
|
|
5798
5838
|
} : censor;
|
|
5799
5839
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -5828,8 +5868,8 @@ var require_redact = __commonJS({
|
|
|
5828
5868
|
return null;
|
|
5829
5869
|
}
|
|
5830
5870
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
5831
|
-
for (const
|
|
5832
|
-
const parts = parsePath(
|
|
5871
|
+
for (const path36 of pathsToClone) {
|
|
5872
|
+
const parts = parsePath(path36);
|
|
5833
5873
|
let current = pathStructure;
|
|
5834
5874
|
for (let i = 0; i < parts.length; i++) {
|
|
5835
5875
|
const part = parts[i];
|
|
@@ -5881,24 +5921,24 @@ var require_redact = __commonJS({
|
|
|
5881
5921
|
}
|
|
5882
5922
|
return cloneSelectively(obj, pathStructure);
|
|
5883
5923
|
}
|
|
5884
|
-
function validatePath(
|
|
5885
|
-
if (typeof
|
|
5924
|
+
function validatePath(path36) {
|
|
5925
|
+
if (typeof path36 !== "string") {
|
|
5886
5926
|
throw new Error("Paths must be (non-empty) strings");
|
|
5887
5927
|
}
|
|
5888
|
-
if (
|
|
5928
|
+
if (path36 === "") {
|
|
5889
5929
|
throw new Error("Invalid redaction path ()");
|
|
5890
5930
|
}
|
|
5891
|
-
if (
|
|
5892
|
-
throw new Error(`Invalid redaction path (${
|
|
5931
|
+
if (path36.includes("..")) {
|
|
5932
|
+
throw new Error(`Invalid redaction path (${path36})`);
|
|
5893
5933
|
}
|
|
5894
|
-
if (
|
|
5895
|
-
throw new Error(`Invalid redaction path (${
|
|
5934
|
+
if (path36.includes(",")) {
|
|
5935
|
+
throw new Error(`Invalid redaction path (${path36})`);
|
|
5896
5936
|
}
|
|
5897
5937
|
let bracketCount = 0;
|
|
5898
5938
|
let inQuotes = false;
|
|
5899
5939
|
let quoteChar = "";
|
|
5900
|
-
for (let i = 0; i <
|
|
5901
|
-
const char =
|
|
5940
|
+
for (let i = 0; i < path36.length; i++) {
|
|
5941
|
+
const char = path36[i];
|
|
5902
5942
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
5903
5943
|
if (!inQuotes) {
|
|
5904
5944
|
inQuotes = true;
|
|
@@ -5912,20 +5952,20 @@ var require_redact = __commonJS({
|
|
|
5912
5952
|
} else if (char === "]" && !inQuotes) {
|
|
5913
5953
|
bracketCount--;
|
|
5914
5954
|
if (bracketCount < 0) {
|
|
5915
|
-
throw new Error(`Invalid redaction path (${
|
|
5955
|
+
throw new Error(`Invalid redaction path (${path36})`);
|
|
5916
5956
|
}
|
|
5917
5957
|
}
|
|
5918
5958
|
}
|
|
5919
5959
|
if (bracketCount !== 0) {
|
|
5920
|
-
throw new Error(`Invalid redaction path (${
|
|
5960
|
+
throw new Error(`Invalid redaction path (${path36})`);
|
|
5921
5961
|
}
|
|
5922
5962
|
}
|
|
5923
5963
|
function validatePaths(paths) {
|
|
5924
5964
|
if (!Array.isArray(paths)) {
|
|
5925
5965
|
throw new TypeError("paths must be an array");
|
|
5926
5966
|
}
|
|
5927
|
-
for (const
|
|
5928
|
-
validatePath(
|
|
5967
|
+
for (const path36 of paths) {
|
|
5968
|
+
validatePath(path36);
|
|
5929
5969
|
}
|
|
5930
5970
|
}
|
|
5931
5971
|
function slowRedact(options = {}) {
|
|
@@ -6093,8 +6133,8 @@ var require_redaction = __commonJS({
|
|
|
6093
6133
|
if (shape[k2] === null) {
|
|
6094
6134
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6095
6135
|
} else {
|
|
6096
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6097
|
-
return censor(value, [k2, ...
|
|
6136
|
+
const wrappedCensor = typeof censor === "function" ? (value, path36) => {
|
|
6137
|
+
return censor(value, [k2, ...path36]);
|
|
6098
6138
|
} : censor;
|
|
6099
6139
|
o[k2] = Redact({
|
|
6100
6140
|
paths: shape[k2],
|
|
@@ -6312,10 +6352,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
6312
6352
|
var require_sonic_boom = __commonJS({
|
|
6313
6353
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
6314
6354
|
"use strict";
|
|
6315
|
-
var
|
|
6355
|
+
var fs32 = require("fs");
|
|
6316
6356
|
var EventEmitter2 = require("events");
|
|
6317
6357
|
var inherits = require("util").inherits;
|
|
6318
|
-
var
|
|
6358
|
+
var path36 = require("path");
|
|
6319
6359
|
var sleep = require_atomic_sleep();
|
|
6320
6360
|
var assert = require("assert");
|
|
6321
6361
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6369,20 +6409,20 @@ var require_sonic_boom = __commonJS({
|
|
|
6369
6409
|
const mode = sonic.mode;
|
|
6370
6410
|
if (sonic.sync) {
|
|
6371
6411
|
try {
|
|
6372
|
-
if (sonic.mkdir)
|
|
6373
|
-
const fd =
|
|
6412
|
+
if (sonic.mkdir) fs32.mkdirSync(path36.dirname(file), { recursive: true });
|
|
6413
|
+
const fd = fs32.openSync(file, flags, mode);
|
|
6374
6414
|
fileOpened(null, fd);
|
|
6375
6415
|
} catch (err) {
|
|
6376
6416
|
fileOpened(err);
|
|
6377
6417
|
throw err;
|
|
6378
6418
|
}
|
|
6379
6419
|
} else if (sonic.mkdir) {
|
|
6380
|
-
|
|
6420
|
+
fs32.mkdir(path36.dirname(file), { recursive: true }, (err) => {
|
|
6381
6421
|
if (err) return fileOpened(err);
|
|
6382
|
-
|
|
6422
|
+
fs32.open(file, flags, mode, fileOpened);
|
|
6383
6423
|
});
|
|
6384
6424
|
} else {
|
|
6385
|
-
|
|
6425
|
+
fs32.open(file, flags, mode, fileOpened);
|
|
6386
6426
|
}
|
|
6387
6427
|
}
|
|
6388
6428
|
function SonicBoom(opts) {
|
|
@@ -6423,8 +6463,8 @@ var require_sonic_boom = __commonJS({
|
|
|
6423
6463
|
this.flush = flushBuffer;
|
|
6424
6464
|
this.flushSync = flushBufferSync;
|
|
6425
6465
|
this._actualWrite = actualWriteBuffer;
|
|
6426
|
-
fsWriteSync = () =>
|
|
6427
|
-
fsWrite = () =>
|
|
6466
|
+
fsWriteSync = () => fs32.writeSync(this.fd, this._writingBuf);
|
|
6467
|
+
fsWrite = () => fs32.write(this.fd, this._writingBuf, this.release);
|
|
6428
6468
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
6429
6469
|
this._writingBuf = "";
|
|
6430
6470
|
this.write = write;
|
|
@@ -6433,15 +6473,15 @@ var require_sonic_boom = __commonJS({
|
|
|
6433
6473
|
this._actualWrite = actualWrite;
|
|
6434
6474
|
fsWriteSync = () => {
|
|
6435
6475
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6436
|
-
return
|
|
6476
|
+
return fs32.writeSync(this.fd, this._writingBuf);
|
|
6437
6477
|
}
|
|
6438
|
-
return
|
|
6478
|
+
return fs32.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6439
6479
|
};
|
|
6440
6480
|
fsWrite = () => {
|
|
6441
6481
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6442
|
-
return
|
|
6482
|
+
return fs32.write(this.fd, this._writingBuf, this.release);
|
|
6443
6483
|
}
|
|
6444
|
-
return
|
|
6484
|
+
return fs32.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
6445
6485
|
};
|
|
6446
6486
|
} else {
|
|
6447
6487
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -6498,7 +6538,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6498
6538
|
}
|
|
6499
6539
|
}
|
|
6500
6540
|
if (this._fsync) {
|
|
6501
|
-
|
|
6541
|
+
fs32.fsyncSync(this.fd);
|
|
6502
6542
|
}
|
|
6503
6543
|
const len = this._len;
|
|
6504
6544
|
if (this._reopening) {
|
|
@@ -6612,7 +6652,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6612
6652
|
const onDrain = () => {
|
|
6613
6653
|
if (!this._fsync) {
|
|
6614
6654
|
try {
|
|
6615
|
-
|
|
6655
|
+
fs32.fsync(this.fd, (err) => {
|
|
6616
6656
|
this._flushPending = false;
|
|
6617
6657
|
cb(err);
|
|
6618
6658
|
});
|
|
@@ -6714,7 +6754,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6714
6754
|
const fd = this.fd;
|
|
6715
6755
|
this.once("ready", () => {
|
|
6716
6756
|
if (fd !== this.fd) {
|
|
6717
|
-
|
|
6757
|
+
fs32.close(fd, (err) => {
|
|
6718
6758
|
if (err) {
|
|
6719
6759
|
return this.emit("error", err);
|
|
6720
6760
|
}
|
|
@@ -6763,7 +6803,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6763
6803
|
buf = this._bufs[0];
|
|
6764
6804
|
}
|
|
6765
6805
|
try {
|
|
6766
|
-
const n = Buffer.isBuffer(buf) ?
|
|
6806
|
+
const n = Buffer.isBuffer(buf) ? fs32.writeSync(this.fd, buf) : fs32.writeSync(this.fd, buf, "utf8");
|
|
6767
6807
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
6768
6808
|
buf = releasedBufObj.writingBuf;
|
|
6769
6809
|
this._len = releasedBufObj.len;
|
|
@@ -6779,7 +6819,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6779
6819
|
}
|
|
6780
6820
|
}
|
|
6781
6821
|
try {
|
|
6782
|
-
|
|
6822
|
+
fs32.fsyncSync(this.fd);
|
|
6783
6823
|
} catch {
|
|
6784
6824
|
}
|
|
6785
6825
|
}
|
|
@@ -6800,7 +6840,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6800
6840
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
6801
6841
|
}
|
|
6802
6842
|
try {
|
|
6803
|
-
const n =
|
|
6843
|
+
const n = fs32.writeSync(this.fd, buf);
|
|
6804
6844
|
buf = buf.subarray(n);
|
|
6805
6845
|
this._len = Math.max(this._len - n, 0);
|
|
6806
6846
|
if (buf.length <= 0) {
|
|
@@ -6828,13 +6868,13 @@ var require_sonic_boom = __commonJS({
|
|
|
6828
6868
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
6829
6869
|
if (this.sync) {
|
|
6830
6870
|
try {
|
|
6831
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
6871
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs32.writeSync(this.fd, this._writingBuf) : fs32.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6832
6872
|
release(null, written);
|
|
6833
6873
|
} catch (err) {
|
|
6834
6874
|
release(err);
|
|
6835
6875
|
}
|
|
6836
6876
|
} else {
|
|
6837
|
-
|
|
6877
|
+
fs32.write(this.fd, this._writingBuf, release);
|
|
6838
6878
|
}
|
|
6839
6879
|
}
|
|
6840
6880
|
function actualWriteBuffer() {
|
|
@@ -6843,7 +6883,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6843
6883
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
6844
6884
|
if (this.sync) {
|
|
6845
6885
|
try {
|
|
6846
|
-
const written =
|
|
6886
|
+
const written = fs32.writeSync(this.fd, this._writingBuf);
|
|
6847
6887
|
release(null, written);
|
|
6848
6888
|
} catch (err) {
|
|
6849
6889
|
release(err);
|
|
@@ -6852,7 +6892,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6852
6892
|
if (kCopyBuffer) {
|
|
6853
6893
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
6854
6894
|
}
|
|
6855
|
-
|
|
6895
|
+
fs32.write(this.fd, this._writingBuf, release);
|
|
6856
6896
|
}
|
|
6857
6897
|
}
|
|
6858
6898
|
function actualClose(sonic) {
|
|
@@ -6868,12 +6908,12 @@ var require_sonic_boom = __commonJS({
|
|
|
6868
6908
|
sonic._lens = [];
|
|
6869
6909
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
6870
6910
|
try {
|
|
6871
|
-
|
|
6911
|
+
fs32.fsync(sonic.fd, closeWrapped);
|
|
6872
6912
|
} catch {
|
|
6873
6913
|
}
|
|
6874
6914
|
function closeWrapped() {
|
|
6875
6915
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
6876
|
-
|
|
6916
|
+
fs32.close(sonic.fd, done);
|
|
6877
6917
|
} else {
|
|
6878
6918
|
done();
|
|
6879
6919
|
}
|
|
@@ -7130,7 +7170,7 @@ var require_thread_stream = __commonJS({
|
|
|
7130
7170
|
var { version: version2 } = require_package();
|
|
7131
7171
|
var { EventEmitter: EventEmitter2 } = require("events");
|
|
7132
7172
|
var { Worker } = require("worker_threads");
|
|
7133
|
-
var { join:
|
|
7173
|
+
var { join: join9 } = require("path");
|
|
7134
7174
|
var { pathToFileURL } = require("url");
|
|
7135
7175
|
var { wait } = require_wait();
|
|
7136
7176
|
var {
|
|
@@ -7166,7 +7206,7 @@ var require_thread_stream = __commonJS({
|
|
|
7166
7206
|
function createWorker(stream, opts) {
|
|
7167
7207
|
const { filename, workerData } = opts;
|
|
7168
7208
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
7169
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
7209
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join9(__dirname, "lib", "worker.js");
|
|
7170
7210
|
const worker = new Worker(toExecute, {
|
|
7171
7211
|
...opts.workerOpts,
|
|
7172
7212
|
trackUnmanagedFds: false,
|
|
@@ -7552,7 +7592,7 @@ var require_transport = __commonJS({
|
|
|
7552
7592
|
"use strict";
|
|
7553
7593
|
var { createRequire } = require("module");
|
|
7554
7594
|
var getCallers = require_caller();
|
|
7555
|
-
var { join:
|
|
7595
|
+
var { join: join9, isAbsolute, sep: sep2 } = require("path");
|
|
7556
7596
|
var sleep = require_atomic_sleep();
|
|
7557
7597
|
var onExit = require_on_exit_leak_free();
|
|
7558
7598
|
var ThreadStream = require_thread_stream();
|
|
@@ -7615,7 +7655,7 @@ var require_transport = __commonJS({
|
|
|
7615
7655
|
throw new Error("only one of target or targets can be specified");
|
|
7616
7656
|
}
|
|
7617
7657
|
if (targets) {
|
|
7618
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
7658
|
+
target = bundlerOverrides["pino-worker"] || join9(__dirname, "worker.js");
|
|
7619
7659
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
7620
7660
|
return {
|
|
7621
7661
|
...dest,
|
|
@@ -7633,7 +7673,7 @@ var require_transport = __commonJS({
|
|
|
7633
7673
|
});
|
|
7634
7674
|
});
|
|
7635
7675
|
} else if (pipeline2) {
|
|
7636
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
7676
|
+
target = bundlerOverrides["pino-worker"] || join9(__dirname, "worker.js");
|
|
7637
7677
|
options.pipelines = [pipeline2.map((dest) => {
|
|
7638
7678
|
return {
|
|
7639
7679
|
...dest,
|
|
@@ -7655,12 +7695,12 @@ var require_transport = __commonJS({
|
|
|
7655
7695
|
return origin;
|
|
7656
7696
|
}
|
|
7657
7697
|
if (origin === "pino/file") {
|
|
7658
|
-
return
|
|
7698
|
+
return join9(__dirname, "..", "file.js");
|
|
7659
7699
|
}
|
|
7660
7700
|
let fixTarget2;
|
|
7661
7701
|
for (const filePath of callers) {
|
|
7662
7702
|
try {
|
|
7663
|
-
const context = filePath === "node:repl" ? process.cwd() +
|
|
7703
|
+
const context = filePath === "node:repl" ? process.cwd() + sep2 : filePath;
|
|
7664
7704
|
fixTarget2 = createRequire(context).resolve(origin);
|
|
7665
7705
|
break;
|
|
7666
7706
|
} catch (err) {
|
|
@@ -8645,7 +8685,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
8645
8685
|
return circularValue;
|
|
8646
8686
|
}
|
|
8647
8687
|
let res = "";
|
|
8648
|
-
let
|
|
8688
|
+
let join9 = ",";
|
|
8649
8689
|
const originalIndentation = indentation;
|
|
8650
8690
|
if (Array.isArray(value)) {
|
|
8651
8691
|
if (value.length === 0) {
|
|
@@ -8659,7 +8699,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
8659
8699
|
indentation += spacer;
|
|
8660
8700
|
res += `
|
|
8661
8701
|
${indentation}`;
|
|
8662
|
-
|
|
8702
|
+
join9 = `,
|
|
8663
8703
|
${indentation}`;
|
|
8664
8704
|
}
|
|
8665
8705
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -8667,13 +8707,13 @@ ${indentation}`;
|
|
|
8667
8707
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
8668
8708
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
8669
8709
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
8670
|
-
res +=
|
|
8710
|
+
res += join9;
|
|
8671
8711
|
}
|
|
8672
8712
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
8673
8713
|
res += tmp !== void 0 ? tmp : "null";
|
|
8674
8714
|
if (value.length - 1 > maximumBreadth) {
|
|
8675
8715
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
8676
|
-
res += `${
|
|
8716
|
+
res += `${join9}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
8677
8717
|
}
|
|
8678
8718
|
if (spacer !== "") {
|
|
8679
8719
|
res += `
|
|
@@ -8694,7 +8734,7 @@ ${originalIndentation}`;
|
|
|
8694
8734
|
let separator = "";
|
|
8695
8735
|
if (spacer !== "") {
|
|
8696
8736
|
indentation += spacer;
|
|
8697
|
-
|
|
8737
|
+
join9 = `,
|
|
8698
8738
|
${indentation}`;
|
|
8699
8739
|
whitespace = " ";
|
|
8700
8740
|
}
|
|
@@ -8708,13 +8748,13 @@ ${indentation}`;
|
|
|
8708
8748
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
8709
8749
|
if (tmp !== void 0) {
|
|
8710
8750
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
8711
|
-
separator =
|
|
8751
|
+
separator = join9;
|
|
8712
8752
|
}
|
|
8713
8753
|
}
|
|
8714
8754
|
if (keyLength > maximumBreadth) {
|
|
8715
8755
|
const removedKeys = keyLength - maximumBreadth;
|
|
8716
8756
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
8717
|
-
separator =
|
|
8757
|
+
separator = join9;
|
|
8718
8758
|
}
|
|
8719
8759
|
if (spacer !== "" && separator.length > 1) {
|
|
8720
8760
|
res = `
|
|
@@ -8755,7 +8795,7 @@ ${originalIndentation}`;
|
|
|
8755
8795
|
}
|
|
8756
8796
|
const originalIndentation = indentation;
|
|
8757
8797
|
let res = "";
|
|
8758
|
-
let
|
|
8798
|
+
let join9 = ",";
|
|
8759
8799
|
if (Array.isArray(value)) {
|
|
8760
8800
|
if (value.length === 0) {
|
|
8761
8801
|
return "[]";
|
|
@@ -8768,7 +8808,7 @@ ${originalIndentation}`;
|
|
|
8768
8808
|
indentation += spacer;
|
|
8769
8809
|
res += `
|
|
8770
8810
|
${indentation}`;
|
|
8771
|
-
|
|
8811
|
+
join9 = `,
|
|
8772
8812
|
${indentation}`;
|
|
8773
8813
|
}
|
|
8774
8814
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -8776,13 +8816,13 @@ ${indentation}`;
|
|
|
8776
8816
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
8777
8817
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
8778
8818
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
8779
|
-
res +=
|
|
8819
|
+
res += join9;
|
|
8780
8820
|
}
|
|
8781
8821
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
8782
8822
|
res += tmp !== void 0 ? tmp : "null";
|
|
8783
8823
|
if (value.length - 1 > maximumBreadth) {
|
|
8784
8824
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
8785
|
-
res += `${
|
|
8825
|
+
res += `${join9}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
8786
8826
|
}
|
|
8787
8827
|
if (spacer !== "") {
|
|
8788
8828
|
res += `
|
|
@@ -8795,7 +8835,7 @@ ${originalIndentation}`;
|
|
|
8795
8835
|
let whitespace = "";
|
|
8796
8836
|
if (spacer !== "") {
|
|
8797
8837
|
indentation += spacer;
|
|
8798
|
-
|
|
8838
|
+
join9 = `,
|
|
8799
8839
|
${indentation}`;
|
|
8800
8840
|
whitespace = " ";
|
|
8801
8841
|
}
|
|
@@ -8804,7 +8844,7 @@ ${indentation}`;
|
|
|
8804
8844
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
8805
8845
|
if (tmp !== void 0) {
|
|
8806
8846
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
8807
|
-
separator =
|
|
8847
|
+
separator = join9;
|
|
8808
8848
|
}
|
|
8809
8849
|
}
|
|
8810
8850
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -8862,20 +8902,20 @@ ${originalIndentation}`;
|
|
|
8862
8902
|
indentation += spacer;
|
|
8863
8903
|
let res2 = `
|
|
8864
8904
|
${indentation}`;
|
|
8865
|
-
const
|
|
8905
|
+
const join10 = `,
|
|
8866
8906
|
${indentation}`;
|
|
8867
8907
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
8868
8908
|
let i = 0;
|
|
8869
8909
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
8870
8910
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
8871
8911
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
8872
|
-
res2 +=
|
|
8912
|
+
res2 += join10;
|
|
8873
8913
|
}
|
|
8874
8914
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
8875
8915
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
8876
8916
|
if (value.length - 1 > maximumBreadth) {
|
|
8877
8917
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
8878
|
-
res2 += `${
|
|
8918
|
+
res2 += `${join10}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
8879
8919
|
}
|
|
8880
8920
|
res2 += `
|
|
8881
8921
|
${originalIndentation}`;
|
|
@@ -8891,16 +8931,16 @@ ${originalIndentation}`;
|
|
|
8891
8931
|
return '"[Object]"';
|
|
8892
8932
|
}
|
|
8893
8933
|
indentation += spacer;
|
|
8894
|
-
const
|
|
8934
|
+
const join9 = `,
|
|
8895
8935
|
${indentation}`;
|
|
8896
8936
|
let res = "";
|
|
8897
8937
|
let separator = "";
|
|
8898
8938
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
8899
8939
|
if (isTypedArrayWithEntries(value)) {
|
|
8900
|
-
res += stringifyTypedArray(value,
|
|
8940
|
+
res += stringifyTypedArray(value, join9, maximumBreadth);
|
|
8901
8941
|
keys = keys.slice(value.length);
|
|
8902
8942
|
maximumPropertiesToStringify -= value.length;
|
|
8903
|
-
separator =
|
|
8943
|
+
separator = join9;
|
|
8904
8944
|
}
|
|
8905
8945
|
if (deterministic) {
|
|
8906
8946
|
keys = sort(keys, comparator);
|
|
@@ -8911,13 +8951,13 @@ ${indentation}`;
|
|
|
8911
8951
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
8912
8952
|
if (tmp !== void 0) {
|
|
8913
8953
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
8914
|
-
separator =
|
|
8954
|
+
separator = join9;
|
|
8915
8955
|
}
|
|
8916
8956
|
}
|
|
8917
8957
|
if (keyLength > maximumBreadth) {
|
|
8918
8958
|
const removedKeys = keyLength - maximumBreadth;
|
|
8919
8959
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
8920
|
-
separator =
|
|
8960
|
+
separator = join9;
|
|
8921
8961
|
}
|
|
8922
8962
|
if (separator !== "") {
|
|
8923
8963
|
res = `
|
|
@@ -10008,11 +10048,11 @@ var init_lib = __esm({
|
|
|
10008
10048
|
}
|
|
10009
10049
|
}
|
|
10010
10050
|
},
|
|
10011
|
-
addToPath: function addToPath(
|
|
10012
|
-
var last =
|
|
10051
|
+
addToPath: function addToPath(path36, added, removed, oldPosInc, options) {
|
|
10052
|
+
var last = path36.lastComponent;
|
|
10013
10053
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10014
10054
|
return {
|
|
10015
|
-
oldPos:
|
|
10055
|
+
oldPos: path36.oldPos + oldPosInc,
|
|
10016
10056
|
lastComponent: {
|
|
10017
10057
|
count: last.count + 1,
|
|
10018
10058
|
added,
|
|
@@ -10022,7 +10062,7 @@ var init_lib = __esm({
|
|
|
10022
10062
|
};
|
|
10023
10063
|
} else {
|
|
10024
10064
|
return {
|
|
10025
|
-
oldPos:
|
|
10065
|
+
oldPos: path36.oldPos + oldPosInc,
|
|
10026
10066
|
lastComponent: {
|
|
10027
10067
|
count: 1,
|
|
10028
10068
|
added,
|
|
@@ -10080,7 +10120,7 @@ var init_lib = __esm({
|
|
|
10080
10120
|
tokenize: function tokenize(value) {
|
|
10081
10121
|
return Array.from(value);
|
|
10082
10122
|
},
|
|
10083
|
-
join: function
|
|
10123
|
+
join: function join4(chars) {
|
|
10084
10124
|
return chars.join("");
|
|
10085
10125
|
},
|
|
10086
10126
|
postProcess: function postProcess(changeObjects) {
|
|
@@ -10453,10 +10493,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10453
10493
|
const memories = raw.map((m2) => {
|
|
10454
10494
|
if (!m2 || typeof m2 !== "object") return null;
|
|
10455
10495
|
const rec = m2;
|
|
10456
|
-
const
|
|
10496
|
+
const path36 = typeof rec.path === "string" ? rec.path : null;
|
|
10457
10497
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
10458
|
-
if (!
|
|
10459
|
-
const entry = { path:
|
|
10498
|
+
if (!path36 || content == null) return null;
|
|
10499
|
+
const entry = { path: path36, content };
|
|
10460
10500
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
10461
10501
|
return entry;
|
|
10462
10502
|
}).filter((m2) => m2 !== null);
|
|
@@ -10916,6 +10956,27 @@ var init_claude_history = __esm({
|
|
|
10916
10956
|
}
|
|
10917
10957
|
});
|
|
10918
10958
|
|
|
10959
|
+
// src/tools/sandbox.ts
|
|
10960
|
+
function shouldSandbox(cwd, personaRoot) {
|
|
10961
|
+
if (!personaRoot) return false;
|
|
10962
|
+
const sep2 = personaRoot.endsWith(path12.sep) ? "" : path12.sep;
|
|
10963
|
+
return cwd.startsWith(personaRoot + sep2) && cwd !== personaRoot;
|
|
10964
|
+
}
|
|
10965
|
+
function inferSandboxSettingsPath(cwd, personaRoot) {
|
|
10966
|
+
if (!shouldSandbox(cwd, personaRoot)) return null;
|
|
10967
|
+
const rel = path12.relative(personaRoot, cwd);
|
|
10968
|
+
const personaId = rel.split(path12.sep)[0];
|
|
10969
|
+
if (!personaId) return null;
|
|
10970
|
+
return path12.join(personaRoot, personaId, ".clawd", "sandbox-settings.json");
|
|
10971
|
+
}
|
|
10972
|
+
var path12;
|
|
10973
|
+
var init_sandbox = __esm({
|
|
10974
|
+
"src/tools/sandbox.ts"() {
|
|
10975
|
+
"use strict";
|
|
10976
|
+
path12 = __toESM(require("path"), 1);
|
|
10977
|
+
}
|
|
10978
|
+
});
|
|
10979
|
+
|
|
10919
10980
|
// src/tools/claude.ts
|
|
10920
10981
|
function macOSDesktopCandidates(home) {
|
|
10921
10982
|
return [
|
|
@@ -10980,7 +11041,8 @@ function buildSpawnArgs(ctx) {
|
|
|
10980
11041
|
throw new Error(`unexpected personaMode: ${String(_exhaustive)}`);
|
|
10981
11042
|
}
|
|
10982
11043
|
}
|
|
10983
|
-
|
|
11044
|
+
const sandboxSettings = ctx.extraSettings ?? inferSandboxSettingsPath(ctx.cwd, ctx.personaRoot);
|
|
11045
|
+
if (sandboxSettings) args.push("--settings", sandboxSettings);
|
|
10984
11046
|
if (ctx.extraSystemPrompt) args.push("--append-system-prompt", ctx.extraSystemPrompt);
|
|
10985
11047
|
if (ctx.effort) args.push("--effort", ctx.effort);
|
|
10986
11048
|
if (ctx.toolSessionId) args.push("--resume", ctx.toolSessionId);
|
|
@@ -11260,10 +11322,10 @@ function parseAttachment(obj) {
|
|
|
11260
11322
|
const memories = raw.map((m2) => {
|
|
11261
11323
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11262
11324
|
const rec = m2;
|
|
11263
|
-
const
|
|
11325
|
+
const path36 = typeof rec.path === "string" ? rec.path : null;
|
|
11264
11326
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11265
|
-
if (!
|
|
11266
|
-
const out = { path:
|
|
11327
|
+
if (!path36 || content == null) return null;
|
|
11328
|
+
const out = { path: path36, content };
|
|
11267
11329
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11268
11330
|
return out;
|
|
11269
11331
|
}).filter((m2) => m2 !== null);
|
|
@@ -11379,6 +11441,7 @@ var init_claude = __esm({
|
|
|
11379
11441
|
init_protocol();
|
|
11380
11442
|
init_claude_history();
|
|
11381
11443
|
init_tool_result_extra();
|
|
11444
|
+
init_sandbox();
|
|
11382
11445
|
ATTACHMENT_SILENT_SUBTYPES2 = /* @__PURE__ */ new Set([
|
|
11383
11446
|
"hook_additional_context",
|
|
11384
11447
|
"hook_success",
|
|
@@ -18761,7 +18824,7 @@ var require_websocket = __commonJS({
|
|
|
18761
18824
|
var http2 = require("http");
|
|
18762
18825
|
var net = require("net");
|
|
18763
18826
|
var tls = require("tls");
|
|
18764
|
-
var { randomBytes:
|
|
18827
|
+
var { randomBytes: randomBytes3, createHash: createHash3 } = require("crypto");
|
|
18765
18828
|
var { Duplex, Readable: Readable3 } = require("stream");
|
|
18766
18829
|
var { URL: URL2 } = require("url");
|
|
18767
18830
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -19291,7 +19354,7 @@ var require_websocket = __commonJS({
|
|
|
19291
19354
|
}
|
|
19292
19355
|
}
|
|
19293
19356
|
const defaultPort = isSecure ? 443 : 80;
|
|
19294
|
-
const key =
|
|
19357
|
+
const key = randomBytes3(16).toString("base64");
|
|
19295
19358
|
const request = isSecure ? https.request : http2.request;
|
|
19296
19359
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
19297
19360
|
let perMessageDeflate;
|
|
@@ -20708,6 +20771,9 @@ function createLogger(opts = {}) {
|
|
|
20708
20771
|
return wrap(base);
|
|
20709
20772
|
}
|
|
20710
20773
|
|
|
20774
|
+
// src/session/store-factory.ts
|
|
20775
|
+
var path5 = __toESM(require("path"), 1);
|
|
20776
|
+
|
|
20711
20777
|
// src/session/store.ts
|
|
20712
20778
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
20713
20779
|
var import_node_path4 = __toESM(require("path"), 1);
|
|
@@ -20745,12 +20811,16 @@ function safeFileName(sessionId) {
|
|
|
20745
20811
|
var SessionStore = class {
|
|
20746
20812
|
root;
|
|
20747
20813
|
constructor(opts) {
|
|
20748
|
-
|
|
20749
|
-
|
|
20750
|
-
|
|
20751
|
-
"
|
|
20752
|
-
|
|
20753
|
-
|
|
20814
|
+
if ("root" in opts) {
|
|
20815
|
+
this.root = opts.root;
|
|
20816
|
+
} else {
|
|
20817
|
+
const scope = opts.scope ?? { kind: "default" };
|
|
20818
|
+
this.root = import_node_path4.default.join(
|
|
20819
|
+
opts.dataDir,
|
|
20820
|
+
"sessions",
|
|
20821
|
+
...scopeSubPath(scope).map(safeFileName)
|
|
20822
|
+
);
|
|
20823
|
+
}
|
|
20754
20824
|
}
|
|
20755
20825
|
filePath(sessionId) {
|
|
20756
20826
|
return import_node_path4.default.join(this.root, `${safeFileName(sessionId)}.json`);
|
|
@@ -20815,6 +20885,66 @@ var SessionStore = class {
|
|
|
20815
20885
|
}
|
|
20816
20886
|
};
|
|
20817
20887
|
|
|
20888
|
+
// src/session/store-factory.ts
|
|
20889
|
+
var SessionStoreFactory = class {
|
|
20890
|
+
dataDir;
|
|
20891
|
+
bareStore = null;
|
|
20892
|
+
vmOwnerStores = /* @__PURE__ */ new Map();
|
|
20893
|
+
// vmGuest 索引 key = `${pid}::${capId}`
|
|
20894
|
+
vmGuestStores = /* @__PURE__ */ new Map();
|
|
20895
|
+
constructor(opts) {
|
|
20896
|
+
this.dataDir = opts.dataDir;
|
|
20897
|
+
}
|
|
20898
|
+
// ---- root path 派生(暴露给 migration / revoke cascade 等外部消费方) ----
|
|
20899
|
+
bareRoot() {
|
|
20900
|
+
return path5.join(this.dataDir, "sessions");
|
|
20901
|
+
}
|
|
20902
|
+
vmOwnerRoot(personaId) {
|
|
20903
|
+
return path5.join(
|
|
20904
|
+
this.dataDir,
|
|
20905
|
+
"personas",
|
|
20906
|
+
safeFileName(personaId),
|
|
20907
|
+
".clawd",
|
|
20908
|
+
"sessions",
|
|
20909
|
+
"owner"
|
|
20910
|
+
);
|
|
20911
|
+
}
|
|
20912
|
+
vmGuestRoot(personaId, capabilityId) {
|
|
20913
|
+
return path5.join(
|
|
20914
|
+
this.dataDir,
|
|
20915
|
+
"personas",
|
|
20916
|
+
safeFileName(personaId),
|
|
20917
|
+
".clawd",
|
|
20918
|
+
"sessions",
|
|
20919
|
+
"guests",
|
|
20920
|
+
safeFileName(capabilityId)
|
|
20921
|
+
);
|
|
20922
|
+
}
|
|
20923
|
+
// ---- SessionStore 工厂(缓存) ----
|
|
20924
|
+
forBare() {
|
|
20925
|
+
if (!this.bareStore) {
|
|
20926
|
+
this.bareStore = new SessionStore({ root: this.bareRoot() });
|
|
20927
|
+
}
|
|
20928
|
+
return this.bareStore;
|
|
20929
|
+
}
|
|
20930
|
+
forVmOwner(personaId) {
|
|
20931
|
+
const key = personaId;
|
|
20932
|
+
const cached = this.vmOwnerStores.get(key);
|
|
20933
|
+
if (cached) return cached;
|
|
20934
|
+
const st = new SessionStore({ root: this.vmOwnerRoot(personaId) });
|
|
20935
|
+
this.vmOwnerStores.set(key, st);
|
|
20936
|
+
return st;
|
|
20937
|
+
}
|
|
20938
|
+
forVmGuest(personaId, capabilityId) {
|
|
20939
|
+
const key = `${personaId}::${capabilityId}`;
|
|
20940
|
+
const cached = this.vmGuestStores.get(key);
|
|
20941
|
+
if (cached) return cached;
|
|
20942
|
+
const st = new SessionStore({ root: this.vmGuestRoot(personaId, capabilityId) });
|
|
20943
|
+
this.vmGuestStores.set(key, st);
|
|
20944
|
+
return st;
|
|
20945
|
+
}
|
|
20946
|
+
};
|
|
20947
|
+
|
|
20818
20948
|
// src/session/manager.ts
|
|
20819
20949
|
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
20820
20950
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
@@ -20974,7 +21104,10 @@ function buildSpawnContext(state, deps) {
|
|
|
20974
21104
|
toolSessionId: file.toolSessionId,
|
|
20975
21105
|
model: file.model,
|
|
20976
21106
|
permissionMode: file.permissionMode,
|
|
20977
|
-
effort: file.effort
|
|
21107
|
+
effort: file.effort,
|
|
21108
|
+
// Phase 2 capability platform (plan §3): personaRoot 透传给 buildSpawnArgs;
|
|
21109
|
+
// 内部 shouldSandbox(cwd, personaRoot) 决定是否注入 --settings sandbox-settings.
|
|
21110
|
+
personaRoot: deps.personaRoot
|
|
20978
21111
|
};
|
|
20979
21112
|
const meta = state.subSessionMeta;
|
|
20980
21113
|
if (meta?.personaMode) {
|
|
@@ -21701,7 +21834,8 @@ var SessionRunner = class {
|
|
|
21701
21834
|
now: this.hooks.now ?? Date.now,
|
|
21702
21835
|
resolveContextWindow: this.hooks.resolveContextWindow,
|
|
21703
21836
|
genUuid: this.hooks.genUuid ?? v4_default,
|
|
21704
|
-
ownerDisplayName: this.hooks.ownerDisplayName
|
|
21837
|
+
ownerDisplayName: this.hooks.ownerDisplayName,
|
|
21838
|
+
personaRoot: this.hooks.personaRoot
|
|
21705
21839
|
};
|
|
21706
21840
|
const { state, effects } = reduceSession(this.state, inputMsg, deps);
|
|
21707
21841
|
this.state = state;
|
|
@@ -22125,9 +22259,20 @@ var SessionManager = class {
|
|
|
22125
22259
|
attachObserver(observer) {
|
|
22126
22260
|
this.attachedObserver = observer;
|
|
22127
22261
|
}
|
|
22128
|
-
// 按 scope 拿对应的 SessionStore
|
|
22129
|
-
//
|
|
22262
|
+
// 按 scope 拿对应的 SessionStore.
|
|
22263
|
+
// Phase 2 (capability platform plan §1) 路由切到 SessionStoreFactory:
|
|
22264
|
+
// default → factory.forBare() <dataDir>/sessions/
|
|
22265
|
+
// persona/<pid>/owner → factory.forVmOwner(pid) <dataDir>/personas/<pid>/.clawd/sessions/owner/
|
|
22266
|
+
// persona/<pid>/listener → throw (listener 角色 #698 已下线, schema 字段保留但运行时不该出现)
|
|
22267
|
+
// 缺省 (无 factory 注入): 回退 dataDir+scope 老路径 (向后兼容旧 spec).
|
|
22130
22268
|
storeFor(scope) {
|
|
22269
|
+
if (this.deps.storeFactory) {
|
|
22270
|
+
if (scope.kind === "default") return this.deps.storeFactory.forBare();
|
|
22271
|
+
if (scope.mode === "owner") return this.deps.storeFactory.forVmOwner(scope.personaId);
|
|
22272
|
+
throw new Error(
|
|
22273
|
+
`SessionManager: listener scope is deprecated (#698); use forVmGuest in Phase 3+ instead`
|
|
22274
|
+
);
|
|
22275
|
+
}
|
|
22131
22276
|
if (scope.kind === "default") return this.deps.store;
|
|
22132
22277
|
const key = scopeKey(scope);
|
|
22133
22278
|
const cached = this.storesByScope.get(key);
|
|
@@ -22155,11 +22300,13 @@ var SessionManager = class {
|
|
|
22155
22300
|
scopeForFile(file) {
|
|
22156
22301
|
return file.ownerPersonaId ? { kind: "persona", personaId: file.ownerPersonaId, mode: "owner" } : { kind: "default" };
|
|
22157
22302
|
}
|
|
22158
|
-
//
|
|
22159
|
-
//
|
|
22303
|
+
// 扫所有 persona 命名空间. 用于 findOwnedSession / listAllOwned 跨 scope 查询.
|
|
22304
|
+
// Phase 2 capability platform: 新布局下 persona 资产在 <dataDir>/personas/<pid>/,
|
|
22305
|
+
// 直接 readdir 这个目录拿所有 personaId. 老布局 (无 storeFactory) fallback 扫
|
|
22306
|
+
// <dataDir>/sessions/ 列子目录 (排除 'default').
|
|
22160
22307
|
listPersonaIdsOnDisk() {
|
|
22161
22308
|
if (!this.deps.dataDir) return [];
|
|
22162
|
-
const root = import_node_path6.default.join(this.deps.dataDir, "sessions");
|
|
22309
|
+
const root = this.deps.storeFactory ? import_node_path6.default.join(this.deps.dataDir, "personas") : import_node_path6.default.join(this.deps.dataDir, "sessions");
|
|
22163
22310
|
let entries;
|
|
22164
22311
|
try {
|
|
22165
22312
|
entries = import_node_fs5.default.readdirSync(root, { withFileTypes: true });
|
|
@@ -22234,6 +22381,9 @@ var SessionManager = class {
|
|
|
22234
22381
|
dataDir: this.deps.dataDir,
|
|
22235
22382
|
personaStore: this.deps.personaStore,
|
|
22236
22383
|
ownerDisplayName: this.deps.ownerDisplayName,
|
|
22384
|
+
// Phase 2 capability platform (plan §3): 透传 personaRoot, buildSpawnArgs 据
|
|
22385
|
+
// cwd 是否在 personaRoot 下自动决定是否注入 --settings sandbox-settings.json.
|
|
22386
|
+
personaRoot: this.deps.personaRoot,
|
|
22237
22387
|
// file-sharing (spec §6 PR 3):闭包 scope + sessionId,runner 只暴露 tool/relPath/cwd
|
|
22238
22388
|
onFileEdit: attachmentGroup ? (input) => attachmentGroup.onFileEdit({
|
|
22239
22389
|
scope,
|
|
@@ -23246,7 +23396,7 @@ var SessionManager = class {
|
|
|
23246
23396
|
|
|
23247
23397
|
// src/persona/store.ts
|
|
23248
23398
|
var fs6 = __toESM(require("fs"), 1);
|
|
23249
|
-
var
|
|
23399
|
+
var path8 = __toESM(require("path"), 1);
|
|
23250
23400
|
init_protocol();
|
|
23251
23401
|
var DEFAULT_SETTINGS = {
|
|
23252
23402
|
permissions: {
|
|
@@ -23275,13 +23425,13 @@ var PersonaStore = class {
|
|
|
23275
23425
|
}
|
|
23276
23426
|
root;
|
|
23277
23427
|
personaDir(personaId) {
|
|
23278
|
-
return
|
|
23428
|
+
return path8.join(this.root, safeFileName(personaId));
|
|
23279
23429
|
}
|
|
23280
23430
|
metaPath(personaId) {
|
|
23281
|
-
return
|
|
23431
|
+
return path8.join(this.personaDir(personaId), ".clawd", "persona.json");
|
|
23282
23432
|
}
|
|
23283
23433
|
claudeMdPath(personaId) {
|
|
23284
|
-
return
|
|
23434
|
+
return path8.join(this.personaDir(personaId), "CLAUDE.md");
|
|
23285
23435
|
}
|
|
23286
23436
|
/**
|
|
23287
23437
|
* Sandbox settings 落盘路径 —— 故意放在 `.clawd/` 而不是 `.claude/`,让 CC 的
|
|
@@ -23291,11 +23441,11 @@ var PersonaStore = class {
|
|
|
23291
23441
|
* 加载 persona 人格,只有 listener 多一层 OS sandbox。
|
|
23292
23442
|
*/
|
|
23293
23443
|
sandboxSettingsPath(personaId) {
|
|
23294
|
-
return
|
|
23444
|
+
return path8.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
|
|
23295
23445
|
}
|
|
23296
23446
|
write(persona, personality) {
|
|
23297
23447
|
const dir = this.personaDir(persona.personaId);
|
|
23298
|
-
fs6.mkdirSync(
|
|
23448
|
+
fs6.mkdirSync(path8.join(dir, ".clawd"), { recursive: true });
|
|
23299
23449
|
this.atomicWrite(this.claudeMdPath(persona.personaId), personality);
|
|
23300
23450
|
this.atomicWrite(
|
|
23301
23451
|
this.sandboxSettingsPath(persona.personaId),
|
|
@@ -23338,12 +23488,12 @@ var PersonaStore = class {
|
|
|
23338
23488
|
}
|
|
23339
23489
|
/** Persona 私有 skills 目录路径:<personaDir>/.claude/skills */
|
|
23340
23490
|
skillsDir(personaId) {
|
|
23341
|
-
return
|
|
23491
|
+
return path8.join(this.personaDir(personaId), ".claude", "skills");
|
|
23342
23492
|
}
|
|
23343
23493
|
list() {
|
|
23344
23494
|
if (!fs6.existsSync(this.root)) return [];
|
|
23345
23495
|
return fs6.readdirSync(this.root).filter((name) => {
|
|
23346
|
-
return fs6.existsSync(
|
|
23496
|
+
return fs6.existsSync(path8.join(this.root, name, ".clawd", "persona.json"));
|
|
23347
23497
|
});
|
|
23348
23498
|
}
|
|
23349
23499
|
remove(personaId) {
|
|
@@ -23742,7 +23892,17 @@ var PersonaManager = class {
|
|
|
23742
23892
|
}
|
|
23743
23893
|
/**
|
|
23744
23894
|
* 删除 persona。
|
|
23745
|
-
* PersonaStore.remove(personaId) 已级联删除整个 <personaRoot>/<personaId>/
|
|
23895
|
+
* PersonaStore.remove(personaId) 已级联删除整个 <personaRoot>/<personaId>/ 目录,
|
|
23896
|
+
* Phase 2 capability platform 新布局下含 .clawd/sessions/owner/ +
|
|
23897
|
+
* .clawd/sessions/guests/<capId>/, rmSync recursive force 一锅清.
|
|
23898
|
+
*
|
|
23899
|
+
* ⚠️ TODO (Phase 3+ design gap, reviewer P1 flagged):
|
|
23900
|
+
* ~/.clawd/capabilities.json 里若有 cap.grants 含本 personaId, grant 会变成
|
|
23901
|
+
* 悬空引用 (guest 仍能持 token 接入, 但调依赖该 persona 的 RPC 会 fail).
|
|
23902
|
+
* 选项: (A) 这里扫所有 cap 过滤掉该 personaId 的 grant; (B) revoke 所有 grant
|
|
23903
|
+
* 含该 personaId 的 cap. 当前因 cleanupGuestSessionsForCapability 用 rmSync
|
|
23904
|
+
* force=true 吞 ENOENT 不会 crash, 但 UI CapabilityManagerDrawer 会展示
|
|
23905
|
+
* "无效的 persona" grant. Phase 3 加 cross-reference 矩阵后正式实现.
|
|
23746
23906
|
*/
|
|
23747
23907
|
delete(personaId) {
|
|
23748
23908
|
this.deps.store.remove(personaId);
|
|
@@ -23807,7 +23967,7 @@ var PersonaManager = class {
|
|
|
23807
23967
|
|
|
23808
23968
|
// src/persona/seed.ts
|
|
23809
23969
|
var fs8 = __toESM(require("fs"), 1);
|
|
23810
|
-
var
|
|
23970
|
+
var path10 = __toESM(require("path"), 1);
|
|
23811
23971
|
var import_node_url = require("url");
|
|
23812
23972
|
var import_meta = {};
|
|
23813
23973
|
var DEFAULT_PERSONAS = [
|
|
@@ -23843,14 +24003,14 @@ var DEFAULT_PERSONAS = [
|
|
|
23843
24003
|
function findDefaultsRoot() {
|
|
23844
24004
|
const candidates = [];
|
|
23845
24005
|
try {
|
|
23846
|
-
const here =
|
|
23847
|
-
candidates.push(
|
|
23848
|
-
candidates.push(
|
|
24006
|
+
const here = path10.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
24007
|
+
candidates.push(path10.resolve(here, "defaults"));
|
|
24008
|
+
candidates.push(path10.resolve(here, "persona-defaults"));
|
|
23849
24009
|
} catch {
|
|
23850
24010
|
}
|
|
23851
24011
|
if (process.argv[1]) {
|
|
23852
|
-
const argvDir =
|
|
23853
|
-
candidates.push(
|
|
24012
|
+
const argvDir = path10.dirname(process.argv[1]);
|
|
24013
|
+
candidates.push(path10.resolve(argvDir, "persona-defaults"));
|
|
23854
24014
|
}
|
|
23855
24015
|
for (const c of candidates) {
|
|
23856
24016
|
try {
|
|
@@ -23867,7 +24027,7 @@ function seedDefaultPersonas(args) {
|
|
|
23867
24027
|
args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
|
|
23868
24028
|
continue;
|
|
23869
24029
|
}
|
|
23870
|
-
const bundleDir =
|
|
24030
|
+
const bundleDir = path10.join(args.defaultsRoot, entry.personaId);
|
|
23871
24031
|
if (!fs8.existsSync(bundleDir)) {
|
|
23872
24032
|
args.logger.warn("persona.seed.skip", {
|
|
23873
24033
|
personaId: entry.personaId,
|
|
@@ -23876,7 +24036,7 @@ function seedDefaultPersonas(args) {
|
|
|
23876
24036
|
});
|
|
23877
24037
|
continue;
|
|
23878
24038
|
}
|
|
23879
|
-
const claudeMdPath =
|
|
24039
|
+
const claudeMdPath = path10.join(bundleDir, "CLAUDE.md");
|
|
23880
24040
|
if (!fs8.existsSync(claudeMdPath)) {
|
|
23881
24041
|
args.logger.warn("persona.seed.skip", {
|
|
23882
24042
|
personaId: entry.personaId,
|
|
@@ -23905,8 +24065,8 @@ function seedDefaultPersonas(args) {
|
|
|
23905
24065
|
function copyBundleExtras(srcDir, dstDir) {
|
|
23906
24066
|
for (const entry of fs8.readdirSync(srcDir, { withFileTypes: true })) {
|
|
23907
24067
|
if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
|
|
23908
|
-
const srcPath =
|
|
23909
|
-
const dstPath =
|
|
24068
|
+
const srcPath = path10.join(srcDir, entry.name);
|
|
24069
|
+
const dstPath = path10.join(dstDir, entry.name);
|
|
23910
24070
|
if (entry.isDirectory()) {
|
|
23911
24071
|
fs8.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
|
|
23912
24072
|
} else if (entry.isFile()) {
|
|
@@ -25792,7 +25952,7 @@ function authenticate(token, deps) {
|
|
|
25792
25952
|
|
|
25793
25953
|
// src/permission/capability-store.ts
|
|
25794
25954
|
var fs15 = __toESM(require("fs"), 1);
|
|
25795
|
-
var
|
|
25955
|
+
var path18 = __toESM(require("path"), 1);
|
|
25796
25956
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
25797
25957
|
var FILE_VERSION = 1;
|
|
25798
25958
|
var CapabilityStore = class {
|
|
@@ -25822,7 +25982,7 @@ var CapabilityStore = class {
|
|
|
25822
25982
|
this.flush();
|
|
25823
25983
|
}
|
|
25824
25984
|
filePath() {
|
|
25825
|
-
return
|
|
25985
|
+
return path18.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
25826
25986
|
}
|
|
25827
25987
|
readFromDisk() {
|
|
25828
25988
|
const file = this.filePath();
|
|
@@ -25976,6 +26136,243 @@ function sha256Hex2(s) {
|
|
|
25976
26136
|
return crypto5.createHash("sha256").update(s).digest("hex");
|
|
25977
26137
|
}
|
|
25978
26138
|
|
|
26139
|
+
// src/permission/cleanup.ts
|
|
26140
|
+
var fs16 = __toESM(require("fs"), 1);
|
|
26141
|
+
function cleanupGuestSessionsForCapability(cap, factory) {
|
|
26142
|
+
const removed = [];
|
|
26143
|
+
for (const g2 of cap.grants) {
|
|
26144
|
+
if (g2.resource.type !== "persona") continue;
|
|
26145
|
+
const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
|
|
26146
|
+
try {
|
|
26147
|
+
fs16.rmSync(dir, { recursive: true, force: true });
|
|
26148
|
+
removed.push(dir);
|
|
26149
|
+
} catch {
|
|
26150
|
+
}
|
|
26151
|
+
}
|
|
26152
|
+
return { removed };
|
|
26153
|
+
}
|
|
26154
|
+
|
|
26155
|
+
// src/inbox/inbox-store.ts
|
|
26156
|
+
var fs17 = __toESM(require("fs"), 1);
|
|
26157
|
+
var path19 = __toESM(require("path"), 1);
|
|
26158
|
+
var INBOX_FILE_NAME = "inbox.jsonl";
|
|
26159
|
+
var InboxStore = class {
|
|
26160
|
+
constructor(dataDir) {
|
|
26161
|
+
this.dataDir = dataDir;
|
|
26162
|
+
fs17.mkdirSync(dataDir, { recursive: true });
|
|
26163
|
+
}
|
|
26164
|
+
dataDir;
|
|
26165
|
+
list() {
|
|
26166
|
+
const file = this.filePath();
|
|
26167
|
+
let raw;
|
|
26168
|
+
try {
|
|
26169
|
+
raw = fs17.readFileSync(file, "utf8");
|
|
26170
|
+
} catch (err) {
|
|
26171
|
+
if (err?.code === "ENOENT") return [];
|
|
26172
|
+
return [];
|
|
26173
|
+
}
|
|
26174
|
+
return parseAllLines(raw);
|
|
26175
|
+
}
|
|
26176
|
+
append(ev) {
|
|
26177
|
+
const file = this.filePath();
|
|
26178
|
+
const line = JSON.stringify(ev) + "\n";
|
|
26179
|
+
fs17.appendFileSync(file, line, { mode: 384 });
|
|
26180
|
+
try {
|
|
26181
|
+
fs17.chmodSync(file, 384);
|
|
26182
|
+
} catch {
|
|
26183
|
+
}
|
|
26184
|
+
}
|
|
26185
|
+
/**
|
|
26186
|
+
* 标记某条 event 为已读. 已有 readAt 时不覆盖 (idempotent: 第二次调用维持第一次时间).
|
|
26187
|
+
* 未知 id 静默 no-op (不抛, 不写文件).
|
|
26188
|
+
*/
|
|
26189
|
+
markRead(id, at) {
|
|
26190
|
+
const events = this.list();
|
|
26191
|
+
let changed = false;
|
|
26192
|
+
const next = events.map((e) => {
|
|
26193
|
+
if (e.id !== id) return e;
|
|
26194
|
+
if (e.readAt !== void 0) return e;
|
|
26195
|
+
changed = true;
|
|
26196
|
+
return { ...e, readAt: at };
|
|
26197
|
+
});
|
|
26198
|
+
if (!changed) return;
|
|
26199
|
+
this.rewrite(next);
|
|
26200
|
+
}
|
|
26201
|
+
rewrite(events) {
|
|
26202
|
+
const file = this.filePath();
|
|
26203
|
+
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
26204
|
+
const content = events.map((e) => JSON.stringify(e)).join("\n") + (events.length > 0 ? "\n" : "");
|
|
26205
|
+
fs17.writeFileSync(tmp, content, { mode: 384 });
|
|
26206
|
+
fs17.renameSync(tmp, file);
|
|
26207
|
+
try {
|
|
26208
|
+
fs17.chmodSync(file, 384);
|
|
26209
|
+
} catch {
|
|
26210
|
+
}
|
|
26211
|
+
}
|
|
26212
|
+
filePath() {
|
|
26213
|
+
return path19.join(this.dataDir, INBOX_FILE_NAME);
|
|
26214
|
+
}
|
|
26215
|
+
};
|
|
26216
|
+
function parseAllLines(raw) {
|
|
26217
|
+
const out = [];
|
|
26218
|
+
for (const line of raw.split("\n")) {
|
|
26219
|
+
const trimmed = line.trim();
|
|
26220
|
+
if (!trimmed) continue;
|
|
26221
|
+
let parsed;
|
|
26222
|
+
try {
|
|
26223
|
+
parsed = JSON.parse(trimmed);
|
|
26224
|
+
} catch {
|
|
26225
|
+
continue;
|
|
26226
|
+
}
|
|
26227
|
+
const r = InboxEventSchema.safeParse(parsed);
|
|
26228
|
+
if (r.success) out.push(r.data);
|
|
26229
|
+
}
|
|
26230
|
+
return out;
|
|
26231
|
+
}
|
|
26232
|
+
|
|
26233
|
+
// src/inbox/inbox-manager.ts
|
|
26234
|
+
var crypto6 = __toESM(require("crypto"), 1);
|
|
26235
|
+
var InboxManager = class {
|
|
26236
|
+
constructor(store, broadcast, opts = {}) {
|
|
26237
|
+
this.store = store;
|
|
26238
|
+
this.broadcast = broadcast;
|
|
26239
|
+
this.now = opts.now ?? Date.now;
|
|
26240
|
+
this.genId = opts.genId ?? defaultGenId;
|
|
26241
|
+
}
|
|
26242
|
+
store;
|
|
26243
|
+
broadcast;
|
|
26244
|
+
now;
|
|
26245
|
+
genId;
|
|
26246
|
+
/**
|
|
26247
|
+
* persona VM 内某 sender 给 CC 发消息 → 跨 principal 时记 inbox event.
|
|
26248
|
+
* 返回 null = owner 自己 (no-op); 否则返回写入的 event (含派生 id / createdAt).
|
|
26249
|
+
*/
|
|
26250
|
+
recordPersonaMention(args) {
|
|
26251
|
+
if (args.sender.kind === "owner") return null;
|
|
26252
|
+
const resource = { type: "persona", id: args.personaId };
|
|
26253
|
+
const ev = {
|
|
26254
|
+
id: this.genId(),
|
|
26255
|
+
kind: "persona-mention",
|
|
26256
|
+
fromPrincipal: args.sender,
|
|
26257
|
+
toPrincipal: OWNER_PRINCIPAL,
|
|
26258
|
+
resource,
|
|
26259
|
+
preview: truncatePreview(args.preview),
|
|
26260
|
+
createdAt: this.now()
|
|
26261
|
+
};
|
|
26262
|
+
this.store.append(ev);
|
|
26263
|
+
this.broadcast({ type: "inbox:event", event: ev });
|
|
26264
|
+
return ev;
|
|
26265
|
+
}
|
|
26266
|
+
list(opts = {}) {
|
|
26267
|
+
const all = this.store.list();
|
|
26268
|
+
if (opts.includeRead) return all;
|
|
26269
|
+
return all.filter((e) => e.readAt === void 0);
|
|
26270
|
+
}
|
|
26271
|
+
markRead(eventId) {
|
|
26272
|
+
this.store.markRead(eventId, this.now());
|
|
26273
|
+
}
|
|
26274
|
+
};
|
|
26275
|
+
function truncatePreview(s) {
|
|
26276
|
+
if (s.length <= INBOX_PREVIEW_MAX_LENGTH) return s;
|
|
26277
|
+
return s.slice(0, INBOX_PREVIEW_MAX_LENGTH);
|
|
26278
|
+
}
|
|
26279
|
+
function defaultGenId() {
|
|
26280
|
+
return "inb_" + crypto6.randomBytes(6).toString("base64url");
|
|
26281
|
+
}
|
|
26282
|
+
|
|
26283
|
+
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
26284
|
+
var fs18 = __toESM(require("fs"), 1);
|
|
26285
|
+
var path20 = __toESM(require("path"), 1);
|
|
26286
|
+
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
26287
|
+
function migrateFlattenSessions(opts) {
|
|
26288
|
+
const dataDir = opts.dataDir;
|
|
26289
|
+
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)) {
|
|
26293
|
+
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
26294
|
+
}
|
|
26295
|
+
let movedBare = 0;
|
|
26296
|
+
let movedVmOwner = 0;
|
|
26297
|
+
let archivedListener = 0;
|
|
26298
|
+
const defaultDir = path20.join(sessionsDir, "default");
|
|
26299
|
+
if (existsSync3(defaultDir)) {
|
|
26300
|
+
for (const entry of readdirSafe(defaultDir)) {
|
|
26301
|
+
if (!entry.endsWith(".json")) continue;
|
|
26302
|
+
const src = path20.join(defaultDir, entry);
|
|
26303
|
+
const dst = path20.join(sessionsDir, entry);
|
|
26304
|
+
fs18.renameSync(src, dst);
|
|
26305
|
+
movedBare += 1;
|
|
26306
|
+
}
|
|
26307
|
+
rmdirIfEmpty(defaultDir);
|
|
26308
|
+
}
|
|
26309
|
+
for (const pid of readdirSafe(sessionsDir)) {
|
|
26310
|
+
const personaDir = path20.join(sessionsDir, pid);
|
|
26311
|
+
if (!isDir(personaDir)) continue;
|
|
26312
|
+
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 });
|
|
26317
|
+
for (const file of readdirSafe(ownerSrc)) {
|
|
26318
|
+
if (!file.endsWith(".json")) continue;
|
|
26319
|
+
fs18.renameSync(path20.join(ownerSrc, file), path20.join(ownerDst, file));
|
|
26320
|
+
movedVmOwner += 1;
|
|
26321
|
+
}
|
|
26322
|
+
rmdirIfEmpty(ownerSrc);
|
|
26323
|
+
}
|
|
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 });
|
|
26328
|
+
for (const file of readdirSafe(listenerSrc)) {
|
|
26329
|
+
if (!file.endsWith(".json")) continue;
|
|
26330
|
+
fs18.renameSync(path20.join(listenerSrc, file), path20.join(archiveDst, file));
|
|
26331
|
+
archivedListener += 1;
|
|
26332
|
+
}
|
|
26333
|
+
rmdirIfEmpty(listenerSrc);
|
|
26334
|
+
}
|
|
26335
|
+
rmdirIfEmpty(personaDir);
|
|
26336
|
+
}
|
|
26337
|
+
fs18.mkdirSync(sessionsDir, { recursive: true });
|
|
26338
|
+
fs18.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
26339
|
+
return {
|
|
26340
|
+
skipped: false,
|
|
26341
|
+
flagWritten: true,
|
|
26342
|
+
movedBare,
|
|
26343
|
+
movedVmOwner,
|
|
26344
|
+
archivedListener
|
|
26345
|
+
};
|
|
26346
|
+
}
|
|
26347
|
+
function existsSync3(p2) {
|
|
26348
|
+
try {
|
|
26349
|
+
fs18.statSync(p2);
|
|
26350
|
+
return true;
|
|
26351
|
+
} catch {
|
|
26352
|
+
return false;
|
|
26353
|
+
}
|
|
26354
|
+
}
|
|
26355
|
+
function isDir(p2) {
|
|
26356
|
+
try {
|
|
26357
|
+
return fs18.statSync(p2).isDirectory();
|
|
26358
|
+
} catch {
|
|
26359
|
+
return false;
|
|
26360
|
+
}
|
|
26361
|
+
}
|
|
26362
|
+
function readdirSafe(p2) {
|
|
26363
|
+
try {
|
|
26364
|
+
return fs18.readdirSync(p2);
|
|
26365
|
+
} catch {
|
|
26366
|
+
return [];
|
|
26367
|
+
}
|
|
26368
|
+
}
|
|
26369
|
+
function rmdirIfEmpty(p2) {
|
|
26370
|
+
try {
|
|
26371
|
+
fs18.rmdirSync(p2);
|
|
26372
|
+
} catch {
|
|
26373
|
+
}
|
|
26374
|
+
}
|
|
26375
|
+
|
|
25979
26376
|
// src/transport/http-router.ts
|
|
25980
26377
|
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
25981
26378
|
var import_node_path16 = __toESM(require("path"), 1);
|
|
@@ -27822,6 +28219,31 @@ function buildCapabilityHandlers(deps) {
|
|
|
27822
28219
|
};
|
|
27823
28220
|
}
|
|
27824
28221
|
|
|
28222
|
+
// src/handlers/inbox.ts
|
|
28223
|
+
function buildInboxHandlers(deps) {
|
|
28224
|
+
const { manager } = deps;
|
|
28225
|
+
const list = async (frame) => {
|
|
28226
|
+
const { type: _t, requestId: _r, ...rest } = frame;
|
|
28227
|
+
const args = InboxListArgsSchema.parse(rest);
|
|
28228
|
+
const events = manager.list({ includeRead: args.includeRead ?? false });
|
|
28229
|
+
return {
|
|
28230
|
+
response: { type: "inbox:list", events }
|
|
28231
|
+
};
|
|
28232
|
+
};
|
|
28233
|
+
const markRead = async (frame) => {
|
|
28234
|
+
const { type: _t, requestId: _r, ...rest } = frame;
|
|
28235
|
+
const args = InboxMarkReadArgsSchema.parse(rest);
|
|
28236
|
+
manager.markRead(args.eventId);
|
|
28237
|
+
return {
|
|
28238
|
+
response: { type: "inbox:markRead:ok", eventId: args.eventId }
|
|
28239
|
+
};
|
|
28240
|
+
};
|
|
28241
|
+
return {
|
|
28242
|
+
"inbox:list": list,
|
|
28243
|
+
"inbox:markRead": markRead
|
|
28244
|
+
};
|
|
28245
|
+
}
|
|
28246
|
+
|
|
27825
28247
|
// src/handlers/meta.ts
|
|
27826
28248
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
27827
28249
|
init_protocol();
|
|
@@ -28074,6 +28496,7 @@ function buildMethodHandlers(deps) {
|
|
|
28074
28496
|
personaRegistry: deps.personaRegistry
|
|
28075
28497
|
}),
|
|
28076
28498
|
...buildCapabilityHandlers({ manager: deps.capabilityManager }),
|
|
28499
|
+
...buildInboxHandlers({ manager: deps.inboxManager }),
|
|
28077
28500
|
...deps.attachment ? buildAttachmentHandlers(deps.attachment) : {}
|
|
28078
28501
|
};
|
|
28079
28502
|
}
|
|
@@ -28092,6 +28515,9 @@ var METHOD_GRANT_MAP = {
|
|
|
28092
28515
|
"capability:issue": ADMIN_ANY,
|
|
28093
28516
|
"capability:list": ADMIN_ANY,
|
|
28094
28517
|
"capability:revoke": ADMIN_ANY,
|
|
28518
|
+
// ---- inbox 跨用户通知 (Phase 3 admin-only, owner 调; Phase 4 加 postMessage) ----
|
|
28519
|
+
"inbox:list": ADMIN_ANY,
|
|
28520
|
+
"inbox:markRead": ADMIN_ANY,
|
|
28095
28521
|
// ---- 业务方法:Phase 1 全 admin-only(owner 自动通过;guest 无法调用) ----
|
|
28096
28522
|
"session:create": ADMIN_ANY,
|
|
28097
28523
|
"session:list": ADMIN_ANY,
|
|
@@ -28213,8 +28639,19 @@ async function startDaemon(config) {
|
|
|
28213
28639
|
revokedAt: cap.revokedAt
|
|
28214
28640
|
});
|
|
28215
28641
|
wsServer?.closeConnectionsByCapability(cap.id);
|
|
28642
|
+
const cleanup = cleanupGuestSessionsForCapability(cap, sessionStoreFactory);
|
|
28643
|
+
if (cleanup.removed.length > 0) {
|
|
28644
|
+
logger.info("capability revoke cascade: guest sessions removed", {
|
|
28645
|
+
capabilityId: cap.id,
|
|
28646
|
+
removedDirs: cleanup.removed
|
|
28647
|
+
});
|
|
28648
|
+
}
|
|
28216
28649
|
}
|
|
28217
28650
|
});
|
|
28651
|
+
const inboxStore = new InboxStore(config.dataDir);
|
|
28652
|
+
const inboxManager = new InboxManager(inboxStore, (frame) => {
|
|
28653
|
+
wsServer?.broadcastToOwners(frame);
|
|
28654
|
+
});
|
|
28218
28655
|
let wsServer = null;
|
|
28219
28656
|
const authGate = authMode === "first-message" ? new AuthGate({
|
|
28220
28657
|
shouldEnforce: buildShouldEnforce({ tunnel: config.tunnel }),
|
|
@@ -28231,7 +28668,16 @@ async function startDaemon(config) {
|
|
|
28231
28668
|
sendOk: (h, payload) => wsServer?.sendToClient(h.id, payload)
|
|
28232
28669
|
}) : null;
|
|
28233
28670
|
resetRegistry();
|
|
28234
|
-
const
|
|
28671
|
+
const migrateResult = migrateFlattenSessions({ dataDir: config.dataDir });
|
|
28672
|
+
if (!migrateResult.skipped && (migrateResult.movedBare || migrateResult.movedVmOwner || migrateResult.archivedListener)) {
|
|
28673
|
+
logger.info("sessions migration applied", {
|
|
28674
|
+
movedBare: migrateResult.movedBare,
|
|
28675
|
+
movedVmOwner: migrateResult.movedVmOwner,
|
|
28676
|
+
archivedListener: migrateResult.archivedListener
|
|
28677
|
+
});
|
|
28678
|
+
}
|
|
28679
|
+
const sessionStoreFactory = new SessionStoreFactory({ dataDir: config.dataDir });
|
|
28680
|
+
const store = sessionStoreFactory.forBare();
|
|
28235
28681
|
const workspace = new WorkspaceBrowser();
|
|
28236
28682
|
const skills = new SkillsScanner();
|
|
28237
28683
|
const agents = new AgentsScanner();
|
|
@@ -28248,6 +28694,9 @@ async function startDaemon(config) {
|
|
|
28248
28694
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
28249
28695
|
const manager = new SessionManager({
|
|
28250
28696
|
store,
|
|
28697
|
+
// Phase 2 (capability platform plan §1): factory 注入后 manager.storeFor 走
|
|
28698
|
+
// 新布局派生 (sessions/* + personas/<pid>/.clawd/sessions/owner/*)
|
|
28699
|
+
storeFactory: sessionStoreFactory,
|
|
28251
28700
|
logger,
|
|
28252
28701
|
getAdapter,
|
|
28253
28702
|
historyReader: history,
|
|
@@ -28392,7 +28841,9 @@ async function startDaemon(config) {
|
|
|
28392
28841
|
}
|
|
28393
28842
|
},
|
|
28394
28843
|
// Task 1.9: capability:issue/list/revoke handler 依赖
|
|
28395
|
-
capabilityManager
|
|
28844
|
+
capabilityManager,
|
|
28845
|
+
// Phase 3 Task 3.4: inbox:list/markRead handler 依赖
|
|
28846
|
+
inboxManager
|
|
28396
28847
|
});
|
|
28397
28848
|
const authResolver = new AuthContextResolver({
|
|
28398
28849
|
ownerToken: resolvedAuthToken,
|