@clawos-dev/clawd 0.2.85-beta.159.97c16b3 → 0.2.85-beta.160.958069f
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 +451 -643
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -643,8 +643,8 @@ var init_parseUtil = __esm({
|
|
|
643
643
|
init_errors2();
|
|
644
644
|
init_en();
|
|
645
645
|
makeIssue = (params) => {
|
|
646
|
-
const { data, path:
|
|
647
|
-
const fullPath = [...
|
|
646
|
+
const { data, path: path44, errorMaps, issueData } = params;
|
|
647
|
+
const fullPath = [...path44, ...issueData.path || []];
|
|
648
648
|
const fullIssue = {
|
|
649
649
|
...issueData,
|
|
650
650
|
path: fullPath
|
|
@@ -955,11 +955,11 @@ var init_types = __esm({
|
|
|
955
955
|
init_parseUtil();
|
|
956
956
|
init_util();
|
|
957
957
|
ParseInputLazyPath = class {
|
|
958
|
-
constructor(parent, value,
|
|
958
|
+
constructor(parent, value, path44, key) {
|
|
959
959
|
this._cachedPath = [];
|
|
960
960
|
this.parent = parent;
|
|
961
961
|
this.data = value;
|
|
962
|
-
this._path =
|
|
962
|
+
this._path = path44;
|
|
963
963
|
this._key = key;
|
|
964
964
|
}
|
|
965
965
|
get path() {
|
|
@@ -4343,13 +4343,13 @@ var init_zod = __esm({
|
|
|
4343
4343
|
});
|
|
4344
4344
|
|
|
4345
4345
|
// ../protocol/src/attachment-schemas.ts
|
|
4346
|
-
var TOKEN_ROLES, GROUP_FILE_SOURCES, GroupFileEntrySchema, AttachmentSignUrlArgs, AttachmentSignUrlResponseSchema, AttachmentGroupAddArgs, AttachmentGroupAddResponseSchema, AttachmentGroupRemoveArgs, AttachmentGroupRemoveResponseSchema, AttachmentGroupListArgs, AttachmentGroupListResponseSchema
|
|
4346
|
+
var TOKEN_ROLES, GROUP_FILE_SOURCES, GroupFileEntrySchema, AttachmentSignUrlArgs, AttachmentSignUrlResponseSchema, AttachmentGroupAddArgs, AttachmentGroupAddResponseSchema, AttachmentGroupRemoveArgs, AttachmentGroupRemoveResponseSchema, AttachmentGroupListArgs, AttachmentGroupListResponseSchema;
|
|
4347
4347
|
var init_attachment_schemas = __esm({
|
|
4348
4348
|
"../protocol/src/attachment-schemas.ts"() {
|
|
4349
4349
|
"use strict";
|
|
4350
4350
|
init_zod();
|
|
4351
4351
|
TOKEN_ROLES = ["owner"];
|
|
4352
|
-
GROUP_FILE_SOURCES = ["agent", "owner"
|
|
4352
|
+
GROUP_FILE_SOURCES = ["agent", "owner"];
|
|
4353
4353
|
GroupFileEntrySchema = external_exports.object({
|
|
4354
4354
|
/** daemon 派发的稳定 id(用于 RPC remove / UI key) */
|
|
4355
4355
|
id: external_exports.string().min(1),
|
|
@@ -4404,16 +4404,6 @@ var init_attachment_schemas = __esm({
|
|
|
4404
4404
|
AttachmentGroupListResponseSchema = external_exports.object({
|
|
4405
4405
|
entries: external_exports.array(GroupFileEntrySchema)
|
|
4406
4406
|
});
|
|
4407
|
-
AttachmentUploadResponseSchema = external_exports.object({
|
|
4408
|
-
/** sha256(bytes) 前 16 位,前端持有的稳定 ref */
|
|
4409
|
-
attachmentId: external_exports.string().min(1),
|
|
4410
|
-
/** 完整 tunnel signed URL,前端拼 marker / 直接送 Anthropic 都用它 */
|
|
4411
|
-
url: external_exports.string().min(1),
|
|
4412
|
-
/** 落在 session 目录下的相对路径(后续 group RPC / drawer 展示用) */
|
|
4413
|
-
relPath: external_exports.string().min(1),
|
|
4414
|
-
sizeBytes: external_exports.number().int().nonnegative(),
|
|
4415
|
-
mimeType: external_exports.string().min(1)
|
|
4416
|
-
});
|
|
4417
4407
|
}
|
|
4418
4408
|
});
|
|
4419
4409
|
|
|
@@ -5590,8 +5580,8 @@ var require_req = __commonJS({
|
|
|
5590
5580
|
if (req.originalUrl) {
|
|
5591
5581
|
_req.url = req.originalUrl;
|
|
5592
5582
|
} else {
|
|
5593
|
-
const
|
|
5594
|
-
_req.url = typeof
|
|
5583
|
+
const path44 = req.path;
|
|
5584
|
+
_req.url = typeof path44 === "string" ? path44 : req.url ? req.url.path || req.url : void 0;
|
|
5595
5585
|
}
|
|
5596
5586
|
if (req.query) {
|
|
5597
5587
|
_req.query = req.query;
|
|
@@ -5756,14 +5746,14 @@ var require_redact = __commonJS({
|
|
|
5756
5746
|
}
|
|
5757
5747
|
return obj;
|
|
5758
5748
|
}
|
|
5759
|
-
function parsePath(
|
|
5749
|
+
function parsePath(path44) {
|
|
5760
5750
|
const parts = [];
|
|
5761
5751
|
let current = "";
|
|
5762
5752
|
let inBrackets = false;
|
|
5763
5753
|
let inQuotes = false;
|
|
5764
5754
|
let quoteChar = "";
|
|
5765
|
-
for (let i = 0; i <
|
|
5766
|
-
const char =
|
|
5755
|
+
for (let i = 0; i < path44.length; i++) {
|
|
5756
|
+
const char = path44[i];
|
|
5767
5757
|
if (!inBrackets && char === ".") {
|
|
5768
5758
|
if (current) {
|
|
5769
5759
|
parts.push(current);
|
|
@@ -5894,10 +5884,10 @@ var require_redact = __commonJS({
|
|
|
5894
5884
|
return current;
|
|
5895
5885
|
}
|
|
5896
5886
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
5897
|
-
for (const
|
|
5898
|
-
const parts = parsePath(
|
|
5887
|
+
for (const path44 of paths) {
|
|
5888
|
+
const parts = parsePath(path44);
|
|
5899
5889
|
if (parts.includes("*")) {
|
|
5900
|
-
redactWildcardPath(obj, parts, censor,
|
|
5890
|
+
redactWildcardPath(obj, parts, censor, path44, remove);
|
|
5901
5891
|
} else {
|
|
5902
5892
|
if (remove) {
|
|
5903
5893
|
removeKey(obj, parts);
|
|
@@ -5982,8 +5972,8 @@ var require_redact = __commonJS({
|
|
|
5982
5972
|
}
|
|
5983
5973
|
} else {
|
|
5984
5974
|
if (afterWildcard.includes("*")) {
|
|
5985
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
5986
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
5975
|
+
const wrappedCensor = typeof censor === "function" ? (value, path44) => {
|
|
5976
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path44];
|
|
5987
5977
|
return censor(value, fullPath);
|
|
5988
5978
|
} : censor;
|
|
5989
5979
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6018,8 +6008,8 @@ var require_redact = __commonJS({
|
|
|
6018
6008
|
return null;
|
|
6019
6009
|
}
|
|
6020
6010
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6021
|
-
for (const
|
|
6022
|
-
const parts = parsePath(
|
|
6011
|
+
for (const path44 of pathsToClone) {
|
|
6012
|
+
const parts = parsePath(path44);
|
|
6023
6013
|
let current = pathStructure;
|
|
6024
6014
|
for (let i = 0; i < parts.length; i++) {
|
|
6025
6015
|
const part = parts[i];
|
|
@@ -6071,24 +6061,24 @@ var require_redact = __commonJS({
|
|
|
6071
6061
|
}
|
|
6072
6062
|
return cloneSelectively(obj, pathStructure);
|
|
6073
6063
|
}
|
|
6074
|
-
function validatePath(
|
|
6075
|
-
if (typeof
|
|
6064
|
+
function validatePath(path44) {
|
|
6065
|
+
if (typeof path44 !== "string") {
|
|
6076
6066
|
throw new Error("Paths must be (non-empty) strings");
|
|
6077
6067
|
}
|
|
6078
|
-
if (
|
|
6068
|
+
if (path44 === "") {
|
|
6079
6069
|
throw new Error("Invalid redaction path ()");
|
|
6080
6070
|
}
|
|
6081
|
-
if (
|
|
6082
|
-
throw new Error(`Invalid redaction path (${
|
|
6071
|
+
if (path44.includes("..")) {
|
|
6072
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6083
6073
|
}
|
|
6084
|
-
if (
|
|
6085
|
-
throw new Error(`Invalid redaction path (${
|
|
6074
|
+
if (path44.includes(",")) {
|
|
6075
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6086
6076
|
}
|
|
6087
6077
|
let bracketCount = 0;
|
|
6088
6078
|
let inQuotes = false;
|
|
6089
6079
|
let quoteChar = "";
|
|
6090
|
-
for (let i = 0; i <
|
|
6091
|
-
const char =
|
|
6080
|
+
for (let i = 0; i < path44.length; i++) {
|
|
6081
|
+
const char = path44[i];
|
|
6092
6082
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6093
6083
|
if (!inQuotes) {
|
|
6094
6084
|
inQuotes = true;
|
|
@@ -6102,20 +6092,20 @@ var require_redact = __commonJS({
|
|
|
6102
6092
|
} else if (char === "]" && !inQuotes) {
|
|
6103
6093
|
bracketCount--;
|
|
6104
6094
|
if (bracketCount < 0) {
|
|
6105
|
-
throw new Error(`Invalid redaction path (${
|
|
6095
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6106
6096
|
}
|
|
6107
6097
|
}
|
|
6108
6098
|
}
|
|
6109
6099
|
if (bracketCount !== 0) {
|
|
6110
|
-
throw new Error(`Invalid redaction path (${
|
|
6100
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6111
6101
|
}
|
|
6112
6102
|
}
|
|
6113
6103
|
function validatePaths(paths) {
|
|
6114
6104
|
if (!Array.isArray(paths)) {
|
|
6115
6105
|
throw new TypeError("paths must be an array");
|
|
6116
6106
|
}
|
|
6117
|
-
for (const
|
|
6118
|
-
validatePath(
|
|
6107
|
+
for (const path44 of paths) {
|
|
6108
|
+
validatePath(path44);
|
|
6119
6109
|
}
|
|
6120
6110
|
}
|
|
6121
6111
|
function slowRedact(options = {}) {
|
|
@@ -6283,8 +6273,8 @@ var require_redaction = __commonJS({
|
|
|
6283
6273
|
if (shape[k2] === null) {
|
|
6284
6274
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6285
6275
|
} else {
|
|
6286
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6287
|
-
return censor(value, [k2, ...
|
|
6276
|
+
const wrappedCensor = typeof censor === "function" ? (value, path44) => {
|
|
6277
|
+
return censor(value, [k2, ...path44]);
|
|
6288
6278
|
} : censor;
|
|
6289
6279
|
o[k2] = Redact({
|
|
6290
6280
|
paths: shape[k2],
|
|
@@ -6502,10 +6492,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
6502
6492
|
var require_sonic_boom = __commonJS({
|
|
6503
6493
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
6504
6494
|
"use strict";
|
|
6505
|
-
var
|
|
6495
|
+
var fs35 = require("fs");
|
|
6506
6496
|
var EventEmitter2 = require("events");
|
|
6507
6497
|
var inherits = require("util").inherits;
|
|
6508
|
-
var
|
|
6498
|
+
var path44 = require("path");
|
|
6509
6499
|
var sleep = require_atomic_sleep();
|
|
6510
6500
|
var assert = require("assert");
|
|
6511
6501
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6559,20 +6549,20 @@ var require_sonic_boom = __commonJS({
|
|
|
6559
6549
|
const mode = sonic.mode;
|
|
6560
6550
|
if (sonic.sync) {
|
|
6561
6551
|
try {
|
|
6562
|
-
if (sonic.mkdir)
|
|
6563
|
-
const fd =
|
|
6552
|
+
if (sonic.mkdir) fs35.mkdirSync(path44.dirname(file), { recursive: true });
|
|
6553
|
+
const fd = fs35.openSync(file, flags, mode);
|
|
6564
6554
|
fileOpened(null, fd);
|
|
6565
6555
|
} catch (err) {
|
|
6566
6556
|
fileOpened(err);
|
|
6567
6557
|
throw err;
|
|
6568
6558
|
}
|
|
6569
6559
|
} else if (sonic.mkdir) {
|
|
6570
|
-
|
|
6560
|
+
fs35.mkdir(path44.dirname(file), { recursive: true }, (err) => {
|
|
6571
6561
|
if (err) return fileOpened(err);
|
|
6572
|
-
|
|
6562
|
+
fs35.open(file, flags, mode, fileOpened);
|
|
6573
6563
|
});
|
|
6574
6564
|
} else {
|
|
6575
|
-
|
|
6565
|
+
fs35.open(file, flags, mode, fileOpened);
|
|
6576
6566
|
}
|
|
6577
6567
|
}
|
|
6578
6568
|
function SonicBoom(opts) {
|
|
@@ -6613,8 +6603,8 @@ var require_sonic_boom = __commonJS({
|
|
|
6613
6603
|
this.flush = flushBuffer;
|
|
6614
6604
|
this.flushSync = flushBufferSync;
|
|
6615
6605
|
this._actualWrite = actualWriteBuffer;
|
|
6616
|
-
fsWriteSync = () =>
|
|
6617
|
-
fsWrite = () =>
|
|
6606
|
+
fsWriteSync = () => fs35.writeSync(this.fd, this._writingBuf);
|
|
6607
|
+
fsWrite = () => fs35.write(this.fd, this._writingBuf, this.release);
|
|
6618
6608
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
6619
6609
|
this._writingBuf = "";
|
|
6620
6610
|
this.write = write;
|
|
@@ -6623,15 +6613,15 @@ var require_sonic_boom = __commonJS({
|
|
|
6623
6613
|
this._actualWrite = actualWrite;
|
|
6624
6614
|
fsWriteSync = () => {
|
|
6625
6615
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6626
|
-
return
|
|
6616
|
+
return fs35.writeSync(this.fd, this._writingBuf);
|
|
6627
6617
|
}
|
|
6628
|
-
return
|
|
6618
|
+
return fs35.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6629
6619
|
};
|
|
6630
6620
|
fsWrite = () => {
|
|
6631
6621
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6632
|
-
return
|
|
6622
|
+
return fs35.write(this.fd, this._writingBuf, this.release);
|
|
6633
6623
|
}
|
|
6634
|
-
return
|
|
6624
|
+
return fs35.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
6635
6625
|
};
|
|
6636
6626
|
} else {
|
|
6637
6627
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -6688,7 +6678,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6688
6678
|
}
|
|
6689
6679
|
}
|
|
6690
6680
|
if (this._fsync) {
|
|
6691
|
-
|
|
6681
|
+
fs35.fsyncSync(this.fd);
|
|
6692
6682
|
}
|
|
6693
6683
|
const len = this._len;
|
|
6694
6684
|
if (this._reopening) {
|
|
@@ -6802,7 +6792,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6802
6792
|
const onDrain = () => {
|
|
6803
6793
|
if (!this._fsync) {
|
|
6804
6794
|
try {
|
|
6805
|
-
|
|
6795
|
+
fs35.fsync(this.fd, (err) => {
|
|
6806
6796
|
this._flushPending = false;
|
|
6807
6797
|
cb(err);
|
|
6808
6798
|
});
|
|
@@ -6904,7 +6894,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6904
6894
|
const fd = this.fd;
|
|
6905
6895
|
this.once("ready", () => {
|
|
6906
6896
|
if (fd !== this.fd) {
|
|
6907
|
-
|
|
6897
|
+
fs35.close(fd, (err) => {
|
|
6908
6898
|
if (err) {
|
|
6909
6899
|
return this.emit("error", err);
|
|
6910
6900
|
}
|
|
@@ -6953,7 +6943,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6953
6943
|
buf = this._bufs[0];
|
|
6954
6944
|
}
|
|
6955
6945
|
try {
|
|
6956
|
-
const n = Buffer.isBuffer(buf) ?
|
|
6946
|
+
const n = Buffer.isBuffer(buf) ? fs35.writeSync(this.fd, buf) : fs35.writeSync(this.fd, buf, "utf8");
|
|
6957
6947
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
6958
6948
|
buf = releasedBufObj.writingBuf;
|
|
6959
6949
|
this._len = releasedBufObj.len;
|
|
@@ -6969,7 +6959,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6969
6959
|
}
|
|
6970
6960
|
}
|
|
6971
6961
|
try {
|
|
6972
|
-
|
|
6962
|
+
fs35.fsyncSync(this.fd);
|
|
6973
6963
|
} catch {
|
|
6974
6964
|
}
|
|
6975
6965
|
}
|
|
@@ -6990,7 +6980,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6990
6980
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
6991
6981
|
}
|
|
6992
6982
|
try {
|
|
6993
|
-
const n =
|
|
6983
|
+
const n = fs35.writeSync(this.fd, buf);
|
|
6994
6984
|
buf = buf.subarray(n);
|
|
6995
6985
|
this._len = Math.max(this._len - n, 0);
|
|
6996
6986
|
if (buf.length <= 0) {
|
|
@@ -7018,13 +7008,13 @@ var require_sonic_boom = __commonJS({
|
|
|
7018
7008
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
7019
7009
|
if (this.sync) {
|
|
7020
7010
|
try {
|
|
7021
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
7011
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs35.writeSync(this.fd, this._writingBuf) : fs35.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7022
7012
|
release(null, written);
|
|
7023
7013
|
} catch (err) {
|
|
7024
7014
|
release(err);
|
|
7025
7015
|
}
|
|
7026
7016
|
} else {
|
|
7027
|
-
|
|
7017
|
+
fs35.write(this.fd, this._writingBuf, release);
|
|
7028
7018
|
}
|
|
7029
7019
|
}
|
|
7030
7020
|
function actualWriteBuffer() {
|
|
@@ -7033,7 +7023,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7033
7023
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
7034
7024
|
if (this.sync) {
|
|
7035
7025
|
try {
|
|
7036
|
-
const written =
|
|
7026
|
+
const written = fs35.writeSync(this.fd, this._writingBuf);
|
|
7037
7027
|
release(null, written);
|
|
7038
7028
|
} catch (err) {
|
|
7039
7029
|
release(err);
|
|
@@ -7042,7 +7032,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7042
7032
|
if (kCopyBuffer) {
|
|
7043
7033
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
7044
7034
|
}
|
|
7045
|
-
|
|
7035
|
+
fs35.write(this.fd, this._writingBuf, release);
|
|
7046
7036
|
}
|
|
7047
7037
|
}
|
|
7048
7038
|
function actualClose(sonic) {
|
|
@@ -7058,12 +7048,12 @@ var require_sonic_boom = __commonJS({
|
|
|
7058
7048
|
sonic._lens = [];
|
|
7059
7049
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
7060
7050
|
try {
|
|
7061
|
-
|
|
7051
|
+
fs35.fsync(sonic.fd, closeWrapped);
|
|
7062
7052
|
} catch {
|
|
7063
7053
|
}
|
|
7064
7054
|
function closeWrapped() {
|
|
7065
7055
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
7066
|
-
|
|
7056
|
+
fs35.close(sonic.fd, done);
|
|
7067
7057
|
} else {
|
|
7068
7058
|
done();
|
|
7069
7059
|
}
|
|
@@ -7794,7 +7784,7 @@ var require_transport = __commonJS({
|
|
|
7794
7784
|
stream.flushSync();
|
|
7795
7785
|
}
|
|
7796
7786
|
function transport(fullOptions) {
|
|
7797
|
-
const { pipeline:
|
|
7787
|
+
const { pipeline: pipeline2, targets, levels, dedupe, worker = {}, caller = getCallers(), sync = false } = fullOptions;
|
|
7798
7788
|
const options = {
|
|
7799
7789
|
...fullOptions.options
|
|
7800
7790
|
};
|
|
@@ -7822,9 +7812,9 @@ var require_transport = __commonJS({
|
|
|
7822
7812
|
};
|
|
7823
7813
|
});
|
|
7824
7814
|
});
|
|
7825
|
-
} else if (
|
|
7815
|
+
} else if (pipeline2) {
|
|
7826
7816
|
target = bundlerOverrides["pino-worker"] || join11(__dirname, "worker.js");
|
|
7827
|
-
options.pipelines = [
|
|
7817
|
+
options.pipelines = [pipeline2.map((dest) => {
|
|
7828
7818
|
return {
|
|
7829
7819
|
...dest,
|
|
7830
7820
|
target: fixTarget(dest.target)
|
|
@@ -9427,7 +9417,7 @@ var require_multistream = __commonJS({
|
|
|
9427
9417
|
var require_pino = __commonJS({
|
|
9428
9418
|
"../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
|
|
9429
9419
|
"use strict";
|
|
9430
|
-
var
|
|
9420
|
+
var os17 = require("os");
|
|
9431
9421
|
var stdSerializers = require_pino_std_serializers();
|
|
9432
9422
|
var caller = require_caller();
|
|
9433
9423
|
var redaction = require_redaction();
|
|
@@ -9474,7 +9464,7 @@ var require_pino = __commonJS({
|
|
|
9474
9464
|
} = symbols;
|
|
9475
9465
|
var { epochTime, nullTime } = time;
|
|
9476
9466
|
var { pid } = process;
|
|
9477
|
-
var hostname =
|
|
9467
|
+
var hostname = os17.hostname();
|
|
9478
9468
|
var defaultErrorSerializer = stdSerializers.err;
|
|
9479
9469
|
var defaultOptions = {
|
|
9480
9470
|
level: "info",
|
|
@@ -10198,11 +10188,11 @@ var init_lib = __esm({
|
|
|
10198
10188
|
}
|
|
10199
10189
|
}
|
|
10200
10190
|
},
|
|
10201
|
-
addToPath: function addToPath(
|
|
10202
|
-
var last =
|
|
10191
|
+
addToPath: function addToPath(path44, added, removed, oldPosInc, options) {
|
|
10192
|
+
var last = path44.lastComponent;
|
|
10203
10193
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10204
10194
|
return {
|
|
10205
|
-
oldPos:
|
|
10195
|
+
oldPos: path44.oldPos + oldPosInc,
|
|
10206
10196
|
lastComponent: {
|
|
10207
10197
|
count: last.count + 1,
|
|
10208
10198
|
added,
|
|
@@ -10212,7 +10202,7 @@ var init_lib = __esm({
|
|
|
10212
10202
|
};
|
|
10213
10203
|
} else {
|
|
10214
10204
|
return {
|
|
10215
|
-
oldPos:
|
|
10205
|
+
oldPos: path44.oldPos + oldPosInc,
|
|
10216
10206
|
lastComponent: {
|
|
10217
10207
|
count: 1,
|
|
10218
10208
|
added,
|
|
@@ -10643,10 +10633,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10643
10633
|
const memories = raw.map((m2) => {
|
|
10644
10634
|
if (!m2 || typeof m2 !== "object") return null;
|
|
10645
10635
|
const rec = m2;
|
|
10646
|
-
const
|
|
10636
|
+
const path44 = typeof rec.path === "string" ? rec.path : null;
|
|
10647
10637
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
10648
|
-
if (!
|
|
10649
|
-
const entry = { path:
|
|
10638
|
+
if (!path44 || content == null) return null;
|
|
10639
|
+
const entry = { path: path44, content };
|
|
10650
10640
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
10651
10641
|
return entry;
|
|
10652
10642
|
}).filter((m2) => m2 !== null);
|
|
@@ -11472,10 +11462,10 @@ function parseAttachment(obj) {
|
|
|
11472
11462
|
const memories = raw.map((m2) => {
|
|
11473
11463
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11474
11464
|
const rec = m2;
|
|
11475
|
-
const
|
|
11465
|
+
const path44 = typeof rec.path === "string" ? rec.path : null;
|
|
11476
11466
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11477
|
-
if (!
|
|
11478
|
-
const out = { path:
|
|
11467
|
+
if (!path44 || content == null) return null;
|
|
11468
|
+
const out = { path: path44, content };
|
|
11479
11469
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11480
11470
|
return out;
|
|
11481
11471
|
}).filter((m2) => m2 !== null);
|
|
@@ -20390,7 +20380,7 @@ var require_websocket_server = __commonJS({
|
|
|
20390
20380
|
// src/run-case/recorder.ts
|
|
20391
20381
|
function startRunCaseRecorder(opts) {
|
|
20392
20382
|
const now = opts.now ?? Date.now;
|
|
20393
|
-
const dir =
|
|
20383
|
+
const dir = import_node_path30.default.dirname(opts.recordPath);
|
|
20394
20384
|
let stream = null;
|
|
20395
20385
|
let closing = false;
|
|
20396
20386
|
let closedSettled = false;
|
|
@@ -20404,8 +20394,8 @@ function startRunCaseRecorder(opts) {
|
|
|
20404
20394
|
});
|
|
20405
20395
|
const ensureStream = () => {
|
|
20406
20396
|
if (stream) return stream;
|
|
20407
|
-
|
|
20408
|
-
stream =
|
|
20397
|
+
import_node_fs27.default.mkdirSync(dir, { recursive: true });
|
|
20398
|
+
stream = import_node_fs27.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
20409
20399
|
stream.on("close", () => closedResolve());
|
|
20410
20400
|
return stream;
|
|
20411
20401
|
};
|
|
@@ -20430,12 +20420,12 @@ function startRunCaseRecorder(opts) {
|
|
|
20430
20420
|
};
|
|
20431
20421
|
return { tap, close, closed };
|
|
20432
20422
|
}
|
|
20433
|
-
var
|
|
20423
|
+
var import_node_fs27, import_node_path30;
|
|
20434
20424
|
var init_recorder = __esm({
|
|
20435
20425
|
"src/run-case/recorder.ts"() {
|
|
20436
20426
|
"use strict";
|
|
20437
|
-
|
|
20438
|
-
|
|
20427
|
+
import_node_fs27 = __toESM(require("fs"), 1);
|
|
20428
|
+
import_node_path30 = __toESM(require("path"), 1);
|
|
20439
20429
|
}
|
|
20440
20430
|
});
|
|
20441
20431
|
|
|
@@ -20478,7 +20468,7 @@ var init_wire = __esm({
|
|
|
20478
20468
|
// src/run-case/controller.ts
|
|
20479
20469
|
async function runController(opts) {
|
|
20480
20470
|
const now = opts.now ?? Date.now;
|
|
20481
|
-
const cwd = opts.cwd ?? (0,
|
|
20471
|
+
const cwd = opts.cwd ?? (0, import_node_fs28.mkdtempSync)(import_node_path31.default.join(import_node_os15.default.tmpdir(), "clawd-runcase-"));
|
|
20482
20472
|
const ownsCwd = opts.cwd === void 0;
|
|
20483
20473
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
20484
20474
|
const spawnCtx = { cwd };
|
|
@@ -20639,19 +20629,19 @@ async function runController(opts) {
|
|
|
20639
20629
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
20640
20630
|
if (ownsCwd) {
|
|
20641
20631
|
try {
|
|
20642
|
-
(0,
|
|
20632
|
+
(0, import_node_fs28.rmSync)(cwd, { recursive: true, force: true });
|
|
20643
20633
|
} catch {
|
|
20644
20634
|
}
|
|
20645
20635
|
}
|
|
20646
20636
|
return exitCode ?? 0;
|
|
20647
20637
|
}
|
|
20648
|
-
var
|
|
20638
|
+
var import_node_fs28, import_node_os15, import_node_path31;
|
|
20649
20639
|
var init_controller = __esm({
|
|
20650
20640
|
"src/run-case/controller.ts"() {
|
|
20651
20641
|
"use strict";
|
|
20652
|
-
|
|
20653
|
-
|
|
20654
|
-
|
|
20642
|
+
import_node_fs28 = require("fs");
|
|
20643
|
+
import_node_os15 = __toESM(require("os"), 1);
|
|
20644
|
+
import_node_path31 = __toESM(require("path"), 1);
|
|
20655
20645
|
init_claude();
|
|
20656
20646
|
init_stdout_splitter();
|
|
20657
20647
|
init_permission_stdio();
|
|
@@ -20883,8 +20873,8 @@ Env (advanced):
|
|
|
20883
20873
|
`;
|
|
20884
20874
|
|
|
20885
20875
|
// src/index.ts
|
|
20886
|
-
var
|
|
20887
|
-
var
|
|
20876
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
20877
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
20888
20878
|
|
|
20889
20879
|
// src/logger.ts
|
|
20890
20880
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
@@ -22619,18 +22609,6 @@ var SessionManager = class {
|
|
|
22619
22609
|
(a, b2) => a.updatedAt > b2.updatedAt ? -1 : a.updatedAt < b2.updatedAt ? 1 : 0
|
|
22620
22610
|
);
|
|
22621
22611
|
}
|
|
22622
|
-
/**
|
|
22623
|
-
* 跨 scope 列出所有 owner 视角的 session(default + persona owner + persona guest),
|
|
22624
|
-
* 附带派生的 SessionScope。attachment GC tick 用 —— 需要遍历所有活跃 session 的
|
|
22625
|
-
* .attachments 目录 + 群文件清单求 liveSet。
|
|
22626
|
-
*/
|
|
22627
|
-
listOwnedSessionScopes() {
|
|
22628
|
-
return this.listAllOwned().map((file) => ({
|
|
22629
|
-
scope: this.scopeForFile(file),
|
|
22630
|
-
sessionId: file.sessionId,
|
|
22631
|
-
cwd: file.cwd
|
|
22632
|
-
}));
|
|
22633
|
-
}
|
|
22634
22612
|
// 写回 SessionFile,自动根据 ownerPersonaId / creatorPrincipalId 派生写入 scope.
|
|
22635
22613
|
// 调用方原先都是 `deps.store.write(updated)`,全部走这里收口路由.
|
|
22636
22614
|
writeOwned(file) {
|
|
@@ -25531,11 +25509,18 @@ var AgentsScanner = class {
|
|
|
25531
25509
|
};
|
|
25532
25510
|
|
|
25533
25511
|
// src/observer/session-observer.ts
|
|
25512
|
+
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
25513
|
+
var import_node_os9 = __toESM(require("os"), 1);
|
|
25514
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
25515
|
+
init_claude_history();
|
|
25516
|
+
|
|
25517
|
+
// src/observer/subagent-meta-observer.ts
|
|
25534
25518
|
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
25535
25519
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
25536
25520
|
var import_node_path13 = __toESM(require("path"), 1);
|
|
25537
25521
|
init_claude_history();
|
|
25538
|
-
var
|
|
25522
|
+
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
25523
|
+
var SubagentMetaObserver = class {
|
|
25539
25524
|
constructor(opts) {
|
|
25540
25525
|
this.opts = opts;
|
|
25541
25526
|
this.home = opts.home ?? import_node_os8.default.homedir();
|
|
@@ -25543,16 +25528,132 @@ var SessionObserver = class {
|
|
|
25543
25528
|
opts;
|
|
25544
25529
|
home;
|
|
25545
25530
|
watches = /* @__PURE__ */ new Map();
|
|
25531
|
+
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
25532
|
+
resolveSubagentDir(cwd, toolSessionId) {
|
|
25533
|
+
return import_node_path13.default.join(
|
|
25534
|
+
this.home,
|
|
25535
|
+
".claude",
|
|
25536
|
+
"projects",
|
|
25537
|
+
cwdToHashDir(cwd),
|
|
25538
|
+
toolSessionId,
|
|
25539
|
+
"subagents"
|
|
25540
|
+
);
|
|
25541
|
+
}
|
|
25542
|
+
start(args) {
|
|
25543
|
+
this.stop(args.sessionId);
|
|
25544
|
+
const dirPath = this.resolveSubagentDir(args.cwd, args.toolSessionId);
|
|
25545
|
+
const w2 = {
|
|
25546
|
+
sessionId: args.sessionId,
|
|
25547
|
+
dirPath,
|
|
25548
|
+
watcher: null,
|
|
25549
|
+
pollTimer: null,
|
|
25550
|
+
emitted: /* @__PURE__ */ new Set()
|
|
25551
|
+
};
|
|
25552
|
+
this.watches.set(args.sessionId, w2);
|
|
25553
|
+
this.scan(w2);
|
|
25554
|
+
this.attachWatcher(w2);
|
|
25555
|
+
w2.pollTimer = setInterval(() => this.scan(w2), 200);
|
|
25556
|
+
return { dirPath };
|
|
25557
|
+
}
|
|
25558
|
+
// fs.watch 必须在目录存在后调用;首次启动时 subagents/ 通常不存在 —— attachWatcher
|
|
25559
|
+
// 失败就交给 pollTimer 200ms 兜底,目录一出现就被下次 poll 捡起来,那时也尝试 attach
|
|
25560
|
+
attachWatcher(w2) {
|
|
25561
|
+
if (w2.watcher) return;
|
|
25562
|
+
try {
|
|
25563
|
+
w2.watcher = import_node_fs12.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
|
|
25564
|
+
if (!name) return;
|
|
25565
|
+
const m2 = META_RE.exec(String(name));
|
|
25566
|
+
if (!m2) return;
|
|
25567
|
+
this.scanOne(w2, String(name));
|
|
25568
|
+
});
|
|
25569
|
+
} catch {
|
|
25570
|
+
}
|
|
25571
|
+
}
|
|
25572
|
+
scan(w2) {
|
|
25573
|
+
let entries;
|
|
25574
|
+
try {
|
|
25575
|
+
entries = import_node_fs12.default.readdirSync(w2.dirPath);
|
|
25576
|
+
} catch {
|
|
25577
|
+
return;
|
|
25578
|
+
}
|
|
25579
|
+
if (!w2.watcher) this.attachWatcher(w2);
|
|
25580
|
+
for (const name of entries) {
|
|
25581
|
+
this.scanOne(w2, name);
|
|
25582
|
+
}
|
|
25583
|
+
}
|
|
25584
|
+
scanOne(w2, name) {
|
|
25585
|
+
const m2 = META_RE.exec(name);
|
|
25586
|
+
if (!m2) return;
|
|
25587
|
+
const agentId = m2[1];
|
|
25588
|
+
if (w2.emitted.has(agentId)) return;
|
|
25589
|
+
const file = import_node_path13.default.join(w2.dirPath, name);
|
|
25590
|
+
let raw;
|
|
25591
|
+
try {
|
|
25592
|
+
raw = import_node_fs12.default.readFileSync(file, "utf8");
|
|
25593
|
+
} catch {
|
|
25594
|
+
return;
|
|
25595
|
+
}
|
|
25596
|
+
let obj;
|
|
25597
|
+
try {
|
|
25598
|
+
obj = JSON.parse(raw);
|
|
25599
|
+
} catch {
|
|
25600
|
+
return;
|
|
25601
|
+
}
|
|
25602
|
+
const toolUseId = typeof obj.toolUseId === "string" ? obj.toolUseId : "";
|
|
25603
|
+
if (!toolUseId) return;
|
|
25604
|
+
w2.emitted.add(agentId);
|
|
25605
|
+
const ev = {
|
|
25606
|
+
kind: "subagent_progress",
|
|
25607
|
+
toolUseId,
|
|
25608
|
+
agentId,
|
|
25609
|
+
status: "started"
|
|
25610
|
+
};
|
|
25611
|
+
if (typeof obj.description === "string" && obj.description) ev.description = obj.description;
|
|
25612
|
+
this.opts.onEvent({ sessionId: w2.sessionId, events: [ev] });
|
|
25613
|
+
}
|
|
25614
|
+
isObserving(sessionId) {
|
|
25615
|
+
return this.watches.has(sessionId);
|
|
25616
|
+
}
|
|
25617
|
+
stop(sessionId) {
|
|
25618
|
+
const w2 = this.watches.get(sessionId);
|
|
25619
|
+
if (!w2) return false;
|
|
25620
|
+
try {
|
|
25621
|
+
w2.watcher?.close();
|
|
25622
|
+
} catch {
|
|
25623
|
+
}
|
|
25624
|
+
if (w2.pollTimer) clearInterval(w2.pollTimer);
|
|
25625
|
+
this.watches.delete(sessionId);
|
|
25626
|
+
return true;
|
|
25627
|
+
}
|
|
25628
|
+
stopAll() {
|
|
25629
|
+
for (const id of [...this.watches.keys()]) this.stop(id);
|
|
25630
|
+
}
|
|
25631
|
+
};
|
|
25632
|
+
|
|
25633
|
+
// src/observer/session-observer.ts
|
|
25634
|
+
var SessionObserver = class {
|
|
25635
|
+
constructor(opts) {
|
|
25636
|
+
this.opts = opts;
|
|
25637
|
+
this.home = opts.home ?? import_node_os9.default.homedir();
|
|
25638
|
+
this.metaObserver = opts.enableSubagentMetaObserver ? new SubagentMetaObserver({ home: this.home, onEvent: opts.onEvent }) : null;
|
|
25639
|
+
}
|
|
25640
|
+
opts;
|
|
25641
|
+
home;
|
|
25642
|
+
watches = /* @__PURE__ */ new Map();
|
|
25643
|
+
// 子 observer:监听 <projectsRoot>/<hashDir>/<toolSessionId>/subagents/ 目录的 meta.json,
|
|
25644
|
+
// 仅 TUI 模式启用——SDK 模式靠 `system.task_started` 帧(claude.ts:466)emit subagent_progress
|
|
25645
|
+
// 已经能解锁 AgentCallLine 抽屉入口,再跑 meta watcher 会让 ring buffer 留双帧
|
|
25646
|
+
metaObserver;
|
|
25546
25647
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
25547
25648
|
if (override) return override;
|
|
25548
|
-
return
|
|
25649
|
+
return import_node_path14.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
25549
25650
|
}
|
|
25550
25651
|
start(args) {
|
|
25551
25652
|
this.stop(args.sessionId);
|
|
25552
25653
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
25553
25654
|
let size = 0;
|
|
25554
25655
|
try {
|
|
25555
|
-
size =
|
|
25656
|
+
size = import_node_fs13.default.statSync(filePath).size;
|
|
25556
25657
|
} catch {
|
|
25557
25658
|
}
|
|
25558
25659
|
const w2 = {
|
|
@@ -25565,10 +25666,10 @@ var SessionObserver = class {
|
|
|
25565
25666
|
adapter: args.adapter
|
|
25566
25667
|
};
|
|
25567
25668
|
try {
|
|
25568
|
-
|
|
25669
|
+
import_node_fs13.default.mkdirSync(import_node_path14.default.dirname(filePath), { recursive: true });
|
|
25569
25670
|
} catch {
|
|
25570
25671
|
}
|
|
25571
|
-
w2.watcher =
|
|
25672
|
+
w2.watcher = import_node_fs13.default.watch(import_node_path14.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
25572
25673
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
25573
25674
|
this.poll(w2);
|
|
25574
25675
|
});
|
|
@@ -25577,6 +25678,11 @@ var SessionObserver = class {
|
|
|
25577
25678
|
this.opts.onStatus?.(args.sessionId, "observing");
|
|
25578
25679
|
this.hydrateMetaTail(w2);
|
|
25579
25680
|
this.poll(w2);
|
|
25681
|
+
this.metaObserver?.start({
|
|
25682
|
+
sessionId: args.sessionId,
|
|
25683
|
+
cwd: args.cwd,
|
|
25684
|
+
toolSessionId: args.toolSessionId
|
|
25685
|
+
});
|
|
25580
25686
|
return { filePath };
|
|
25581
25687
|
}
|
|
25582
25688
|
// 读 JSONL 文件尾部 N 行,把每行的 meta_update 字段**合并成一个 patch** 喂给 reducer。
|
|
@@ -25586,7 +25692,7 @@ var SessionObserver = class {
|
|
|
25586
25692
|
// 异常静默吞,不阻塞 watcher 启动
|
|
25587
25693
|
hydrateMetaTail(w2, maxLines = 200) {
|
|
25588
25694
|
try {
|
|
25589
|
-
const raw =
|
|
25695
|
+
const raw = import_node_fs13.default.readFileSync(w2.filePath, "utf8");
|
|
25590
25696
|
if (!raw) return;
|
|
25591
25697
|
const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
25592
25698
|
if (allLines.length === 0) return;
|
|
@@ -25610,7 +25716,7 @@ var SessionObserver = class {
|
|
|
25610
25716
|
poll(w2) {
|
|
25611
25717
|
let size = 0;
|
|
25612
25718
|
try {
|
|
25613
|
-
size =
|
|
25719
|
+
size = import_node_fs13.default.statSync(w2.filePath).size;
|
|
25614
25720
|
} catch {
|
|
25615
25721
|
return;
|
|
25616
25722
|
}
|
|
@@ -25619,11 +25725,11 @@ var SessionObserver = class {
|
|
|
25619
25725
|
w2.buf = "";
|
|
25620
25726
|
}
|
|
25621
25727
|
if (size === w2.lastSize) return;
|
|
25622
|
-
const fd =
|
|
25728
|
+
const fd = import_node_fs13.default.openSync(w2.filePath, "r");
|
|
25623
25729
|
try {
|
|
25624
25730
|
const len = size - w2.lastSize;
|
|
25625
25731
|
const buf = Buffer.alloc(len);
|
|
25626
|
-
|
|
25732
|
+
import_node_fs13.default.readSync(fd, buf, 0, len, w2.lastSize);
|
|
25627
25733
|
w2.lastSize = size;
|
|
25628
25734
|
w2.buf += buf.toString("utf8");
|
|
25629
25735
|
let newlineIndex;
|
|
@@ -25637,7 +25743,7 @@ var SessionObserver = class {
|
|
|
25637
25743
|
}
|
|
25638
25744
|
}
|
|
25639
25745
|
} finally {
|
|
25640
|
-
|
|
25746
|
+
import_node_fs13.default.closeSync(fd);
|
|
25641
25747
|
}
|
|
25642
25748
|
}
|
|
25643
25749
|
// 解析 JSONL 单行:仅当是主链 user 文本行(非 sidechain / 非 sub-agent / message.role='user'
|
|
@@ -25690,11 +25796,13 @@ var SessionObserver = class {
|
|
|
25690
25796
|
}
|
|
25691
25797
|
if (w2.pollTimer) clearInterval(w2.pollTimer);
|
|
25692
25798
|
this.watches.delete(sessionId);
|
|
25799
|
+
this.metaObserver?.stop(sessionId);
|
|
25693
25800
|
this.opts.onStatus?.(sessionId, "stopped");
|
|
25694
25801
|
return true;
|
|
25695
25802
|
}
|
|
25696
25803
|
stopAll() {
|
|
25697
25804
|
for (const id of [...this.watches.keys()]) this.stop(id);
|
|
25805
|
+
this.metaObserver?.stopAll();
|
|
25698
25806
|
}
|
|
25699
25807
|
};
|
|
25700
25808
|
|
|
@@ -26295,14 +26403,14 @@ function authenticate(token, deps) {
|
|
|
26295
26403
|
}
|
|
26296
26404
|
|
|
26297
26405
|
// src/permission/capability-store.ts
|
|
26298
|
-
var
|
|
26299
|
-
var
|
|
26406
|
+
var fs16 = __toESM(require("fs"), 1);
|
|
26407
|
+
var path19 = __toESM(require("path"), 1);
|
|
26300
26408
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
26301
26409
|
var FILE_VERSION = 1;
|
|
26302
26410
|
var CapabilityStore = class {
|
|
26303
26411
|
constructor(dataDir) {
|
|
26304
26412
|
this.dataDir = dataDir;
|
|
26305
|
-
|
|
26413
|
+
fs16.mkdirSync(dataDir, { recursive: true });
|
|
26306
26414
|
this.cache = this.readFromDisk();
|
|
26307
26415
|
}
|
|
26308
26416
|
dataDir;
|
|
@@ -26326,13 +26434,13 @@ var CapabilityStore = class {
|
|
|
26326
26434
|
this.flush();
|
|
26327
26435
|
}
|
|
26328
26436
|
filePath() {
|
|
26329
|
-
return
|
|
26437
|
+
return path19.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
26330
26438
|
}
|
|
26331
26439
|
readFromDisk() {
|
|
26332
26440
|
const file = this.filePath();
|
|
26333
26441
|
let raw;
|
|
26334
26442
|
try {
|
|
26335
|
-
raw =
|
|
26443
|
+
raw = fs16.readFileSync(file, "utf8");
|
|
26336
26444
|
} catch (err) {
|
|
26337
26445
|
if (err?.code === "ENOENT") return [];
|
|
26338
26446
|
return [];
|
|
@@ -26360,10 +26468,10 @@ var CapabilityStore = class {
|
|
|
26360
26468
|
}
|
|
26361
26469
|
atomicWrite(file, content) {
|
|
26362
26470
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
26363
|
-
|
|
26364
|
-
|
|
26471
|
+
fs16.writeFileSync(tmp, content, { mode: 384 });
|
|
26472
|
+
fs16.renameSync(tmp, file);
|
|
26365
26473
|
try {
|
|
26366
|
-
|
|
26474
|
+
fs16.chmodSync(file, 384);
|
|
26367
26475
|
} catch {
|
|
26368
26476
|
}
|
|
26369
26477
|
}
|
|
@@ -26456,14 +26564,14 @@ var CapabilityManager = class {
|
|
|
26456
26564
|
};
|
|
26457
26565
|
|
|
26458
26566
|
// src/permission/cleanup.ts
|
|
26459
|
-
var
|
|
26567
|
+
var fs17 = __toESM(require("fs"), 1);
|
|
26460
26568
|
function cleanupGuestSessionsForCapability(cap, factory) {
|
|
26461
26569
|
const removed = [];
|
|
26462
26570
|
for (const g2 of cap.grants) {
|
|
26463
26571
|
if (g2.resource.type !== "persona") continue;
|
|
26464
26572
|
const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
|
|
26465
26573
|
try {
|
|
26466
|
-
|
|
26574
|
+
fs17.rmSync(dir, { recursive: true, force: true });
|
|
26467
26575
|
removed.push(dir);
|
|
26468
26576
|
} catch {
|
|
26469
26577
|
}
|
|
@@ -26472,13 +26580,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
26472
26580
|
}
|
|
26473
26581
|
|
|
26474
26582
|
// src/permission/personal-capability.ts
|
|
26475
|
-
var
|
|
26476
|
-
var
|
|
26583
|
+
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
26584
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
26477
26585
|
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
26478
26586
|
var PERSONAL_CAP_FILE_NAME = "personal-capability.json";
|
|
26479
26587
|
var PERSONAL_CAP_DISPLAY_NAME = "personal";
|
|
26480
26588
|
function personalCapFilePath(dataDir) {
|
|
26481
|
-
return
|
|
26589
|
+
return import_node_path15.default.join(dataDir, PERSONAL_CAP_FILE_NAME);
|
|
26482
26590
|
}
|
|
26483
26591
|
function loadOrCreatePersonalCapability(opts) {
|
|
26484
26592
|
const file = personalCapFilePath(opts.dataDir);
|
|
@@ -26508,7 +26616,7 @@ function loadOrCreatePersonalCapability(opts) {
|
|
|
26508
26616
|
function readFile(file) {
|
|
26509
26617
|
let raw;
|
|
26510
26618
|
try {
|
|
26511
|
-
raw =
|
|
26619
|
+
raw = import_node_fs14.default.readFileSync(file, "utf8");
|
|
26512
26620
|
} catch (err) {
|
|
26513
26621
|
const code = err?.code;
|
|
26514
26622
|
if (code === "ENOENT") return null;
|
|
@@ -26529,10 +26637,10 @@ function readFile(file) {
|
|
|
26529
26637
|
return { token: obj.token, capability: capParsed.data };
|
|
26530
26638
|
}
|
|
26531
26639
|
function writeFile(file, content) {
|
|
26532
|
-
|
|
26533
|
-
|
|
26640
|
+
import_node_fs14.default.mkdirSync(import_node_path15.default.dirname(file), { recursive: true });
|
|
26641
|
+
import_node_fs14.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
26534
26642
|
try {
|
|
26535
|
-
|
|
26643
|
+
import_node_fs14.default.chmodSync(file, 384);
|
|
26536
26644
|
} catch {
|
|
26537
26645
|
}
|
|
26538
26646
|
}
|
|
@@ -26547,13 +26655,13 @@ function sha256Hex2(s) {
|
|
|
26547
26655
|
}
|
|
26548
26656
|
|
|
26549
26657
|
// src/inbox/inbox-store.ts
|
|
26550
|
-
var
|
|
26551
|
-
var
|
|
26658
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
26659
|
+
var path21 = __toESM(require("path"), 1);
|
|
26552
26660
|
var INBOX_SUBDIR = "inbox";
|
|
26553
26661
|
var InboxStore = class {
|
|
26554
26662
|
constructor(dataDir) {
|
|
26555
26663
|
this.dataDir = dataDir;
|
|
26556
|
-
|
|
26664
|
+
fs19.mkdirSync(this.dirPath(), { recursive: true });
|
|
26557
26665
|
}
|
|
26558
26666
|
dataDir;
|
|
26559
26667
|
/**
|
|
@@ -26565,7 +26673,7 @@ var InboxStore = class {
|
|
|
26565
26673
|
const file = this.filePath(peerOwnerId);
|
|
26566
26674
|
let raw;
|
|
26567
26675
|
try {
|
|
26568
|
-
raw =
|
|
26676
|
+
raw = fs19.readFileSync(file, "utf8");
|
|
26569
26677
|
} catch (err) {
|
|
26570
26678
|
if (err?.code === "ENOENT") return [];
|
|
26571
26679
|
return [];
|
|
@@ -26581,7 +26689,7 @@ var InboxStore = class {
|
|
|
26581
26689
|
const dir = this.dirPath();
|
|
26582
26690
|
let entries;
|
|
26583
26691
|
try {
|
|
26584
|
-
entries =
|
|
26692
|
+
entries = fs19.readdirSync(dir);
|
|
26585
26693
|
} catch (err) {
|
|
26586
26694
|
if (err?.code === "ENOENT") return [];
|
|
26587
26695
|
return [];
|
|
@@ -26597,9 +26705,9 @@ var InboxStore = class {
|
|
|
26597
26705
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
26598
26706
|
const file = this.filePath(message.peerOwnerId);
|
|
26599
26707
|
const line = JSON.stringify(message) + "\n";
|
|
26600
|
-
|
|
26708
|
+
fs19.appendFileSync(file, line, { mode: 384 });
|
|
26601
26709
|
try {
|
|
26602
|
-
|
|
26710
|
+
fs19.chmodSync(file, 384);
|
|
26603
26711
|
} catch {
|
|
26604
26712
|
}
|
|
26605
26713
|
}
|
|
@@ -26629,7 +26737,7 @@ var InboxStore = class {
|
|
|
26629
26737
|
removeByPeerOwnerId(peerOwnerId) {
|
|
26630
26738
|
const file = this.filePath(peerOwnerId);
|
|
26631
26739
|
try {
|
|
26632
|
-
|
|
26740
|
+
fs19.unlinkSync(file);
|
|
26633
26741
|
} catch (err) {
|
|
26634
26742
|
if (err?.code === "ENOENT") return;
|
|
26635
26743
|
}
|
|
@@ -26638,18 +26746,18 @@ var InboxStore = class {
|
|
|
26638
26746
|
const file = this.filePath(peerOwnerId);
|
|
26639
26747
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
26640
26748
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
26641
|
-
|
|
26642
|
-
|
|
26749
|
+
fs19.writeFileSync(tmp, content, { mode: 384 });
|
|
26750
|
+
fs19.renameSync(tmp, file);
|
|
26643
26751
|
try {
|
|
26644
|
-
|
|
26752
|
+
fs19.chmodSync(file, 384);
|
|
26645
26753
|
} catch {
|
|
26646
26754
|
}
|
|
26647
26755
|
}
|
|
26648
26756
|
dirPath() {
|
|
26649
|
-
return
|
|
26757
|
+
return path21.join(this.dataDir, INBOX_SUBDIR);
|
|
26650
26758
|
}
|
|
26651
26759
|
filePath(peerOwnerId) {
|
|
26652
|
-
return
|
|
26760
|
+
return path21.join(this.dirPath(), `${peerOwnerId}.jsonl`);
|
|
26653
26761
|
}
|
|
26654
26762
|
};
|
|
26655
26763
|
function parseAllLines(raw) {
|
|
@@ -26736,8 +26844,8 @@ var InboxManager = class {
|
|
|
26736
26844
|
};
|
|
26737
26845
|
|
|
26738
26846
|
// src/state/received-capability-store.ts
|
|
26739
|
-
var
|
|
26740
|
-
var
|
|
26847
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
26848
|
+
var path22 = __toESM(require("path"), 1);
|
|
26741
26849
|
var FILE_NAME = "received-capabilities.json";
|
|
26742
26850
|
var ReceivedCapabilityStore = class {
|
|
26743
26851
|
constructor(dataDir) {
|
|
@@ -26747,10 +26855,10 @@ var ReceivedCapabilityStore = class {
|
|
|
26747
26855
|
caps = /* @__PURE__ */ new Map();
|
|
26748
26856
|
load() {
|
|
26749
26857
|
this.caps.clear();
|
|
26750
|
-
const file =
|
|
26858
|
+
const file = path22.join(this.dataDir, FILE_NAME);
|
|
26751
26859
|
let raw;
|
|
26752
26860
|
try {
|
|
26753
|
-
raw =
|
|
26861
|
+
raw = fs20.readFileSync(file, "utf8");
|
|
26754
26862
|
} catch (err) {
|
|
26755
26863
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
26756
26864
|
return;
|
|
@@ -26787,20 +26895,20 @@ var ReceivedCapabilityStore = class {
|
|
|
26787
26895
|
this.flush();
|
|
26788
26896
|
}
|
|
26789
26897
|
flush() {
|
|
26790
|
-
const file =
|
|
26898
|
+
const file = path22.join(this.dataDir, FILE_NAME);
|
|
26791
26899
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
26792
26900
|
const content = JSON.stringify(
|
|
26793
26901
|
{ receivedCaps: Array.from(this.caps.values()) },
|
|
26794
26902
|
null,
|
|
26795
26903
|
2
|
|
26796
26904
|
);
|
|
26797
|
-
|
|
26798
|
-
|
|
26799
|
-
|
|
26905
|
+
fs20.mkdirSync(this.dataDir, { recursive: true });
|
|
26906
|
+
fs20.writeFileSync(tmp, content, { mode: 384 });
|
|
26907
|
+
fs20.renameSync(tmp, file);
|
|
26800
26908
|
}
|
|
26801
26909
|
renameBak(file) {
|
|
26802
26910
|
try {
|
|
26803
|
-
|
|
26911
|
+
fs20.renameSync(file, `${file}.bak`);
|
|
26804
26912
|
} catch {
|
|
26805
26913
|
}
|
|
26806
26914
|
}
|
|
@@ -26898,61 +27006,61 @@ async function connectRemote(args) {
|
|
|
26898
27006
|
}
|
|
26899
27007
|
|
|
26900
27008
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
26901
|
-
var
|
|
26902
|
-
var
|
|
27009
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
27010
|
+
var path23 = __toESM(require("path"), 1);
|
|
26903
27011
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
26904
27012
|
function migrateFlattenSessions(opts) {
|
|
26905
27013
|
const dataDir = opts.dataDir;
|
|
26906
27014
|
const now = opts.now ?? Date.now;
|
|
26907
|
-
const sessionsDir =
|
|
26908
|
-
const flagPath =
|
|
27015
|
+
const sessionsDir = path23.join(dataDir, "sessions");
|
|
27016
|
+
const flagPath = path23.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
26909
27017
|
if (existsSync3(flagPath)) {
|
|
26910
27018
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
26911
27019
|
}
|
|
26912
27020
|
let movedBare = 0;
|
|
26913
27021
|
let movedVmOwner = 0;
|
|
26914
27022
|
let archivedListener = 0;
|
|
26915
|
-
const defaultDir =
|
|
27023
|
+
const defaultDir = path23.join(sessionsDir, "default");
|
|
26916
27024
|
if (existsSync3(defaultDir)) {
|
|
26917
27025
|
for (const entry of readdirSafe(defaultDir)) {
|
|
26918
27026
|
if (!entry.endsWith(".json")) continue;
|
|
26919
|
-
const src =
|
|
26920
|
-
const dst =
|
|
26921
|
-
|
|
27027
|
+
const src = path23.join(defaultDir, entry);
|
|
27028
|
+
const dst = path23.join(sessionsDir, entry);
|
|
27029
|
+
fs21.renameSync(src, dst);
|
|
26922
27030
|
movedBare += 1;
|
|
26923
27031
|
}
|
|
26924
27032
|
rmdirIfEmpty(defaultDir);
|
|
26925
27033
|
}
|
|
26926
27034
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
26927
|
-
const personaDir =
|
|
27035
|
+
const personaDir = path23.join(sessionsDir, pid);
|
|
26928
27036
|
if (!isDir(personaDir)) continue;
|
|
26929
27037
|
if (pid === "default") continue;
|
|
26930
|
-
const ownerSrc =
|
|
27038
|
+
const ownerSrc = path23.join(personaDir, "owner");
|
|
26931
27039
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
26932
|
-
const ownerDst =
|
|
26933
|
-
|
|
27040
|
+
const ownerDst = path23.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
27041
|
+
fs21.mkdirSync(ownerDst, { recursive: true });
|
|
26934
27042
|
for (const file of readdirSafe(ownerSrc)) {
|
|
26935
27043
|
if (!file.endsWith(".json")) continue;
|
|
26936
|
-
|
|
27044
|
+
fs21.renameSync(path23.join(ownerSrc, file), path23.join(ownerDst, file));
|
|
26937
27045
|
movedVmOwner += 1;
|
|
26938
27046
|
}
|
|
26939
27047
|
rmdirIfEmpty(ownerSrc);
|
|
26940
27048
|
}
|
|
26941
|
-
const listenerSrc =
|
|
27049
|
+
const listenerSrc = path23.join(personaDir, "listener");
|
|
26942
27050
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
26943
|
-
const archiveDst =
|
|
26944
|
-
|
|
27051
|
+
const archiveDst = path23.join(dataDir, ".legacy", `listener-${pid}`);
|
|
27052
|
+
fs21.mkdirSync(archiveDst, { recursive: true });
|
|
26945
27053
|
for (const file of readdirSafe(listenerSrc)) {
|
|
26946
27054
|
if (!file.endsWith(".json")) continue;
|
|
26947
|
-
|
|
27055
|
+
fs21.renameSync(path23.join(listenerSrc, file), path23.join(archiveDst, file));
|
|
26948
27056
|
archivedListener += 1;
|
|
26949
27057
|
}
|
|
26950
27058
|
rmdirIfEmpty(listenerSrc);
|
|
26951
27059
|
}
|
|
26952
27060
|
rmdirIfEmpty(personaDir);
|
|
26953
27061
|
}
|
|
26954
|
-
|
|
26955
|
-
|
|
27062
|
+
fs21.mkdirSync(sessionsDir, { recursive: true });
|
|
27063
|
+
fs21.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
26956
27064
|
return {
|
|
26957
27065
|
skipped: false,
|
|
26958
27066
|
flagWritten: true,
|
|
@@ -26963,7 +27071,7 @@ function migrateFlattenSessions(opts) {
|
|
|
26963
27071
|
}
|
|
26964
27072
|
function existsSync3(p2) {
|
|
26965
27073
|
try {
|
|
26966
|
-
|
|
27074
|
+
fs21.statSync(p2);
|
|
26967
27075
|
return true;
|
|
26968
27076
|
} catch {
|
|
26969
27077
|
return false;
|
|
@@ -26971,21 +27079,21 @@ function existsSync3(p2) {
|
|
|
26971
27079
|
}
|
|
26972
27080
|
function isDir(p2) {
|
|
26973
27081
|
try {
|
|
26974
|
-
return
|
|
27082
|
+
return fs21.statSync(p2).isDirectory();
|
|
26975
27083
|
} catch {
|
|
26976
27084
|
return false;
|
|
26977
27085
|
}
|
|
26978
27086
|
}
|
|
26979
27087
|
function readdirSafe(p2) {
|
|
26980
27088
|
try {
|
|
26981
|
-
return
|
|
27089
|
+
return fs21.readdirSync(p2);
|
|
26982
27090
|
} catch {
|
|
26983
27091
|
return [];
|
|
26984
27092
|
}
|
|
26985
27093
|
}
|
|
26986
27094
|
function rmdirIfEmpty(p2) {
|
|
26987
27095
|
try {
|
|
26988
|
-
|
|
27096
|
+
fs21.rmdirSync(p2);
|
|
26989
27097
|
} catch {
|
|
26990
27098
|
}
|
|
26991
27099
|
}
|
|
@@ -26995,7 +27103,7 @@ var import_node_fs15 = __toESM(require("fs"), 1);
|
|
|
26995
27103
|
var import_node_path17 = __toESM(require("path"), 1);
|
|
26996
27104
|
|
|
26997
27105
|
// src/attachment/mime.ts
|
|
26998
|
-
var
|
|
27106
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
26999
27107
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
27000
27108
|
var EXT_TO_NATIVE_MIME = {
|
|
27001
27109
|
// 图片
|
|
@@ -27102,7 +27210,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
27102
27210
|
".mk"
|
|
27103
27211
|
]);
|
|
27104
27212
|
function lookupMime(filePathOrName) {
|
|
27105
|
-
const ext =
|
|
27213
|
+
const ext = import_node_path16.default.extname(filePathOrName).toLowerCase();
|
|
27106
27214
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
27107
27215
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
27108
27216
|
return "application/octet-stream";
|
|
@@ -27170,118 +27278,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
27170
27278
|
return { ok: true, absPath };
|
|
27171
27279
|
}
|
|
27172
27280
|
|
|
27173
|
-
// src/attachment/upload.ts
|
|
27174
|
-
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
27175
|
-
var import_node_path16 = __toESM(require("path"), 1);
|
|
27176
|
-
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
27177
|
-
var import_promises = require("stream/promises");
|
|
27178
|
-
var UploadError = class extends Error {
|
|
27179
|
-
constructor(code, message) {
|
|
27180
|
-
super(message);
|
|
27181
|
-
this.code = code;
|
|
27182
|
-
this.name = "UploadError";
|
|
27183
|
-
}
|
|
27184
|
-
code;
|
|
27185
|
-
};
|
|
27186
|
-
var HASH_PREFIX_LEN = 16;
|
|
27187
|
-
async function writeUploadedAttachment(args) {
|
|
27188
|
-
const attachmentsRoot = import_node_path16.default.join(args.sessionDir, ".attachments");
|
|
27189
|
-
try {
|
|
27190
|
-
import_node_fs14.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
27191
|
-
} catch (err) {
|
|
27192
|
-
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
27193
|
-
}
|
|
27194
|
-
const hasher = import_node_crypto6.default.createHash("sha256");
|
|
27195
|
-
let actualSize = 0;
|
|
27196
|
-
const tmpPath = import_node_path16.default.join(
|
|
27197
|
-
attachmentsRoot,
|
|
27198
|
-
`.upload-${process.pid}-${Date.now()}-${import_node_crypto6.default.randomBytes(4).toString("hex")}`
|
|
27199
|
-
);
|
|
27200
|
-
try {
|
|
27201
|
-
await (0, import_promises.pipeline)(
|
|
27202
|
-
args.body,
|
|
27203
|
-
async function* (source) {
|
|
27204
|
-
for await (const chunk of source) {
|
|
27205
|
-
const buf = chunk;
|
|
27206
|
-
actualSize += buf.length;
|
|
27207
|
-
hasher.update(buf);
|
|
27208
|
-
yield buf;
|
|
27209
|
-
}
|
|
27210
|
-
},
|
|
27211
|
-
import_node_fs14.default.createWriteStream(tmpPath, { mode: 384 })
|
|
27212
|
-
);
|
|
27213
|
-
} catch (err) {
|
|
27214
|
-
try {
|
|
27215
|
-
import_node_fs14.default.unlinkSync(tmpPath);
|
|
27216
|
-
} catch {
|
|
27217
|
-
}
|
|
27218
|
-
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
27219
|
-
}
|
|
27220
|
-
if (actualSize !== args.contentLength) {
|
|
27221
|
-
try {
|
|
27222
|
-
import_node_fs14.default.unlinkSync(tmpPath);
|
|
27223
|
-
} catch {
|
|
27224
|
-
}
|
|
27225
|
-
throw new UploadError(
|
|
27226
|
-
"SIZE_MISMATCH",
|
|
27227
|
-
`expected ${args.contentLength} bytes, got ${actualSize}`
|
|
27228
|
-
);
|
|
27229
|
-
}
|
|
27230
|
-
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
27231
|
-
const hashDir = import_node_path16.default.join(attachmentsRoot, attachmentId);
|
|
27232
|
-
let finalFileName;
|
|
27233
|
-
let hashDirExists = false;
|
|
27234
|
-
try {
|
|
27235
|
-
hashDirExists = import_node_fs14.default.statSync(hashDir).isDirectory();
|
|
27236
|
-
} catch {
|
|
27237
|
-
}
|
|
27238
|
-
if (hashDirExists) {
|
|
27239
|
-
const existing = import_node_fs14.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
|
|
27240
|
-
finalFileName = existing[0] ?? args.fileName;
|
|
27241
|
-
try {
|
|
27242
|
-
import_node_fs14.default.unlinkSync(tmpPath);
|
|
27243
|
-
} catch {
|
|
27244
|
-
}
|
|
27245
|
-
} else {
|
|
27246
|
-
try {
|
|
27247
|
-
import_node_fs14.default.mkdirSync(hashDir, { recursive: true });
|
|
27248
|
-
finalFileName = args.fileName;
|
|
27249
|
-
import_node_fs14.default.renameSync(tmpPath, import_node_path16.default.join(hashDir, finalFileName));
|
|
27250
|
-
} catch (err) {
|
|
27251
|
-
try {
|
|
27252
|
-
import_node_fs14.default.unlinkSync(tmpPath);
|
|
27253
|
-
} catch {
|
|
27254
|
-
}
|
|
27255
|
-
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
27256
|
-
}
|
|
27257
|
-
}
|
|
27258
|
-
const absPath = import_node_path16.default.join(hashDir, finalFileName);
|
|
27259
|
-
const relPath = import_node_path16.default.relative(args.sessionDir, absPath);
|
|
27260
|
-
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
27261
|
-
relPath: absPath,
|
|
27262
|
-
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
27263
|
-
from: "user-upload",
|
|
27264
|
-
label: args.fileName,
|
|
27265
|
-
size: actualSize,
|
|
27266
|
-
mime: args.mimeType
|
|
27267
|
-
});
|
|
27268
|
-
return { attachmentId, absPath, relPath, sizeBytes: actualSize, mimeType: args.mimeType };
|
|
27269
|
-
}
|
|
27270
|
-
|
|
27271
27281
|
// src/transport/http-router.ts
|
|
27272
|
-
var UPLOAD_MIME_ALLOW = /* @__PURE__ */ new Set([
|
|
27273
|
-
"image/png",
|
|
27274
|
-
"image/jpeg",
|
|
27275
|
-
"image/gif",
|
|
27276
|
-
"image/webp",
|
|
27277
|
-
"application/pdf"
|
|
27278
|
-
]);
|
|
27279
|
-
var UPLOAD_MIME_ALLOW_PREFIX = ["text/"];
|
|
27280
|
-
var UPLOAD_MAX_BYTES = 25 * 1024 * 1024;
|
|
27281
|
-
function isUploadMimeAllowed(mime) {
|
|
27282
|
-
if (UPLOAD_MIME_ALLOW.has(mime)) return true;
|
|
27283
|
-
return UPLOAD_MIME_ALLOW_PREFIX.some((p2) => mime.startsWith(p2));
|
|
27284
|
-
}
|
|
27285
27282
|
function createHttpRouter(deps) {
|
|
27286
27283
|
return async (req, res) => {
|
|
27287
27284
|
const url = parseUrl(req.url);
|
|
@@ -27295,7 +27292,7 @@ function createHttpRouter(deps) {
|
|
|
27295
27292
|
});
|
|
27296
27293
|
return true;
|
|
27297
27294
|
}
|
|
27298
|
-
if (!url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/")
|
|
27295
|
+
if (!url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/")) {
|
|
27299
27296
|
return false;
|
|
27300
27297
|
}
|
|
27301
27298
|
if (url.pathname.startsWith("/files/") && req.method === "GET") {
|
|
@@ -27335,99 +27332,6 @@ function createHttpRouter(deps) {
|
|
|
27335
27332
|
sendJson(res, 401, { code: "UNAUTHORIZED", message: "missing or invalid bearer token" });
|
|
27336
27333
|
return true;
|
|
27337
27334
|
}
|
|
27338
|
-
if (url.pathname === "/attachments/upload" && req.method === "POST") {
|
|
27339
|
-
if (ctx.role !== "owner") {
|
|
27340
|
-
sendJson(res, 403, { code: "FORBIDDEN", message: "owner only" });
|
|
27341
|
-
return true;
|
|
27342
|
-
}
|
|
27343
|
-
const up = deps.attachmentUpload;
|
|
27344
|
-
if (!up) {
|
|
27345
|
-
sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "attachment upload not wired" });
|
|
27346
|
-
return true;
|
|
27347
|
-
}
|
|
27348
|
-
const sessionId = url.searchParams.get("sessionId");
|
|
27349
|
-
const fileName = url.searchParams.get("fileName");
|
|
27350
|
-
const mimeType = url.searchParams.get("mimeType");
|
|
27351
|
-
const contentLengthRaw = req.headers["content-length"];
|
|
27352
|
-
if (!sessionId || !fileName || !mimeType || !contentLengthRaw) {
|
|
27353
|
-
sendJson(res, 400, {
|
|
27354
|
-
code: "INVALID_PARAM",
|
|
27355
|
-
message: "missing sessionId/fileName/mimeType/Content-Length"
|
|
27356
|
-
});
|
|
27357
|
-
return true;
|
|
27358
|
-
}
|
|
27359
|
-
const contentLength = Number.parseInt(contentLengthRaw, 10);
|
|
27360
|
-
if (!Number.isFinite(contentLength) || contentLength < 0) {
|
|
27361
|
-
sendJson(res, 400, { code: "INVALID_PARAM", message: "malformed Content-Length" });
|
|
27362
|
-
return true;
|
|
27363
|
-
}
|
|
27364
|
-
if (contentLength > UPLOAD_MAX_BYTES) {
|
|
27365
|
-
sendJson(res, 413, {
|
|
27366
|
-
code: "FILE_TOO_LARGE",
|
|
27367
|
-
message: `max ${UPLOAD_MAX_BYTES} bytes`
|
|
27368
|
-
});
|
|
27369
|
-
return true;
|
|
27370
|
-
}
|
|
27371
|
-
if (!isUploadMimeAllowed(mimeType)) {
|
|
27372
|
-
sendJson(res, 400, {
|
|
27373
|
-
code: "UNSUPPORTED_MIME",
|
|
27374
|
-
message: `mime ${mimeType} not allowed`
|
|
27375
|
-
});
|
|
27376
|
-
return true;
|
|
27377
|
-
}
|
|
27378
|
-
const sessionDir = up.getSessionDir(sessionId);
|
|
27379
|
-
const scope = up.getSessionScope(sessionId);
|
|
27380
|
-
if (!sessionDir || !scope) {
|
|
27381
|
-
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sessionId} not found` });
|
|
27382
|
-
return true;
|
|
27383
|
-
}
|
|
27384
|
-
const httpBaseUrl = up.getHttpBaseUrl();
|
|
27385
|
-
if (!httpBaseUrl) {
|
|
27386
|
-
sendJson(res, 503, {
|
|
27387
|
-
code: "TUNNEL_NOT_READY",
|
|
27388
|
-
message: "httpBaseUrl unavailable"
|
|
27389
|
-
});
|
|
27390
|
-
return true;
|
|
27391
|
-
}
|
|
27392
|
-
const secret = deps.getSignSecret?.();
|
|
27393
|
-
if (!secret) {
|
|
27394
|
-
sendJson(res, 501, {
|
|
27395
|
-
code: "NOT_IMPLEMENTED",
|
|
27396
|
-
message: "sign secret unavailable (noAuth?)"
|
|
27397
|
-
});
|
|
27398
|
-
return true;
|
|
27399
|
-
}
|
|
27400
|
-
try {
|
|
27401
|
-
const result = await writeUploadedAttachment({
|
|
27402
|
-
sessionDir,
|
|
27403
|
-
sessionId,
|
|
27404
|
-
scope,
|
|
27405
|
-
fileName,
|
|
27406
|
-
mimeType,
|
|
27407
|
-
contentLength,
|
|
27408
|
-
body: req,
|
|
27409
|
-
groupFileStore: up.groupFileStore
|
|
27410
|
-
});
|
|
27411
|
-
const parts = signUrlParts(secret, result.absPath, null);
|
|
27412
|
-
const fullUrl = buildSignedFileUrl(httpBaseUrl, parts);
|
|
27413
|
-
sendJson(res, 200, {
|
|
27414
|
-
attachmentId: result.attachmentId,
|
|
27415
|
-
url: fullUrl,
|
|
27416
|
-
relPath: result.relPath,
|
|
27417
|
-
sizeBytes: result.sizeBytes,
|
|
27418
|
-
mimeType: result.mimeType
|
|
27419
|
-
});
|
|
27420
|
-
} catch (err) {
|
|
27421
|
-
if (err instanceof UploadError) {
|
|
27422
|
-
const status = err.code === "SIZE_MISMATCH" ? 400 : 500;
|
|
27423
|
-
sendJson(res, status, { code: err.code, message: err.message });
|
|
27424
|
-
} else {
|
|
27425
|
-
deps.logger?.warn("attachment upload failed", { err: err.message });
|
|
27426
|
-
sendJson(res, 500, { code: "STORAGE_ERROR", message: err.message });
|
|
27427
|
-
}
|
|
27428
|
-
}
|
|
27429
|
-
return true;
|
|
27430
|
-
}
|
|
27431
27335
|
const sessionFilesMatch = url.pathname.match(/^\/session\/([^/]+)\/files$/);
|
|
27432
27336
|
if (sessionFilesMatch && req.method === "GET") {
|
|
27433
27337
|
const sid = sessionFilesMatch[1];
|
|
@@ -27509,78 +27413,10 @@ function streamFile(res, absPath, logger) {
|
|
|
27509
27413
|
stream.pipe(res);
|
|
27510
27414
|
}
|
|
27511
27415
|
|
|
27512
|
-
// src/attachment/
|
|
27416
|
+
// src/attachment/group.ts
|
|
27513
27417
|
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
27514
27418
|
var import_node_path18 = __toESM(require("path"), 1);
|
|
27515
|
-
var
|
|
27516
|
-
function runAttachmentGc(args) {
|
|
27517
|
-
const now = (args.now ?? Date.now)();
|
|
27518
|
-
const ttlMs = args.ttlMs ?? DEFAULT_TTL_MS;
|
|
27519
|
-
const liveAbs = /* @__PURE__ */ new Set();
|
|
27520
|
-
for (const { scope, sessionId } of args.sessionScopes) {
|
|
27521
|
-
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
27522
|
-
if (entry.stale) continue;
|
|
27523
|
-
if (import_node_path18.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
27524
|
-
}
|
|
27525
|
-
}
|
|
27526
|
-
for (const { scope, sessionId } of args.sessionScopes) {
|
|
27527
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path18.default.join(
|
|
27528
|
-
args.dataDir,
|
|
27529
|
-
"sessions",
|
|
27530
|
-
...scopeSubPath(scope).map(safeFileName),
|
|
27531
|
-
safeFileName(sessionId)
|
|
27532
|
-
);
|
|
27533
|
-
const attRoot = import_node_path18.default.join(sessionDir, ".attachments");
|
|
27534
|
-
let hashDirs;
|
|
27535
|
-
try {
|
|
27536
|
-
hashDirs = import_node_fs16.default.readdirSync(attRoot);
|
|
27537
|
-
} catch (err) {
|
|
27538
|
-
if (err.code === "ENOENT") continue;
|
|
27539
|
-
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
27540
|
-
continue;
|
|
27541
|
-
}
|
|
27542
|
-
for (const hashDir of hashDirs) {
|
|
27543
|
-
const hashDirAbs = import_node_path18.default.join(attRoot, hashDir);
|
|
27544
|
-
let files;
|
|
27545
|
-
try {
|
|
27546
|
-
files = import_node_fs16.default.readdirSync(hashDirAbs);
|
|
27547
|
-
} catch {
|
|
27548
|
-
continue;
|
|
27549
|
-
}
|
|
27550
|
-
for (const name of files) {
|
|
27551
|
-
const file = import_node_path18.default.join(hashDirAbs, name);
|
|
27552
|
-
let stat;
|
|
27553
|
-
try {
|
|
27554
|
-
stat = import_node_fs16.default.statSync(file);
|
|
27555
|
-
} catch {
|
|
27556
|
-
continue;
|
|
27557
|
-
}
|
|
27558
|
-
if (!stat.isFile()) continue;
|
|
27559
|
-
const age = now - stat.mtimeMs;
|
|
27560
|
-
if (age < ttlMs) continue;
|
|
27561
|
-
if (liveAbs.has(file)) continue;
|
|
27562
|
-
try {
|
|
27563
|
-
import_node_fs16.default.unlinkSync(file);
|
|
27564
|
-
} catch (err) {
|
|
27565
|
-
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
27566
|
-
}
|
|
27567
|
-
}
|
|
27568
|
-
try {
|
|
27569
|
-
if (import_node_fs16.default.readdirSync(hashDirAbs).length === 0) import_node_fs16.default.rmdirSync(hashDirAbs);
|
|
27570
|
-
} catch {
|
|
27571
|
-
}
|
|
27572
|
-
}
|
|
27573
|
-
try {
|
|
27574
|
-
if (import_node_fs16.default.readdirSync(attRoot).length === 0) import_node_fs16.default.rmdirSync(attRoot);
|
|
27575
|
-
} catch {
|
|
27576
|
-
}
|
|
27577
|
-
}
|
|
27578
|
-
}
|
|
27579
|
-
|
|
27580
|
-
// src/attachment/group.ts
|
|
27581
|
-
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
27582
|
-
var import_node_path19 = __toESM(require("path"), 1);
|
|
27583
|
-
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
27419
|
+
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
27584
27420
|
init_protocol();
|
|
27585
27421
|
var GroupFileStore = class {
|
|
27586
27422
|
dataDir;
|
|
@@ -27591,11 +27427,11 @@ var GroupFileStore = class {
|
|
|
27591
27427
|
this.logger = opts.logger;
|
|
27592
27428
|
}
|
|
27593
27429
|
rootForScope(scope) {
|
|
27594
|
-
return
|
|
27430
|
+
return import_node_path18.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
27595
27431
|
}
|
|
27596
27432
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
27597
27433
|
filePath(scope, sessionId) {
|
|
27598
|
-
return
|
|
27434
|
+
return import_node_path18.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
27599
27435
|
}
|
|
27600
27436
|
cacheKey(scope, sessionId) {
|
|
27601
27437
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -27604,7 +27440,7 @@ var GroupFileStore = class {
|
|
|
27604
27440
|
readFile(scope, sessionId) {
|
|
27605
27441
|
const file = this.filePath(scope, sessionId);
|
|
27606
27442
|
try {
|
|
27607
|
-
const raw =
|
|
27443
|
+
const raw = import_node_fs16.default.readFileSync(file, "utf8");
|
|
27608
27444
|
const parsed = JSON.parse(raw);
|
|
27609
27445
|
if (!Array.isArray(parsed)) {
|
|
27610
27446
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -27630,10 +27466,10 @@ var GroupFileStore = class {
|
|
|
27630
27466
|
}
|
|
27631
27467
|
writeFile(scope, sessionId, entries) {
|
|
27632
27468
|
const file = this.filePath(scope, sessionId);
|
|
27633
|
-
|
|
27469
|
+
import_node_fs16.default.mkdirSync(import_node_path18.default.dirname(file), { recursive: true });
|
|
27634
27470
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
27635
|
-
|
|
27636
|
-
|
|
27471
|
+
import_node_fs16.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
27472
|
+
import_node_fs16.default.renameSync(tmp, file);
|
|
27637
27473
|
}
|
|
27638
27474
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
27639
27475
|
list(scope, sessionId) {
|
|
@@ -27669,7 +27505,7 @@ var GroupFileStore = class {
|
|
|
27669
27505
|
entries[idx] = next;
|
|
27670
27506
|
} else {
|
|
27671
27507
|
next = {
|
|
27672
|
-
id: `gf-${
|
|
27508
|
+
id: `gf-${import_node_crypto6.default.randomBytes(6).toString("base64url")}`,
|
|
27673
27509
|
relPath: input.relPath,
|
|
27674
27510
|
from: input.from,
|
|
27675
27511
|
label: input.label,
|
|
@@ -27719,10 +27555,10 @@ var GroupFileStore = class {
|
|
|
27719
27555
|
};
|
|
27720
27556
|
|
|
27721
27557
|
// src/discovery/state-file.ts
|
|
27722
|
-
var
|
|
27723
|
-
var
|
|
27558
|
+
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
27559
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
27724
27560
|
function defaultStateFilePath(dataDir) {
|
|
27725
|
-
return
|
|
27561
|
+
return import_node_path19.default.join(dataDir, "state.json");
|
|
27726
27562
|
}
|
|
27727
27563
|
function isPidAlive(pid) {
|
|
27728
27564
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -27744,7 +27580,7 @@ var StateFileManager = class {
|
|
|
27744
27580
|
}
|
|
27745
27581
|
read() {
|
|
27746
27582
|
try {
|
|
27747
|
-
const raw =
|
|
27583
|
+
const raw = import_node_fs17.default.readFileSync(this.file, "utf8");
|
|
27748
27584
|
const parsed = JSON.parse(raw);
|
|
27749
27585
|
return parsed;
|
|
27750
27586
|
} catch {
|
|
@@ -27758,34 +27594,34 @@ var StateFileManager = class {
|
|
|
27758
27594
|
return { status: "stale", existing };
|
|
27759
27595
|
}
|
|
27760
27596
|
write(state) {
|
|
27761
|
-
|
|
27597
|
+
import_node_fs17.default.mkdirSync(import_node_path19.default.dirname(this.file), { recursive: true });
|
|
27762
27598
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
27763
|
-
|
|
27764
|
-
|
|
27599
|
+
import_node_fs17.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
27600
|
+
import_node_fs17.default.renameSync(tmp, this.file);
|
|
27765
27601
|
if (process.platform !== "win32") {
|
|
27766
27602
|
try {
|
|
27767
|
-
|
|
27603
|
+
import_node_fs17.default.chmodSync(this.file, 384);
|
|
27768
27604
|
} catch {
|
|
27769
27605
|
}
|
|
27770
27606
|
}
|
|
27771
27607
|
}
|
|
27772
27608
|
delete() {
|
|
27773
27609
|
try {
|
|
27774
|
-
|
|
27610
|
+
import_node_fs17.default.unlinkSync(this.file);
|
|
27775
27611
|
} catch {
|
|
27776
27612
|
}
|
|
27777
27613
|
}
|
|
27778
27614
|
};
|
|
27779
27615
|
|
|
27780
27616
|
// src/tunnel/tunnel-manager.ts
|
|
27781
|
-
var
|
|
27782
|
-
var
|
|
27783
|
-
var
|
|
27617
|
+
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
27618
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
27619
|
+
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
27784
27620
|
var import_node_child_process5 = require("child_process");
|
|
27785
27621
|
|
|
27786
27622
|
// src/tunnel/tunnel-store.ts
|
|
27787
|
-
var
|
|
27788
|
-
var
|
|
27623
|
+
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
27624
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
27789
27625
|
var TunnelStore = class {
|
|
27790
27626
|
constructor(filePath) {
|
|
27791
27627
|
this.filePath = filePath;
|
|
@@ -27793,7 +27629,7 @@ var TunnelStore = class {
|
|
|
27793
27629
|
filePath;
|
|
27794
27630
|
async get() {
|
|
27795
27631
|
try {
|
|
27796
|
-
const raw = await
|
|
27632
|
+
const raw = await import_node_fs18.default.promises.readFile(this.filePath, "utf8");
|
|
27797
27633
|
const obj = JSON.parse(raw);
|
|
27798
27634
|
if (!isPersistedTunnel(obj)) return null;
|
|
27799
27635
|
return obj;
|
|
@@ -27804,22 +27640,22 @@ var TunnelStore = class {
|
|
|
27804
27640
|
}
|
|
27805
27641
|
}
|
|
27806
27642
|
async set(v2) {
|
|
27807
|
-
const dir =
|
|
27808
|
-
await
|
|
27643
|
+
const dir = import_node_path20.default.dirname(this.filePath);
|
|
27644
|
+
await import_node_fs18.default.promises.mkdir(dir, { recursive: true });
|
|
27809
27645
|
const data = JSON.stringify(v2, null, 2);
|
|
27810
27646
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
27811
|
-
await
|
|
27647
|
+
await import_node_fs18.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
27812
27648
|
if (process.platform !== "win32") {
|
|
27813
27649
|
try {
|
|
27814
|
-
await
|
|
27650
|
+
await import_node_fs18.default.promises.chmod(tmp, 384);
|
|
27815
27651
|
} catch {
|
|
27816
27652
|
}
|
|
27817
27653
|
}
|
|
27818
|
-
await
|
|
27654
|
+
await import_node_fs18.default.promises.rename(tmp, this.filePath);
|
|
27819
27655
|
}
|
|
27820
27656
|
async clear() {
|
|
27821
27657
|
try {
|
|
27822
|
-
await
|
|
27658
|
+
await import_node_fs18.default.promises.unlink(this.filePath);
|
|
27823
27659
|
} catch (err) {
|
|
27824
27660
|
const code = err?.code;
|
|
27825
27661
|
if (code !== "ENOENT") throw err;
|
|
@@ -27914,12 +27750,12 @@ function escape(v2) {
|
|
|
27914
27750
|
}
|
|
27915
27751
|
|
|
27916
27752
|
// src/tunnel/frpc-binary.ts
|
|
27917
|
-
var
|
|
27918
|
-
var
|
|
27919
|
-
var
|
|
27753
|
+
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
27754
|
+
var import_node_os10 = __toESM(require("os"), 1);
|
|
27755
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
27920
27756
|
var import_node_child_process3 = require("child_process");
|
|
27921
27757
|
var import_node_stream2 = require("stream");
|
|
27922
|
-
var
|
|
27758
|
+
var import_promises = require("stream/promises");
|
|
27923
27759
|
var FRPC_VERSION = "0.68.0";
|
|
27924
27760
|
var UnsupportedPlatformError = class extends Error {
|
|
27925
27761
|
constructor(platform, arch) {
|
|
@@ -27948,20 +27784,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
27948
27784
|
}
|
|
27949
27785
|
async function ensureFrpcBinary(opts) {
|
|
27950
27786
|
if (opts.override) {
|
|
27951
|
-
if (!
|
|
27787
|
+
if (!import_node_fs19.default.existsSync(opts.override)) {
|
|
27952
27788
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
27953
27789
|
}
|
|
27954
27790
|
return opts.override;
|
|
27955
27791
|
}
|
|
27956
27792
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
27957
27793
|
const platform = opts.platform ?? detectPlatform();
|
|
27958
|
-
const binDir =
|
|
27959
|
-
|
|
27794
|
+
const binDir = import_node_path21.default.join(opts.dataDir, "bin");
|
|
27795
|
+
import_node_fs19.default.mkdirSync(binDir, { recursive: true });
|
|
27960
27796
|
cleanupStaleArtifacts(binDir);
|
|
27961
|
-
const stableBin =
|
|
27962
|
-
if (
|
|
27797
|
+
const stableBin = import_node_path21.default.join(binDir, "frpc");
|
|
27798
|
+
if (import_node_fs19.default.existsSync(stableBin)) return stableBin;
|
|
27963
27799
|
const partialBin = `${stableBin}.partial`;
|
|
27964
|
-
const tarballPath =
|
|
27800
|
+
const tarballPath = import_node_path21.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
27965
27801
|
try {
|
|
27966
27802
|
const url = frpcDownloadUrl(version2, platform);
|
|
27967
27803
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -27970,8 +27806,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
27970
27806
|
} else {
|
|
27971
27807
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
27972
27808
|
}
|
|
27973
|
-
|
|
27974
|
-
|
|
27809
|
+
import_node_fs19.default.chmodSync(partialBin, 493);
|
|
27810
|
+
import_node_fs19.default.renameSync(partialBin, stableBin);
|
|
27975
27811
|
} finally {
|
|
27976
27812
|
safeUnlink(tarballPath);
|
|
27977
27813
|
safeUnlink(partialBin);
|
|
@@ -27981,15 +27817,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
27981
27817
|
function cleanupStaleArtifacts(binDir) {
|
|
27982
27818
|
let entries;
|
|
27983
27819
|
try {
|
|
27984
|
-
entries =
|
|
27820
|
+
entries = import_node_fs19.default.readdirSync(binDir);
|
|
27985
27821
|
} catch {
|
|
27986
27822
|
return;
|
|
27987
27823
|
}
|
|
27988
27824
|
for (const name of entries) {
|
|
27989
27825
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
27990
|
-
const full =
|
|
27826
|
+
const full = import_node_path21.default.join(binDir, name);
|
|
27991
27827
|
try {
|
|
27992
|
-
|
|
27828
|
+
import_node_fs19.default.rmSync(full, { recursive: true, force: true });
|
|
27993
27829
|
} catch {
|
|
27994
27830
|
}
|
|
27995
27831
|
}
|
|
@@ -27997,7 +27833,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
27997
27833
|
}
|
|
27998
27834
|
function safeUnlink(p2) {
|
|
27999
27835
|
try {
|
|
28000
|
-
|
|
27836
|
+
import_node_fs19.default.unlinkSync(p2);
|
|
28001
27837
|
} catch {
|
|
28002
27838
|
}
|
|
28003
27839
|
}
|
|
@@ -28008,13 +27844,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
28008
27844
|
if (!res.ok || !res.body) {
|
|
28009
27845
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
28010
27846
|
}
|
|
28011
|
-
const out =
|
|
27847
|
+
const out = import_node_fs19.default.createWriteStream(dest);
|
|
28012
27848
|
const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
|
|
28013
|
-
await (0,
|
|
27849
|
+
await (0, import_promises.pipeline)(nodeStream, out);
|
|
28014
27850
|
}
|
|
28015
27851
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
28016
|
-
const work =
|
|
28017
|
-
|
|
27852
|
+
const work = import_node_path21.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
27853
|
+
import_node_fs19.default.mkdirSync(work, { recursive: true });
|
|
28018
27854
|
try {
|
|
28019
27855
|
await new Promise((resolve6, reject) => {
|
|
28020
27856
|
const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -28022,32 +27858,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
28022
27858
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
28023
27859
|
});
|
|
28024
27860
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
28025
|
-
const src =
|
|
28026
|
-
if (!
|
|
27861
|
+
const src = import_node_path21.default.join(work, dirName, "frpc");
|
|
27862
|
+
if (!import_node_fs19.default.existsSync(src)) {
|
|
28027
27863
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
28028
27864
|
}
|
|
28029
|
-
|
|
27865
|
+
import_node_fs19.default.copyFileSync(src, destBin);
|
|
28030
27866
|
} finally {
|
|
28031
|
-
|
|
27867
|
+
import_node_fs19.default.rmSync(work, { recursive: true, force: true });
|
|
28032
27868
|
}
|
|
28033
27869
|
}
|
|
28034
27870
|
|
|
28035
27871
|
// src/tunnel/frpc-process.ts
|
|
28036
|
-
var
|
|
28037
|
-
var
|
|
27872
|
+
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
27873
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
28038
27874
|
var import_node_child_process4 = require("child_process");
|
|
28039
27875
|
function frpcPidFilePath(dataDir) {
|
|
28040
|
-
return
|
|
27876
|
+
return import_node_path22.default.join(dataDir, "frpc.pid");
|
|
28041
27877
|
}
|
|
28042
27878
|
function writeFrpcPid(dataDir, pid) {
|
|
28043
27879
|
try {
|
|
28044
|
-
|
|
27880
|
+
import_node_fs20.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
28045
27881
|
} catch {
|
|
28046
27882
|
}
|
|
28047
27883
|
}
|
|
28048
27884
|
function clearFrpcPid(dataDir) {
|
|
28049
27885
|
try {
|
|
28050
|
-
|
|
27886
|
+
import_node_fs20.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
28051
27887
|
} catch {
|
|
28052
27888
|
}
|
|
28053
27889
|
}
|
|
@@ -28063,7 +27899,7 @@ function defaultIsPidAlive(pid) {
|
|
|
28063
27899
|
}
|
|
28064
27900
|
function defaultReadPidFile(file) {
|
|
28065
27901
|
try {
|
|
28066
|
-
return
|
|
27902
|
+
return import_node_fs20.default.readFileSync(file, "utf8");
|
|
28067
27903
|
} catch {
|
|
28068
27904
|
return null;
|
|
28069
27905
|
}
|
|
@@ -28079,7 +27915,7 @@ function defaultSleep(ms) {
|
|
|
28079
27915
|
}
|
|
28080
27916
|
async function killStaleFrpc(deps) {
|
|
28081
27917
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
28082
|
-
const tomlPath =
|
|
27918
|
+
const tomlPath = import_node_path22.default.join(deps.dataDir, "frpc.toml");
|
|
28083
27919
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
28084
27920
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
28085
27921
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -28103,7 +27939,7 @@ async function killStaleFrpc(deps) {
|
|
|
28103
27939
|
}
|
|
28104
27940
|
if (victims.size === 0) {
|
|
28105
27941
|
try {
|
|
28106
|
-
|
|
27942
|
+
import_node_fs20.default.unlinkSync(pidFile);
|
|
28107
27943
|
} catch {
|
|
28108
27944
|
}
|
|
28109
27945
|
return;
|
|
@@ -28114,7 +27950,7 @@ async function killStaleFrpc(deps) {
|
|
|
28114
27950
|
}
|
|
28115
27951
|
await sleep(deps.reapWaitMs ?? 300);
|
|
28116
27952
|
try {
|
|
28117
|
-
|
|
27953
|
+
import_node_fs20.default.unlinkSync(pidFile);
|
|
28118
27954
|
} catch {
|
|
28119
27955
|
}
|
|
28120
27956
|
}
|
|
@@ -28151,7 +27987,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
28151
27987
|
var TunnelManager = class {
|
|
28152
27988
|
constructor(deps) {
|
|
28153
27989
|
this.deps = deps;
|
|
28154
|
-
this.store = deps.store ?? new TunnelStore(
|
|
27990
|
+
this.store = deps.store ?? new TunnelStore(import_node_path23.default.join(deps.dataDir, "tunnel.json"));
|
|
28155
27991
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
28156
27992
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
28157
27993
|
}
|
|
@@ -28278,8 +28114,8 @@ var TunnelManager = class {
|
|
|
28278
28114
|
dataDir: this.deps.dataDir,
|
|
28279
28115
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
28280
28116
|
});
|
|
28281
|
-
const tomlPath =
|
|
28282
|
-
const proxyName = `clawd-${t.subdomain}-${localPort}-${
|
|
28117
|
+
const tomlPath = import_node_path23.default.join(this.deps.dataDir, "frpc.toml");
|
|
28118
|
+
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
|
|
28283
28119
|
const toml = buildFrpcToml({
|
|
28284
28120
|
serverAddr: t.frpsHost,
|
|
28285
28121
|
serverPort: t.frpsPort,
|
|
@@ -28289,12 +28125,12 @@ var TunnelManager = class {
|
|
|
28289
28125
|
localPort,
|
|
28290
28126
|
logLevel: "info"
|
|
28291
28127
|
});
|
|
28292
|
-
await
|
|
28128
|
+
await import_node_fs21.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
28293
28129
|
const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
|
|
28294
28130
|
stdio: ["ignore", "pipe", "pipe"]
|
|
28295
28131
|
});
|
|
28296
|
-
const logFilePath =
|
|
28297
|
-
const logStream =
|
|
28132
|
+
const logFilePath = import_node_path23.default.join(this.deps.dataDir, "frpc.log");
|
|
28133
|
+
const logStream = import_node_fs21.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
28298
28134
|
logStream.on("error", () => {
|
|
28299
28135
|
});
|
|
28300
28136
|
const tee = (chunk) => {
|
|
@@ -28376,23 +28212,23 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
28376
28212
|
}
|
|
28377
28213
|
|
|
28378
28214
|
// src/tunnel/device-key.ts
|
|
28379
|
-
var
|
|
28380
|
-
var
|
|
28215
|
+
var import_node_os11 = __toESM(require("os"), 1);
|
|
28216
|
+
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
28381
28217
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
28382
28218
|
function deriveStableDeviceKey(opts = {}) {
|
|
28383
|
-
const hostname = opts.hostname ??
|
|
28384
|
-
const uid = opts.uid ?? (typeof
|
|
28219
|
+
const hostname = opts.hostname ?? import_node_os11.default.hostname();
|
|
28220
|
+
const uid = opts.uid ?? (typeof import_node_os11.default.userInfo === "function" ? import_node_os11.default.userInfo().uid : 0);
|
|
28385
28221
|
const input = `${hostname}::${uid}`;
|
|
28386
|
-
return
|
|
28222
|
+
return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
28387
28223
|
}
|
|
28388
28224
|
|
|
28389
28225
|
// src/auth-store.ts
|
|
28390
|
-
var
|
|
28391
|
-
var
|
|
28392
|
-
var
|
|
28226
|
+
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
28227
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
28228
|
+
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
28393
28229
|
var AUTH_FILE_NAME = "auth.json";
|
|
28394
28230
|
function authFilePath(dataDir) {
|
|
28395
|
-
return
|
|
28231
|
+
return import_node_path24.default.join(dataDir, AUTH_FILE_NAME);
|
|
28396
28232
|
}
|
|
28397
28233
|
function loadOrCreateAuthFile(opts) {
|
|
28398
28234
|
const file = authFilePath(opts.dataDir);
|
|
@@ -28417,14 +28253,14 @@ function loadOrCreateAuthFile(opts) {
|
|
|
28417
28253
|
return next;
|
|
28418
28254
|
}
|
|
28419
28255
|
function defaultGenerateToken2() {
|
|
28420
|
-
return
|
|
28256
|
+
return import_node_crypto9.default.randomBytes(32).toString("base64url");
|
|
28421
28257
|
}
|
|
28422
28258
|
function defaultGenerateOwnerPrincipalId() {
|
|
28423
|
-
return `owner-${
|
|
28259
|
+
return `owner-${import_node_crypto9.default.randomUUID()}`;
|
|
28424
28260
|
}
|
|
28425
28261
|
function readAuthFile(file) {
|
|
28426
28262
|
try {
|
|
28427
|
-
const raw =
|
|
28263
|
+
const raw = import_node_fs22.default.readFileSync(file, "utf8");
|
|
28428
28264
|
const parsed = JSON.parse(raw);
|
|
28429
28265
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
28430
28266
|
return null;
|
|
@@ -28442,25 +28278,25 @@ function readAuthFile(file) {
|
|
|
28442
28278
|
}
|
|
28443
28279
|
}
|
|
28444
28280
|
function writeAuthFile(file, content) {
|
|
28445
|
-
|
|
28446
|
-
|
|
28281
|
+
import_node_fs22.default.mkdirSync(import_node_path24.default.dirname(file), { recursive: true });
|
|
28282
|
+
import_node_fs22.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
28447
28283
|
try {
|
|
28448
|
-
|
|
28284
|
+
import_node_fs22.default.chmodSync(file, 384);
|
|
28449
28285
|
} catch {
|
|
28450
28286
|
}
|
|
28451
28287
|
}
|
|
28452
28288
|
|
|
28453
28289
|
// src/owner-profile.ts
|
|
28454
|
-
var
|
|
28455
|
-
var
|
|
28456
|
-
var
|
|
28290
|
+
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
28291
|
+
var import_node_os12 = __toESM(require("os"), 1);
|
|
28292
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
28457
28293
|
var PROFILE_FILENAME = "profile.json";
|
|
28458
28294
|
function loadOwnerDisplayName(dataDir) {
|
|
28459
|
-
const fallback =
|
|
28460
|
-
const profilePath =
|
|
28295
|
+
const fallback = import_node_os12.default.userInfo().username;
|
|
28296
|
+
const profilePath = import_node_path25.default.join(dataDir, PROFILE_FILENAME);
|
|
28461
28297
|
let raw;
|
|
28462
28298
|
try {
|
|
28463
|
-
raw =
|
|
28299
|
+
raw = import_node_fs23.default.readFileSync(profilePath, "utf8");
|
|
28464
28300
|
} catch {
|
|
28465
28301
|
return fallback;
|
|
28466
28302
|
}
|
|
@@ -28489,12 +28325,12 @@ init_protocol();
|
|
|
28489
28325
|
init_protocol();
|
|
28490
28326
|
|
|
28491
28327
|
// src/session/fork.ts
|
|
28492
|
-
var
|
|
28493
|
-
var
|
|
28494
|
-
var
|
|
28328
|
+
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
28329
|
+
var import_node_os13 = __toESM(require("os"), 1);
|
|
28330
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
28495
28331
|
init_claude_history();
|
|
28496
28332
|
function readJsonlEntries(file) {
|
|
28497
|
-
const raw =
|
|
28333
|
+
const raw = import_node_fs24.default.readFileSync(file, "utf8");
|
|
28498
28334
|
const out = [];
|
|
28499
28335
|
for (const line of raw.split("\n")) {
|
|
28500
28336
|
const t = line.trim();
|
|
@@ -28507,10 +28343,10 @@ function readJsonlEntries(file) {
|
|
|
28507
28343
|
return out;
|
|
28508
28344
|
}
|
|
28509
28345
|
function forkSession(input) {
|
|
28510
|
-
const baseDir = input.baseDir ??
|
|
28511
|
-
const projectDir =
|
|
28512
|
-
const sourceFile =
|
|
28513
|
-
if (!
|
|
28346
|
+
const baseDir = input.baseDir ?? import_node_path26.default.join(import_node_os13.default.homedir(), ".claude");
|
|
28347
|
+
const projectDir = import_node_path26.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
28348
|
+
const sourceFile = import_node_path26.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
28349
|
+
if (!import_node_fs24.default.existsSync(sourceFile)) {
|
|
28514
28350
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
28515
28351
|
}
|
|
28516
28352
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -28540,9 +28376,9 @@ function forkSession(input) {
|
|
|
28540
28376
|
}
|
|
28541
28377
|
forkedLines.push(JSON.stringify(forked));
|
|
28542
28378
|
}
|
|
28543
|
-
const forkedFilePath =
|
|
28544
|
-
|
|
28545
|
-
|
|
28379
|
+
const forkedFilePath = import_node_path26.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
28380
|
+
import_node_fs24.default.mkdirSync(projectDir, { recursive: true });
|
|
28381
|
+
import_node_fs24.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
28546
28382
|
return { forkedToolSessionId, forkedFilePath };
|
|
28547
28383
|
}
|
|
28548
28384
|
|
|
@@ -28874,7 +28710,7 @@ function buildPermissionHandlers(deps) {
|
|
|
28874
28710
|
}
|
|
28875
28711
|
|
|
28876
28712
|
// src/handlers/history.ts
|
|
28877
|
-
var
|
|
28713
|
+
var path36 = __toESM(require("path"), 1);
|
|
28878
28714
|
init_protocol();
|
|
28879
28715
|
|
|
28880
28716
|
// src/session/recent-dirs.ts
|
|
@@ -28892,7 +28728,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
28892
28728
|
}
|
|
28893
28729
|
|
|
28894
28730
|
// src/permission/persona-paths.ts
|
|
28895
|
-
var
|
|
28731
|
+
var path35 = __toESM(require("path"), 1);
|
|
28896
28732
|
function getAllowedPersonaIds(grants, action) {
|
|
28897
28733
|
const ids = /* @__PURE__ */ new Set();
|
|
28898
28734
|
for (const g2 of grants) {
|
|
@@ -28905,26 +28741,26 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
28905
28741
|
return ids;
|
|
28906
28742
|
}
|
|
28907
28743
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read") {
|
|
28908
|
-
const root =
|
|
28909
|
-
const target =
|
|
28910
|
-
const sep3 = root.endsWith(
|
|
28744
|
+
const root = path35.resolve(personaRoot);
|
|
28745
|
+
const target = path35.resolve(absPath);
|
|
28746
|
+
const sep3 = root.endsWith(path35.sep) ? "" : path35.sep;
|
|
28911
28747
|
if (!target.startsWith(root + sep3)) return false;
|
|
28912
|
-
const rel =
|
|
28748
|
+
const rel = path35.relative(root, target);
|
|
28913
28749
|
if (!rel || rel.startsWith("..")) return false;
|
|
28914
|
-
const personaId = rel.split(
|
|
28750
|
+
const personaId = rel.split(path35.sep)[0];
|
|
28915
28751
|
if (!personaId) return false;
|
|
28916
28752
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
28917
28753
|
if (allowed === "*") return true;
|
|
28918
28754
|
return allowed.has(personaId);
|
|
28919
28755
|
}
|
|
28920
28756
|
function personaIdFromPath(absPath, personaRoot) {
|
|
28921
|
-
const root =
|
|
28922
|
-
const target =
|
|
28923
|
-
const sep3 = root.endsWith(
|
|
28757
|
+
const root = path35.resolve(personaRoot);
|
|
28758
|
+
const target = path35.resolve(absPath);
|
|
28759
|
+
const sep3 = root.endsWith(path35.sep) ? "" : path35.sep;
|
|
28924
28760
|
if (!target.startsWith(root + sep3)) return null;
|
|
28925
|
-
const rel =
|
|
28761
|
+
const rel = path35.relative(root, target);
|
|
28926
28762
|
if (!rel || rel.startsWith("..")) return null;
|
|
28927
|
-
const id = rel.split(
|
|
28763
|
+
const id = rel.split(path35.sep)[0];
|
|
28928
28764
|
return id || null;
|
|
28929
28765
|
}
|
|
28930
28766
|
|
|
@@ -28949,7 +28785,7 @@ function buildHistoryHandlers(deps) {
|
|
|
28949
28785
|
if (!pid) return false;
|
|
28950
28786
|
return isGuestPathAllowed(
|
|
28951
28787
|
ctx.grants,
|
|
28952
|
-
|
|
28788
|
+
path36.join(personaRoot, pid),
|
|
28953
28789
|
personaRoot,
|
|
28954
28790
|
"read"
|
|
28955
28791
|
);
|
|
@@ -28960,7 +28796,7 @@ function buildHistoryHandlers(deps) {
|
|
|
28960
28796
|
};
|
|
28961
28797
|
const list = async (frame, _client, ctx) => {
|
|
28962
28798
|
const args = HistoryListArgs.parse(frame);
|
|
28963
|
-
assertGuestPath(ctx,
|
|
28799
|
+
assertGuestPath(ctx, path36.resolve(args.projectPath), personaRoot, "history:list");
|
|
28964
28800
|
const sessions = await history.listSessions(args);
|
|
28965
28801
|
return { response: { type: "history:list", sessions } };
|
|
28966
28802
|
};
|
|
@@ -28992,13 +28828,13 @@ function buildHistoryHandlers(deps) {
|
|
|
28992
28828
|
};
|
|
28993
28829
|
const subagents = async (frame, _client, ctx) => {
|
|
28994
28830
|
const args = HistorySubagentsArgs.parse(frame);
|
|
28995
|
-
assertGuestPath(ctx,
|
|
28831
|
+
assertGuestPath(ctx, path36.resolve(args.cwd), personaRoot, "history:subagents");
|
|
28996
28832
|
const subs = await history.listSubagents(args);
|
|
28997
28833
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
28998
28834
|
};
|
|
28999
28835
|
const subagentRead = async (frame, _client, ctx) => {
|
|
29000
28836
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
29001
|
-
assertGuestPath(ctx,
|
|
28837
|
+
assertGuestPath(ctx, path36.resolve(args.cwd), personaRoot, "history:subagent-read");
|
|
29002
28838
|
const res = await history.readSubagent(args);
|
|
29003
28839
|
return { response: { type: "history:subagent-read", ...res } };
|
|
29004
28840
|
};
|
|
@@ -29006,7 +28842,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29006
28842
|
const dirs = listRecentDirs(store);
|
|
29007
28843
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
29008
28844
|
const filtered = dirs.filter(
|
|
29009
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
28845
|
+
(d) => isGuestPathAllowed(ctx.grants, path36.resolve(d.cwd), personaRoot, "read")
|
|
29010
28846
|
);
|
|
29011
28847
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
29012
28848
|
}
|
|
@@ -29023,8 +28859,8 @@ function buildHistoryHandlers(deps) {
|
|
|
29023
28859
|
}
|
|
29024
28860
|
|
|
29025
28861
|
// src/handlers/workspace.ts
|
|
29026
|
-
var
|
|
29027
|
-
var
|
|
28862
|
+
var path37 = __toESM(require("path"), 1);
|
|
28863
|
+
var os14 = __toESM(require("os"), 1);
|
|
29028
28864
|
init_protocol();
|
|
29029
28865
|
init_protocol();
|
|
29030
28866
|
function buildEnabledPluginNames(personaManager, personaId) {
|
|
@@ -29063,23 +28899,23 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29063
28899
|
const list = async (frame, _client, ctx) => {
|
|
29064
28900
|
const args = WorkspaceListArgs.parse(frame);
|
|
29065
28901
|
const isGuest = ctx?.principal.kind === "guest";
|
|
29066
|
-
const fallbackCwd = isGuest && personaRoot ? personaRoot :
|
|
29067
|
-
const resolvedCwd =
|
|
29068
|
-
const target = args.path ?
|
|
28902
|
+
const fallbackCwd = isGuest && personaRoot ? personaRoot : os14.homedir();
|
|
28903
|
+
const resolvedCwd = path37.resolve(args.cwd ?? fallbackCwd);
|
|
28904
|
+
const target = args.path ? path37.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
29069
28905
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list");
|
|
29070
28906
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
29071
28907
|
return { response: { type: "workspace:list", ...res } };
|
|
29072
28908
|
};
|
|
29073
28909
|
const read = async (frame, _client, ctx) => {
|
|
29074
28910
|
const args = WorkspaceReadArgs.parse(frame);
|
|
29075
|
-
const target =
|
|
28911
|
+
const target = path37.isAbsolute(args.path) ? path37.resolve(args.path) : path37.resolve(args.cwd, args.path);
|
|
29076
28912
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read");
|
|
29077
28913
|
const res = workspace.read(args);
|
|
29078
28914
|
return { response: { type: "workspace:read", ...res } };
|
|
29079
28915
|
};
|
|
29080
28916
|
const skillsList = async (frame, _client, ctx) => {
|
|
29081
28917
|
const args = SkillsListArgs.parse(frame);
|
|
29082
|
-
const cwdAbs =
|
|
28918
|
+
const cwdAbs = path37.resolve(args.cwd);
|
|
29083
28919
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
|
|
29084
28920
|
const list2 = skills.list(args);
|
|
29085
28921
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -29091,7 +28927,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29091
28927
|
};
|
|
29092
28928
|
const agentsList = async (frame, _client, ctx) => {
|
|
29093
28929
|
const args = AgentsListArgs.parse(frame);
|
|
29094
|
-
const cwdAbs =
|
|
28930
|
+
const cwdAbs = path37.resolve(args.cwd);
|
|
29095
28931
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
|
|
29096
28932
|
const list2 = agents.list(args);
|
|
29097
28933
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -29110,20 +28946,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29110
28946
|
}
|
|
29111
28947
|
|
|
29112
28948
|
// src/handlers/git.ts
|
|
29113
|
-
var
|
|
28949
|
+
var path39 = __toESM(require("path"), 1);
|
|
29114
28950
|
init_protocol();
|
|
29115
28951
|
init_protocol();
|
|
29116
28952
|
|
|
29117
28953
|
// src/workspace/git.ts
|
|
29118
28954
|
var import_node_child_process6 = require("child_process");
|
|
29119
|
-
var
|
|
29120
|
-
var
|
|
28955
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
28956
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
29121
28957
|
var import_node_util = require("util");
|
|
29122
28958
|
var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
|
|
29123
28959
|
function normalizePath(p2) {
|
|
29124
|
-
const resolved =
|
|
28960
|
+
const resolved = import_node_path27.default.resolve(p2);
|
|
29125
28961
|
try {
|
|
29126
|
-
return
|
|
28962
|
+
return import_node_fs25.default.realpathSync(resolved);
|
|
29127
28963
|
} catch {
|
|
29128
28964
|
return resolved;
|
|
29129
28965
|
}
|
|
@@ -29196,7 +29032,7 @@ async function listGitBranches(cwd) {
|
|
|
29196
29032
|
// src/handlers/git.ts
|
|
29197
29033
|
function assertGuestCwd(ctx, cwd, personaRoot, method) {
|
|
29198
29034
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
29199
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
29035
|
+
if (!isGuestPathAllowed(ctx.grants, path39.resolve(cwd), personaRoot, "read")) {
|
|
29200
29036
|
throw new ClawdError(
|
|
29201
29037
|
ERROR_CODES.UNAUTHORIZED,
|
|
29202
29038
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -29559,7 +29395,7 @@ function buildWhoamiHandler(deps) {
|
|
|
29559
29395
|
}
|
|
29560
29396
|
|
|
29561
29397
|
// src/handlers/meta.ts
|
|
29562
|
-
var
|
|
29398
|
+
var import_node_os14 = __toESM(require("os"), 1);
|
|
29563
29399
|
init_protocol();
|
|
29564
29400
|
|
|
29565
29401
|
// src/version.ts
|
|
@@ -29589,7 +29425,7 @@ function buildReadyFrame(deps, client) {
|
|
|
29589
29425
|
return {
|
|
29590
29426
|
version,
|
|
29591
29427
|
protocolVersion: PROTOCOL_VERSION,
|
|
29592
|
-
hostname:
|
|
29428
|
+
hostname: import_node_os14.default.hostname(),
|
|
29593
29429
|
os: process.platform,
|
|
29594
29430
|
tools,
|
|
29595
29431
|
runningSessions: info.runningSessions,
|
|
@@ -29683,7 +29519,7 @@ function buildPersonaHandlers(deps) {
|
|
|
29683
29519
|
}
|
|
29684
29520
|
|
|
29685
29521
|
// src/handlers/attachment.ts
|
|
29686
|
-
var
|
|
29522
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
29687
29523
|
init_protocol();
|
|
29688
29524
|
init_protocol();
|
|
29689
29525
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -29737,12 +29573,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
29737
29573
|
`session ${args.sessionId} scope unresolved`
|
|
29738
29574
|
);
|
|
29739
29575
|
}
|
|
29740
|
-
const cwdAbs =
|
|
29741
|
-
const candidateAbs =
|
|
29576
|
+
const cwdAbs = import_node_path28.default.resolve(sessionFile.cwd);
|
|
29577
|
+
const candidateAbs = import_node_path28.default.isAbsolute(args.relPath) ? import_node_path28.default.resolve(args.relPath) : import_node_path28.default.resolve(cwdAbs, args.relPath);
|
|
29742
29578
|
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
|
|
29743
29579
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
29744
29580
|
const entry = entries.find((e) => {
|
|
29745
|
-
const storedAbs =
|
|
29581
|
+
const storedAbs = import_node_path28.default.isAbsolute(e.relPath) ? import_node_path28.default.resolve(e.relPath) : import_node_path28.default.resolve(cwdAbs, e.relPath);
|
|
29746
29582
|
return storedAbs === candidateAbs && !e.stale;
|
|
29747
29583
|
});
|
|
29748
29584
|
if (!entry) {
|
|
@@ -29766,7 +29602,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
29766
29602
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
29767
29603
|
const f = deps.sessionStore.read(sessionId);
|
|
29768
29604
|
if (!f) return;
|
|
29769
|
-
assertGuestAttachmentPath(ctx,
|
|
29605
|
+
assertGuestAttachmentPath(ctx, import_node_path28.default.resolve(f.cwd), deps.personaRoot, method);
|
|
29770
29606
|
}
|
|
29771
29607
|
const groupAdd = async (frame, _client, ctx) => {
|
|
29772
29608
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -29807,7 +29643,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
29807
29643
|
}
|
|
29808
29644
|
const entries = deps.groupFileStore.list(scope, parsed.data.sessionId);
|
|
29809
29645
|
const target = entries.find((e) => e.relPath === parsed.data.relPath);
|
|
29810
|
-
if (target?.from === "owner"
|
|
29646
|
+
if (target?.from === "owner") {
|
|
29811
29647
|
deps.groupFileStore.remove(scope, parsed.data.sessionId, parsed.data.relPath);
|
|
29812
29648
|
} else {
|
|
29813
29649
|
deps.groupFileStore.markStale(scope, parsed.data.sessionId, parsed.data.relPath);
|
|
@@ -30003,7 +29839,7 @@ function computeGrantForFrame(method, frame) {
|
|
|
30003
29839
|
async function startDaemon(config) {
|
|
30004
29840
|
const logger = createLogger({
|
|
30005
29841
|
level: config.logLevel,
|
|
30006
|
-
file:
|
|
29842
|
+
file: import_node_path29.default.join(config.dataDir, "clawd.log")
|
|
30007
29843
|
});
|
|
30008
29844
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
30009
29845
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -30090,7 +29926,7 @@ async function startDaemon(config) {
|
|
|
30090
29926
|
const agents = new AgentsScanner();
|
|
30091
29927
|
const history = new ClaudeHistoryReader();
|
|
30092
29928
|
let transport = null;
|
|
30093
|
-
const personaStore = new PersonaStore(
|
|
29929
|
+
const personaStore = new PersonaStore(import_node_path29.default.join(config.dataDir, "personas"));
|
|
30094
29930
|
const defaultsRoot = findDefaultsRoot();
|
|
30095
29931
|
if (defaultsRoot) {
|
|
30096
29932
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -30107,7 +29943,7 @@ async function startDaemon(config) {
|
|
|
30107
29943
|
getAdapter,
|
|
30108
29944
|
historyReader: history,
|
|
30109
29945
|
dataDir: config.dataDir,
|
|
30110
|
-
personaRoot:
|
|
29946
|
+
personaRoot: import_node_path29.default.join(config.dataDir, "personas"),
|
|
30111
29947
|
personaStore,
|
|
30112
29948
|
ownerDisplayName,
|
|
30113
29949
|
ownerPrincipalId,
|
|
@@ -30131,10 +29967,10 @@ async function startDaemon(config) {
|
|
|
30131
29967
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
30132
29968
|
attachmentGroup: {
|
|
30133
29969
|
onFileEdit: (input) => {
|
|
30134
|
-
const absPath =
|
|
29970
|
+
const absPath = import_node_path29.default.isAbsolute(input.relPath) ? input.relPath : import_node_path29.default.join(input.cwd, input.relPath);
|
|
30135
29971
|
let size = 0;
|
|
30136
29972
|
try {
|
|
30137
|
-
size =
|
|
29973
|
+
size = import_node_fs26.default.statSync(absPath).size;
|
|
30138
29974
|
} catch (err) {
|
|
30139
29975
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
30140
29976
|
sessionId: input.sessionId,
|
|
@@ -30160,6 +29996,11 @@ async function startDaemon(config) {
|
|
|
30160
29996
|
}
|
|
30161
29997
|
});
|
|
30162
29998
|
const observer = new SessionObserver({
|
|
29999
|
+
// TUI 模式 pty 跑 CC 不发 SDK system.task_started 帧 → UI pending 期 progress.agentId
|
|
30000
|
+
// 永远 undefined,子 agent 调用过程没有抽屉入口。开 meta observer 后从 subagents 目录
|
|
30001
|
+
// 新出现的 agent-*.meta.json 派生 subagent_progress(started) 补这块缺口。SDK 模式仍走
|
|
30002
|
+
// task_started 路径,避免双 emit 让 ring buffer 双帧。
|
|
30003
|
+
enableSubagentMetaObserver: config.mode === "tui",
|
|
30163
30004
|
onEvent: ({ sessionId, events }) => {
|
|
30164
30005
|
manager.feedObserverEvents(sessionId, events);
|
|
30165
30006
|
},
|
|
@@ -30247,10 +30088,10 @@ async function startDaemon(config) {
|
|
|
30247
30088
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
30248
30089
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
30249
30090
|
// guest path guard:candidate 必须在 personaRoot 子树下
|
|
30250
|
-
personaRoot:
|
|
30091
|
+
personaRoot: import_node_path29.default.join(config.dataDir, "personas")
|
|
30251
30092
|
},
|
|
30252
30093
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
30253
|
-
personaRoot:
|
|
30094
|
+
personaRoot: import_node_path29.default.join(config.dataDir, "personas"),
|
|
30254
30095
|
// capability:list / delete handler 依赖
|
|
30255
30096
|
capabilityManager,
|
|
30256
30097
|
// personal-cap:get 返回的 shareBaseUrl 用此 base URL:
|
|
@@ -30286,19 +30127,7 @@ async function startDaemon(config) {
|
|
|
30286
30127
|
sessionStore: store,
|
|
30287
30128
|
// /files HMAC verify 用 auth.json 的 signSecret 字段(与 attachment.signUrl 同源)。
|
|
30288
30129
|
// --auth-token CLI 模式没 signSecret → 路由返 501,sign URL 功能整体禁用。
|
|
30289
|
-
getSignSecret: () => authFile?.signSecret ?? null
|
|
30290
|
-
// chatinput 附件上传(POST /attachments/upload,spec §6.1)。upload pipeline
|
|
30291
|
-
// 在 session.cwd 下的 .attachments/ 落盘;signSecret 与 /files HMAC 同源;
|
|
30292
|
-
// tunnel 未启时返 503 TUNNEL_NOT_READY 让前端显式提示。
|
|
30293
|
-
attachmentUpload: {
|
|
30294
|
-
groupFileStore,
|
|
30295
|
-
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
30296
|
-
getSessionDir: (sid) => {
|
|
30297
|
-
const f = manager.findOwnedSession(sid);
|
|
30298
|
-
return f ? f.cwd : null;
|
|
30299
|
-
},
|
|
30300
|
-
getHttpBaseUrl: () => currentTunnelUrl ? getHttpBaseUrl() : null
|
|
30301
|
-
}
|
|
30130
|
+
getSignSecret: () => authFile?.signSecret ?? null
|
|
30302
30131
|
});
|
|
30303
30132
|
wsServer = new LocalWsServer({
|
|
30304
30133
|
host: config.host,
|
|
@@ -30463,8 +30292,8 @@ async function startDaemon(config) {
|
|
|
30463
30292
|
const lines = [
|
|
30464
30293
|
`Tunnel: ${r.url}`,
|
|
30465
30294
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
30466
|
-
`Frpc config: ${
|
|
30467
|
-
`Frpc log: ${
|
|
30295
|
+
`Frpc config: ${import_node_path29.default.join(config.dataDir, "frpc.toml")}`,
|
|
30296
|
+
`Frpc log: ${import_node_path29.default.join(config.dataDir, "frpc.log")}`
|
|
30468
30297
|
];
|
|
30469
30298
|
const width = Math.max(...lines.map((l) => l.length));
|
|
30470
30299
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -30477,8 +30306,8 @@ ${bar}
|
|
|
30477
30306
|
|
|
30478
30307
|
`);
|
|
30479
30308
|
try {
|
|
30480
|
-
const connectPath =
|
|
30481
|
-
|
|
30309
|
+
const connectPath = import_node_path29.default.join(config.dataDir, "connect.txt");
|
|
30310
|
+
import_node_fs26.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
30482
30311
|
} catch {
|
|
30483
30312
|
}
|
|
30484
30313
|
} catch (err) {
|
|
@@ -30503,29 +30332,8 @@ ${bar}
|
|
|
30503
30332
|
logger.warn("tunnel unavailable, degraded to local mode", { reason: tunnelError });
|
|
30504
30333
|
}
|
|
30505
30334
|
}
|
|
30506
|
-
const tickAttachmentGc = () => {
|
|
30507
|
-
try {
|
|
30508
|
-
runAttachmentGc({
|
|
30509
|
-
dataDir: config.dataDir,
|
|
30510
|
-
groupFileStore,
|
|
30511
|
-
sessionScopes: manager.listOwnedSessionScopes().map(({ scope, sessionId }) => ({
|
|
30512
|
-
scope,
|
|
30513
|
-
sessionId
|
|
30514
|
-
})),
|
|
30515
|
-
// 注入 cwd 让 GC 直接定位 .attachments 目录(与 upload 落盘点一致)
|
|
30516
|
-
getSessionCwd: (sid) => manager.findOwnedSession(sid)?.cwd ?? null,
|
|
30517
|
-
logger
|
|
30518
|
-
});
|
|
30519
|
-
} catch (err) {
|
|
30520
|
-
logger.warn("attachment gc tick failed", { err: err.message });
|
|
30521
|
-
}
|
|
30522
|
-
};
|
|
30523
|
-
setImmediate(tickAttachmentGc);
|
|
30524
|
-
const attachmentGcInterval = setInterval(tickAttachmentGc, 24 * 3600 * 1e3);
|
|
30525
|
-
attachmentGcInterval.unref();
|
|
30526
30335
|
const shutdown = async () => {
|
|
30527
30336
|
logger.info("stopping clawd");
|
|
30528
|
-
clearInterval(attachmentGcInterval);
|
|
30529
30337
|
observer.stopAll();
|
|
30530
30338
|
manager.stopAll();
|
|
30531
30339
|
if (tunnelMgr) {
|
|
@@ -30543,9 +30351,9 @@ ${bar}
|
|
|
30543
30351
|
};
|
|
30544
30352
|
}
|
|
30545
30353
|
function migrateDropPersonsDir(dataDir) {
|
|
30546
|
-
const dir =
|
|
30354
|
+
const dir = import_node_path29.default.join(dataDir, "persons");
|
|
30547
30355
|
try {
|
|
30548
|
-
|
|
30356
|
+
import_node_fs26.default.rmSync(dir, { recursive: true, force: true });
|
|
30549
30357
|
} catch {
|
|
30550
30358
|
}
|
|
30551
30359
|
}
|