@clawos-dev/clawd 0.2.86 → 0.2.87-beta.163.de7e74a
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 +362 -485
- 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: path45, errorMaps, issueData } = params;
|
|
647
|
+
const fullPath = [...path45, ...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, path45, key) {
|
|
959
959
|
this._cachedPath = [];
|
|
960
960
|
this.parent = parent;
|
|
961
961
|
this.data = value;
|
|
962
|
-
this._path =
|
|
962
|
+
this._path = path45;
|
|
963
963
|
this._key = key;
|
|
964
964
|
}
|
|
965
965
|
get path() {
|
|
@@ -5590,8 +5590,8 @@ var require_req = __commonJS({
|
|
|
5590
5590
|
if (req.originalUrl) {
|
|
5591
5591
|
_req.url = req.originalUrl;
|
|
5592
5592
|
} else {
|
|
5593
|
-
const
|
|
5594
|
-
_req.url = typeof
|
|
5593
|
+
const path45 = req.path;
|
|
5594
|
+
_req.url = typeof path45 === "string" ? path45 : req.url ? req.url.path || req.url : void 0;
|
|
5595
5595
|
}
|
|
5596
5596
|
if (req.query) {
|
|
5597
5597
|
_req.query = req.query;
|
|
@@ -5756,14 +5756,14 @@ var require_redact = __commonJS({
|
|
|
5756
5756
|
}
|
|
5757
5757
|
return obj;
|
|
5758
5758
|
}
|
|
5759
|
-
function parsePath(
|
|
5759
|
+
function parsePath(path45) {
|
|
5760
5760
|
const parts = [];
|
|
5761
5761
|
let current = "";
|
|
5762
5762
|
let inBrackets = false;
|
|
5763
5763
|
let inQuotes = false;
|
|
5764
5764
|
let quoteChar = "";
|
|
5765
|
-
for (let i = 0; i <
|
|
5766
|
-
const char =
|
|
5765
|
+
for (let i = 0; i < path45.length; i++) {
|
|
5766
|
+
const char = path45[i];
|
|
5767
5767
|
if (!inBrackets && char === ".") {
|
|
5768
5768
|
if (current) {
|
|
5769
5769
|
parts.push(current);
|
|
@@ -5894,10 +5894,10 @@ var require_redact = __commonJS({
|
|
|
5894
5894
|
return current;
|
|
5895
5895
|
}
|
|
5896
5896
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
5897
|
-
for (const
|
|
5898
|
-
const parts = parsePath(
|
|
5897
|
+
for (const path45 of paths) {
|
|
5898
|
+
const parts = parsePath(path45);
|
|
5899
5899
|
if (parts.includes("*")) {
|
|
5900
|
-
redactWildcardPath(obj, parts, censor,
|
|
5900
|
+
redactWildcardPath(obj, parts, censor, path45, remove);
|
|
5901
5901
|
} else {
|
|
5902
5902
|
if (remove) {
|
|
5903
5903
|
removeKey(obj, parts);
|
|
@@ -5982,8 +5982,8 @@ var require_redact = __commonJS({
|
|
|
5982
5982
|
}
|
|
5983
5983
|
} else {
|
|
5984
5984
|
if (afterWildcard.includes("*")) {
|
|
5985
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
5986
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
5985
|
+
const wrappedCensor = typeof censor === "function" ? (value, path45) => {
|
|
5986
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path45];
|
|
5987
5987
|
return censor(value, fullPath);
|
|
5988
5988
|
} : censor;
|
|
5989
5989
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6018,8 +6018,8 @@ var require_redact = __commonJS({
|
|
|
6018
6018
|
return null;
|
|
6019
6019
|
}
|
|
6020
6020
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6021
|
-
for (const
|
|
6022
|
-
const parts = parsePath(
|
|
6021
|
+
for (const path45 of pathsToClone) {
|
|
6022
|
+
const parts = parsePath(path45);
|
|
6023
6023
|
let current = pathStructure;
|
|
6024
6024
|
for (let i = 0; i < parts.length; i++) {
|
|
6025
6025
|
const part = parts[i];
|
|
@@ -6071,24 +6071,24 @@ var require_redact = __commonJS({
|
|
|
6071
6071
|
}
|
|
6072
6072
|
return cloneSelectively(obj, pathStructure);
|
|
6073
6073
|
}
|
|
6074
|
-
function validatePath(
|
|
6075
|
-
if (typeof
|
|
6074
|
+
function validatePath(path45) {
|
|
6075
|
+
if (typeof path45 !== "string") {
|
|
6076
6076
|
throw new Error("Paths must be (non-empty) strings");
|
|
6077
6077
|
}
|
|
6078
|
-
if (
|
|
6078
|
+
if (path45 === "") {
|
|
6079
6079
|
throw new Error("Invalid redaction path ()");
|
|
6080
6080
|
}
|
|
6081
|
-
if (
|
|
6082
|
-
throw new Error(`Invalid redaction path (${
|
|
6081
|
+
if (path45.includes("..")) {
|
|
6082
|
+
throw new Error(`Invalid redaction path (${path45})`);
|
|
6083
6083
|
}
|
|
6084
|
-
if (
|
|
6085
|
-
throw new Error(`Invalid redaction path (${
|
|
6084
|
+
if (path45.includes(",")) {
|
|
6085
|
+
throw new Error(`Invalid redaction path (${path45})`);
|
|
6086
6086
|
}
|
|
6087
6087
|
let bracketCount = 0;
|
|
6088
6088
|
let inQuotes = false;
|
|
6089
6089
|
let quoteChar = "";
|
|
6090
|
-
for (let i = 0; i <
|
|
6091
|
-
const char =
|
|
6090
|
+
for (let i = 0; i < path45.length; i++) {
|
|
6091
|
+
const char = path45[i];
|
|
6092
6092
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6093
6093
|
if (!inQuotes) {
|
|
6094
6094
|
inQuotes = true;
|
|
@@ -6102,20 +6102,20 @@ var require_redact = __commonJS({
|
|
|
6102
6102
|
} else if (char === "]" && !inQuotes) {
|
|
6103
6103
|
bracketCount--;
|
|
6104
6104
|
if (bracketCount < 0) {
|
|
6105
|
-
throw new Error(`Invalid redaction path (${
|
|
6105
|
+
throw new Error(`Invalid redaction path (${path45})`);
|
|
6106
6106
|
}
|
|
6107
6107
|
}
|
|
6108
6108
|
}
|
|
6109
6109
|
if (bracketCount !== 0) {
|
|
6110
|
-
throw new Error(`Invalid redaction path (${
|
|
6110
|
+
throw new Error(`Invalid redaction path (${path45})`);
|
|
6111
6111
|
}
|
|
6112
6112
|
}
|
|
6113
6113
|
function validatePaths(paths) {
|
|
6114
6114
|
if (!Array.isArray(paths)) {
|
|
6115
6115
|
throw new TypeError("paths must be an array");
|
|
6116
6116
|
}
|
|
6117
|
-
for (const
|
|
6118
|
-
validatePath(
|
|
6117
|
+
for (const path45 of paths) {
|
|
6118
|
+
validatePath(path45);
|
|
6119
6119
|
}
|
|
6120
6120
|
}
|
|
6121
6121
|
function slowRedact(options = {}) {
|
|
@@ -6283,8 +6283,8 @@ var require_redaction = __commonJS({
|
|
|
6283
6283
|
if (shape[k2] === null) {
|
|
6284
6284
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6285
6285
|
} else {
|
|
6286
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6287
|
-
return censor(value, [k2, ...
|
|
6286
|
+
const wrappedCensor = typeof censor === "function" ? (value, path45) => {
|
|
6287
|
+
return censor(value, [k2, ...path45]);
|
|
6288
6288
|
} : censor;
|
|
6289
6289
|
o[k2] = Redact({
|
|
6290
6290
|
paths: shape[k2],
|
|
@@ -6502,10 +6502,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
6502
6502
|
var require_sonic_boom = __commonJS({
|
|
6503
6503
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
6504
6504
|
"use strict";
|
|
6505
|
-
var
|
|
6505
|
+
var fs36 = require("fs");
|
|
6506
6506
|
var EventEmitter2 = require("events");
|
|
6507
6507
|
var inherits = require("util").inherits;
|
|
6508
|
-
var
|
|
6508
|
+
var path45 = require("path");
|
|
6509
6509
|
var sleep = require_atomic_sleep();
|
|
6510
6510
|
var assert = require("assert");
|
|
6511
6511
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6559,20 +6559,20 @@ var require_sonic_boom = __commonJS({
|
|
|
6559
6559
|
const mode = sonic.mode;
|
|
6560
6560
|
if (sonic.sync) {
|
|
6561
6561
|
try {
|
|
6562
|
-
if (sonic.mkdir)
|
|
6563
|
-
const fd =
|
|
6562
|
+
if (sonic.mkdir) fs36.mkdirSync(path45.dirname(file), { recursive: true });
|
|
6563
|
+
const fd = fs36.openSync(file, flags, mode);
|
|
6564
6564
|
fileOpened(null, fd);
|
|
6565
6565
|
} catch (err) {
|
|
6566
6566
|
fileOpened(err);
|
|
6567
6567
|
throw err;
|
|
6568
6568
|
}
|
|
6569
6569
|
} else if (sonic.mkdir) {
|
|
6570
|
-
|
|
6570
|
+
fs36.mkdir(path45.dirname(file), { recursive: true }, (err) => {
|
|
6571
6571
|
if (err) return fileOpened(err);
|
|
6572
|
-
|
|
6572
|
+
fs36.open(file, flags, mode, fileOpened);
|
|
6573
6573
|
});
|
|
6574
6574
|
} else {
|
|
6575
|
-
|
|
6575
|
+
fs36.open(file, flags, mode, fileOpened);
|
|
6576
6576
|
}
|
|
6577
6577
|
}
|
|
6578
6578
|
function SonicBoom(opts) {
|
|
@@ -6613,8 +6613,8 @@ var require_sonic_boom = __commonJS({
|
|
|
6613
6613
|
this.flush = flushBuffer;
|
|
6614
6614
|
this.flushSync = flushBufferSync;
|
|
6615
6615
|
this._actualWrite = actualWriteBuffer;
|
|
6616
|
-
fsWriteSync = () =>
|
|
6617
|
-
fsWrite = () =>
|
|
6616
|
+
fsWriteSync = () => fs36.writeSync(this.fd, this._writingBuf);
|
|
6617
|
+
fsWrite = () => fs36.write(this.fd, this._writingBuf, this.release);
|
|
6618
6618
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
6619
6619
|
this._writingBuf = "";
|
|
6620
6620
|
this.write = write;
|
|
@@ -6623,15 +6623,15 @@ var require_sonic_boom = __commonJS({
|
|
|
6623
6623
|
this._actualWrite = actualWrite;
|
|
6624
6624
|
fsWriteSync = () => {
|
|
6625
6625
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6626
|
-
return
|
|
6626
|
+
return fs36.writeSync(this.fd, this._writingBuf);
|
|
6627
6627
|
}
|
|
6628
|
-
return
|
|
6628
|
+
return fs36.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6629
6629
|
};
|
|
6630
6630
|
fsWrite = () => {
|
|
6631
6631
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6632
|
-
return
|
|
6632
|
+
return fs36.write(this.fd, this._writingBuf, this.release);
|
|
6633
6633
|
}
|
|
6634
|
-
return
|
|
6634
|
+
return fs36.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
6635
6635
|
};
|
|
6636
6636
|
} else {
|
|
6637
6637
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -6688,7 +6688,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6688
6688
|
}
|
|
6689
6689
|
}
|
|
6690
6690
|
if (this._fsync) {
|
|
6691
|
-
|
|
6691
|
+
fs36.fsyncSync(this.fd);
|
|
6692
6692
|
}
|
|
6693
6693
|
const len = this._len;
|
|
6694
6694
|
if (this._reopening) {
|
|
@@ -6802,7 +6802,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6802
6802
|
const onDrain = () => {
|
|
6803
6803
|
if (!this._fsync) {
|
|
6804
6804
|
try {
|
|
6805
|
-
|
|
6805
|
+
fs36.fsync(this.fd, (err) => {
|
|
6806
6806
|
this._flushPending = false;
|
|
6807
6807
|
cb(err);
|
|
6808
6808
|
});
|
|
@@ -6904,7 +6904,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6904
6904
|
const fd = this.fd;
|
|
6905
6905
|
this.once("ready", () => {
|
|
6906
6906
|
if (fd !== this.fd) {
|
|
6907
|
-
|
|
6907
|
+
fs36.close(fd, (err) => {
|
|
6908
6908
|
if (err) {
|
|
6909
6909
|
return this.emit("error", err);
|
|
6910
6910
|
}
|
|
@@ -6953,7 +6953,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6953
6953
|
buf = this._bufs[0];
|
|
6954
6954
|
}
|
|
6955
6955
|
try {
|
|
6956
|
-
const n = Buffer.isBuffer(buf) ?
|
|
6956
|
+
const n = Buffer.isBuffer(buf) ? fs36.writeSync(this.fd, buf) : fs36.writeSync(this.fd, buf, "utf8");
|
|
6957
6957
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
6958
6958
|
buf = releasedBufObj.writingBuf;
|
|
6959
6959
|
this._len = releasedBufObj.len;
|
|
@@ -6969,7 +6969,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6969
6969
|
}
|
|
6970
6970
|
}
|
|
6971
6971
|
try {
|
|
6972
|
-
|
|
6972
|
+
fs36.fsyncSync(this.fd);
|
|
6973
6973
|
} catch {
|
|
6974
6974
|
}
|
|
6975
6975
|
}
|
|
@@ -6990,7 +6990,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6990
6990
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
6991
6991
|
}
|
|
6992
6992
|
try {
|
|
6993
|
-
const n =
|
|
6993
|
+
const n = fs36.writeSync(this.fd, buf);
|
|
6994
6994
|
buf = buf.subarray(n);
|
|
6995
6995
|
this._len = Math.max(this._len - n, 0);
|
|
6996
6996
|
if (buf.length <= 0) {
|
|
@@ -7018,13 +7018,13 @@ var require_sonic_boom = __commonJS({
|
|
|
7018
7018
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
7019
7019
|
if (this.sync) {
|
|
7020
7020
|
try {
|
|
7021
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
7021
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs36.writeSync(this.fd, this._writingBuf) : fs36.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7022
7022
|
release(null, written);
|
|
7023
7023
|
} catch (err) {
|
|
7024
7024
|
release(err);
|
|
7025
7025
|
}
|
|
7026
7026
|
} else {
|
|
7027
|
-
|
|
7027
|
+
fs36.write(this.fd, this._writingBuf, release);
|
|
7028
7028
|
}
|
|
7029
7029
|
}
|
|
7030
7030
|
function actualWriteBuffer() {
|
|
@@ -7033,7 +7033,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7033
7033
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
7034
7034
|
if (this.sync) {
|
|
7035
7035
|
try {
|
|
7036
|
-
const written =
|
|
7036
|
+
const written = fs36.writeSync(this.fd, this._writingBuf);
|
|
7037
7037
|
release(null, written);
|
|
7038
7038
|
} catch (err) {
|
|
7039
7039
|
release(err);
|
|
@@ -7042,7 +7042,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7042
7042
|
if (kCopyBuffer) {
|
|
7043
7043
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
7044
7044
|
}
|
|
7045
|
-
|
|
7045
|
+
fs36.write(this.fd, this._writingBuf, release);
|
|
7046
7046
|
}
|
|
7047
7047
|
}
|
|
7048
7048
|
function actualClose(sonic) {
|
|
@@ -7058,12 +7058,12 @@ var require_sonic_boom = __commonJS({
|
|
|
7058
7058
|
sonic._lens = [];
|
|
7059
7059
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
7060
7060
|
try {
|
|
7061
|
-
|
|
7061
|
+
fs36.fsync(sonic.fd, closeWrapped);
|
|
7062
7062
|
} catch {
|
|
7063
7063
|
}
|
|
7064
7064
|
function closeWrapped() {
|
|
7065
7065
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
7066
|
-
|
|
7066
|
+
fs36.close(sonic.fd, done);
|
|
7067
7067
|
} else {
|
|
7068
7068
|
done();
|
|
7069
7069
|
}
|
|
@@ -9427,7 +9427,7 @@ var require_multistream = __commonJS({
|
|
|
9427
9427
|
var require_pino = __commonJS({
|
|
9428
9428
|
"../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
|
|
9429
9429
|
"use strict";
|
|
9430
|
-
var
|
|
9430
|
+
var os16 = require("os");
|
|
9431
9431
|
var stdSerializers = require_pino_std_serializers();
|
|
9432
9432
|
var caller = require_caller();
|
|
9433
9433
|
var redaction = require_redaction();
|
|
@@ -9474,7 +9474,7 @@ var require_pino = __commonJS({
|
|
|
9474
9474
|
} = symbols;
|
|
9475
9475
|
var { epochTime, nullTime } = time;
|
|
9476
9476
|
var { pid } = process;
|
|
9477
|
-
var hostname =
|
|
9477
|
+
var hostname = os16.hostname();
|
|
9478
9478
|
var defaultErrorSerializer = stdSerializers.err;
|
|
9479
9479
|
var defaultOptions = {
|
|
9480
9480
|
level: "info",
|
|
@@ -10198,11 +10198,11 @@ var init_lib = __esm({
|
|
|
10198
10198
|
}
|
|
10199
10199
|
}
|
|
10200
10200
|
},
|
|
10201
|
-
addToPath: function addToPath(
|
|
10202
|
-
var last =
|
|
10201
|
+
addToPath: function addToPath(path45, added, removed, oldPosInc, options) {
|
|
10202
|
+
var last = path45.lastComponent;
|
|
10203
10203
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10204
10204
|
return {
|
|
10205
|
-
oldPos:
|
|
10205
|
+
oldPos: path45.oldPos + oldPosInc,
|
|
10206
10206
|
lastComponent: {
|
|
10207
10207
|
count: last.count + 1,
|
|
10208
10208
|
added,
|
|
@@ -10212,7 +10212,7 @@ var init_lib = __esm({
|
|
|
10212
10212
|
};
|
|
10213
10213
|
} else {
|
|
10214
10214
|
return {
|
|
10215
|
-
oldPos:
|
|
10215
|
+
oldPos: path45.oldPos + oldPosInc,
|
|
10216
10216
|
lastComponent: {
|
|
10217
10217
|
count: 1,
|
|
10218
10218
|
added,
|
|
@@ -10643,10 +10643,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10643
10643
|
const memories = raw.map((m2) => {
|
|
10644
10644
|
if (!m2 || typeof m2 !== "object") return null;
|
|
10645
10645
|
const rec = m2;
|
|
10646
|
-
const
|
|
10646
|
+
const path45 = typeof rec.path === "string" ? rec.path : null;
|
|
10647
10647
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
10648
|
-
if (!
|
|
10649
|
-
const entry = { path:
|
|
10648
|
+
if (!path45 || content == null) return null;
|
|
10649
|
+
const entry = { path: path45, content };
|
|
10650
10650
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
10651
10651
|
return entry;
|
|
10652
10652
|
}).filter((m2) => m2 !== null);
|
|
@@ -11472,10 +11472,10 @@ function parseAttachment(obj) {
|
|
|
11472
11472
|
const memories = raw.map((m2) => {
|
|
11473
11473
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11474
11474
|
const rec = m2;
|
|
11475
|
-
const
|
|
11475
|
+
const path45 = typeof rec.path === "string" ? rec.path : null;
|
|
11476
11476
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11477
|
-
if (!
|
|
11478
|
-
const out = { path:
|
|
11477
|
+
if (!path45 || content == null) return null;
|
|
11478
|
+
const out = { path: path45, content };
|
|
11479
11479
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11480
11480
|
return out;
|
|
11481
11481
|
}).filter((m2) => m2 !== null);
|
|
@@ -20390,7 +20390,7 @@ var require_websocket_server = __commonJS({
|
|
|
20390
20390
|
// src/run-case/recorder.ts
|
|
20391
20391
|
function startRunCaseRecorder(opts) {
|
|
20392
20392
|
const now = opts.now ?? Date.now;
|
|
20393
|
-
const dir =
|
|
20393
|
+
const dir = import_node_path31.default.dirname(opts.recordPath);
|
|
20394
20394
|
let stream = null;
|
|
20395
20395
|
let closing = false;
|
|
20396
20396
|
let closedSettled = false;
|
|
@@ -20404,8 +20404,8 @@ function startRunCaseRecorder(opts) {
|
|
|
20404
20404
|
});
|
|
20405
20405
|
const ensureStream = () => {
|
|
20406
20406
|
if (stream) return stream;
|
|
20407
|
-
|
|
20408
|
-
stream =
|
|
20407
|
+
import_node_fs28.default.mkdirSync(dir, { recursive: true });
|
|
20408
|
+
stream = import_node_fs28.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
20409
20409
|
stream.on("close", () => closedResolve());
|
|
20410
20410
|
return stream;
|
|
20411
20411
|
};
|
|
@@ -20430,12 +20430,12 @@ function startRunCaseRecorder(opts) {
|
|
|
20430
20430
|
};
|
|
20431
20431
|
return { tap, close, closed };
|
|
20432
20432
|
}
|
|
20433
|
-
var
|
|
20433
|
+
var import_node_fs28, import_node_path31;
|
|
20434
20434
|
var init_recorder = __esm({
|
|
20435
20435
|
"src/run-case/recorder.ts"() {
|
|
20436
20436
|
"use strict";
|
|
20437
|
-
|
|
20438
|
-
|
|
20437
|
+
import_node_fs28 = __toESM(require("fs"), 1);
|
|
20438
|
+
import_node_path31 = __toESM(require("path"), 1);
|
|
20439
20439
|
}
|
|
20440
20440
|
});
|
|
20441
20441
|
|
|
@@ -20478,7 +20478,7 @@ var init_wire = __esm({
|
|
|
20478
20478
|
// src/run-case/controller.ts
|
|
20479
20479
|
async function runController(opts) {
|
|
20480
20480
|
const now = opts.now ?? Date.now;
|
|
20481
|
-
const cwd = opts.cwd ?? (0,
|
|
20481
|
+
const cwd = opts.cwd ?? (0, import_node_fs29.mkdtempSync)(import_node_path32.default.join(import_node_os14.default.tmpdir(), "clawd-runcase-"));
|
|
20482
20482
|
const ownsCwd = opts.cwd === void 0;
|
|
20483
20483
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
20484
20484
|
const spawnCtx = { cwd };
|
|
@@ -20639,19 +20639,19 @@ async function runController(opts) {
|
|
|
20639
20639
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
20640
20640
|
if (ownsCwd) {
|
|
20641
20641
|
try {
|
|
20642
|
-
(0,
|
|
20642
|
+
(0, import_node_fs29.rmSync)(cwd, { recursive: true, force: true });
|
|
20643
20643
|
} catch {
|
|
20644
20644
|
}
|
|
20645
20645
|
}
|
|
20646
20646
|
return exitCode ?? 0;
|
|
20647
20647
|
}
|
|
20648
|
-
var
|
|
20648
|
+
var import_node_fs29, import_node_os14, import_node_path32;
|
|
20649
20649
|
var init_controller = __esm({
|
|
20650
20650
|
"src/run-case/controller.ts"() {
|
|
20651
20651
|
"use strict";
|
|
20652
|
-
|
|
20653
|
-
|
|
20654
|
-
|
|
20652
|
+
import_node_fs29 = require("fs");
|
|
20653
|
+
import_node_os14 = __toESM(require("os"), 1);
|
|
20654
|
+
import_node_path32 = __toESM(require("path"), 1);
|
|
20655
20655
|
init_claude();
|
|
20656
20656
|
init_stdout_splitter();
|
|
20657
20657
|
init_permission_stdio();
|
|
@@ -20883,8 +20883,8 @@ Env (advanced):
|
|
|
20883
20883
|
`;
|
|
20884
20884
|
|
|
20885
20885
|
// src/index.ts
|
|
20886
|
-
var
|
|
20887
|
-
var
|
|
20886
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
20887
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
20888
20888
|
|
|
20889
20889
|
// src/logger.ts
|
|
20890
20890
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
@@ -25531,151 +25531,28 @@ var AgentsScanner = class {
|
|
|
25531
25531
|
};
|
|
25532
25532
|
|
|
25533
25533
|
// src/observer/session-observer.ts
|
|
25534
|
-
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
25535
|
-
var import_node_os9 = __toESM(require("os"), 1);
|
|
25536
|
-
var import_node_path14 = __toESM(require("path"), 1);
|
|
25537
|
-
init_claude_history();
|
|
25538
|
-
|
|
25539
|
-
// src/observer/subagent-meta-observer.ts
|
|
25540
25534
|
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
25541
25535
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
25542
25536
|
var import_node_path13 = __toESM(require("path"), 1);
|
|
25543
25537
|
init_claude_history();
|
|
25544
|
-
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
25545
|
-
var SubagentMetaObserver = class {
|
|
25546
|
-
constructor(opts) {
|
|
25547
|
-
this.opts = opts;
|
|
25548
|
-
this.home = opts.home ?? import_node_os8.default.homedir();
|
|
25549
|
-
}
|
|
25550
|
-
opts;
|
|
25551
|
-
home;
|
|
25552
|
-
watches = /* @__PURE__ */ new Map();
|
|
25553
|
-
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
25554
|
-
resolveSubagentDir(cwd, toolSessionId) {
|
|
25555
|
-
return import_node_path13.default.join(
|
|
25556
|
-
this.home,
|
|
25557
|
-
".claude",
|
|
25558
|
-
"projects",
|
|
25559
|
-
cwdToHashDir(cwd),
|
|
25560
|
-
toolSessionId,
|
|
25561
|
-
"subagents"
|
|
25562
|
-
);
|
|
25563
|
-
}
|
|
25564
|
-
start(args) {
|
|
25565
|
-
this.stop(args.sessionId);
|
|
25566
|
-
const dirPath = this.resolveSubagentDir(args.cwd, args.toolSessionId);
|
|
25567
|
-
const w2 = {
|
|
25568
|
-
sessionId: args.sessionId,
|
|
25569
|
-
dirPath,
|
|
25570
|
-
watcher: null,
|
|
25571
|
-
pollTimer: null,
|
|
25572
|
-
emitted: /* @__PURE__ */ new Set()
|
|
25573
|
-
};
|
|
25574
|
-
this.watches.set(args.sessionId, w2);
|
|
25575
|
-
this.scan(w2);
|
|
25576
|
-
this.attachWatcher(w2);
|
|
25577
|
-
w2.pollTimer = setInterval(() => this.scan(w2), 200);
|
|
25578
|
-
return { dirPath };
|
|
25579
|
-
}
|
|
25580
|
-
// fs.watch 必须在目录存在后调用;首次启动时 subagents/ 通常不存在 —— attachWatcher
|
|
25581
|
-
// 失败就交给 pollTimer 200ms 兜底,目录一出现就被下次 poll 捡起来,那时也尝试 attach
|
|
25582
|
-
attachWatcher(w2) {
|
|
25583
|
-
if (w2.watcher) return;
|
|
25584
|
-
try {
|
|
25585
|
-
w2.watcher = import_node_fs12.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
|
|
25586
|
-
if (!name) return;
|
|
25587
|
-
const m2 = META_RE.exec(String(name));
|
|
25588
|
-
if (!m2) return;
|
|
25589
|
-
this.scanOne(w2, String(name));
|
|
25590
|
-
});
|
|
25591
|
-
} catch {
|
|
25592
|
-
}
|
|
25593
|
-
}
|
|
25594
|
-
scan(w2) {
|
|
25595
|
-
let entries;
|
|
25596
|
-
try {
|
|
25597
|
-
entries = import_node_fs12.default.readdirSync(w2.dirPath);
|
|
25598
|
-
} catch {
|
|
25599
|
-
return;
|
|
25600
|
-
}
|
|
25601
|
-
if (!w2.watcher) this.attachWatcher(w2);
|
|
25602
|
-
for (const name of entries) {
|
|
25603
|
-
this.scanOne(w2, name);
|
|
25604
|
-
}
|
|
25605
|
-
}
|
|
25606
|
-
scanOne(w2, name) {
|
|
25607
|
-
const m2 = META_RE.exec(name);
|
|
25608
|
-
if (!m2) return;
|
|
25609
|
-
const agentId = m2[1];
|
|
25610
|
-
if (w2.emitted.has(agentId)) return;
|
|
25611
|
-
const file = import_node_path13.default.join(w2.dirPath, name);
|
|
25612
|
-
let raw;
|
|
25613
|
-
try {
|
|
25614
|
-
raw = import_node_fs12.default.readFileSync(file, "utf8");
|
|
25615
|
-
} catch {
|
|
25616
|
-
return;
|
|
25617
|
-
}
|
|
25618
|
-
let obj;
|
|
25619
|
-
try {
|
|
25620
|
-
obj = JSON.parse(raw);
|
|
25621
|
-
} catch {
|
|
25622
|
-
return;
|
|
25623
|
-
}
|
|
25624
|
-
const toolUseId = typeof obj.toolUseId === "string" ? obj.toolUseId : "";
|
|
25625
|
-
if (!toolUseId) return;
|
|
25626
|
-
w2.emitted.add(agentId);
|
|
25627
|
-
const ev = {
|
|
25628
|
-
kind: "subagent_progress",
|
|
25629
|
-
toolUseId,
|
|
25630
|
-
agentId,
|
|
25631
|
-
status: "started"
|
|
25632
|
-
};
|
|
25633
|
-
if (typeof obj.description === "string" && obj.description) ev.description = obj.description;
|
|
25634
|
-
this.opts.onEvent({ sessionId: w2.sessionId, events: [ev] });
|
|
25635
|
-
}
|
|
25636
|
-
isObserving(sessionId) {
|
|
25637
|
-
return this.watches.has(sessionId);
|
|
25638
|
-
}
|
|
25639
|
-
stop(sessionId) {
|
|
25640
|
-
const w2 = this.watches.get(sessionId);
|
|
25641
|
-
if (!w2) return false;
|
|
25642
|
-
try {
|
|
25643
|
-
w2.watcher?.close();
|
|
25644
|
-
} catch {
|
|
25645
|
-
}
|
|
25646
|
-
if (w2.pollTimer) clearInterval(w2.pollTimer);
|
|
25647
|
-
this.watches.delete(sessionId);
|
|
25648
|
-
return true;
|
|
25649
|
-
}
|
|
25650
|
-
stopAll() {
|
|
25651
|
-
for (const id of [...this.watches.keys()]) this.stop(id);
|
|
25652
|
-
}
|
|
25653
|
-
};
|
|
25654
|
-
|
|
25655
|
-
// src/observer/session-observer.ts
|
|
25656
25538
|
var SessionObserver = class {
|
|
25657
25539
|
constructor(opts) {
|
|
25658
25540
|
this.opts = opts;
|
|
25659
|
-
this.home = opts.home ??
|
|
25660
|
-
this.metaObserver = opts.enableSubagentMetaObserver ? new SubagentMetaObserver({ home: this.home, onEvent: opts.onEvent }) : null;
|
|
25541
|
+
this.home = opts.home ?? import_node_os8.default.homedir();
|
|
25661
25542
|
}
|
|
25662
25543
|
opts;
|
|
25663
25544
|
home;
|
|
25664
25545
|
watches = /* @__PURE__ */ new Map();
|
|
25665
|
-
// 子 observer:监听 <projectsRoot>/<hashDir>/<toolSessionId>/subagents/ 目录的 meta.json,
|
|
25666
|
-
// 仅 TUI 模式启用——SDK 模式靠 `system.task_started` 帧(claude.ts:466)emit subagent_progress
|
|
25667
|
-
// 已经能解锁 AgentCallLine 抽屉入口,再跑 meta watcher 会让 ring buffer 留双帧
|
|
25668
|
-
metaObserver;
|
|
25669
25546
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
25670
25547
|
if (override) return override;
|
|
25671
|
-
return
|
|
25548
|
+
return import_node_path13.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
25672
25549
|
}
|
|
25673
25550
|
start(args) {
|
|
25674
25551
|
this.stop(args.sessionId);
|
|
25675
25552
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
25676
25553
|
let size = 0;
|
|
25677
25554
|
try {
|
|
25678
|
-
size =
|
|
25555
|
+
size = import_node_fs12.default.statSync(filePath).size;
|
|
25679
25556
|
} catch {
|
|
25680
25557
|
}
|
|
25681
25558
|
const w2 = {
|
|
@@ -25688,10 +25565,10 @@ var SessionObserver = class {
|
|
|
25688
25565
|
adapter: args.adapter
|
|
25689
25566
|
};
|
|
25690
25567
|
try {
|
|
25691
|
-
|
|
25568
|
+
import_node_fs12.default.mkdirSync(import_node_path13.default.dirname(filePath), { recursive: true });
|
|
25692
25569
|
} catch {
|
|
25693
25570
|
}
|
|
25694
|
-
w2.watcher =
|
|
25571
|
+
w2.watcher = import_node_fs12.default.watch(import_node_path13.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
25695
25572
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
25696
25573
|
this.poll(w2);
|
|
25697
25574
|
});
|
|
@@ -25700,11 +25577,6 @@ var SessionObserver = class {
|
|
|
25700
25577
|
this.opts.onStatus?.(args.sessionId, "observing");
|
|
25701
25578
|
this.hydrateMetaTail(w2);
|
|
25702
25579
|
this.poll(w2);
|
|
25703
|
-
this.metaObserver?.start({
|
|
25704
|
-
sessionId: args.sessionId,
|
|
25705
|
-
cwd: args.cwd,
|
|
25706
|
-
toolSessionId: args.toolSessionId
|
|
25707
|
-
});
|
|
25708
25580
|
return { filePath };
|
|
25709
25581
|
}
|
|
25710
25582
|
// 读 JSONL 文件尾部 N 行,把每行的 meta_update 字段**合并成一个 patch** 喂给 reducer。
|
|
@@ -25714,7 +25586,7 @@ var SessionObserver = class {
|
|
|
25714
25586
|
// 异常静默吞,不阻塞 watcher 启动
|
|
25715
25587
|
hydrateMetaTail(w2, maxLines = 200) {
|
|
25716
25588
|
try {
|
|
25717
|
-
const raw =
|
|
25589
|
+
const raw = import_node_fs12.default.readFileSync(w2.filePath, "utf8");
|
|
25718
25590
|
if (!raw) return;
|
|
25719
25591
|
const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
25720
25592
|
if (allLines.length === 0) return;
|
|
@@ -25738,7 +25610,7 @@ var SessionObserver = class {
|
|
|
25738
25610
|
poll(w2) {
|
|
25739
25611
|
let size = 0;
|
|
25740
25612
|
try {
|
|
25741
|
-
size =
|
|
25613
|
+
size = import_node_fs12.default.statSync(w2.filePath).size;
|
|
25742
25614
|
} catch {
|
|
25743
25615
|
return;
|
|
25744
25616
|
}
|
|
@@ -25747,11 +25619,11 @@ var SessionObserver = class {
|
|
|
25747
25619
|
w2.buf = "";
|
|
25748
25620
|
}
|
|
25749
25621
|
if (size === w2.lastSize) return;
|
|
25750
|
-
const fd =
|
|
25622
|
+
const fd = import_node_fs12.default.openSync(w2.filePath, "r");
|
|
25751
25623
|
try {
|
|
25752
25624
|
const len = size - w2.lastSize;
|
|
25753
25625
|
const buf = Buffer.alloc(len);
|
|
25754
|
-
|
|
25626
|
+
import_node_fs12.default.readSync(fd, buf, 0, len, w2.lastSize);
|
|
25755
25627
|
w2.lastSize = size;
|
|
25756
25628
|
w2.buf += buf.toString("utf8");
|
|
25757
25629
|
let newlineIndex;
|
|
@@ -25765,7 +25637,7 @@ var SessionObserver = class {
|
|
|
25765
25637
|
}
|
|
25766
25638
|
}
|
|
25767
25639
|
} finally {
|
|
25768
|
-
|
|
25640
|
+
import_node_fs12.default.closeSync(fd);
|
|
25769
25641
|
}
|
|
25770
25642
|
}
|
|
25771
25643
|
// 解析 JSONL 单行:仅当是主链 user 文本行(非 sidechain / 非 sub-agent / message.role='user'
|
|
@@ -25818,13 +25690,11 @@ var SessionObserver = class {
|
|
|
25818
25690
|
}
|
|
25819
25691
|
if (w2.pollTimer) clearInterval(w2.pollTimer);
|
|
25820
25692
|
this.watches.delete(sessionId);
|
|
25821
|
-
this.metaObserver?.stop(sessionId);
|
|
25822
25693
|
this.opts.onStatus?.(sessionId, "stopped");
|
|
25823
25694
|
return true;
|
|
25824
25695
|
}
|
|
25825
25696
|
stopAll() {
|
|
25826
25697
|
for (const id of [...this.watches.keys()]) this.stop(id);
|
|
25827
|
-
this.metaObserver?.stopAll();
|
|
25828
25698
|
}
|
|
25829
25699
|
};
|
|
25830
25700
|
|
|
@@ -26425,14 +26295,14 @@ function authenticate(token, deps) {
|
|
|
26425
26295
|
}
|
|
26426
26296
|
|
|
26427
26297
|
// src/permission/capability-store.ts
|
|
26428
|
-
var
|
|
26429
|
-
var
|
|
26298
|
+
var fs15 = __toESM(require("fs"), 1);
|
|
26299
|
+
var path18 = __toESM(require("path"), 1);
|
|
26430
26300
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
26431
26301
|
var FILE_VERSION = 1;
|
|
26432
26302
|
var CapabilityStore = class {
|
|
26433
26303
|
constructor(dataDir) {
|
|
26434
26304
|
this.dataDir = dataDir;
|
|
26435
|
-
|
|
26305
|
+
fs15.mkdirSync(dataDir, { recursive: true });
|
|
26436
26306
|
this.cache = this.readFromDisk();
|
|
26437
26307
|
}
|
|
26438
26308
|
dataDir;
|
|
@@ -26456,13 +26326,13 @@ var CapabilityStore = class {
|
|
|
26456
26326
|
this.flush();
|
|
26457
26327
|
}
|
|
26458
26328
|
filePath() {
|
|
26459
|
-
return
|
|
26329
|
+
return path18.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
26460
26330
|
}
|
|
26461
26331
|
readFromDisk() {
|
|
26462
26332
|
const file = this.filePath();
|
|
26463
26333
|
let raw;
|
|
26464
26334
|
try {
|
|
26465
|
-
raw =
|
|
26335
|
+
raw = fs15.readFileSync(file, "utf8");
|
|
26466
26336
|
} catch (err) {
|
|
26467
26337
|
if (err?.code === "ENOENT") return [];
|
|
26468
26338
|
return [];
|
|
@@ -26490,10 +26360,10 @@ var CapabilityStore = class {
|
|
|
26490
26360
|
}
|
|
26491
26361
|
atomicWrite(file, content) {
|
|
26492
26362
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
26493
|
-
|
|
26494
|
-
|
|
26363
|
+
fs15.writeFileSync(tmp, content, { mode: 384 });
|
|
26364
|
+
fs15.renameSync(tmp, file);
|
|
26495
26365
|
try {
|
|
26496
|
-
|
|
26366
|
+
fs15.chmodSync(file, 384);
|
|
26497
26367
|
} catch {
|
|
26498
26368
|
}
|
|
26499
26369
|
}
|
|
@@ -26586,14 +26456,14 @@ var CapabilityManager = class {
|
|
|
26586
26456
|
};
|
|
26587
26457
|
|
|
26588
26458
|
// src/permission/cleanup.ts
|
|
26589
|
-
var
|
|
26459
|
+
var fs16 = __toESM(require("fs"), 1);
|
|
26590
26460
|
function cleanupGuestSessionsForCapability(cap, factory) {
|
|
26591
26461
|
const removed = [];
|
|
26592
26462
|
for (const g2 of cap.grants) {
|
|
26593
26463
|
if (g2.resource.type !== "persona") continue;
|
|
26594
26464
|
const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
|
|
26595
26465
|
try {
|
|
26596
|
-
|
|
26466
|
+
fs16.rmSync(dir, { recursive: true, force: true });
|
|
26597
26467
|
removed.push(dir);
|
|
26598
26468
|
} catch {
|
|
26599
26469
|
}
|
|
@@ -26602,13 +26472,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
26602
26472
|
}
|
|
26603
26473
|
|
|
26604
26474
|
// src/permission/personal-capability.ts
|
|
26605
|
-
var
|
|
26606
|
-
var
|
|
26475
|
+
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
26476
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
26607
26477
|
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
26608
26478
|
var PERSONAL_CAP_FILE_NAME = "personal-capability.json";
|
|
26609
26479
|
var PERSONAL_CAP_DISPLAY_NAME = "personal";
|
|
26610
26480
|
function personalCapFilePath(dataDir) {
|
|
26611
|
-
return
|
|
26481
|
+
return import_node_path14.default.join(dataDir, PERSONAL_CAP_FILE_NAME);
|
|
26612
26482
|
}
|
|
26613
26483
|
function loadOrCreatePersonalCapability(opts) {
|
|
26614
26484
|
const file = personalCapFilePath(opts.dataDir);
|
|
@@ -26638,7 +26508,7 @@ function loadOrCreatePersonalCapability(opts) {
|
|
|
26638
26508
|
function readFile(file) {
|
|
26639
26509
|
let raw;
|
|
26640
26510
|
try {
|
|
26641
|
-
raw =
|
|
26511
|
+
raw = import_node_fs13.default.readFileSync(file, "utf8");
|
|
26642
26512
|
} catch (err) {
|
|
26643
26513
|
const code = err?.code;
|
|
26644
26514
|
if (code === "ENOENT") return null;
|
|
@@ -26659,10 +26529,10 @@ function readFile(file) {
|
|
|
26659
26529
|
return { token: obj.token, capability: capParsed.data };
|
|
26660
26530
|
}
|
|
26661
26531
|
function writeFile(file, content) {
|
|
26662
|
-
|
|
26663
|
-
|
|
26532
|
+
import_node_fs13.default.mkdirSync(import_node_path14.default.dirname(file), { recursive: true });
|
|
26533
|
+
import_node_fs13.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
26664
26534
|
try {
|
|
26665
|
-
|
|
26535
|
+
import_node_fs13.default.chmodSync(file, 384);
|
|
26666
26536
|
} catch {
|
|
26667
26537
|
}
|
|
26668
26538
|
}
|
|
@@ -26677,13 +26547,13 @@ function sha256Hex2(s) {
|
|
|
26677
26547
|
}
|
|
26678
26548
|
|
|
26679
26549
|
// src/inbox/inbox-store.ts
|
|
26680
|
-
var
|
|
26681
|
-
var
|
|
26550
|
+
var fs18 = __toESM(require("fs"), 1);
|
|
26551
|
+
var path20 = __toESM(require("path"), 1);
|
|
26682
26552
|
var INBOX_SUBDIR = "inbox";
|
|
26683
26553
|
var InboxStore = class {
|
|
26684
26554
|
constructor(dataDir) {
|
|
26685
26555
|
this.dataDir = dataDir;
|
|
26686
|
-
|
|
26556
|
+
fs18.mkdirSync(this.dirPath(), { recursive: true });
|
|
26687
26557
|
}
|
|
26688
26558
|
dataDir;
|
|
26689
26559
|
/**
|
|
@@ -26695,7 +26565,7 @@ var InboxStore = class {
|
|
|
26695
26565
|
const file = this.filePath(peerOwnerId);
|
|
26696
26566
|
let raw;
|
|
26697
26567
|
try {
|
|
26698
|
-
raw =
|
|
26568
|
+
raw = fs18.readFileSync(file, "utf8");
|
|
26699
26569
|
} catch (err) {
|
|
26700
26570
|
if (err?.code === "ENOENT") return [];
|
|
26701
26571
|
return [];
|
|
@@ -26711,7 +26581,7 @@ var InboxStore = class {
|
|
|
26711
26581
|
const dir = this.dirPath();
|
|
26712
26582
|
let entries;
|
|
26713
26583
|
try {
|
|
26714
|
-
entries =
|
|
26584
|
+
entries = fs18.readdirSync(dir);
|
|
26715
26585
|
} catch (err) {
|
|
26716
26586
|
if (err?.code === "ENOENT") return [];
|
|
26717
26587
|
return [];
|
|
@@ -26727,9 +26597,9 @@ var InboxStore = class {
|
|
|
26727
26597
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
26728
26598
|
const file = this.filePath(message.peerOwnerId);
|
|
26729
26599
|
const line = JSON.stringify(message) + "\n";
|
|
26730
|
-
|
|
26600
|
+
fs18.appendFileSync(file, line, { mode: 384 });
|
|
26731
26601
|
try {
|
|
26732
|
-
|
|
26602
|
+
fs18.chmodSync(file, 384);
|
|
26733
26603
|
} catch {
|
|
26734
26604
|
}
|
|
26735
26605
|
}
|
|
@@ -26759,7 +26629,7 @@ var InboxStore = class {
|
|
|
26759
26629
|
removeByPeerOwnerId(peerOwnerId) {
|
|
26760
26630
|
const file = this.filePath(peerOwnerId);
|
|
26761
26631
|
try {
|
|
26762
|
-
|
|
26632
|
+
fs18.unlinkSync(file);
|
|
26763
26633
|
} catch (err) {
|
|
26764
26634
|
if (err?.code === "ENOENT") return;
|
|
26765
26635
|
}
|
|
@@ -26768,18 +26638,18 @@ var InboxStore = class {
|
|
|
26768
26638
|
const file = this.filePath(peerOwnerId);
|
|
26769
26639
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
26770
26640
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
26771
|
-
|
|
26772
|
-
|
|
26641
|
+
fs18.writeFileSync(tmp, content, { mode: 384 });
|
|
26642
|
+
fs18.renameSync(tmp, file);
|
|
26773
26643
|
try {
|
|
26774
|
-
|
|
26644
|
+
fs18.chmodSync(file, 384);
|
|
26775
26645
|
} catch {
|
|
26776
26646
|
}
|
|
26777
26647
|
}
|
|
26778
26648
|
dirPath() {
|
|
26779
|
-
return
|
|
26649
|
+
return path20.join(this.dataDir, INBOX_SUBDIR);
|
|
26780
26650
|
}
|
|
26781
26651
|
filePath(peerOwnerId) {
|
|
26782
|
-
return
|
|
26652
|
+
return path20.join(this.dirPath(), `${peerOwnerId}.jsonl`);
|
|
26783
26653
|
}
|
|
26784
26654
|
};
|
|
26785
26655
|
function parseAllLines(raw) {
|
|
@@ -26866,8 +26736,8 @@ var InboxManager = class {
|
|
|
26866
26736
|
};
|
|
26867
26737
|
|
|
26868
26738
|
// src/state/received-capability-store.ts
|
|
26869
|
-
var
|
|
26870
|
-
var
|
|
26739
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
26740
|
+
var path21 = __toESM(require("path"), 1);
|
|
26871
26741
|
var FILE_NAME = "received-capabilities.json";
|
|
26872
26742
|
var ReceivedCapabilityStore = class {
|
|
26873
26743
|
constructor(dataDir) {
|
|
@@ -26877,10 +26747,10 @@ var ReceivedCapabilityStore = class {
|
|
|
26877
26747
|
caps = /* @__PURE__ */ new Map();
|
|
26878
26748
|
load() {
|
|
26879
26749
|
this.caps.clear();
|
|
26880
|
-
const file =
|
|
26750
|
+
const file = path21.join(this.dataDir, FILE_NAME);
|
|
26881
26751
|
let raw;
|
|
26882
26752
|
try {
|
|
26883
|
-
raw =
|
|
26753
|
+
raw = fs19.readFileSync(file, "utf8");
|
|
26884
26754
|
} catch (err) {
|
|
26885
26755
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
26886
26756
|
return;
|
|
@@ -26917,20 +26787,20 @@ var ReceivedCapabilityStore = class {
|
|
|
26917
26787
|
this.flush();
|
|
26918
26788
|
}
|
|
26919
26789
|
flush() {
|
|
26920
|
-
const file =
|
|
26790
|
+
const file = path21.join(this.dataDir, FILE_NAME);
|
|
26921
26791
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
26922
26792
|
const content = JSON.stringify(
|
|
26923
26793
|
{ receivedCaps: Array.from(this.caps.values()) },
|
|
26924
26794
|
null,
|
|
26925
26795
|
2
|
|
26926
26796
|
);
|
|
26927
|
-
|
|
26928
|
-
|
|
26929
|
-
|
|
26797
|
+
fs19.mkdirSync(this.dataDir, { recursive: true });
|
|
26798
|
+
fs19.writeFileSync(tmp, content, { mode: 384 });
|
|
26799
|
+
fs19.renameSync(tmp, file);
|
|
26930
26800
|
}
|
|
26931
26801
|
renameBak(file) {
|
|
26932
26802
|
try {
|
|
26933
|
-
|
|
26803
|
+
fs19.renameSync(file, `${file}.bak`);
|
|
26934
26804
|
} catch {
|
|
26935
26805
|
}
|
|
26936
26806
|
}
|
|
@@ -27028,61 +26898,61 @@ async function connectRemote(args) {
|
|
|
27028
26898
|
}
|
|
27029
26899
|
|
|
27030
26900
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
27031
|
-
var
|
|
27032
|
-
var
|
|
26901
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
26902
|
+
var path22 = __toESM(require("path"), 1);
|
|
27033
26903
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
27034
26904
|
function migrateFlattenSessions(opts) {
|
|
27035
26905
|
const dataDir = opts.dataDir;
|
|
27036
26906
|
const now = opts.now ?? Date.now;
|
|
27037
|
-
const sessionsDir =
|
|
27038
|
-
const flagPath =
|
|
26907
|
+
const sessionsDir = path22.join(dataDir, "sessions");
|
|
26908
|
+
const flagPath = path22.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
27039
26909
|
if (existsSync3(flagPath)) {
|
|
27040
26910
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
27041
26911
|
}
|
|
27042
26912
|
let movedBare = 0;
|
|
27043
26913
|
let movedVmOwner = 0;
|
|
27044
26914
|
let archivedListener = 0;
|
|
27045
|
-
const defaultDir =
|
|
26915
|
+
const defaultDir = path22.join(sessionsDir, "default");
|
|
27046
26916
|
if (existsSync3(defaultDir)) {
|
|
27047
26917
|
for (const entry of readdirSafe(defaultDir)) {
|
|
27048
26918
|
if (!entry.endsWith(".json")) continue;
|
|
27049
|
-
const src =
|
|
27050
|
-
const dst =
|
|
27051
|
-
|
|
26919
|
+
const src = path22.join(defaultDir, entry);
|
|
26920
|
+
const dst = path22.join(sessionsDir, entry);
|
|
26921
|
+
fs20.renameSync(src, dst);
|
|
27052
26922
|
movedBare += 1;
|
|
27053
26923
|
}
|
|
27054
26924
|
rmdirIfEmpty(defaultDir);
|
|
27055
26925
|
}
|
|
27056
26926
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
27057
|
-
const personaDir =
|
|
26927
|
+
const personaDir = path22.join(sessionsDir, pid);
|
|
27058
26928
|
if (!isDir(personaDir)) continue;
|
|
27059
26929
|
if (pid === "default") continue;
|
|
27060
|
-
const ownerSrc =
|
|
26930
|
+
const ownerSrc = path22.join(personaDir, "owner");
|
|
27061
26931
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
27062
|
-
const ownerDst =
|
|
27063
|
-
|
|
26932
|
+
const ownerDst = path22.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
26933
|
+
fs20.mkdirSync(ownerDst, { recursive: true });
|
|
27064
26934
|
for (const file of readdirSafe(ownerSrc)) {
|
|
27065
26935
|
if (!file.endsWith(".json")) continue;
|
|
27066
|
-
|
|
26936
|
+
fs20.renameSync(path22.join(ownerSrc, file), path22.join(ownerDst, file));
|
|
27067
26937
|
movedVmOwner += 1;
|
|
27068
26938
|
}
|
|
27069
26939
|
rmdirIfEmpty(ownerSrc);
|
|
27070
26940
|
}
|
|
27071
|
-
const listenerSrc =
|
|
26941
|
+
const listenerSrc = path22.join(personaDir, "listener");
|
|
27072
26942
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
27073
|
-
const archiveDst =
|
|
27074
|
-
|
|
26943
|
+
const archiveDst = path22.join(dataDir, ".legacy", `listener-${pid}`);
|
|
26944
|
+
fs20.mkdirSync(archiveDst, { recursive: true });
|
|
27075
26945
|
for (const file of readdirSafe(listenerSrc)) {
|
|
27076
26946
|
if (!file.endsWith(".json")) continue;
|
|
27077
|
-
|
|
26947
|
+
fs20.renameSync(path22.join(listenerSrc, file), path22.join(archiveDst, file));
|
|
27078
26948
|
archivedListener += 1;
|
|
27079
26949
|
}
|
|
27080
26950
|
rmdirIfEmpty(listenerSrc);
|
|
27081
26951
|
}
|
|
27082
26952
|
rmdirIfEmpty(personaDir);
|
|
27083
26953
|
}
|
|
27084
|
-
|
|
27085
|
-
|
|
26954
|
+
fs20.mkdirSync(sessionsDir, { recursive: true });
|
|
26955
|
+
fs20.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
27086
26956
|
return {
|
|
27087
26957
|
skipped: false,
|
|
27088
26958
|
flagWritten: true,
|
|
@@ -27093,7 +26963,7 @@ function migrateFlattenSessions(opts) {
|
|
|
27093
26963
|
}
|
|
27094
26964
|
function existsSync3(p2) {
|
|
27095
26965
|
try {
|
|
27096
|
-
|
|
26966
|
+
fs20.statSync(p2);
|
|
27097
26967
|
return true;
|
|
27098
26968
|
} catch {
|
|
27099
26969
|
return false;
|
|
@@ -27101,31 +26971,31 @@ function existsSync3(p2) {
|
|
|
27101
26971
|
}
|
|
27102
26972
|
function isDir(p2) {
|
|
27103
26973
|
try {
|
|
27104
|
-
return
|
|
26974
|
+
return fs20.statSync(p2).isDirectory();
|
|
27105
26975
|
} catch {
|
|
27106
26976
|
return false;
|
|
27107
26977
|
}
|
|
27108
26978
|
}
|
|
27109
26979
|
function readdirSafe(p2) {
|
|
27110
26980
|
try {
|
|
27111
|
-
return
|
|
26981
|
+
return fs20.readdirSync(p2);
|
|
27112
26982
|
} catch {
|
|
27113
26983
|
return [];
|
|
27114
26984
|
}
|
|
27115
26985
|
}
|
|
27116
26986
|
function rmdirIfEmpty(p2) {
|
|
27117
26987
|
try {
|
|
27118
|
-
|
|
26988
|
+
fs20.rmdirSync(p2);
|
|
27119
26989
|
} catch {
|
|
27120
26990
|
}
|
|
27121
26991
|
}
|
|
27122
26992
|
|
|
27123
26993
|
// src/transport/http-router.ts
|
|
27124
|
-
var
|
|
27125
|
-
var
|
|
26994
|
+
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
26995
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
27126
26996
|
|
|
27127
26997
|
// src/attachment/mime.ts
|
|
27128
|
-
var
|
|
26998
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
27129
26999
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
27130
27000
|
var EXT_TO_NATIVE_MIME = {
|
|
27131
27001
|
// 图片
|
|
@@ -27232,7 +27102,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
27232
27102
|
".mk"
|
|
27233
27103
|
]);
|
|
27234
27104
|
function lookupMime(filePathOrName) {
|
|
27235
|
-
const ext =
|
|
27105
|
+
const ext = import_node_path15.default.extname(filePathOrName).toLowerCase();
|
|
27236
27106
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
27237
27107
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
27238
27108
|
return "application/octet-stream";
|
|
@@ -27301,8 +27171,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
27301
27171
|
}
|
|
27302
27172
|
|
|
27303
27173
|
// src/attachment/upload.ts
|
|
27304
|
-
var
|
|
27305
|
-
var
|
|
27174
|
+
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
27175
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
27306
27176
|
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
27307
27177
|
var import_promises = require("stream/promises");
|
|
27308
27178
|
var UploadError = class extends Error {
|
|
@@ -27314,22 +27184,22 @@ var UploadError = class extends Error {
|
|
|
27314
27184
|
code;
|
|
27315
27185
|
};
|
|
27316
27186
|
function assertValidFileName(fileName) {
|
|
27317
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
27187
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path16.default.basename(fileName)) {
|
|
27318
27188
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
27319
27189
|
}
|
|
27320
27190
|
}
|
|
27321
27191
|
var HASH_PREFIX_LEN = 16;
|
|
27322
27192
|
async function writeUploadedAttachment(args) {
|
|
27323
27193
|
assertValidFileName(args.fileName);
|
|
27324
|
-
const attachmentsRoot =
|
|
27194
|
+
const attachmentsRoot = import_node_path16.default.join(args.sessionDir, ".attachments");
|
|
27325
27195
|
try {
|
|
27326
|
-
|
|
27196
|
+
import_node_fs14.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
27327
27197
|
} catch (err) {
|
|
27328
27198
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
27329
27199
|
}
|
|
27330
27200
|
const hasher = import_node_crypto6.default.createHash("sha256");
|
|
27331
27201
|
let actualSize = 0;
|
|
27332
|
-
const tmpPath =
|
|
27202
|
+
const tmpPath = import_node_path16.default.join(
|
|
27333
27203
|
attachmentsRoot,
|
|
27334
27204
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto6.default.randomBytes(4).toString("hex")}`
|
|
27335
27205
|
);
|
|
@@ -27344,18 +27214,18 @@ async function writeUploadedAttachment(args) {
|
|
|
27344
27214
|
yield buf;
|
|
27345
27215
|
}
|
|
27346
27216
|
},
|
|
27347
|
-
|
|
27217
|
+
import_node_fs14.default.createWriteStream(tmpPath, { mode: 384 })
|
|
27348
27218
|
);
|
|
27349
27219
|
} catch (err) {
|
|
27350
27220
|
try {
|
|
27351
|
-
|
|
27221
|
+
import_node_fs14.default.unlinkSync(tmpPath);
|
|
27352
27222
|
} catch {
|
|
27353
27223
|
}
|
|
27354
27224
|
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
27355
27225
|
}
|
|
27356
27226
|
if (actualSize !== args.contentLength) {
|
|
27357
27227
|
try {
|
|
27358
|
-
|
|
27228
|
+
import_node_fs14.default.unlinkSync(tmpPath);
|
|
27359
27229
|
} catch {
|
|
27360
27230
|
}
|
|
27361
27231
|
throw new UploadError(
|
|
@@ -27364,35 +27234,35 @@ async function writeUploadedAttachment(args) {
|
|
|
27364
27234
|
);
|
|
27365
27235
|
}
|
|
27366
27236
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
27367
|
-
const hashDir =
|
|
27237
|
+
const hashDir = import_node_path16.default.join(attachmentsRoot, attachmentId);
|
|
27368
27238
|
let finalFileName;
|
|
27369
27239
|
let hashDirExists = false;
|
|
27370
27240
|
try {
|
|
27371
|
-
hashDirExists =
|
|
27241
|
+
hashDirExists = import_node_fs14.default.statSync(hashDir).isDirectory();
|
|
27372
27242
|
} catch {
|
|
27373
27243
|
}
|
|
27374
27244
|
if (hashDirExists) {
|
|
27375
|
-
const existing =
|
|
27245
|
+
const existing = import_node_fs14.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
|
|
27376
27246
|
finalFileName = existing[0] ?? args.fileName;
|
|
27377
27247
|
try {
|
|
27378
|
-
|
|
27248
|
+
import_node_fs14.default.unlinkSync(tmpPath);
|
|
27379
27249
|
} catch {
|
|
27380
27250
|
}
|
|
27381
27251
|
} else {
|
|
27382
27252
|
try {
|
|
27383
|
-
|
|
27253
|
+
import_node_fs14.default.mkdirSync(hashDir, { recursive: true });
|
|
27384
27254
|
finalFileName = args.fileName;
|
|
27385
|
-
|
|
27255
|
+
import_node_fs14.default.renameSync(tmpPath, import_node_path16.default.join(hashDir, finalFileName));
|
|
27386
27256
|
} catch (err) {
|
|
27387
27257
|
try {
|
|
27388
|
-
|
|
27258
|
+
import_node_fs14.default.unlinkSync(tmpPath);
|
|
27389
27259
|
} catch {
|
|
27390
27260
|
}
|
|
27391
27261
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
27392
27262
|
}
|
|
27393
27263
|
}
|
|
27394
|
-
const absPath =
|
|
27395
|
-
const relPath =
|
|
27264
|
+
const absPath = import_node_path16.default.join(hashDir, finalFileName);
|
|
27265
|
+
const relPath = import_node_path16.default.relative(args.sessionDir, absPath);
|
|
27396
27266
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
27397
27267
|
relPath: absPath,
|
|
27398
27268
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -27414,6 +27284,12 @@ var UPLOAD_MIME_ALLOW = /* @__PURE__ */ new Set([
|
|
|
27414
27284
|
]);
|
|
27415
27285
|
var UPLOAD_MIME_ALLOW_PREFIX = ["text/"];
|
|
27416
27286
|
var UPLOAD_MAX_BYTES = 25 * 1024 * 1024;
|
|
27287
|
+
var UPLOAD_CORS_HEADERS = {
|
|
27288
|
+
"Access-Control-Allow-Origin": "*",
|
|
27289
|
+
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
27290
|
+
"Access-Control-Allow-Headers": "Authorization, Content-Type",
|
|
27291
|
+
"Access-Control-Max-Age": "86400"
|
|
27292
|
+
};
|
|
27417
27293
|
function isUploadMimeAllowed(mime) {
|
|
27418
27294
|
if (UPLOAD_MIME_ALLOW.has(mime)) return true;
|
|
27419
27295
|
return UPLOAD_MIME_ALLOW_PREFIX.some((p2) => mime.startsWith(p2));
|
|
@@ -27423,7 +27299,7 @@ function isValidUploadFileName(fileName) {
|
|
|
27423
27299
|
if (fileName === "." || fileName === "..") return false;
|
|
27424
27300
|
if (fileName.startsWith(".")) return false;
|
|
27425
27301
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
27426
|
-
return fileName ===
|
|
27302
|
+
return fileName === import_node_path17.default.basename(fileName);
|
|
27427
27303
|
}
|
|
27428
27304
|
function createHttpRouter(deps) {
|
|
27429
27305
|
return async (req, res) => {
|
|
@@ -27441,6 +27317,11 @@ function createHttpRouter(deps) {
|
|
|
27441
27317
|
if (!url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/") && url.pathname !== "/attachments/upload") {
|
|
27442
27318
|
return false;
|
|
27443
27319
|
}
|
|
27320
|
+
if (url.pathname === "/attachments/upload" && req.method === "OPTIONS") {
|
|
27321
|
+
res.writeHead(204, UPLOAD_CORS_HEADERS);
|
|
27322
|
+
res.end();
|
|
27323
|
+
return true;
|
|
27324
|
+
}
|
|
27444
27325
|
if (url.pathname.startsWith("/files/") && req.method === "GET") {
|
|
27445
27326
|
const secret = deps.getSignSecret?.();
|
|
27446
27327
|
if (!secret) {
|
|
@@ -27479,13 +27360,14 @@ function createHttpRouter(deps) {
|
|
|
27479
27360
|
return true;
|
|
27480
27361
|
}
|
|
27481
27362
|
if (url.pathname === "/attachments/upload" && req.method === "POST") {
|
|
27363
|
+
const sendUploadJson = (status, body) => sendJson(res, status, body, UPLOAD_CORS_HEADERS);
|
|
27482
27364
|
if (ctx.role !== "owner") {
|
|
27483
|
-
|
|
27365
|
+
sendUploadJson(403, { code: "FORBIDDEN", message: "owner only" });
|
|
27484
27366
|
return true;
|
|
27485
27367
|
}
|
|
27486
27368
|
const up = deps.attachmentUpload;
|
|
27487
27369
|
if (!up) {
|
|
27488
|
-
|
|
27370
|
+
sendUploadJson(501, { code: "NOT_IMPLEMENTED", message: "attachment upload not wired" });
|
|
27489
27371
|
return true;
|
|
27490
27372
|
}
|
|
27491
27373
|
const sessionId = url.searchParams.get("sessionId");
|
|
@@ -27493,14 +27375,14 @@ function createHttpRouter(deps) {
|
|
|
27493
27375
|
const mimeType = url.searchParams.get("mimeType");
|
|
27494
27376
|
const contentLengthRaw = req.headers["content-length"];
|
|
27495
27377
|
if (!sessionId || !fileName || !mimeType || !contentLengthRaw) {
|
|
27496
|
-
|
|
27378
|
+
sendUploadJson(400, {
|
|
27497
27379
|
code: "INVALID_PARAM",
|
|
27498
27380
|
message: "missing sessionId/fileName/mimeType/Content-Length"
|
|
27499
27381
|
});
|
|
27500
27382
|
return true;
|
|
27501
27383
|
}
|
|
27502
27384
|
if (!isValidUploadFileName(fileName)) {
|
|
27503
|
-
|
|
27385
|
+
sendUploadJson(400, {
|
|
27504
27386
|
code: "INVALID_FILENAME",
|
|
27505
27387
|
message: `fileName must be a plain basename (no path separators, no dotfiles): ${fileName}`
|
|
27506
27388
|
});
|
|
@@ -27508,18 +27390,18 @@ function createHttpRouter(deps) {
|
|
|
27508
27390
|
}
|
|
27509
27391
|
const contentLength = Number.parseInt(contentLengthRaw, 10);
|
|
27510
27392
|
if (!Number.isFinite(contentLength) || contentLength < 0) {
|
|
27511
|
-
|
|
27393
|
+
sendUploadJson(400, { code: "INVALID_PARAM", message: "malformed Content-Length" });
|
|
27512
27394
|
return true;
|
|
27513
27395
|
}
|
|
27514
27396
|
if (contentLength > UPLOAD_MAX_BYTES) {
|
|
27515
|
-
|
|
27397
|
+
sendUploadJson(413, {
|
|
27516
27398
|
code: "FILE_TOO_LARGE",
|
|
27517
27399
|
message: `max ${UPLOAD_MAX_BYTES} bytes`
|
|
27518
27400
|
});
|
|
27519
27401
|
return true;
|
|
27520
27402
|
}
|
|
27521
27403
|
if (!isUploadMimeAllowed(mimeType)) {
|
|
27522
|
-
|
|
27404
|
+
sendUploadJson(400, {
|
|
27523
27405
|
code: "UNSUPPORTED_MIME",
|
|
27524
27406
|
message: `mime ${mimeType} not allowed`
|
|
27525
27407
|
});
|
|
@@ -27528,12 +27410,12 @@ function createHttpRouter(deps) {
|
|
|
27528
27410
|
const sessionDir = up.getSessionDir(sessionId);
|
|
27529
27411
|
const scope = up.getSessionScope(sessionId);
|
|
27530
27412
|
if (!sessionDir || !scope) {
|
|
27531
|
-
|
|
27413
|
+
sendUploadJson(404, { code: "NOT_FOUND", message: `session ${sessionId} not found` });
|
|
27532
27414
|
return true;
|
|
27533
27415
|
}
|
|
27534
27416
|
const httpBaseUrl = up.getHttpBaseUrl();
|
|
27535
27417
|
if (!httpBaseUrl) {
|
|
27536
|
-
|
|
27418
|
+
sendUploadJson(503, {
|
|
27537
27419
|
code: "TUNNEL_NOT_READY",
|
|
27538
27420
|
message: "httpBaseUrl unavailable"
|
|
27539
27421
|
});
|
|
@@ -27541,7 +27423,7 @@ function createHttpRouter(deps) {
|
|
|
27541
27423
|
}
|
|
27542
27424
|
const secret = deps.getSignSecret?.();
|
|
27543
27425
|
if (!secret) {
|
|
27544
|
-
|
|
27426
|
+
sendUploadJson(501, {
|
|
27545
27427
|
code: "NOT_IMPLEMENTED",
|
|
27546
27428
|
message: "sign secret unavailable (noAuth?)"
|
|
27547
27429
|
});
|
|
@@ -27560,7 +27442,7 @@ function createHttpRouter(deps) {
|
|
|
27560
27442
|
});
|
|
27561
27443
|
const parts = signUrlParts(secret, result.absPath, null);
|
|
27562
27444
|
const fullUrl = buildSignedFileUrl(httpBaseUrl, parts);
|
|
27563
|
-
|
|
27445
|
+
sendUploadJson(200, {
|
|
27564
27446
|
attachmentId: result.attachmentId,
|
|
27565
27447
|
url: fullUrl,
|
|
27566
27448
|
relPath: result.relPath,
|
|
@@ -27570,10 +27452,10 @@ function createHttpRouter(deps) {
|
|
|
27570
27452
|
} catch (err) {
|
|
27571
27453
|
if (err instanceof UploadError) {
|
|
27572
27454
|
const status = err.code === "SIZE_MISMATCH" ? 400 : 500;
|
|
27573
|
-
|
|
27455
|
+
sendUploadJson(status, { code: err.code, message: err.message });
|
|
27574
27456
|
} else {
|
|
27575
27457
|
deps.logger?.warn("attachment upload failed", { err: err.message });
|
|
27576
|
-
|
|
27458
|
+
sendUploadJson(500, { code: "STORAGE_ERROR", message: err.message });
|
|
27577
27459
|
}
|
|
27578
27460
|
}
|
|
27579
27461
|
return true;
|
|
@@ -27587,7 +27469,7 @@ function createHttpRouter(deps) {
|
|
|
27587
27469
|
return true;
|
|
27588
27470
|
}
|
|
27589
27471
|
let absPath;
|
|
27590
|
-
if (
|
|
27472
|
+
if (import_node_path17.default.isAbsolute(pathParam)) {
|
|
27591
27473
|
absPath = pathParam;
|
|
27592
27474
|
} else if (deps.sessionStore) {
|
|
27593
27475
|
const file = deps.sessionStore.read(sid);
|
|
@@ -27595,7 +27477,7 @@ function createHttpRouter(deps) {
|
|
|
27595
27477
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
27596
27478
|
return true;
|
|
27597
27479
|
}
|
|
27598
|
-
absPath =
|
|
27480
|
+
absPath = import_node_path17.default.join(file.cwd, pathParam);
|
|
27599
27481
|
} else {
|
|
27600
27482
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
27601
27483
|
return true;
|
|
@@ -27628,7 +27510,7 @@ function withCtx(ctx, body) {
|
|
|
27628
27510
|
function streamFile(res, absPath, logger) {
|
|
27629
27511
|
let stat;
|
|
27630
27512
|
try {
|
|
27631
|
-
stat =
|
|
27513
|
+
stat = import_node_fs15.default.statSync(absPath);
|
|
27632
27514
|
} catch (err) {
|
|
27633
27515
|
const code = err?.code;
|
|
27634
27516
|
if (code === "ENOENT") {
|
|
@@ -27643,7 +27525,7 @@ function streamFile(res, absPath, logger) {
|
|
|
27643
27525
|
return;
|
|
27644
27526
|
}
|
|
27645
27527
|
const mime = lookupMime(absPath);
|
|
27646
|
-
const basename =
|
|
27528
|
+
const basename = import_node_path17.default.basename(absPath);
|
|
27647
27529
|
res.writeHead(200, {
|
|
27648
27530
|
"Content-Type": mime,
|
|
27649
27531
|
"Content-Length": String(stat.size),
|
|
@@ -27651,7 +27533,7 @@ function streamFile(res, absPath, logger) {
|
|
|
27651
27533
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
27652
27534
|
"X-Content-Type-Options": "nosniff"
|
|
27653
27535
|
});
|
|
27654
|
-
const stream =
|
|
27536
|
+
const stream = import_node_fs15.default.createReadStream(absPath);
|
|
27655
27537
|
stream.on("error", (err) => {
|
|
27656
27538
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
27657
27539
|
res.destroy();
|
|
@@ -27660,8 +27542,8 @@ function streamFile(res, absPath, logger) {
|
|
|
27660
27542
|
}
|
|
27661
27543
|
|
|
27662
27544
|
// src/attachment/gc.ts
|
|
27663
|
-
var
|
|
27664
|
-
var
|
|
27545
|
+
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
27546
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
27665
27547
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
27666
27548
|
function runAttachmentGc(args) {
|
|
27667
27549
|
const now = (args.now ?? Date.now)();
|
|
@@ -27670,38 +27552,38 @@ function runAttachmentGc(args) {
|
|
|
27670
27552
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
27671
27553
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
27672
27554
|
if (entry.stale) continue;
|
|
27673
|
-
if (
|
|
27555
|
+
if (import_node_path18.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
27674
27556
|
}
|
|
27675
27557
|
}
|
|
27676
27558
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
27677
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
27559
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path18.default.join(
|
|
27678
27560
|
args.dataDir,
|
|
27679
27561
|
"sessions",
|
|
27680
27562
|
...scopeSubPath(scope).map(safeFileName),
|
|
27681
27563
|
safeFileName(sessionId)
|
|
27682
27564
|
);
|
|
27683
|
-
const attRoot =
|
|
27565
|
+
const attRoot = import_node_path18.default.join(sessionDir, ".attachments");
|
|
27684
27566
|
let hashDirs;
|
|
27685
27567
|
try {
|
|
27686
|
-
hashDirs =
|
|
27568
|
+
hashDirs = import_node_fs16.default.readdirSync(attRoot);
|
|
27687
27569
|
} catch (err) {
|
|
27688
27570
|
if (err.code === "ENOENT") continue;
|
|
27689
27571
|
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
27690
27572
|
continue;
|
|
27691
27573
|
}
|
|
27692
27574
|
for (const hashDir of hashDirs) {
|
|
27693
|
-
const hashDirAbs =
|
|
27575
|
+
const hashDirAbs = import_node_path18.default.join(attRoot, hashDir);
|
|
27694
27576
|
let files;
|
|
27695
27577
|
try {
|
|
27696
|
-
files =
|
|
27578
|
+
files = import_node_fs16.default.readdirSync(hashDirAbs);
|
|
27697
27579
|
} catch {
|
|
27698
27580
|
continue;
|
|
27699
27581
|
}
|
|
27700
27582
|
for (const name of files) {
|
|
27701
|
-
const file =
|
|
27583
|
+
const file = import_node_path18.default.join(hashDirAbs, name);
|
|
27702
27584
|
let stat;
|
|
27703
27585
|
try {
|
|
27704
|
-
stat =
|
|
27586
|
+
stat = import_node_fs16.default.statSync(file);
|
|
27705
27587
|
} catch {
|
|
27706
27588
|
continue;
|
|
27707
27589
|
}
|
|
@@ -27710,26 +27592,26 @@ function runAttachmentGc(args) {
|
|
|
27710
27592
|
if (age < ttlMs) continue;
|
|
27711
27593
|
if (liveAbs.has(file)) continue;
|
|
27712
27594
|
try {
|
|
27713
|
-
|
|
27595
|
+
import_node_fs16.default.unlinkSync(file);
|
|
27714
27596
|
} catch (err) {
|
|
27715
27597
|
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
27716
27598
|
}
|
|
27717
27599
|
}
|
|
27718
27600
|
try {
|
|
27719
|
-
if (
|
|
27601
|
+
if (import_node_fs16.default.readdirSync(hashDirAbs).length === 0) import_node_fs16.default.rmdirSync(hashDirAbs);
|
|
27720
27602
|
} catch {
|
|
27721
27603
|
}
|
|
27722
27604
|
}
|
|
27723
27605
|
try {
|
|
27724
|
-
if (
|
|
27606
|
+
if (import_node_fs16.default.readdirSync(attRoot).length === 0) import_node_fs16.default.rmdirSync(attRoot);
|
|
27725
27607
|
} catch {
|
|
27726
27608
|
}
|
|
27727
27609
|
}
|
|
27728
27610
|
}
|
|
27729
27611
|
|
|
27730
27612
|
// src/attachment/group.ts
|
|
27731
|
-
var
|
|
27732
|
-
var
|
|
27613
|
+
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
27614
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
27733
27615
|
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
27734
27616
|
init_protocol();
|
|
27735
27617
|
var GroupFileStore = class {
|
|
@@ -27741,11 +27623,11 @@ var GroupFileStore = class {
|
|
|
27741
27623
|
this.logger = opts.logger;
|
|
27742
27624
|
}
|
|
27743
27625
|
rootForScope(scope) {
|
|
27744
|
-
return
|
|
27626
|
+
return import_node_path19.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
27745
27627
|
}
|
|
27746
27628
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
27747
27629
|
filePath(scope, sessionId) {
|
|
27748
|
-
return
|
|
27630
|
+
return import_node_path19.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
27749
27631
|
}
|
|
27750
27632
|
cacheKey(scope, sessionId) {
|
|
27751
27633
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -27754,7 +27636,7 @@ var GroupFileStore = class {
|
|
|
27754
27636
|
readFile(scope, sessionId) {
|
|
27755
27637
|
const file = this.filePath(scope, sessionId);
|
|
27756
27638
|
try {
|
|
27757
|
-
const raw =
|
|
27639
|
+
const raw = import_node_fs17.default.readFileSync(file, "utf8");
|
|
27758
27640
|
const parsed = JSON.parse(raw);
|
|
27759
27641
|
if (!Array.isArray(parsed)) {
|
|
27760
27642
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -27780,10 +27662,10 @@ var GroupFileStore = class {
|
|
|
27780
27662
|
}
|
|
27781
27663
|
writeFile(scope, sessionId, entries) {
|
|
27782
27664
|
const file = this.filePath(scope, sessionId);
|
|
27783
|
-
|
|
27665
|
+
import_node_fs17.default.mkdirSync(import_node_path19.default.dirname(file), { recursive: true });
|
|
27784
27666
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
27785
|
-
|
|
27786
|
-
|
|
27667
|
+
import_node_fs17.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
27668
|
+
import_node_fs17.default.renameSync(tmp, file);
|
|
27787
27669
|
}
|
|
27788
27670
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
27789
27671
|
list(scope, sessionId) {
|
|
@@ -27869,10 +27751,10 @@ var GroupFileStore = class {
|
|
|
27869
27751
|
};
|
|
27870
27752
|
|
|
27871
27753
|
// src/discovery/state-file.ts
|
|
27872
|
-
var
|
|
27873
|
-
var
|
|
27754
|
+
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
27755
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
27874
27756
|
function defaultStateFilePath(dataDir) {
|
|
27875
|
-
return
|
|
27757
|
+
return import_node_path20.default.join(dataDir, "state.json");
|
|
27876
27758
|
}
|
|
27877
27759
|
function isPidAlive(pid) {
|
|
27878
27760
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -27894,7 +27776,7 @@ var StateFileManager = class {
|
|
|
27894
27776
|
}
|
|
27895
27777
|
read() {
|
|
27896
27778
|
try {
|
|
27897
|
-
const raw =
|
|
27779
|
+
const raw = import_node_fs18.default.readFileSync(this.file, "utf8");
|
|
27898
27780
|
const parsed = JSON.parse(raw);
|
|
27899
27781
|
return parsed;
|
|
27900
27782
|
} catch {
|
|
@@ -27908,34 +27790,34 @@ var StateFileManager = class {
|
|
|
27908
27790
|
return { status: "stale", existing };
|
|
27909
27791
|
}
|
|
27910
27792
|
write(state) {
|
|
27911
|
-
|
|
27793
|
+
import_node_fs18.default.mkdirSync(import_node_path20.default.dirname(this.file), { recursive: true });
|
|
27912
27794
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
27913
|
-
|
|
27914
|
-
|
|
27795
|
+
import_node_fs18.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
27796
|
+
import_node_fs18.default.renameSync(tmp, this.file);
|
|
27915
27797
|
if (process.platform !== "win32") {
|
|
27916
27798
|
try {
|
|
27917
|
-
|
|
27799
|
+
import_node_fs18.default.chmodSync(this.file, 384);
|
|
27918
27800
|
} catch {
|
|
27919
27801
|
}
|
|
27920
27802
|
}
|
|
27921
27803
|
}
|
|
27922
27804
|
delete() {
|
|
27923
27805
|
try {
|
|
27924
|
-
|
|
27806
|
+
import_node_fs18.default.unlinkSync(this.file);
|
|
27925
27807
|
} catch {
|
|
27926
27808
|
}
|
|
27927
27809
|
}
|
|
27928
27810
|
};
|
|
27929
27811
|
|
|
27930
27812
|
// src/tunnel/tunnel-manager.ts
|
|
27931
|
-
var
|
|
27932
|
-
var
|
|
27813
|
+
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
27814
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
27933
27815
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
27934
27816
|
var import_node_child_process5 = require("child_process");
|
|
27935
27817
|
|
|
27936
27818
|
// src/tunnel/tunnel-store.ts
|
|
27937
|
-
var
|
|
27938
|
-
var
|
|
27819
|
+
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
27820
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
27939
27821
|
var TunnelStore = class {
|
|
27940
27822
|
constructor(filePath) {
|
|
27941
27823
|
this.filePath = filePath;
|
|
@@ -27943,7 +27825,7 @@ var TunnelStore = class {
|
|
|
27943
27825
|
filePath;
|
|
27944
27826
|
async get() {
|
|
27945
27827
|
try {
|
|
27946
|
-
const raw = await
|
|
27828
|
+
const raw = await import_node_fs19.default.promises.readFile(this.filePath, "utf8");
|
|
27947
27829
|
const obj = JSON.parse(raw);
|
|
27948
27830
|
if (!isPersistedTunnel(obj)) return null;
|
|
27949
27831
|
return obj;
|
|
@@ -27954,22 +27836,22 @@ var TunnelStore = class {
|
|
|
27954
27836
|
}
|
|
27955
27837
|
}
|
|
27956
27838
|
async set(v2) {
|
|
27957
|
-
const dir =
|
|
27958
|
-
await
|
|
27839
|
+
const dir = import_node_path21.default.dirname(this.filePath);
|
|
27840
|
+
await import_node_fs19.default.promises.mkdir(dir, { recursive: true });
|
|
27959
27841
|
const data = JSON.stringify(v2, null, 2);
|
|
27960
27842
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
27961
|
-
await
|
|
27843
|
+
await import_node_fs19.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
27962
27844
|
if (process.platform !== "win32") {
|
|
27963
27845
|
try {
|
|
27964
|
-
await
|
|
27846
|
+
await import_node_fs19.default.promises.chmod(tmp, 384);
|
|
27965
27847
|
} catch {
|
|
27966
27848
|
}
|
|
27967
27849
|
}
|
|
27968
|
-
await
|
|
27850
|
+
await import_node_fs19.default.promises.rename(tmp, this.filePath);
|
|
27969
27851
|
}
|
|
27970
27852
|
async clear() {
|
|
27971
27853
|
try {
|
|
27972
|
-
await
|
|
27854
|
+
await import_node_fs19.default.promises.unlink(this.filePath);
|
|
27973
27855
|
} catch (err) {
|
|
27974
27856
|
const code = err?.code;
|
|
27975
27857
|
if (code !== "ENOENT") throw err;
|
|
@@ -28064,9 +27946,9 @@ function escape(v2) {
|
|
|
28064
27946
|
}
|
|
28065
27947
|
|
|
28066
27948
|
// src/tunnel/frpc-binary.ts
|
|
28067
|
-
var
|
|
28068
|
-
var
|
|
28069
|
-
var
|
|
27949
|
+
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
27950
|
+
var import_node_os9 = __toESM(require("os"), 1);
|
|
27951
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
28070
27952
|
var import_node_child_process3 = require("child_process");
|
|
28071
27953
|
var import_node_stream2 = require("stream");
|
|
28072
27954
|
var import_promises2 = require("stream/promises");
|
|
@@ -28098,20 +27980,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
28098
27980
|
}
|
|
28099
27981
|
async function ensureFrpcBinary(opts) {
|
|
28100
27982
|
if (opts.override) {
|
|
28101
|
-
if (!
|
|
27983
|
+
if (!import_node_fs20.default.existsSync(opts.override)) {
|
|
28102
27984
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
28103
27985
|
}
|
|
28104
27986
|
return opts.override;
|
|
28105
27987
|
}
|
|
28106
27988
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
28107
27989
|
const platform = opts.platform ?? detectPlatform();
|
|
28108
|
-
const binDir =
|
|
28109
|
-
|
|
27990
|
+
const binDir = import_node_path22.default.join(opts.dataDir, "bin");
|
|
27991
|
+
import_node_fs20.default.mkdirSync(binDir, { recursive: true });
|
|
28110
27992
|
cleanupStaleArtifacts(binDir);
|
|
28111
|
-
const stableBin =
|
|
28112
|
-
if (
|
|
27993
|
+
const stableBin = import_node_path22.default.join(binDir, "frpc");
|
|
27994
|
+
if (import_node_fs20.default.existsSync(stableBin)) return stableBin;
|
|
28113
27995
|
const partialBin = `${stableBin}.partial`;
|
|
28114
|
-
const tarballPath =
|
|
27996
|
+
const tarballPath = import_node_path22.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
28115
27997
|
try {
|
|
28116
27998
|
const url = frpcDownloadUrl(version2, platform);
|
|
28117
27999
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -28120,8 +28002,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
28120
28002
|
} else {
|
|
28121
28003
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
28122
28004
|
}
|
|
28123
|
-
|
|
28124
|
-
|
|
28005
|
+
import_node_fs20.default.chmodSync(partialBin, 493);
|
|
28006
|
+
import_node_fs20.default.renameSync(partialBin, stableBin);
|
|
28125
28007
|
} finally {
|
|
28126
28008
|
safeUnlink(tarballPath);
|
|
28127
28009
|
safeUnlink(partialBin);
|
|
@@ -28131,15 +28013,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
28131
28013
|
function cleanupStaleArtifacts(binDir) {
|
|
28132
28014
|
let entries;
|
|
28133
28015
|
try {
|
|
28134
|
-
entries =
|
|
28016
|
+
entries = import_node_fs20.default.readdirSync(binDir);
|
|
28135
28017
|
} catch {
|
|
28136
28018
|
return;
|
|
28137
28019
|
}
|
|
28138
28020
|
for (const name of entries) {
|
|
28139
28021
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
28140
|
-
const full =
|
|
28022
|
+
const full = import_node_path22.default.join(binDir, name);
|
|
28141
28023
|
try {
|
|
28142
|
-
|
|
28024
|
+
import_node_fs20.default.rmSync(full, { recursive: true, force: true });
|
|
28143
28025
|
} catch {
|
|
28144
28026
|
}
|
|
28145
28027
|
}
|
|
@@ -28147,7 +28029,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
28147
28029
|
}
|
|
28148
28030
|
function safeUnlink(p2) {
|
|
28149
28031
|
try {
|
|
28150
|
-
|
|
28032
|
+
import_node_fs20.default.unlinkSync(p2);
|
|
28151
28033
|
} catch {
|
|
28152
28034
|
}
|
|
28153
28035
|
}
|
|
@@ -28158,13 +28040,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
28158
28040
|
if (!res.ok || !res.body) {
|
|
28159
28041
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
28160
28042
|
}
|
|
28161
|
-
const out =
|
|
28043
|
+
const out = import_node_fs20.default.createWriteStream(dest);
|
|
28162
28044
|
const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
|
|
28163
28045
|
await (0, import_promises2.pipeline)(nodeStream, out);
|
|
28164
28046
|
}
|
|
28165
28047
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
28166
|
-
const work =
|
|
28167
|
-
|
|
28048
|
+
const work = import_node_path22.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
28049
|
+
import_node_fs20.default.mkdirSync(work, { recursive: true });
|
|
28168
28050
|
try {
|
|
28169
28051
|
await new Promise((resolve6, reject) => {
|
|
28170
28052
|
const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -28172,32 +28054,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
28172
28054
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
28173
28055
|
});
|
|
28174
28056
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
28175
|
-
const src =
|
|
28176
|
-
if (!
|
|
28057
|
+
const src = import_node_path22.default.join(work, dirName, "frpc");
|
|
28058
|
+
if (!import_node_fs20.default.existsSync(src)) {
|
|
28177
28059
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
28178
28060
|
}
|
|
28179
|
-
|
|
28061
|
+
import_node_fs20.default.copyFileSync(src, destBin);
|
|
28180
28062
|
} finally {
|
|
28181
|
-
|
|
28063
|
+
import_node_fs20.default.rmSync(work, { recursive: true, force: true });
|
|
28182
28064
|
}
|
|
28183
28065
|
}
|
|
28184
28066
|
|
|
28185
28067
|
// src/tunnel/frpc-process.ts
|
|
28186
|
-
var
|
|
28187
|
-
var
|
|
28068
|
+
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
28069
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
28188
28070
|
var import_node_child_process4 = require("child_process");
|
|
28189
28071
|
function frpcPidFilePath(dataDir) {
|
|
28190
|
-
return
|
|
28072
|
+
return import_node_path23.default.join(dataDir, "frpc.pid");
|
|
28191
28073
|
}
|
|
28192
28074
|
function writeFrpcPid(dataDir, pid) {
|
|
28193
28075
|
try {
|
|
28194
|
-
|
|
28076
|
+
import_node_fs21.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
28195
28077
|
} catch {
|
|
28196
28078
|
}
|
|
28197
28079
|
}
|
|
28198
28080
|
function clearFrpcPid(dataDir) {
|
|
28199
28081
|
try {
|
|
28200
|
-
|
|
28082
|
+
import_node_fs21.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
28201
28083
|
} catch {
|
|
28202
28084
|
}
|
|
28203
28085
|
}
|
|
@@ -28213,7 +28095,7 @@ function defaultIsPidAlive(pid) {
|
|
|
28213
28095
|
}
|
|
28214
28096
|
function defaultReadPidFile(file) {
|
|
28215
28097
|
try {
|
|
28216
|
-
return
|
|
28098
|
+
return import_node_fs21.default.readFileSync(file, "utf8");
|
|
28217
28099
|
} catch {
|
|
28218
28100
|
return null;
|
|
28219
28101
|
}
|
|
@@ -28229,7 +28111,7 @@ function defaultSleep(ms) {
|
|
|
28229
28111
|
}
|
|
28230
28112
|
async function killStaleFrpc(deps) {
|
|
28231
28113
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
28232
|
-
const tomlPath =
|
|
28114
|
+
const tomlPath = import_node_path23.default.join(deps.dataDir, "frpc.toml");
|
|
28233
28115
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
28234
28116
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
28235
28117
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -28253,7 +28135,7 @@ async function killStaleFrpc(deps) {
|
|
|
28253
28135
|
}
|
|
28254
28136
|
if (victims.size === 0) {
|
|
28255
28137
|
try {
|
|
28256
|
-
|
|
28138
|
+
import_node_fs21.default.unlinkSync(pidFile);
|
|
28257
28139
|
} catch {
|
|
28258
28140
|
}
|
|
28259
28141
|
return;
|
|
@@ -28264,7 +28146,7 @@ async function killStaleFrpc(deps) {
|
|
|
28264
28146
|
}
|
|
28265
28147
|
await sleep(deps.reapWaitMs ?? 300);
|
|
28266
28148
|
try {
|
|
28267
|
-
|
|
28149
|
+
import_node_fs21.default.unlinkSync(pidFile);
|
|
28268
28150
|
} catch {
|
|
28269
28151
|
}
|
|
28270
28152
|
}
|
|
@@ -28301,7 +28183,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
28301
28183
|
var TunnelManager = class {
|
|
28302
28184
|
constructor(deps) {
|
|
28303
28185
|
this.deps = deps;
|
|
28304
|
-
this.store = deps.store ?? new TunnelStore(
|
|
28186
|
+
this.store = deps.store ?? new TunnelStore(import_node_path24.default.join(deps.dataDir, "tunnel.json"));
|
|
28305
28187
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
28306
28188
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
28307
28189
|
}
|
|
@@ -28428,7 +28310,7 @@ var TunnelManager = class {
|
|
|
28428
28310
|
dataDir: this.deps.dataDir,
|
|
28429
28311
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
28430
28312
|
});
|
|
28431
|
-
const tomlPath =
|
|
28313
|
+
const tomlPath = import_node_path24.default.join(this.deps.dataDir, "frpc.toml");
|
|
28432
28314
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto8.default.randomBytes(3).toString("hex")}`;
|
|
28433
28315
|
const toml = buildFrpcToml({
|
|
28434
28316
|
serverAddr: t.frpsHost,
|
|
@@ -28439,12 +28321,12 @@ var TunnelManager = class {
|
|
|
28439
28321
|
localPort,
|
|
28440
28322
|
logLevel: "info"
|
|
28441
28323
|
});
|
|
28442
|
-
await
|
|
28324
|
+
await import_node_fs22.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
28443
28325
|
const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
|
|
28444
28326
|
stdio: ["ignore", "pipe", "pipe"]
|
|
28445
28327
|
});
|
|
28446
|
-
const logFilePath =
|
|
28447
|
-
const logStream =
|
|
28328
|
+
const logFilePath = import_node_path24.default.join(this.deps.dataDir, "frpc.log");
|
|
28329
|
+
const logStream = import_node_fs22.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
28448
28330
|
logStream.on("error", () => {
|
|
28449
28331
|
});
|
|
28450
28332
|
const tee = (chunk) => {
|
|
@@ -28526,23 +28408,23 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
28526
28408
|
}
|
|
28527
28409
|
|
|
28528
28410
|
// src/tunnel/device-key.ts
|
|
28529
|
-
var
|
|
28411
|
+
var import_node_os10 = __toESM(require("os"), 1);
|
|
28530
28412
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
28531
28413
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
28532
28414
|
function deriveStableDeviceKey(opts = {}) {
|
|
28533
|
-
const hostname = opts.hostname ??
|
|
28534
|
-
const uid = opts.uid ?? (typeof
|
|
28415
|
+
const hostname = opts.hostname ?? import_node_os10.default.hostname();
|
|
28416
|
+
const uid = opts.uid ?? (typeof import_node_os10.default.userInfo === "function" ? import_node_os10.default.userInfo().uid : 0);
|
|
28535
28417
|
const input = `${hostname}::${uid}`;
|
|
28536
28418
|
return import_node_crypto9.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
28537
28419
|
}
|
|
28538
28420
|
|
|
28539
28421
|
// src/auth-store.ts
|
|
28540
|
-
var
|
|
28541
|
-
var
|
|
28422
|
+
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
28423
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
28542
28424
|
var import_node_crypto10 = __toESM(require("crypto"), 1);
|
|
28543
28425
|
var AUTH_FILE_NAME = "auth.json";
|
|
28544
28426
|
function authFilePath(dataDir) {
|
|
28545
|
-
return
|
|
28427
|
+
return import_node_path25.default.join(dataDir, AUTH_FILE_NAME);
|
|
28546
28428
|
}
|
|
28547
28429
|
function loadOrCreateAuthFile(opts) {
|
|
28548
28430
|
const file = authFilePath(opts.dataDir);
|
|
@@ -28574,7 +28456,7 @@ function defaultGenerateOwnerPrincipalId() {
|
|
|
28574
28456
|
}
|
|
28575
28457
|
function readAuthFile(file) {
|
|
28576
28458
|
try {
|
|
28577
|
-
const raw =
|
|
28459
|
+
const raw = import_node_fs23.default.readFileSync(file, "utf8");
|
|
28578
28460
|
const parsed = JSON.parse(raw);
|
|
28579
28461
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
28580
28462
|
return null;
|
|
@@ -28592,25 +28474,25 @@ function readAuthFile(file) {
|
|
|
28592
28474
|
}
|
|
28593
28475
|
}
|
|
28594
28476
|
function writeAuthFile(file, content) {
|
|
28595
|
-
|
|
28596
|
-
|
|
28477
|
+
import_node_fs23.default.mkdirSync(import_node_path25.default.dirname(file), { recursive: true });
|
|
28478
|
+
import_node_fs23.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
28597
28479
|
try {
|
|
28598
|
-
|
|
28480
|
+
import_node_fs23.default.chmodSync(file, 384);
|
|
28599
28481
|
} catch {
|
|
28600
28482
|
}
|
|
28601
28483
|
}
|
|
28602
28484
|
|
|
28603
28485
|
// src/owner-profile.ts
|
|
28604
|
-
var
|
|
28605
|
-
var
|
|
28606
|
-
var
|
|
28486
|
+
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
28487
|
+
var import_node_os11 = __toESM(require("os"), 1);
|
|
28488
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
28607
28489
|
var PROFILE_FILENAME = "profile.json";
|
|
28608
28490
|
function loadOwnerDisplayName(dataDir) {
|
|
28609
|
-
const fallback =
|
|
28610
|
-
const profilePath =
|
|
28491
|
+
const fallback = import_node_os11.default.userInfo().username;
|
|
28492
|
+
const profilePath = import_node_path26.default.join(dataDir, PROFILE_FILENAME);
|
|
28611
28493
|
let raw;
|
|
28612
28494
|
try {
|
|
28613
|
-
raw =
|
|
28495
|
+
raw = import_node_fs24.default.readFileSync(profilePath, "utf8");
|
|
28614
28496
|
} catch {
|
|
28615
28497
|
return fallback;
|
|
28616
28498
|
}
|
|
@@ -28639,12 +28521,12 @@ init_protocol();
|
|
|
28639
28521
|
init_protocol();
|
|
28640
28522
|
|
|
28641
28523
|
// src/session/fork.ts
|
|
28642
|
-
var
|
|
28643
|
-
var
|
|
28644
|
-
var
|
|
28524
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
28525
|
+
var import_node_os12 = __toESM(require("os"), 1);
|
|
28526
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
28645
28527
|
init_claude_history();
|
|
28646
28528
|
function readJsonlEntries(file) {
|
|
28647
|
-
const raw =
|
|
28529
|
+
const raw = import_node_fs25.default.readFileSync(file, "utf8");
|
|
28648
28530
|
const out = [];
|
|
28649
28531
|
for (const line of raw.split("\n")) {
|
|
28650
28532
|
const t = line.trim();
|
|
@@ -28657,10 +28539,10 @@ function readJsonlEntries(file) {
|
|
|
28657
28539
|
return out;
|
|
28658
28540
|
}
|
|
28659
28541
|
function forkSession(input) {
|
|
28660
|
-
const baseDir = input.baseDir ??
|
|
28661
|
-
const projectDir =
|
|
28662
|
-
const sourceFile =
|
|
28663
|
-
if (!
|
|
28542
|
+
const baseDir = input.baseDir ?? import_node_path27.default.join(import_node_os12.default.homedir(), ".claude");
|
|
28543
|
+
const projectDir = import_node_path27.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
28544
|
+
const sourceFile = import_node_path27.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
28545
|
+
if (!import_node_fs25.default.existsSync(sourceFile)) {
|
|
28664
28546
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
28665
28547
|
}
|
|
28666
28548
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -28690,9 +28572,9 @@ function forkSession(input) {
|
|
|
28690
28572
|
}
|
|
28691
28573
|
forkedLines.push(JSON.stringify(forked));
|
|
28692
28574
|
}
|
|
28693
|
-
const forkedFilePath =
|
|
28694
|
-
|
|
28695
|
-
|
|
28575
|
+
const forkedFilePath = import_node_path27.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
28576
|
+
import_node_fs25.default.mkdirSync(projectDir, { recursive: true });
|
|
28577
|
+
import_node_fs25.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
28696
28578
|
return { forkedToolSessionId, forkedFilePath };
|
|
28697
28579
|
}
|
|
28698
28580
|
|
|
@@ -29024,7 +28906,7 @@ function buildPermissionHandlers(deps) {
|
|
|
29024
28906
|
}
|
|
29025
28907
|
|
|
29026
28908
|
// src/handlers/history.ts
|
|
29027
|
-
var
|
|
28909
|
+
var path37 = __toESM(require("path"), 1);
|
|
29028
28910
|
init_protocol();
|
|
29029
28911
|
|
|
29030
28912
|
// src/session/recent-dirs.ts
|
|
@@ -29042,7 +28924,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
29042
28924
|
}
|
|
29043
28925
|
|
|
29044
28926
|
// src/permission/persona-paths.ts
|
|
29045
|
-
var
|
|
28927
|
+
var path36 = __toESM(require("path"), 1);
|
|
29046
28928
|
function getAllowedPersonaIds(grants, action) {
|
|
29047
28929
|
const ids = /* @__PURE__ */ new Set();
|
|
29048
28930
|
for (const g2 of grants) {
|
|
@@ -29055,26 +28937,26 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
29055
28937
|
return ids;
|
|
29056
28938
|
}
|
|
29057
28939
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read") {
|
|
29058
|
-
const root =
|
|
29059
|
-
const target =
|
|
29060
|
-
const sep3 = root.endsWith(
|
|
28940
|
+
const root = path36.resolve(personaRoot);
|
|
28941
|
+
const target = path36.resolve(absPath);
|
|
28942
|
+
const sep3 = root.endsWith(path36.sep) ? "" : path36.sep;
|
|
29061
28943
|
if (!target.startsWith(root + sep3)) return false;
|
|
29062
|
-
const rel =
|
|
28944
|
+
const rel = path36.relative(root, target);
|
|
29063
28945
|
if (!rel || rel.startsWith("..")) return false;
|
|
29064
|
-
const personaId = rel.split(
|
|
28946
|
+
const personaId = rel.split(path36.sep)[0];
|
|
29065
28947
|
if (!personaId) return false;
|
|
29066
28948
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
29067
28949
|
if (allowed === "*") return true;
|
|
29068
28950
|
return allowed.has(personaId);
|
|
29069
28951
|
}
|
|
29070
28952
|
function personaIdFromPath(absPath, personaRoot) {
|
|
29071
|
-
const root =
|
|
29072
|
-
const target =
|
|
29073
|
-
const sep3 = root.endsWith(
|
|
28953
|
+
const root = path36.resolve(personaRoot);
|
|
28954
|
+
const target = path36.resolve(absPath);
|
|
28955
|
+
const sep3 = root.endsWith(path36.sep) ? "" : path36.sep;
|
|
29074
28956
|
if (!target.startsWith(root + sep3)) return null;
|
|
29075
|
-
const rel =
|
|
28957
|
+
const rel = path36.relative(root, target);
|
|
29076
28958
|
if (!rel || rel.startsWith("..")) return null;
|
|
29077
|
-
const id = rel.split(
|
|
28959
|
+
const id = rel.split(path36.sep)[0];
|
|
29078
28960
|
return id || null;
|
|
29079
28961
|
}
|
|
29080
28962
|
|
|
@@ -29099,7 +28981,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29099
28981
|
if (!pid) return false;
|
|
29100
28982
|
return isGuestPathAllowed(
|
|
29101
28983
|
ctx.grants,
|
|
29102
|
-
|
|
28984
|
+
path37.join(personaRoot, pid),
|
|
29103
28985
|
personaRoot,
|
|
29104
28986
|
"read"
|
|
29105
28987
|
);
|
|
@@ -29110,7 +28992,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29110
28992
|
};
|
|
29111
28993
|
const list = async (frame, _client, ctx) => {
|
|
29112
28994
|
const args = HistoryListArgs.parse(frame);
|
|
29113
|
-
assertGuestPath(ctx,
|
|
28995
|
+
assertGuestPath(ctx, path37.resolve(args.projectPath), personaRoot, "history:list");
|
|
29114
28996
|
const sessions = await history.listSessions(args);
|
|
29115
28997
|
return { response: { type: "history:list", sessions } };
|
|
29116
28998
|
};
|
|
@@ -29142,13 +29024,13 @@ function buildHistoryHandlers(deps) {
|
|
|
29142
29024
|
};
|
|
29143
29025
|
const subagents = async (frame, _client, ctx) => {
|
|
29144
29026
|
const args = HistorySubagentsArgs.parse(frame);
|
|
29145
|
-
assertGuestPath(ctx,
|
|
29027
|
+
assertGuestPath(ctx, path37.resolve(args.cwd), personaRoot, "history:subagents");
|
|
29146
29028
|
const subs = await history.listSubagents(args);
|
|
29147
29029
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
29148
29030
|
};
|
|
29149
29031
|
const subagentRead = async (frame, _client, ctx) => {
|
|
29150
29032
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
29151
|
-
assertGuestPath(ctx,
|
|
29033
|
+
assertGuestPath(ctx, path37.resolve(args.cwd), personaRoot, "history:subagent-read");
|
|
29152
29034
|
const res = await history.readSubagent(args);
|
|
29153
29035
|
return { response: { type: "history:subagent-read", ...res } };
|
|
29154
29036
|
};
|
|
@@ -29156,7 +29038,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29156
29038
|
const dirs = listRecentDirs(store);
|
|
29157
29039
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
29158
29040
|
const filtered = dirs.filter(
|
|
29159
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
29041
|
+
(d) => isGuestPathAllowed(ctx.grants, path37.resolve(d.cwd), personaRoot, "read")
|
|
29160
29042
|
);
|
|
29161
29043
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
29162
29044
|
}
|
|
@@ -29173,8 +29055,8 @@ function buildHistoryHandlers(deps) {
|
|
|
29173
29055
|
}
|
|
29174
29056
|
|
|
29175
29057
|
// src/handlers/workspace.ts
|
|
29176
|
-
var
|
|
29177
|
-
var
|
|
29058
|
+
var path38 = __toESM(require("path"), 1);
|
|
29059
|
+
var os13 = __toESM(require("os"), 1);
|
|
29178
29060
|
init_protocol();
|
|
29179
29061
|
init_protocol();
|
|
29180
29062
|
function buildEnabledPluginNames(personaManager, personaId) {
|
|
@@ -29213,23 +29095,23 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29213
29095
|
const list = async (frame, _client, ctx) => {
|
|
29214
29096
|
const args = WorkspaceListArgs.parse(frame);
|
|
29215
29097
|
const isGuest = ctx?.principal.kind === "guest";
|
|
29216
|
-
const fallbackCwd = isGuest && personaRoot ? personaRoot :
|
|
29217
|
-
const resolvedCwd =
|
|
29218
|
-
const target = args.path ?
|
|
29098
|
+
const fallbackCwd = isGuest && personaRoot ? personaRoot : os13.homedir();
|
|
29099
|
+
const resolvedCwd = path38.resolve(args.cwd ?? fallbackCwd);
|
|
29100
|
+
const target = args.path ? path38.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
29219
29101
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list");
|
|
29220
29102
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
29221
29103
|
return { response: { type: "workspace:list", ...res } };
|
|
29222
29104
|
};
|
|
29223
29105
|
const read = async (frame, _client, ctx) => {
|
|
29224
29106
|
const args = WorkspaceReadArgs.parse(frame);
|
|
29225
|
-
const target =
|
|
29107
|
+
const target = path38.isAbsolute(args.path) ? path38.resolve(args.path) : path38.resolve(args.cwd, args.path);
|
|
29226
29108
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read");
|
|
29227
29109
|
const res = workspace.read(args);
|
|
29228
29110
|
return { response: { type: "workspace:read", ...res } };
|
|
29229
29111
|
};
|
|
29230
29112
|
const skillsList = async (frame, _client, ctx) => {
|
|
29231
29113
|
const args = SkillsListArgs.parse(frame);
|
|
29232
|
-
const cwdAbs =
|
|
29114
|
+
const cwdAbs = path38.resolve(args.cwd);
|
|
29233
29115
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
|
|
29234
29116
|
const list2 = skills.list(args);
|
|
29235
29117
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -29241,7 +29123,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29241
29123
|
};
|
|
29242
29124
|
const agentsList = async (frame, _client, ctx) => {
|
|
29243
29125
|
const args = AgentsListArgs.parse(frame);
|
|
29244
|
-
const cwdAbs =
|
|
29126
|
+
const cwdAbs = path38.resolve(args.cwd);
|
|
29245
29127
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
|
|
29246
29128
|
const list2 = agents.list(args);
|
|
29247
29129
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -29260,20 +29142,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29260
29142
|
}
|
|
29261
29143
|
|
|
29262
29144
|
// src/handlers/git.ts
|
|
29263
|
-
var
|
|
29145
|
+
var path40 = __toESM(require("path"), 1);
|
|
29264
29146
|
init_protocol();
|
|
29265
29147
|
init_protocol();
|
|
29266
29148
|
|
|
29267
29149
|
// src/workspace/git.ts
|
|
29268
29150
|
var import_node_child_process6 = require("child_process");
|
|
29269
|
-
var
|
|
29270
|
-
var
|
|
29151
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
29152
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
29271
29153
|
var import_node_util = require("util");
|
|
29272
29154
|
var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
|
|
29273
29155
|
function normalizePath(p2) {
|
|
29274
|
-
const resolved =
|
|
29156
|
+
const resolved = import_node_path28.default.resolve(p2);
|
|
29275
29157
|
try {
|
|
29276
|
-
return
|
|
29158
|
+
return import_node_fs26.default.realpathSync(resolved);
|
|
29277
29159
|
} catch {
|
|
29278
29160
|
return resolved;
|
|
29279
29161
|
}
|
|
@@ -29346,7 +29228,7 @@ async function listGitBranches(cwd) {
|
|
|
29346
29228
|
// src/handlers/git.ts
|
|
29347
29229
|
function assertGuestCwd(ctx, cwd, personaRoot, method) {
|
|
29348
29230
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
29349
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
29231
|
+
if (!isGuestPathAllowed(ctx.grants, path40.resolve(cwd), personaRoot, "read")) {
|
|
29350
29232
|
throw new ClawdError(
|
|
29351
29233
|
ERROR_CODES.UNAUTHORIZED,
|
|
29352
29234
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -29709,7 +29591,7 @@ function buildWhoamiHandler(deps) {
|
|
|
29709
29591
|
}
|
|
29710
29592
|
|
|
29711
29593
|
// src/handlers/meta.ts
|
|
29712
|
-
var
|
|
29594
|
+
var import_node_os13 = __toESM(require("os"), 1);
|
|
29713
29595
|
init_protocol();
|
|
29714
29596
|
|
|
29715
29597
|
// src/version.ts
|
|
@@ -29739,7 +29621,7 @@ function buildReadyFrame(deps, client) {
|
|
|
29739
29621
|
return {
|
|
29740
29622
|
version,
|
|
29741
29623
|
protocolVersion: PROTOCOL_VERSION,
|
|
29742
|
-
hostname:
|
|
29624
|
+
hostname: import_node_os13.default.hostname(),
|
|
29743
29625
|
os: process.platform,
|
|
29744
29626
|
tools,
|
|
29745
29627
|
runningSessions: info.runningSessions,
|
|
@@ -29833,7 +29715,7 @@ function buildPersonaHandlers(deps) {
|
|
|
29833
29715
|
}
|
|
29834
29716
|
|
|
29835
29717
|
// src/handlers/attachment.ts
|
|
29836
|
-
var
|
|
29718
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
29837
29719
|
init_protocol();
|
|
29838
29720
|
init_protocol();
|
|
29839
29721
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -29887,12 +29769,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
29887
29769
|
`session ${args.sessionId} scope unresolved`
|
|
29888
29770
|
);
|
|
29889
29771
|
}
|
|
29890
|
-
const cwdAbs =
|
|
29891
|
-
const candidateAbs =
|
|
29772
|
+
const cwdAbs = import_node_path29.default.resolve(sessionFile.cwd);
|
|
29773
|
+
const candidateAbs = import_node_path29.default.isAbsolute(args.relPath) ? import_node_path29.default.resolve(args.relPath) : import_node_path29.default.resolve(cwdAbs, args.relPath);
|
|
29892
29774
|
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
|
|
29893
29775
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
29894
29776
|
const entry = entries.find((e) => {
|
|
29895
|
-
const storedAbs =
|
|
29777
|
+
const storedAbs = import_node_path29.default.isAbsolute(e.relPath) ? import_node_path29.default.resolve(e.relPath) : import_node_path29.default.resolve(cwdAbs, e.relPath);
|
|
29896
29778
|
return storedAbs === candidateAbs && !e.stale;
|
|
29897
29779
|
});
|
|
29898
29780
|
if (!entry) {
|
|
@@ -29916,7 +29798,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
29916
29798
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
29917
29799
|
const f = deps.sessionStore.read(sessionId);
|
|
29918
29800
|
if (!f) return;
|
|
29919
|
-
assertGuestAttachmentPath(ctx,
|
|
29801
|
+
assertGuestAttachmentPath(ctx, import_node_path29.default.resolve(f.cwd), deps.personaRoot, method);
|
|
29920
29802
|
}
|
|
29921
29803
|
const groupAdd = async (frame, _client, ctx) => {
|
|
29922
29804
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -30153,7 +30035,7 @@ function computeGrantForFrame(method, frame) {
|
|
|
30153
30035
|
async function startDaemon(config) {
|
|
30154
30036
|
const logger = createLogger({
|
|
30155
30037
|
level: config.logLevel,
|
|
30156
|
-
file:
|
|
30038
|
+
file: import_node_path30.default.join(config.dataDir, "clawd.log")
|
|
30157
30039
|
});
|
|
30158
30040
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
30159
30041
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -30240,7 +30122,7 @@ async function startDaemon(config) {
|
|
|
30240
30122
|
const agents = new AgentsScanner();
|
|
30241
30123
|
const history = new ClaudeHistoryReader();
|
|
30242
30124
|
let transport = null;
|
|
30243
|
-
const personaStore = new PersonaStore(
|
|
30125
|
+
const personaStore = new PersonaStore(import_node_path30.default.join(config.dataDir, "personas"));
|
|
30244
30126
|
const defaultsRoot = findDefaultsRoot();
|
|
30245
30127
|
if (defaultsRoot) {
|
|
30246
30128
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -30257,7 +30139,7 @@ async function startDaemon(config) {
|
|
|
30257
30139
|
getAdapter,
|
|
30258
30140
|
historyReader: history,
|
|
30259
30141
|
dataDir: config.dataDir,
|
|
30260
|
-
personaRoot:
|
|
30142
|
+
personaRoot: import_node_path30.default.join(config.dataDir, "personas"),
|
|
30261
30143
|
personaStore,
|
|
30262
30144
|
ownerDisplayName,
|
|
30263
30145
|
ownerPrincipalId,
|
|
@@ -30281,10 +30163,10 @@ async function startDaemon(config) {
|
|
|
30281
30163
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
30282
30164
|
attachmentGroup: {
|
|
30283
30165
|
onFileEdit: (input) => {
|
|
30284
|
-
const absPath =
|
|
30166
|
+
const absPath = import_node_path30.default.isAbsolute(input.relPath) ? input.relPath : import_node_path30.default.join(input.cwd, input.relPath);
|
|
30285
30167
|
let size = 0;
|
|
30286
30168
|
try {
|
|
30287
|
-
size =
|
|
30169
|
+
size = import_node_fs27.default.statSync(absPath).size;
|
|
30288
30170
|
} catch (err) {
|
|
30289
30171
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
30290
30172
|
sessionId: input.sessionId,
|
|
@@ -30310,11 +30192,6 @@ async function startDaemon(config) {
|
|
|
30310
30192
|
}
|
|
30311
30193
|
});
|
|
30312
30194
|
const observer = new SessionObserver({
|
|
30313
|
-
// TUI 模式 pty 跑 CC 不发 SDK system.task_started 帧 → UI pending 期 progress.agentId
|
|
30314
|
-
// 永远 undefined,子 agent 调用过程没有抽屉入口。开 meta observer 后从 subagents 目录
|
|
30315
|
-
// 新出现的 agent-*.meta.json 派生 subagent_progress(started) 补这块缺口。SDK 模式仍走
|
|
30316
|
-
// task_started 路径,避免双 emit 让 ring buffer 双帧。
|
|
30317
|
-
enableSubagentMetaObserver: config.mode === "tui",
|
|
30318
30195
|
onEvent: ({ sessionId, events }) => {
|
|
30319
30196
|
manager.feedObserverEvents(sessionId, events);
|
|
30320
30197
|
},
|
|
@@ -30402,10 +30279,10 @@ async function startDaemon(config) {
|
|
|
30402
30279
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
30403
30280
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
30404
30281
|
// guest path guard:candidate 必须在 personaRoot 子树下
|
|
30405
|
-
personaRoot:
|
|
30282
|
+
personaRoot: import_node_path30.default.join(config.dataDir, "personas")
|
|
30406
30283
|
},
|
|
30407
30284
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
30408
|
-
personaRoot:
|
|
30285
|
+
personaRoot: import_node_path30.default.join(config.dataDir, "personas"),
|
|
30409
30286
|
// capability:list / delete handler 依赖
|
|
30410
30287
|
capabilityManager,
|
|
30411
30288
|
// personal-cap:get 返回的 shareBaseUrl 用此 base URL:
|
|
@@ -30618,8 +30495,8 @@ async function startDaemon(config) {
|
|
|
30618
30495
|
const lines = [
|
|
30619
30496
|
`Tunnel: ${r.url}`,
|
|
30620
30497
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
30621
|
-
`Frpc config: ${
|
|
30622
|
-
`Frpc log: ${
|
|
30498
|
+
`Frpc config: ${import_node_path30.default.join(config.dataDir, "frpc.toml")}`,
|
|
30499
|
+
`Frpc log: ${import_node_path30.default.join(config.dataDir, "frpc.log")}`
|
|
30623
30500
|
];
|
|
30624
30501
|
const width = Math.max(...lines.map((l) => l.length));
|
|
30625
30502
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -30632,8 +30509,8 @@ ${bar}
|
|
|
30632
30509
|
|
|
30633
30510
|
`);
|
|
30634
30511
|
try {
|
|
30635
|
-
const connectPath =
|
|
30636
|
-
|
|
30512
|
+
const connectPath = import_node_path30.default.join(config.dataDir, "connect.txt");
|
|
30513
|
+
import_node_fs27.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
30637
30514
|
} catch {
|
|
30638
30515
|
}
|
|
30639
30516
|
} catch (err) {
|
|
@@ -30698,9 +30575,9 @@ ${bar}
|
|
|
30698
30575
|
};
|
|
30699
30576
|
}
|
|
30700
30577
|
function migrateDropPersonsDir(dataDir) {
|
|
30701
|
-
const dir =
|
|
30578
|
+
const dir = import_node_path30.default.join(dataDir, "persons");
|
|
30702
30579
|
try {
|
|
30703
|
-
|
|
30580
|
+
import_node_fs27.default.rmSync(dir, { recursive: true, force: true });
|
|
30704
30581
|
} catch {
|
|
30705
30582
|
}
|
|
30706
30583
|
}
|