@clawos-dev/clawd 0.2.88 → 0.2.89-beta.165.fab5549
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 +250 -602
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -651,8 +651,8 @@ var init_parseUtil = __esm({
|
|
|
651
651
|
init_errors2();
|
|
652
652
|
init_en();
|
|
653
653
|
makeIssue = (params) => {
|
|
654
|
-
const { data, path:
|
|
655
|
-
const fullPath = [...
|
|
654
|
+
const { data, path: path44, errorMaps, issueData } = params;
|
|
655
|
+
const fullPath = [...path44, ...issueData.path || []];
|
|
656
656
|
const fullIssue = {
|
|
657
657
|
...issueData,
|
|
658
658
|
path: fullPath
|
|
@@ -963,11 +963,11 @@ var init_types = __esm({
|
|
|
963
963
|
init_parseUtil();
|
|
964
964
|
init_util();
|
|
965
965
|
ParseInputLazyPath = class {
|
|
966
|
-
constructor(parent, value,
|
|
966
|
+
constructor(parent, value, path44, key) {
|
|
967
967
|
this._cachedPath = [];
|
|
968
968
|
this.parent = parent;
|
|
969
969
|
this.data = value;
|
|
970
|
-
this._path =
|
|
970
|
+
this._path = path44;
|
|
971
971
|
this._key = key;
|
|
972
972
|
}
|
|
973
973
|
get path() {
|
|
@@ -4351,13 +4351,13 @@ var init_zod = __esm({
|
|
|
4351
4351
|
});
|
|
4352
4352
|
|
|
4353
4353
|
// ../protocol/src/attachment-schemas.ts
|
|
4354
|
-
var TOKEN_ROLES, GROUP_FILE_SOURCES, GroupFileEntrySchema, AttachmentSignUrlArgs, AttachmentSignUrlResponseSchema, AttachmentGroupAddArgs, AttachmentGroupAddResponseSchema, AttachmentGroupRemoveArgs, AttachmentGroupRemoveResponseSchema, AttachmentGroupListArgs, AttachmentGroupListResponseSchema
|
|
4354
|
+
var TOKEN_ROLES, GROUP_FILE_SOURCES, GroupFileEntrySchema, AttachmentSignUrlArgs, AttachmentSignUrlResponseSchema, AttachmentGroupAddArgs, AttachmentGroupAddResponseSchema, AttachmentGroupRemoveArgs, AttachmentGroupRemoveResponseSchema, AttachmentGroupListArgs, AttachmentGroupListResponseSchema;
|
|
4355
4355
|
var init_attachment_schemas = __esm({
|
|
4356
4356
|
"../protocol/src/attachment-schemas.ts"() {
|
|
4357
4357
|
"use strict";
|
|
4358
4358
|
init_zod();
|
|
4359
4359
|
TOKEN_ROLES = ["owner"];
|
|
4360
|
-
GROUP_FILE_SOURCES = ["agent", "owner"
|
|
4360
|
+
GROUP_FILE_SOURCES = ["agent", "owner"];
|
|
4361
4361
|
GroupFileEntrySchema = external_exports.object({
|
|
4362
4362
|
/** daemon 派发的稳定 id(用于 RPC remove / UI key) */
|
|
4363
4363
|
id: external_exports.string().min(1),
|
|
@@ -4412,16 +4412,6 @@ var init_attachment_schemas = __esm({
|
|
|
4412
4412
|
AttachmentGroupListResponseSchema = external_exports.object({
|
|
4413
4413
|
entries: external_exports.array(GroupFileEntrySchema)
|
|
4414
4414
|
});
|
|
4415
|
-
AttachmentUploadResponseSchema = external_exports.object({
|
|
4416
|
-
/** sha256(bytes) 前 16 位,前端持有的稳定 ref */
|
|
4417
|
-
attachmentId: external_exports.string().min(1),
|
|
4418
|
-
/** 完整 tunnel signed URL,前端拼 marker / 直接送 Anthropic 都用它 */
|
|
4419
|
-
url: external_exports.string().min(1),
|
|
4420
|
-
/** 落在 session 目录下的相对路径(后续 group RPC / drawer 展示用) */
|
|
4421
|
-
relPath: external_exports.string().min(1),
|
|
4422
|
-
sizeBytes: external_exports.number().int().nonnegative(),
|
|
4423
|
-
mimeType: external_exports.string().min(1)
|
|
4424
|
-
});
|
|
4425
4415
|
}
|
|
4426
4416
|
});
|
|
4427
4417
|
|
|
@@ -5635,8 +5625,8 @@ var require_req = __commonJS({
|
|
|
5635
5625
|
if (req.originalUrl) {
|
|
5636
5626
|
_req.url = req.originalUrl;
|
|
5637
5627
|
} else {
|
|
5638
|
-
const
|
|
5639
|
-
_req.url = typeof
|
|
5628
|
+
const path44 = req.path;
|
|
5629
|
+
_req.url = typeof path44 === "string" ? path44 : req.url ? req.url.path || req.url : void 0;
|
|
5640
5630
|
}
|
|
5641
5631
|
if (req.query) {
|
|
5642
5632
|
_req.query = req.query;
|
|
@@ -5801,14 +5791,14 @@ var require_redact = __commonJS({
|
|
|
5801
5791
|
}
|
|
5802
5792
|
return obj;
|
|
5803
5793
|
}
|
|
5804
|
-
function parsePath(
|
|
5794
|
+
function parsePath(path44) {
|
|
5805
5795
|
const parts = [];
|
|
5806
5796
|
let current = "";
|
|
5807
5797
|
let inBrackets = false;
|
|
5808
5798
|
let inQuotes = false;
|
|
5809
5799
|
let quoteChar = "";
|
|
5810
|
-
for (let i = 0; i <
|
|
5811
|
-
const char =
|
|
5800
|
+
for (let i = 0; i < path44.length; i++) {
|
|
5801
|
+
const char = path44[i];
|
|
5812
5802
|
if (!inBrackets && char === ".") {
|
|
5813
5803
|
if (current) {
|
|
5814
5804
|
parts.push(current);
|
|
@@ -5939,10 +5929,10 @@ var require_redact = __commonJS({
|
|
|
5939
5929
|
return current;
|
|
5940
5930
|
}
|
|
5941
5931
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
5942
|
-
for (const
|
|
5943
|
-
const parts = parsePath(
|
|
5932
|
+
for (const path44 of paths) {
|
|
5933
|
+
const parts = parsePath(path44);
|
|
5944
5934
|
if (parts.includes("*")) {
|
|
5945
|
-
redactWildcardPath(obj, parts, censor,
|
|
5935
|
+
redactWildcardPath(obj, parts, censor, path44, remove);
|
|
5946
5936
|
} else {
|
|
5947
5937
|
if (remove) {
|
|
5948
5938
|
removeKey(obj, parts);
|
|
@@ -6027,8 +6017,8 @@ var require_redact = __commonJS({
|
|
|
6027
6017
|
}
|
|
6028
6018
|
} else {
|
|
6029
6019
|
if (afterWildcard.includes("*")) {
|
|
6030
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6031
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
6020
|
+
const wrappedCensor = typeof censor === "function" ? (value, path44) => {
|
|
6021
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path44];
|
|
6032
6022
|
return censor(value, fullPath);
|
|
6033
6023
|
} : censor;
|
|
6034
6024
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6063,8 +6053,8 @@ var require_redact = __commonJS({
|
|
|
6063
6053
|
return null;
|
|
6064
6054
|
}
|
|
6065
6055
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6066
|
-
for (const
|
|
6067
|
-
const parts = parsePath(
|
|
6056
|
+
for (const path44 of pathsToClone) {
|
|
6057
|
+
const parts = parsePath(path44);
|
|
6068
6058
|
let current = pathStructure;
|
|
6069
6059
|
for (let i = 0; i < parts.length; i++) {
|
|
6070
6060
|
const part = parts[i];
|
|
@@ -6116,24 +6106,24 @@ var require_redact = __commonJS({
|
|
|
6116
6106
|
}
|
|
6117
6107
|
return cloneSelectively(obj, pathStructure);
|
|
6118
6108
|
}
|
|
6119
|
-
function validatePath(
|
|
6120
|
-
if (typeof
|
|
6109
|
+
function validatePath(path44) {
|
|
6110
|
+
if (typeof path44 !== "string") {
|
|
6121
6111
|
throw new Error("Paths must be (non-empty) strings");
|
|
6122
6112
|
}
|
|
6123
|
-
if (
|
|
6113
|
+
if (path44 === "") {
|
|
6124
6114
|
throw new Error("Invalid redaction path ()");
|
|
6125
6115
|
}
|
|
6126
|
-
if (
|
|
6127
|
-
throw new Error(`Invalid redaction path (${
|
|
6116
|
+
if (path44.includes("..")) {
|
|
6117
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6128
6118
|
}
|
|
6129
|
-
if (
|
|
6130
|
-
throw new Error(`Invalid redaction path (${
|
|
6119
|
+
if (path44.includes(",")) {
|
|
6120
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6131
6121
|
}
|
|
6132
6122
|
let bracketCount = 0;
|
|
6133
6123
|
let inQuotes = false;
|
|
6134
6124
|
let quoteChar = "";
|
|
6135
|
-
for (let i = 0; i <
|
|
6136
|
-
const char =
|
|
6125
|
+
for (let i = 0; i < path44.length; i++) {
|
|
6126
|
+
const char = path44[i];
|
|
6137
6127
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6138
6128
|
if (!inQuotes) {
|
|
6139
6129
|
inQuotes = true;
|
|
@@ -6147,20 +6137,20 @@ var require_redact = __commonJS({
|
|
|
6147
6137
|
} else if (char === "]" && !inQuotes) {
|
|
6148
6138
|
bracketCount--;
|
|
6149
6139
|
if (bracketCount < 0) {
|
|
6150
|
-
throw new Error(`Invalid redaction path (${
|
|
6140
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6151
6141
|
}
|
|
6152
6142
|
}
|
|
6153
6143
|
}
|
|
6154
6144
|
if (bracketCount !== 0) {
|
|
6155
|
-
throw new Error(`Invalid redaction path (${
|
|
6145
|
+
throw new Error(`Invalid redaction path (${path44})`);
|
|
6156
6146
|
}
|
|
6157
6147
|
}
|
|
6158
6148
|
function validatePaths(paths) {
|
|
6159
6149
|
if (!Array.isArray(paths)) {
|
|
6160
6150
|
throw new TypeError("paths must be an array");
|
|
6161
6151
|
}
|
|
6162
|
-
for (const
|
|
6163
|
-
validatePath(
|
|
6152
|
+
for (const path44 of paths) {
|
|
6153
|
+
validatePath(path44);
|
|
6164
6154
|
}
|
|
6165
6155
|
}
|
|
6166
6156
|
function slowRedact(options = {}) {
|
|
@@ -6328,8 +6318,8 @@ var require_redaction = __commonJS({
|
|
|
6328
6318
|
if (shape[k2] === null) {
|
|
6329
6319
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6330
6320
|
} else {
|
|
6331
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6332
|
-
return censor(value, [k2, ...
|
|
6321
|
+
const wrappedCensor = typeof censor === "function" ? (value, path44) => {
|
|
6322
|
+
return censor(value, [k2, ...path44]);
|
|
6333
6323
|
} : censor;
|
|
6334
6324
|
o[k2] = Redact({
|
|
6335
6325
|
paths: shape[k2],
|
|
@@ -6547,10 +6537,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
6547
6537
|
var require_sonic_boom = __commonJS({
|
|
6548
6538
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
6549
6539
|
"use strict";
|
|
6550
|
-
var
|
|
6540
|
+
var fs35 = require("fs");
|
|
6551
6541
|
var EventEmitter2 = require("events");
|
|
6552
6542
|
var inherits = require("util").inherits;
|
|
6553
|
-
var
|
|
6543
|
+
var path44 = require("path");
|
|
6554
6544
|
var sleep = require_atomic_sleep();
|
|
6555
6545
|
var assert = require("assert");
|
|
6556
6546
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6604,20 +6594,20 @@ var require_sonic_boom = __commonJS({
|
|
|
6604
6594
|
const mode = sonic.mode;
|
|
6605
6595
|
if (sonic.sync) {
|
|
6606
6596
|
try {
|
|
6607
|
-
if (sonic.mkdir)
|
|
6608
|
-
const fd =
|
|
6597
|
+
if (sonic.mkdir) fs35.mkdirSync(path44.dirname(file), { recursive: true });
|
|
6598
|
+
const fd = fs35.openSync(file, flags, mode);
|
|
6609
6599
|
fileOpened(null, fd);
|
|
6610
6600
|
} catch (err) {
|
|
6611
6601
|
fileOpened(err);
|
|
6612
6602
|
throw err;
|
|
6613
6603
|
}
|
|
6614
6604
|
} else if (sonic.mkdir) {
|
|
6615
|
-
|
|
6605
|
+
fs35.mkdir(path44.dirname(file), { recursive: true }, (err) => {
|
|
6616
6606
|
if (err) return fileOpened(err);
|
|
6617
|
-
|
|
6607
|
+
fs35.open(file, flags, mode, fileOpened);
|
|
6618
6608
|
});
|
|
6619
6609
|
} else {
|
|
6620
|
-
|
|
6610
|
+
fs35.open(file, flags, mode, fileOpened);
|
|
6621
6611
|
}
|
|
6622
6612
|
}
|
|
6623
6613
|
function SonicBoom(opts) {
|
|
@@ -6658,8 +6648,8 @@ var require_sonic_boom = __commonJS({
|
|
|
6658
6648
|
this.flush = flushBuffer;
|
|
6659
6649
|
this.flushSync = flushBufferSync;
|
|
6660
6650
|
this._actualWrite = actualWriteBuffer;
|
|
6661
|
-
fsWriteSync = () =>
|
|
6662
|
-
fsWrite = () =>
|
|
6651
|
+
fsWriteSync = () => fs35.writeSync(this.fd, this._writingBuf);
|
|
6652
|
+
fsWrite = () => fs35.write(this.fd, this._writingBuf, this.release);
|
|
6663
6653
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
6664
6654
|
this._writingBuf = "";
|
|
6665
6655
|
this.write = write;
|
|
@@ -6668,15 +6658,15 @@ var require_sonic_boom = __commonJS({
|
|
|
6668
6658
|
this._actualWrite = actualWrite;
|
|
6669
6659
|
fsWriteSync = () => {
|
|
6670
6660
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6671
|
-
return
|
|
6661
|
+
return fs35.writeSync(this.fd, this._writingBuf);
|
|
6672
6662
|
}
|
|
6673
|
-
return
|
|
6663
|
+
return fs35.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6674
6664
|
};
|
|
6675
6665
|
fsWrite = () => {
|
|
6676
6666
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6677
|
-
return
|
|
6667
|
+
return fs35.write(this.fd, this._writingBuf, this.release);
|
|
6678
6668
|
}
|
|
6679
|
-
return
|
|
6669
|
+
return fs35.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
6680
6670
|
};
|
|
6681
6671
|
} else {
|
|
6682
6672
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -6733,7 +6723,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6733
6723
|
}
|
|
6734
6724
|
}
|
|
6735
6725
|
if (this._fsync) {
|
|
6736
|
-
|
|
6726
|
+
fs35.fsyncSync(this.fd);
|
|
6737
6727
|
}
|
|
6738
6728
|
const len = this._len;
|
|
6739
6729
|
if (this._reopening) {
|
|
@@ -6847,7 +6837,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6847
6837
|
const onDrain = () => {
|
|
6848
6838
|
if (!this._fsync) {
|
|
6849
6839
|
try {
|
|
6850
|
-
|
|
6840
|
+
fs35.fsync(this.fd, (err) => {
|
|
6851
6841
|
this._flushPending = false;
|
|
6852
6842
|
cb(err);
|
|
6853
6843
|
});
|
|
@@ -6949,7 +6939,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6949
6939
|
const fd = this.fd;
|
|
6950
6940
|
this.once("ready", () => {
|
|
6951
6941
|
if (fd !== this.fd) {
|
|
6952
|
-
|
|
6942
|
+
fs35.close(fd, (err) => {
|
|
6953
6943
|
if (err) {
|
|
6954
6944
|
return this.emit("error", err);
|
|
6955
6945
|
}
|
|
@@ -6998,7 +6988,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6998
6988
|
buf = this._bufs[0];
|
|
6999
6989
|
}
|
|
7000
6990
|
try {
|
|
7001
|
-
const n = Buffer.isBuffer(buf) ?
|
|
6991
|
+
const n = Buffer.isBuffer(buf) ? fs35.writeSync(this.fd, buf) : fs35.writeSync(this.fd, buf, "utf8");
|
|
7002
6992
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
7003
6993
|
buf = releasedBufObj.writingBuf;
|
|
7004
6994
|
this._len = releasedBufObj.len;
|
|
@@ -7014,7 +7004,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7014
7004
|
}
|
|
7015
7005
|
}
|
|
7016
7006
|
try {
|
|
7017
|
-
|
|
7007
|
+
fs35.fsyncSync(this.fd);
|
|
7018
7008
|
} catch {
|
|
7019
7009
|
}
|
|
7020
7010
|
}
|
|
@@ -7035,7 +7025,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7035
7025
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
7036
7026
|
}
|
|
7037
7027
|
try {
|
|
7038
|
-
const n =
|
|
7028
|
+
const n = fs35.writeSync(this.fd, buf);
|
|
7039
7029
|
buf = buf.subarray(n);
|
|
7040
7030
|
this._len = Math.max(this._len - n, 0);
|
|
7041
7031
|
if (buf.length <= 0) {
|
|
@@ -7063,13 +7053,13 @@ var require_sonic_boom = __commonJS({
|
|
|
7063
7053
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
7064
7054
|
if (this.sync) {
|
|
7065
7055
|
try {
|
|
7066
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
7056
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs35.writeSync(this.fd, this._writingBuf) : fs35.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7067
7057
|
release(null, written);
|
|
7068
7058
|
} catch (err) {
|
|
7069
7059
|
release(err);
|
|
7070
7060
|
}
|
|
7071
7061
|
} else {
|
|
7072
|
-
|
|
7062
|
+
fs35.write(this.fd, this._writingBuf, release);
|
|
7073
7063
|
}
|
|
7074
7064
|
}
|
|
7075
7065
|
function actualWriteBuffer() {
|
|
@@ -7078,7 +7068,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7078
7068
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
7079
7069
|
if (this.sync) {
|
|
7080
7070
|
try {
|
|
7081
|
-
const written =
|
|
7071
|
+
const written = fs35.writeSync(this.fd, this._writingBuf);
|
|
7082
7072
|
release(null, written);
|
|
7083
7073
|
} catch (err) {
|
|
7084
7074
|
release(err);
|
|
@@ -7087,7 +7077,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7087
7077
|
if (kCopyBuffer) {
|
|
7088
7078
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
7089
7079
|
}
|
|
7090
|
-
|
|
7080
|
+
fs35.write(this.fd, this._writingBuf, release);
|
|
7091
7081
|
}
|
|
7092
7082
|
}
|
|
7093
7083
|
function actualClose(sonic) {
|
|
@@ -7103,12 +7093,12 @@ var require_sonic_boom = __commonJS({
|
|
|
7103
7093
|
sonic._lens = [];
|
|
7104
7094
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
7105
7095
|
try {
|
|
7106
|
-
|
|
7096
|
+
fs35.fsync(sonic.fd, closeWrapped);
|
|
7107
7097
|
} catch {
|
|
7108
7098
|
}
|
|
7109
7099
|
function closeWrapped() {
|
|
7110
7100
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
7111
|
-
|
|
7101
|
+
fs35.close(sonic.fd, done);
|
|
7112
7102
|
} else {
|
|
7113
7103
|
done();
|
|
7114
7104
|
}
|
|
@@ -7839,7 +7829,7 @@ var require_transport = __commonJS({
|
|
|
7839
7829
|
stream.flushSync();
|
|
7840
7830
|
}
|
|
7841
7831
|
function transport(fullOptions) {
|
|
7842
|
-
const { pipeline:
|
|
7832
|
+
const { pipeline: pipeline2, targets, levels, dedupe, worker = {}, caller = getCallers(), sync = false } = fullOptions;
|
|
7843
7833
|
const options = {
|
|
7844
7834
|
...fullOptions.options
|
|
7845
7835
|
};
|
|
@@ -7867,9 +7857,9 @@ var require_transport = __commonJS({
|
|
|
7867
7857
|
};
|
|
7868
7858
|
});
|
|
7869
7859
|
});
|
|
7870
|
-
} else if (
|
|
7860
|
+
} else if (pipeline2) {
|
|
7871
7861
|
target = bundlerOverrides["pino-worker"] || join11(__dirname, "worker.js");
|
|
7872
|
-
options.pipelines = [
|
|
7862
|
+
options.pipelines = [pipeline2.map((dest) => {
|
|
7873
7863
|
return {
|
|
7874
7864
|
...dest,
|
|
7875
7865
|
target: fixTarget(dest.target)
|
|
@@ -10243,11 +10233,11 @@ var init_lib = __esm({
|
|
|
10243
10233
|
}
|
|
10244
10234
|
}
|
|
10245
10235
|
},
|
|
10246
|
-
addToPath: function addToPath(
|
|
10247
|
-
var last =
|
|
10236
|
+
addToPath: function addToPath(path44, added, removed, oldPosInc, options) {
|
|
10237
|
+
var last = path44.lastComponent;
|
|
10248
10238
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10249
10239
|
return {
|
|
10250
|
-
oldPos:
|
|
10240
|
+
oldPos: path44.oldPos + oldPosInc,
|
|
10251
10241
|
lastComponent: {
|
|
10252
10242
|
count: last.count + 1,
|
|
10253
10243
|
added,
|
|
@@ -10257,7 +10247,7 @@ var init_lib = __esm({
|
|
|
10257
10247
|
};
|
|
10258
10248
|
} else {
|
|
10259
10249
|
return {
|
|
10260
|
-
oldPos:
|
|
10250
|
+
oldPos: path44.oldPos + oldPosInc,
|
|
10261
10251
|
lastComponent: {
|
|
10262
10252
|
count: 1,
|
|
10263
10253
|
added,
|
|
@@ -10688,10 +10678,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10688
10678
|
const memories = raw.map((m2) => {
|
|
10689
10679
|
if (!m2 || typeof m2 !== "object") return null;
|
|
10690
10680
|
const rec = m2;
|
|
10691
|
-
const
|
|
10681
|
+
const path44 = typeof rec.path === "string" ? rec.path : null;
|
|
10692
10682
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
10693
|
-
if (!
|
|
10694
|
-
const entry = { path:
|
|
10683
|
+
if (!path44 || content == null) return null;
|
|
10684
|
+
const entry = { path: path44, content };
|
|
10695
10685
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
10696
10686
|
return entry;
|
|
10697
10687
|
}).filter((m2) => m2 !== null);
|
|
@@ -11517,10 +11507,10 @@ function parseAttachment(obj) {
|
|
|
11517
11507
|
const memories = raw.map((m2) => {
|
|
11518
11508
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11519
11509
|
const rec = m2;
|
|
11520
|
-
const
|
|
11510
|
+
const path44 = typeof rec.path === "string" ? rec.path : null;
|
|
11521
11511
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11522
|
-
if (!
|
|
11523
|
-
const out = { path:
|
|
11512
|
+
if (!path44 || content == null) return null;
|
|
11513
|
+
const out = { path: path44, content };
|
|
11524
11514
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11525
11515
|
return out;
|
|
11526
11516
|
}).filter((m2) => m2 !== null);
|
|
@@ -20435,7 +20425,7 @@ var require_websocket_server = __commonJS({
|
|
|
20435
20425
|
// src/run-case/recorder.ts
|
|
20436
20426
|
function startRunCaseRecorder(opts) {
|
|
20437
20427
|
const now = opts.now ?? Date.now;
|
|
20438
|
-
const dir =
|
|
20428
|
+
const dir = import_node_path30.default.dirname(opts.recordPath);
|
|
20439
20429
|
let stream = null;
|
|
20440
20430
|
let closing = false;
|
|
20441
20431
|
let closedSettled = false;
|
|
@@ -20449,8 +20439,8 @@ function startRunCaseRecorder(opts) {
|
|
|
20449
20439
|
});
|
|
20450
20440
|
const ensureStream = () => {
|
|
20451
20441
|
if (stream) return stream;
|
|
20452
|
-
|
|
20453
|
-
stream =
|
|
20442
|
+
import_node_fs27.default.mkdirSync(dir, { recursive: true });
|
|
20443
|
+
stream = import_node_fs27.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
20454
20444
|
stream.on("close", () => closedResolve());
|
|
20455
20445
|
return stream;
|
|
20456
20446
|
};
|
|
@@ -20475,12 +20465,12 @@ function startRunCaseRecorder(opts) {
|
|
|
20475
20465
|
};
|
|
20476
20466
|
return { tap, close, closed };
|
|
20477
20467
|
}
|
|
20478
|
-
var
|
|
20468
|
+
var import_node_fs27, import_node_path30;
|
|
20479
20469
|
var init_recorder = __esm({
|
|
20480
20470
|
"src/run-case/recorder.ts"() {
|
|
20481
20471
|
"use strict";
|
|
20482
|
-
|
|
20483
|
-
|
|
20472
|
+
import_node_fs27 = __toESM(require("fs"), 1);
|
|
20473
|
+
import_node_path30 = __toESM(require("path"), 1);
|
|
20484
20474
|
}
|
|
20485
20475
|
});
|
|
20486
20476
|
|
|
@@ -20523,7 +20513,7 @@ var init_wire = __esm({
|
|
|
20523
20513
|
// src/run-case/controller.ts
|
|
20524
20514
|
async function runController(opts) {
|
|
20525
20515
|
const now = opts.now ?? Date.now;
|
|
20526
|
-
const cwd = opts.cwd ?? (0,
|
|
20516
|
+
const cwd = opts.cwd ?? (0, import_node_fs28.mkdtempSync)(import_node_path31.default.join(import_node_os15.default.tmpdir(), "clawd-runcase-"));
|
|
20527
20517
|
const ownsCwd = opts.cwd === void 0;
|
|
20528
20518
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
20529
20519
|
const spawnCtx = { cwd };
|
|
@@ -20684,19 +20674,19 @@ async function runController(opts) {
|
|
|
20684
20674
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
20685
20675
|
if (ownsCwd) {
|
|
20686
20676
|
try {
|
|
20687
|
-
(0,
|
|
20677
|
+
(0, import_node_fs28.rmSync)(cwd, { recursive: true, force: true });
|
|
20688
20678
|
} catch {
|
|
20689
20679
|
}
|
|
20690
20680
|
}
|
|
20691
20681
|
return exitCode ?? 0;
|
|
20692
20682
|
}
|
|
20693
|
-
var
|
|
20683
|
+
var import_node_fs28, import_node_os15, import_node_path31;
|
|
20694
20684
|
var init_controller = __esm({
|
|
20695
20685
|
"src/run-case/controller.ts"() {
|
|
20696
20686
|
"use strict";
|
|
20697
|
-
|
|
20687
|
+
import_node_fs28 = require("fs");
|
|
20698
20688
|
import_node_os15 = __toESM(require("os"), 1);
|
|
20699
|
-
|
|
20689
|
+
import_node_path31 = __toESM(require("path"), 1);
|
|
20700
20690
|
init_claude();
|
|
20701
20691
|
init_stdout_splitter();
|
|
20702
20692
|
init_permission_stdio();
|
|
@@ -20928,8 +20918,8 @@ Env (advanced):
|
|
|
20928
20918
|
`;
|
|
20929
20919
|
|
|
20930
20920
|
// src/index.ts
|
|
20931
|
-
var
|
|
20932
|
-
var
|
|
20921
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
20922
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
20933
20923
|
|
|
20934
20924
|
// src/logger.ts
|
|
20935
20925
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
@@ -22664,18 +22654,6 @@ var SessionManager = class {
|
|
|
22664
22654
|
(a, b2) => a.updatedAt > b2.updatedAt ? -1 : a.updatedAt < b2.updatedAt ? 1 : 0
|
|
22665
22655
|
);
|
|
22666
22656
|
}
|
|
22667
|
-
/**
|
|
22668
|
-
* 跨 scope 列出所有 owner 视角的 session(default + persona owner + persona guest),
|
|
22669
|
-
* 附带派生的 SessionScope。attachment GC tick 用 —— 需要遍历所有活跃 session 的
|
|
22670
|
-
* .attachments 目录 + 群文件清单求 liveSet。
|
|
22671
|
-
*/
|
|
22672
|
-
listOwnedSessionScopes() {
|
|
22673
|
-
return this.listAllOwned().map((file) => ({
|
|
22674
|
-
scope: this.scopeForFile(file),
|
|
22675
|
-
sessionId: file.sessionId,
|
|
22676
|
-
cwd: file.cwd
|
|
22677
|
-
}));
|
|
22678
|
-
}
|
|
22679
22657
|
// 写回 SessionFile,自动根据 ownerPersonaId / creatorPrincipalId 派生写入 scope.
|
|
22680
22658
|
// 调用方原先都是 `deps.store.write(updated)`,全部走这里收口路由.
|
|
22681
22659
|
writeOwned(file) {
|
|
@@ -22933,20 +22911,27 @@ var SessionManager = class {
|
|
|
22933
22911
|
// 非空)持久化到本机 default store。dumb write,**不广播 push 帧**——UI 是写入唯一源,
|
|
22934
22912
|
// 双写完成后通过 cache.setData 同步 sidebar 本地 state。
|
|
22935
22913
|
//
|
|
22936
|
-
// 强制走 deps.store(即 default scope),不走 scopeForFile
|
|
22937
|
-
// 远端 ownerPersonaId(远端 persona session),本机也落 default,不创建本机 persona 目录。
|
|
22914
|
+
// 强制走 deps.store(即 default scope),不走 scopeForFile:mirror 物理落 default 即可。
|
|
22938
22915
|
// 远端 creator / origin 字段原值保留(不被本机 ctx 派生覆写)。
|
|
22939
22916
|
//
|
|
22917
|
+
// strip 远端 personaId:mirror SessionFile 上的 ownerPersonaId 是朋友 daemon 的 persona
|
|
22918
|
+
// 目录 id,本机不持有对应 persona。留着会让按 ownerPersonaId 反查的本机消费者
|
|
22919
|
+
// (MyPersonasSection 等)把 mirror 误聚到同 id persona 下。写入前清掉。
|
|
22920
|
+
//
|
|
22940
22921
|
// 与 manager.create / manager.update 区别:
|
|
22941
22922
|
// - 不走 newRunner / attachObserver / cwd 校验(mirror 是纯 metadata 层)
|
|
22942
22923
|
// - 不发 session:info 帧(manager.create / .update 通过 reducer/wireCollector 发 push)
|
|
22943
22924
|
mirrorUpsert(file) {
|
|
22944
|
-
|
|
22945
|
-
|
|
22946
|
-
|
|
22947
|
-
//
|
|
22925
|
+
const { ownerPersonaId: _stripped, ...rest } = file;
|
|
22926
|
+
return this.deps.store.write(rest);
|
|
22927
|
+
}
|
|
22928
|
+
// mirror peer sessions:删本机 mirror SessionFile。**跟 listAllOwned 对称扫所有 scope**
|
|
22929
|
+
// (default + persona/owner + persona/guest)。光删 deps.store 会有 store.delete 返回
|
|
22930
|
+
// false 但 handler 仍 ack `peerSession:remove:ok` 的假象(文件落到 persona scope 时
|
|
22931
|
+
// listAllOwned 还能扫出来 → sidebar 刷新页面 mirror 复活)。deleteOwned 跟 listAllOwned
|
|
22932
|
+
// 一对,对账齐全。idempotent:找不到不 throw。**不广播 session:deleted**。
|
|
22948
22933
|
mirrorRemove(sessionId) {
|
|
22949
|
-
this.
|
|
22934
|
+
this.deleteOwned(sessionId);
|
|
22950
22935
|
}
|
|
22951
22936
|
// observer 上报"jsonl 写入了一条 user 行"时调用:在 buffer 里找到与之对应的、
|
|
22952
22937
|
// 还没建立映射的最早一条 synth user_text,记下 synth → real 映射。
|
|
@@ -27185,8 +27170,8 @@ function rmdirIfEmpty(p2) {
|
|
|
27185
27170
|
}
|
|
27186
27171
|
|
|
27187
27172
|
// src/transport/http-router.ts
|
|
27188
|
-
var
|
|
27189
|
-
var
|
|
27173
|
+
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
27174
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
27190
27175
|
|
|
27191
27176
|
// src/attachment/mime.ts
|
|
27192
27177
|
var import_node_path16 = __toESM(require("path"), 1);
|
|
@@ -27364,137 +27349,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
27364
27349
|
return { ok: true, absPath };
|
|
27365
27350
|
}
|
|
27366
27351
|
|
|
27367
|
-
// src/attachment/upload.ts
|
|
27368
|
-
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
27369
|
-
var import_node_path17 = __toESM(require("path"), 1);
|
|
27370
|
-
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
27371
|
-
var import_promises = require("stream/promises");
|
|
27372
|
-
var UploadError = class extends Error {
|
|
27373
|
-
constructor(code, message) {
|
|
27374
|
-
super(message);
|
|
27375
|
-
this.code = code;
|
|
27376
|
-
this.name = "UploadError";
|
|
27377
|
-
}
|
|
27378
|
-
code;
|
|
27379
|
-
};
|
|
27380
|
-
function assertValidFileName(fileName) {
|
|
27381
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path17.default.basename(fileName)) {
|
|
27382
|
-
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
27383
|
-
}
|
|
27384
|
-
}
|
|
27385
|
-
var HASH_PREFIX_LEN = 16;
|
|
27386
|
-
async function writeUploadedAttachment(args) {
|
|
27387
|
-
assertValidFileName(args.fileName);
|
|
27388
|
-
const attachmentsRoot = import_node_path17.default.join(args.sessionDir, ".attachments");
|
|
27389
|
-
try {
|
|
27390
|
-
import_node_fs15.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
27391
|
-
} catch (err) {
|
|
27392
|
-
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
27393
|
-
}
|
|
27394
|
-
const hasher = import_node_crypto6.default.createHash("sha256");
|
|
27395
|
-
let actualSize = 0;
|
|
27396
|
-
const tmpPath = import_node_path17.default.join(
|
|
27397
|
-
attachmentsRoot,
|
|
27398
|
-
`.upload-${process.pid}-${Date.now()}-${import_node_crypto6.default.randomBytes(4).toString("hex")}`
|
|
27399
|
-
);
|
|
27400
|
-
try {
|
|
27401
|
-
await (0, import_promises.pipeline)(
|
|
27402
|
-
args.body,
|
|
27403
|
-
async function* (source) {
|
|
27404
|
-
for await (const chunk of source) {
|
|
27405
|
-
const buf = chunk;
|
|
27406
|
-
actualSize += buf.length;
|
|
27407
|
-
hasher.update(buf);
|
|
27408
|
-
yield buf;
|
|
27409
|
-
}
|
|
27410
|
-
},
|
|
27411
|
-
import_node_fs15.default.createWriteStream(tmpPath, { mode: 384 })
|
|
27412
|
-
);
|
|
27413
|
-
} catch (err) {
|
|
27414
|
-
try {
|
|
27415
|
-
import_node_fs15.default.unlinkSync(tmpPath);
|
|
27416
|
-
} catch {
|
|
27417
|
-
}
|
|
27418
|
-
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
27419
|
-
}
|
|
27420
|
-
if (actualSize !== args.contentLength) {
|
|
27421
|
-
try {
|
|
27422
|
-
import_node_fs15.default.unlinkSync(tmpPath);
|
|
27423
|
-
} catch {
|
|
27424
|
-
}
|
|
27425
|
-
throw new UploadError(
|
|
27426
|
-
"SIZE_MISMATCH",
|
|
27427
|
-
`expected ${args.contentLength} bytes, got ${actualSize}`
|
|
27428
|
-
);
|
|
27429
|
-
}
|
|
27430
|
-
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
27431
|
-
const hashDir = import_node_path17.default.join(attachmentsRoot, attachmentId);
|
|
27432
|
-
let finalFileName;
|
|
27433
|
-
let hashDirExists = false;
|
|
27434
|
-
try {
|
|
27435
|
-
hashDirExists = import_node_fs15.default.statSync(hashDir).isDirectory();
|
|
27436
|
-
} catch {
|
|
27437
|
-
}
|
|
27438
|
-
if (hashDirExists) {
|
|
27439
|
-
const existing = import_node_fs15.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
|
|
27440
|
-
finalFileName = existing[0] ?? args.fileName;
|
|
27441
|
-
try {
|
|
27442
|
-
import_node_fs15.default.unlinkSync(tmpPath);
|
|
27443
|
-
} catch {
|
|
27444
|
-
}
|
|
27445
|
-
} else {
|
|
27446
|
-
try {
|
|
27447
|
-
import_node_fs15.default.mkdirSync(hashDir, { recursive: true });
|
|
27448
|
-
finalFileName = args.fileName;
|
|
27449
|
-
import_node_fs15.default.renameSync(tmpPath, import_node_path17.default.join(hashDir, finalFileName));
|
|
27450
|
-
} catch (err) {
|
|
27451
|
-
try {
|
|
27452
|
-
import_node_fs15.default.unlinkSync(tmpPath);
|
|
27453
|
-
} catch {
|
|
27454
|
-
}
|
|
27455
|
-
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
27456
|
-
}
|
|
27457
|
-
}
|
|
27458
|
-
const absPath = import_node_path17.default.join(hashDir, finalFileName);
|
|
27459
|
-
const relPath = import_node_path17.default.relative(args.sessionDir, absPath);
|
|
27460
|
-
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
27461
|
-
relPath: absPath,
|
|
27462
|
-
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
27463
|
-
from: "user-upload",
|
|
27464
|
-
label: args.fileName,
|
|
27465
|
-
size: actualSize,
|
|
27466
|
-
mime: args.mimeType
|
|
27467
|
-
});
|
|
27468
|
-
return { attachmentId, absPath, relPath, sizeBytes: actualSize, mimeType: args.mimeType };
|
|
27469
|
-
}
|
|
27470
|
-
|
|
27471
27352
|
// src/transport/http-router.ts
|
|
27472
|
-
var UPLOAD_MIME_ALLOW = /* @__PURE__ */ new Set([
|
|
27473
|
-
"image/png",
|
|
27474
|
-
"image/jpeg",
|
|
27475
|
-
"image/gif",
|
|
27476
|
-
"image/webp",
|
|
27477
|
-
"application/pdf"
|
|
27478
|
-
]);
|
|
27479
|
-
var UPLOAD_MIME_ALLOW_PREFIX = ["text/"];
|
|
27480
|
-
var UPLOAD_MAX_BYTES = 25 * 1024 * 1024;
|
|
27481
|
-
var UPLOAD_CORS_HEADERS = {
|
|
27482
|
-
"Access-Control-Allow-Origin": "*",
|
|
27483
|
-
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
27484
|
-
"Access-Control-Allow-Headers": "Authorization, Content-Type",
|
|
27485
|
-
"Access-Control-Max-Age": "86400"
|
|
27486
|
-
};
|
|
27487
|
-
function isUploadMimeAllowed(mime) {
|
|
27488
|
-
if (UPLOAD_MIME_ALLOW.has(mime)) return true;
|
|
27489
|
-
return UPLOAD_MIME_ALLOW_PREFIX.some((p2) => mime.startsWith(p2));
|
|
27490
|
-
}
|
|
27491
|
-
function isValidUploadFileName(fileName) {
|
|
27492
|
-
if (fileName.length === 0) return false;
|
|
27493
|
-
if (fileName === "." || fileName === "..") return false;
|
|
27494
|
-
if (fileName.startsWith(".")) return false;
|
|
27495
|
-
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
27496
|
-
return fileName === import_node_path18.default.basename(fileName);
|
|
27497
|
-
}
|
|
27498
27353
|
function createHttpRouter(deps) {
|
|
27499
27354
|
return async (req, res) => {
|
|
27500
27355
|
const url = parseUrl(req.url);
|
|
@@ -27508,14 +27363,9 @@ function createHttpRouter(deps) {
|
|
|
27508
27363
|
});
|
|
27509
27364
|
return true;
|
|
27510
27365
|
}
|
|
27511
|
-
if (!url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/")
|
|
27366
|
+
if (!url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/")) {
|
|
27512
27367
|
return false;
|
|
27513
27368
|
}
|
|
27514
|
-
if (url.pathname === "/attachments/upload" && req.method === "OPTIONS") {
|
|
27515
|
-
res.writeHead(204, UPLOAD_CORS_HEADERS);
|
|
27516
|
-
res.end();
|
|
27517
|
-
return true;
|
|
27518
|
-
}
|
|
27519
27369
|
if (url.pathname.startsWith("/files/") && req.method === "GET") {
|
|
27520
27370
|
const secret = deps.getSignSecret?.();
|
|
27521
27371
|
if (!secret) {
|
|
@@ -27553,107 +27403,6 @@ function createHttpRouter(deps) {
|
|
|
27553
27403
|
sendJson(res, 401, { code: "UNAUTHORIZED", message: "missing or invalid bearer token" });
|
|
27554
27404
|
return true;
|
|
27555
27405
|
}
|
|
27556
|
-
if (url.pathname === "/attachments/upload" && req.method === "POST") {
|
|
27557
|
-
const sendUploadJson = (status, body) => sendJson(res, status, body, UPLOAD_CORS_HEADERS);
|
|
27558
|
-
if (ctx.role !== "owner") {
|
|
27559
|
-
sendUploadJson(403, { code: "FORBIDDEN", message: "owner only" });
|
|
27560
|
-
return true;
|
|
27561
|
-
}
|
|
27562
|
-
const up = deps.attachmentUpload;
|
|
27563
|
-
if (!up) {
|
|
27564
|
-
sendUploadJson(501, { code: "NOT_IMPLEMENTED", message: "attachment upload not wired" });
|
|
27565
|
-
return true;
|
|
27566
|
-
}
|
|
27567
|
-
const sessionId = url.searchParams.get("sessionId");
|
|
27568
|
-
const fileName = url.searchParams.get("fileName");
|
|
27569
|
-
const mimeType = url.searchParams.get("mimeType");
|
|
27570
|
-
const contentLengthRaw = req.headers["content-length"];
|
|
27571
|
-
if (!sessionId || !fileName || !mimeType || !contentLengthRaw) {
|
|
27572
|
-
sendUploadJson(400, {
|
|
27573
|
-
code: "INVALID_PARAM",
|
|
27574
|
-
message: "missing sessionId/fileName/mimeType/Content-Length"
|
|
27575
|
-
});
|
|
27576
|
-
return true;
|
|
27577
|
-
}
|
|
27578
|
-
if (!isValidUploadFileName(fileName)) {
|
|
27579
|
-
sendUploadJson(400, {
|
|
27580
|
-
code: "INVALID_FILENAME",
|
|
27581
|
-
message: `fileName must be a plain basename (no path separators, no dotfiles): ${fileName}`
|
|
27582
|
-
});
|
|
27583
|
-
return true;
|
|
27584
|
-
}
|
|
27585
|
-
const contentLength = Number.parseInt(contentLengthRaw, 10);
|
|
27586
|
-
if (!Number.isFinite(contentLength) || contentLength < 0) {
|
|
27587
|
-
sendUploadJson(400, { code: "INVALID_PARAM", message: "malformed Content-Length" });
|
|
27588
|
-
return true;
|
|
27589
|
-
}
|
|
27590
|
-
if (contentLength > UPLOAD_MAX_BYTES) {
|
|
27591
|
-
sendUploadJson(413, {
|
|
27592
|
-
code: "FILE_TOO_LARGE",
|
|
27593
|
-
message: `max ${UPLOAD_MAX_BYTES} bytes`
|
|
27594
|
-
});
|
|
27595
|
-
return true;
|
|
27596
|
-
}
|
|
27597
|
-
if (!isUploadMimeAllowed(mimeType)) {
|
|
27598
|
-
sendUploadJson(400, {
|
|
27599
|
-
code: "UNSUPPORTED_MIME",
|
|
27600
|
-
message: `mime ${mimeType} not allowed`
|
|
27601
|
-
});
|
|
27602
|
-
return true;
|
|
27603
|
-
}
|
|
27604
|
-
const sessionDir = up.getSessionDir(sessionId);
|
|
27605
|
-
const scope = up.getSessionScope(sessionId);
|
|
27606
|
-
if (!sessionDir || !scope) {
|
|
27607
|
-
sendUploadJson(404, { code: "NOT_FOUND", message: `session ${sessionId} not found` });
|
|
27608
|
-
return true;
|
|
27609
|
-
}
|
|
27610
|
-
const httpBaseUrl = up.getHttpBaseUrl();
|
|
27611
|
-
if (!httpBaseUrl) {
|
|
27612
|
-
sendUploadJson(503, {
|
|
27613
|
-
code: "TUNNEL_NOT_READY",
|
|
27614
|
-
message: "httpBaseUrl unavailable"
|
|
27615
|
-
});
|
|
27616
|
-
return true;
|
|
27617
|
-
}
|
|
27618
|
-
const secret = deps.getSignSecret?.();
|
|
27619
|
-
if (!secret) {
|
|
27620
|
-
sendUploadJson(501, {
|
|
27621
|
-
code: "NOT_IMPLEMENTED",
|
|
27622
|
-
message: "sign secret unavailable (noAuth?)"
|
|
27623
|
-
});
|
|
27624
|
-
return true;
|
|
27625
|
-
}
|
|
27626
|
-
try {
|
|
27627
|
-
const result = await writeUploadedAttachment({
|
|
27628
|
-
sessionDir,
|
|
27629
|
-
sessionId,
|
|
27630
|
-
scope,
|
|
27631
|
-
fileName,
|
|
27632
|
-
mimeType,
|
|
27633
|
-
contentLength,
|
|
27634
|
-
body: req,
|
|
27635
|
-
groupFileStore: up.groupFileStore
|
|
27636
|
-
});
|
|
27637
|
-
const parts = signUrlParts(secret, result.absPath, null);
|
|
27638
|
-
const fullUrl = buildSignedFileUrl(httpBaseUrl, parts);
|
|
27639
|
-
sendUploadJson(200, {
|
|
27640
|
-
attachmentId: result.attachmentId,
|
|
27641
|
-
url: fullUrl,
|
|
27642
|
-
relPath: result.relPath,
|
|
27643
|
-
sizeBytes: result.sizeBytes,
|
|
27644
|
-
mimeType: result.mimeType
|
|
27645
|
-
});
|
|
27646
|
-
} catch (err) {
|
|
27647
|
-
if (err instanceof UploadError) {
|
|
27648
|
-
const status = err.code === "SIZE_MISMATCH" ? 400 : 500;
|
|
27649
|
-
sendUploadJson(status, { code: err.code, message: err.message });
|
|
27650
|
-
} else {
|
|
27651
|
-
deps.logger?.warn("attachment upload failed", { err: err.message });
|
|
27652
|
-
sendUploadJson(500, { code: "STORAGE_ERROR", message: err.message });
|
|
27653
|
-
}
|
|
27654
|
-
}
|
|
27655
|
-
return true;
|
|
27656
|
-
}
|
|
27657
27406
|
const sessionFilesMatch = url.pathname.match(/^\/session\/([^/]+)\/files$/);
|
|
27658
27407
|
if (sessionFilesMatch && req.method === "GET") {
|
|
27659
27408
|
const sid = sessionFilesMatch[1];
|
|
@@ -27663,7 +27412,7 @@ function createHttpRouter(deps) {
|
|
|
27663
27412
|
return true;
|
|
27664
27413
|
}
|
|
27665
27414
|
let absPath;
|
|
27666
|
-
if (
|
|
27415
|
+
if (import_node_path17.default.isAbsolute(pathParam)) {
|
|
27667
27416
|
absPath = pathParam;
|
|
27668
27417
|
} else if (deps.sessionStore) {
|
|
27669
27418
|
const file = deps.sessionStore.read(sid);
|
|
@@ -27671,7 +27420,7 @@ function createHttpRouter(deps) {
|
|
|
27671
27420
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
27672
27421
|
return true;
|
|
27673
27422
|
}
|
|
27674
|
-
absPath =
|
|
27423
|
+
absPath = import_node_path17.default.join(file.cwd, pathParam);
|
|
27675
27424
|
} else {
|
|
27676
27425
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
27677
27426
|
return true;
|
|
@@ -27704,7 +27453,7 @@ function withCtx(ctx, body) {
|
|
|
27704
27453
|
function streamFile(res, absPath, logger) {
|
|
27705
27454
|
let stat;
|
|
27706
27455
|
try {
|
|
27707
|
-
stat =
|
|
27456
|
+
stat = import_node_fs15.default.statSync(absPath);
|
|
27708
27457
|
} catch (err) {
|
|
27709
27458
|
const code = err?.code;
|
|
27710
27459
|
if (code === "ENOENT") {
|
|
@@ -27719,7 +27468,7 @@ function streamFile(res, absPath, logger) {
|
|
|
27719
27468
|
return;
|
|
27720
27469
|
}
|
|
27721
27470
|
const mime = lookupMime(absPath);
|
|
27722
|
-
const basename =
|
|
27471
|
+
const basename = import_node_path17.default.basename(absPath);
|
|
27723
27472
|
res.writeHead(200, {
|
|
27724
27473
|
"Content-Type": mime,
|
|
27725
27474
|
"Content-Length": String(stat.size),
|
|
@@ -27727,7 +27476,7 @@ function streamFile(res, absPath, logger) {
|
|
|
27727
27476
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
27728
27477
|
"X-Content-Type-Options": "nosniff"
|
|
27729
27478
|
});
|
|
27730
|
-
const stream =
|
|
27479
|
+
const stream = import_node_fs15.default.createReadStream(absPath);
|
|
27731
27480
|
stream.on("error", (err) => {
|
|
27732
27481
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
27733
27482
|
res.destroy();
|
|
@@ -27735,78 +27484,10 @@ function streamFile(res, absPath, logger) {
|
|
|
27735
27484
|
stream.pipe(res);
|
|
27736
27485
|
}
|
|
27737
27486
|
|
|
27738
|
-
// src/attachment/gc.ts
|
|
27739
|
-
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
27740
|
-
var import_node_path19 = __toESM(require("path"), 1);
|
|
27741
|
-
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
27742
|
-
function runAttachmentGc(args) {
|
|
27743
|
-
const now = (args.now ?? Date.now)();
|
|
27744
|
-
const ttlMs = args.ttlMs ?? DEFAULT_TTL_MS;
|
|
27745
|
-
const liveAbs = /* @__PURE__ */ new Set();
|
|
27746
|
-
for (const { scope, sessionId } of args.sessionScopes) {
|
|
27747
|
-
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
27748
|
-
if (entry.stale) continue;
|
|
27749
|
-
if (import_node_path19.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
27750
|
-
}
|
|
27751
|
-
}
|
|
27752
|
-
for (const { scope, sessionId } of args.sessionScopes) {
|
|
27753
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path19.default.join(
|
|
27754
|
-
args.dataDir,
|
|
27755
|
-
"sessions",
|
|
27756
|
-
...scopeSubPath(scope).map(safeFileName),
|
|
27757
|
-
safeFileName(sessionId)
|
|
27758
|
-
);
|
|
27759
|
-
const attRoot = import_node_path19.default.join(sessionDir, ".attachments");
|
|
27760
|
-
let hashDirs;
|
|
27761
|
-
try {
|
|
27762
|
-
hashDirs = import_node_fs17.default.readdirSync(attRoot);
|
|
27763
|
-
} catch (err) {
|
|
27764
|
-
if (err.code === "ENOENT") continue;
|
|
27765
|
-
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
27766
|
-
continue;
|
|
27767
|
-
}
|
|
27768
|
-
for (const hashDir of hashDirs) {
|
|
27769
|
-
const hashDirAbs = import_node_path19.default.join(attRoot, hashDir);
|
|
27770
|
-
let files;
|
|
27771
|
-
try {
|
|
27772
|
-
files = import_node_fs17.default.readdirSync(hashDirAbs);
|
|
27773
|
-
} catch {
|
|
27774
|
-
continue;
|
|
27775
|
-
}
|
|
27776
|
-
for (const name of files) {
|
|
27777
|
-
const file = import_node_path19.default.join(hashDirAbs, name);
|
|
27778
|
-
let stat;
|
|
27779
|
-
try {
|
|
27780
|
-
stat = import_node_fs17.default.statSync(file);
|
|
27781
|
-
} catch {
|
|
27782
|
-
continue;
|
|
27783
|
-
}
|
|
27784
|
-
if (!stat.isFile()) continue;
|
|
27785
|
-
const age = now - stat.mtimeMs;
|
|
27786
|
-
if (age < ttlMs) continue;
|
|
27787
|
-
if (liveAbs.has(file)) continue;
|
|
27788
|
-
try {
|
|
27789
|
-
import_node_fs17.default.unlinkSync(file);
|
|
27790
|
-
} catch (err) {
|
|
27791
|
-
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
27792
|
-
}
|
|
27793
|
-
}
|
|
27794
|
-
try {
|
|
27795
|
-
if (import_node_fs17.default.readdirSync(hashDirAbs).length === 0) import_node_fs17.default.rmdirSync(hashDirAbs);
|
|
27796
|
-
} catch {
|
|
27797
|
-
}
|
|
27798
|
-
}
|
|
27799
|
-
try {
|
|
27800
|
-
if (import_node_fs17.default.readdirSync(attRoot).length === 0) import_node_fs17.default.rmdirSync(attRoot);
|
|
27801
|
-
} catch {
|
|
27802
|
-
}
|
|
27803
|
-
}
|
|
27804
|
-
}
|
|
27805
|
-
|
|
27806
27487
|
// src/attachment/group.ts
|
|
27807
|
-
var
|
|
27808
|
-
var
|
|
27809
|
-
var
|
|
27488
|
+
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
27489
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
27490
|
+
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
27810
27491
|
init_protocol();
|
|
27811
27492
|
var GroupFileStore = class {
|
|
27812
27493
|
dataDir;
|
|
@@ -27817,11 +27498,11 @@ var GroupFileStore = class {
|
|
|
27817
27498
|
this.logger = opts.logger;
|
|
27818
27499
|
}
|
|
27819
27500
|
rootForScope(scope) {
|
|
27820
|
-
return
|
|
27501
|
+
return import_node_path18.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
27821
27502
|
}
|
|
27822
27503
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
27823
27504
|
filePath(scope, sessionId) {
|
|
27824
|
-
return
|
|
27505
|
+
return import_node_path18.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
27825
27506
|
}
|
|
27826
27507
|
cacheKey(scope, sessionId) {
|
|
27827
27508
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -27830,7 +27511,7 @@ var GroupFileStore = class {
|
|
|
27830
27511
|
readFile(scope, sessionId) {
|
|
27831
27512
|
const file = this.filePath(scope, sessionId);
|
|
27832
27513
|
try {
|
|
27833
|
-
const raw =
|
|
27514
|
+
const raw = import_node_fs16.default.readFileSync(file, "utf8");
|
|
27834
27515
|
const parsed = JSON.parse(raw);
|
|
27835
27516
|
if (!Array.isArray(parsed)) {
|
|
27836
27517
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -27856,10 +27537,10 @@ var GroupFileStore = class {
|
|
|
27856
27537
|
}
|
|
27857
27538
|
writeFile(scope, sessionId, entries) {
|
|
27858
27539
|
const file = this.filePath(scope, sessionId);
|
|
27859
|
-
|
|
27540
|
+
import_node_fs16.default.mkdirSync(import_node_path18.default.dirname(file), { recursive: true });
|
|
27860
27541
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
27861
|
-
|
|
27862
|
-
|
|
27542
|
+
import_node_fs16.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
27543
|
+
import_node_fs16.default.renameSync(tmp, file);
|
|
27863
27544
|
}
|
|
27864
27545
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
27865
27546
|
list(scope, sessionId) {
|
|
@@ -27895,7 +27576,7 @@ var GroupFileStore = class {
|
|
|
27895
27576
|
entries[idx] = next;
|
|
27896
27577
|
} else {
|
|
27897
27578
|
next = {
|
|
27898
|
-
id: `gf-${
|
|
27579
|
+
id: `gf-${import_node_crypto6.default.randomBytes(6).toString("base64url")}`,
|
|
27899
27580
|
relPath: input.relPath,
|
|
27900
27581
|
from: input.from,
|
|
27901
27582
|
label: input.label,
|
|
@@ -27945,10 +27626,10 @@ var GroupFileStore = class {
|
|
|
27945
27626
|
};
|
|
27946
27627
|
|
|
27947
27628
|
// src/discovery/state-file.ts
|
|
27948
|
-
var
|
|
27949
|
-
var
|
|
27629
|
+
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
27630
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
27950
27631
|
function defaultStateFilePath(dataDir) {
|
|
27951
|
-
return
|
|
27632
|
+
return import_node_path19.default.join(dataDir, "state.json");
|
|
27952
27633
|
}
|
|
27953
27634
|
function isPidAlive(pid) {
|
|
27954
27635
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -27970,7 +27651,7 @@ var StateFileManager = class {
|
|
|
27970
27651
|
}
|
|
27971
27652
|
read() {
|
|
27972
27653
|
try {
|
|
27973
|
-
const raw =
|
|
27654
|
+
const raw = import_node_fs17.default.readFileSync(this.file, "utf8");
|
|
27974
27655
|
const parsed = JSON.parse(raw);
|
|
27975
27656
|
return parsed;
|
|
27976
27657
|
} catch {
|
|
@@ -27984,34 +27665,34 @@ var StateFileManager = class {
|
|
|
27984
27665
|
return { status: "stale", existing };
|
|
27985
27666
|
}
|
|
27986
27667
|
write(state) {
|
|
27987
|
-
|
|
27668
|
+
import_node_fs17.default.mkdirSync(import_node_path19.default.dirname(this.file), { recursive: true });
|
|
27988
27669
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
27989
|
-
|
|
27990
|
-
|
|
27670
|
+
import_node_fs17.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
27671
|
+
import_node_fs17.default.renameSync(tmp, this.file);
|
|
27991
27672
|
if (process.platform !== "win32") {
|
|
27992
27673
|
try {
|
|
27993
|
-
|
|
27674
|
+
import_node_fs17.default.chmodSync(this.file, 384);
|
|
27994
27675
|
} catch {
|
|
27995
27676
|
}
|
|
27996
27677
|
}
|
|
27997
27678
|
}
|
|
27998
27679
|
delete() {
|
|
27999
27680
|
try {
|
|
28000
|
-
|
|
27681
|
+
import_node_fs17.default.unlinkSync(this.file);
|
|
28001
27682
|
} catch {
|
|
28002
27683
|
}
|
|
28003
27684
|
}
|
|
28004
27685
|
};
|
|
28005
27686
|
|
|
28006
27687
|
// src/tunnel/tunnel-manager.ts
|
|
28007
|
-
var
|
|
28008
|
-
var
|
|
28009
|
-
var
|
|
27688
|
+
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
27689
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
27690
|
+
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
28010
27691
|
var import_node_child_process5 = require("child_process");
|
|
28011
27692
|
|
|
28012
27693
|
// src/tunnel/tunnel-store.ts
|
|
28013
|
-
var
|
|
28014
|
-
var
|
|
27694
|
+
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
27695
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
28015
27696
|
var TunnelStore = class {
|
|
28016
27697
|
constructor(filePath) {
|
|
28017
27698
|
this.filePath = filePath;
|
|
@@ -28019,7 +27700,7 @@ var TunnelStore = class {
|
|
|
28019
27700
|
filePath;
|
|
28020
27701
|
async get() {
|
|
28021
27702
|
try {
|
|
28022
|
-
const raw = await
|
|
27703
|
+
const raw = await import_node_fs18.default.promises.readFile(this.filePath, "utf8");
|
|
28023
27704
|
const obj = JSON.parse(raw);
|
|
28024
27705
|
if (!isPersistedTunnel(obj)) return null;
|
|
28025
27706
|
return obj;
|
|
@@ -28030,22 +27711,22 @@ var TunnelStore = class {
|
|
|
28030
27711
|
}
|
|
28031
27712
|
}
|
|
28032
27713
|
async set(v2) {
|
|
28033
|
-
const dir =
|
|
28034
|
-
await
|
|
27714
|
+
const dir = import_node_path20.default.dirname(this.filePath);
|
|
27715
|
+
await import_node_fs18.default.promises.mkdir(dir, { recursive: true });
|
|
28035
27716
|
const data = JSON.stringify(v2, null, 2);
|
|
28036
27717
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
28037
|
-
await
|
|
27718
|
+
await import_node_fs18.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
28038
27719
|
if (process.platform !== "win32") {
|
|
28039
27720
|
try {
|
|
28040
|
-
await
|
|
27721
|
+
await import_node_fs18.default.promises.chmod(tmp, 384);
|
|
28041
27722
|
} catch {
|
|
28042
27723
|
}
|
|
28043
27724
|
}
|
|
28044
|
-
await
|
|
27725
|
+
await import_node_fs18.default.promises.rename(tmp, this.filePath);
|
|
28045
27726
|
}
|
|
28046
27727
|
async clear() {
|
|
28047
27728
|
try {
|
|
28048
|
-
await
|
|
27729
|
+
await import_node_fs18.default.promises.unlink(this.filePath);
|
|
28049
27730
|
} catch (err) {
|
|
28050
27731
|
const code = err?.code;
|
|
28051
27732
|
if (code !== "ENOENT") throw err;
|
|
@@ -28140,12 +27821,12 @@ function escape(v2) {
|
|
|
28140
27821
|
}
|
|
28141
27822
|
|
|
28142
27823
|
// src/tunnel/frpc-binary.ts
|
|
28143
|
-
var
|
|
27824
|
+
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
28144
27825
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
28145
|
-
var
|
|
27826
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
28146
27827
|
var import_node_child_process3 = require("child_process");
|
|
28147
27828
|
var import_node_stream2 = require("stream");
|
|
28148
|
-
var
|
|
27829
|
+
var import_promises = require("stream/promises");
|
|
28149
27830
|
var FRPC_VERSION = "0.68.0";
|
|
28150
27831
|
var UnsupportedPlatformError = class extends Error {
|
|
28151
27832
|
constructor(platform, arch) {
|
|
@@ -28174,20 +27855,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
28174
27855
|
}
|
|
28175
27856
|
async function ensureFrpcBinary(opts) {
|
|
28176
27857
|
if (opts.override) {
|
|
28177
|
-
if (!
|
|
27858
|
+
if (!import_node_fs19.default.existsSync(opts.override)) {
|
|
28178
27859
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
28179
27860
|
}
|
|
28180
27861
|
return opts.override;
|
|
28181
27862
|
}
|
|
28182
27863
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
28183
27864
|
const platform = opts.platform ?? detectPlatform();
|
|
28184
|
-
const binDir =
|
|
28185
|
-
|
|
27865
|
+
const binDir = import_node_path21.default.join(opts.dataDir, "bin");
|
|
27866
|
+
import_node_fs19.default.mkdirSync(binDir, { recursive: true });
|
|
28186
27867
|
cleanupStaleArtifacts(binDir);
|
|
28187
|
-
const stableBin =
|
|
28188
|
-
if (
|
|
27868
|
+
const stableBin = import_node_path21.default.join(binDir, "frpc");
|
|
27869
|
+
if (import_node_fs19.default.existsSync(stableBin)) return stableBin;
|
|
28189
27870
|
const partialBin = `${stableBin}.partial`;
|
|
28190
|
-
const tarballPath =
|
|
27871
|
+
const tarballPath = import_node_path21.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
28191
27872
|
try {
|
|
28192
27873
|
const url = frpcDownloadUrl(version2, platform);
|
|
28193
27874
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -28196,8 +27877,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
28196
27877
|
} else {
|
|
28197
27878
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
28198
27879
|
}
|
|
28199
|
-
|
|
28200
|
-
|
|
27880
|
+
import_node_fs19.default.chmodSync(partialBin, 493);
|
|
27881
|
+
import_node_fs19.default.renameSync(partialBin, stableBin);
|
|
28201
27882
|
} finally {
|
|
28202
27883
|
safeUnlink(tarballPath);
|
|
28203
27884
|
safeUnlink(partialBin);
|
|
@@ -28207,15 +27888,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
28207
27888
|
function cleanupStaleArtifacts(binDir) {
|
|
28208
27889
|
let entries;
|
|
28209
27890
|
try {
|
|
28210
|
-
entries =
|
|
27891
|
+
entries = import_node_fs19.default.readdirSync(binDir);
|
|
28211
27892
|
} catch {
|
|
28212
27893
|
return;
|
|
28213
27894
|
}
|
|
28214
27895
|
for (const name of entries) {
|
|
28215
27896
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
28216
|
-
const full =
|
|
27897
|
+
const full = import_node_path21.default.join(binDir, name);
|
|
28217
27898
|
try {
|
|
28218
|
-
|
|
27899
|
+
import_node_fs19.default.rmSync(full, { recursive: true, force: true });
|
|
28219
27900
|
} catch {
|
|
28220
27901
|
}
|
|
28221
27902
|
}
|
|
@@ -28223,7 +27904,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
28223
27904
|
}
|
|
28224
27905
|
function safeUnlink(p2) {
|
|
28225
27906
|
try {
|
|
28226
|
-
|
|
27907
|
+
import_node_fs19.default.unlinkSync(p2);
|
|
28227
27908
|
} catch {
|
|
28228
27909
|
}
|
|
28229
27910
|
}
|
|
@@ -28234,13 +27915,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
28234
27915
|
if (!res.ok || !res.body) {
|
|
28235
27916
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
28236
27917
|
}
|
|
28237
|
-
const out =
|
|
27918
|
+
const out = import_node_fs19.default.createWriteStream(dest);
|
|
28238
27919
|
const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
|
|
28239
|
-
await (0,
|
|
27920
|
+
await (0, import_promises.pipeline)(nodeStream, out);
|
|
28240
27921
|
}
|
|
28241
27922
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
28242
|
-
const work =
|
|
28243
|
-
|
|
27923
|
+
const work = import_node_path21.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
27924
|
+
import_node_fs19.default.mkdirSync(work, { recursive: true });
|
|
28244
27925
|
try {
|
|
28245
27926
|
await new Promise((resolve6, reject) => {
|
|
28246
27927
|
const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -28248,32 +27929,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
28248
27929
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
28249
27930
|
});
|
|
28250
27931
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
28251
|
-
const src =
|
|
28252
|
-
if (!
|
|
27932
|
+
const src = import_node_path21.default.join(work, dirName, "frpc");
|
|
27933
|
+
if (!import_node_fs19.default.existsSync(src)) {
|
|
28253
27934
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
28254
27935
|
}
|
|
28255
|
-
|
|
27936
|
+
import_node_fs19.default.copyFileSync(src, destBin);
|
|
28256
27937
|
} finally {
|
|
28257
|
-
|
|
27938
|
+
import_node_fs19.default.rmSync(work, { recursive: true, force: true });
|
|
28258
27939
|
}
|
|
28259
27940
|
}
|
|
28260
27941
|
|
|
28261
27942
|
// src/tunnel/frpc-process.ts
|
|
28262
|
-
var
|
|
28263
|
-
var
|
|
27943
|
+
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
27944
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
28264
27945
|
var import_node_child_process4 = require("child_process");
|
|
28265
27946
|
function frpcPidFilePath(dataDir) {
|
|
28266
|
-
return
|
|
27947
|
+
return import_node_path22.default.join(dataDir, "frpc.pid");
|
|
28267
27948
|
}
|
|
28268
27949
|
function writeFrpcPid(dataDir, pid) {
|
|
28269
27950
|
try {
|
|
28270
|
-
|
|
27951
|
+
import_node_fs20.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
28271
27952
|
} catch {
|
|
28272
27953
|
}
|
|
28273
27954
|
}
|
|
28274
27955
|
function clearFrpcPid(dataDir) {
|
|
28275
27956
|
try {
|
|
28276
|
-
|
|
27957
|
+
import_node_fs20.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
28277
27958
|
} catch {
|
|
28278
27959
|
}
|
|
28279
27960
|
}
|
|
@@ -28289,7 +27970,7 @@ function defaultIsPidAlive(pid) {
|
|
|
28289
27970
|
}
|
|
28290
27971
|
function defaultReadPidFile(file) {
|
|
28291
27972
|
try {
|
|
28292
|
-
return
|
|
27973
|
+
return import_node_fs20.default.readFileSync(file, "utf8");
|
|
28293
27974
|
} catch {
|
|
28294
27975
|
return null;
|
|
28295
27976
|
}
|
|
@@ -28305,7 +27986,7 @@ function defaultSleep(ms) {
|
|
|
28305
27986
|
}
|
|
28306
27987
|
async function killStaleFrpc(deps) {
|
|
28307
27988
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
28308
|
-
const tomlPath =
|
|
27989
|
+
const tomlPath = import_node_path22.default.join(deps.dataDir, "frpc.toml");
|
|
28309
27990
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
28310
27991
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
28311
27992
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -28329,7 +28010,7 @@ async function killStaleFrpc(deps) {
|
|
|
28329
28010
|
}
|
|
28330
28011
|
if (victims.size === 0) {
|
|
28331
28012
|
try {
|
|
28332
|
-
|
|
28013
|
+
import_node_fs20.default.unlinkSync(pidFile);
|
|
28333
28014
|
} catch {
|
|
28334
28015
|
}
|
|
28335
28016
|
return;
|
|
@@ -28340,7 +28021,7 @@ async function killStaleFrpc(deps) {
|
|
|
28340
28021
|
}
|
|
28341
28022
|
await sleep(deps.reapWaitMs ?? 300);
|
|
28342
28023
|
try {
|
|
28343
|
-
|
|
28024
|
+
import_node_fs20.default.unlinkSync(pidFile);
|
|
28344
28025
|
} catch {
|
|
28345
28026
|
}
|
|
28346
28027
|
}
|
|
@@ -28377,7 +28058,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
28377
28058
|
var TunnelManager = class {
|
|
28378
28059
|
constructor(deps) {
|
|
28379
28060
|
this.deps = deps;
|
|
28380
|
-
this.store = deps.store ?? new TunnelStore(
|
|
28061
|
+
this.store = deps.store ?? new TunnelStore(import_node_path23.default.join(deps.dataDir, "tunnel.json"));
|
|
28381
28062
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
28382
28063
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
28383
28064
|
}
|
|
@@ -28504,8 +28185,8 @@ var TunnelManager = class {
|
|
|
28504
28185
|
dataDir: this.deps.dataDir,
|
|
28505
28186
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
28506
28187
|
});
|
|
28507
|
-
const tomlPath =
|
|
28508
|
-
const proxyName = `clawd-${t.subdomain}-${localPort}-${
|
|
28188
|
+
const tomlPath = import_node_path23.default.join(this.deps.dataDir, "frpc.toml");
|
|
28189
|
+
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
|
|
28509
28190
|
const toml = buildFrpcToml({
|
|
28510
28191
|
serverAddr: t.frpsHost,
|
|
28511
28192
|
serverPort: t.frpsPort,
|
|
@@ -28515,12 +28196,12 @@ var TunnelManager = class {
|
|
|
28515
28196
|
localPort,
|
|
28516
28197
|
logLevel: "info"
|
|
28517
28198
|
});
|
|
28518
|
-
await
|
|
28199
|
+
await import_node_fs21.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
28519
28200
|
const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
|
|
28520
28201
|
stdio: ["ignore", "pipe", "pipe"]
|
|
28521
28202
|
});
|
|
28522
|
-
const logFilePath =
|
|
28523
|
-
const logStream =
|
|
28203
|
+
const logFilePath = import_node_path23.default.join(this.deps.dataDir, "frpc.log");
|
|
28204
|
+
const logStream = import_node_fs21.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
28524
28205
|
logStream.on("error", () => {
|
|
28525
28206
|
});
|
|
28526
28207
|
const tee = (chunk) => {
|
|
@@ -28603,22 +28284,22 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
28603
28284
|
|
|
28604
28285
|
// src/tunnel/device-key.ts
|
|
28605
28286
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
28606
|
-
var
|
|
28287
|
+
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
28607
28288
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
28608
28289
|
function deriveStableDeviceKey(opts = {}) {
|
|
28609
28290
|
const hostname = opts.hostname ?? import_node_os11.default.hostname();
|
|
28610
28291
|
const uid = opts.uid ?? (typeof import_node_os11.default.userInfo === "function" ? import_node_os11.default.userInfo().uid : 0);
|
|
28611
28292
|
const input = `${hostname}::${uid}`;
|
|
28612
|
-
return
|
|
28293
|
+
return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
28613
28294
|
}
|
|
28614
28295
|
|
|
28615
28296
|
// src/auth-store.ts
|
|
28616
|
-
var
|
|
28617
|
-
var
|
|
28618
|
-
var
|
|
28297
|
+
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
28298
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
28299
|
+
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
28619
28300
|
var AUTH_FILE_NAME = "auth.json";
|
|
28620
28301
|
function authFilePath(dataDir) {
|
|
28621
|
-
return
|
|
28302
|
+
return import_node_path24.default.join(dataDir, AUTH_FILE_NAME);
|
|
28622
28303
|
}
|
|
28623
28304
|
function loadOrCreateAuthFile(opts) {
|
|
28624
28305
|
const file = authFilePath(opts.dataDir);
|
|
@@ -28643,14 +28324,14 @@ function loadOrCreateAuthFile(opts) {
|
|
|
28643
28324
|
return next;
|
|
28644
28325
|
}
|
|
28645
28326
|
function defaultGenerateToken2() {
|
|
28646
|
-
return
|
|
28327
|
+
return import_node_crypto9.default.randomBytes(32).toString("base64url");
|
|
28647
28328
|
}
|
|
28648
28329
|
function defaultGenerateOwnerPrincipalId() {
|
|
28649
|
-
return `owner-${
|
|
28330
|
+
return `owner-${import_node_crypto9.default.randomUUID()}`;
|
|
28650
28331
|
}
|
|
28651
28332
|
function readAuthFile(file) {
|
|
28652
28333
|
try {
|
|
28653
|
-
const raw =
|
|
28334
|
+
const raw = import_node_fs22.default.readFileSync(file, "utf8");
|
|
28654
28335
|
const parsed = JSON.parse(raw);
|
|
28655
28336
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
28656
28337
|
return null;
|
|
@@ -28668,25 +28349,25 @@ function readAuthFile(file) {
|
|
|
28668
28349
|
}
|
|
28669
28350
|
}
|
|
28670
28351
|
function writeAuthFile(file, content) {
|
|
28671
|
-
|
|
28672
|
-
|
|
28352
|
+
import_node_fs22.default.mkdirSync(import_node_path24.default.dirname(file), { recursive: true });
|
|
28353
|
+
import_node_fs22.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
28673
28354
|
try {
|
|
28674
|
-
|
|
28355
|
+
import_node_fs22.default.chmodSync(file, 384);
|
|
28675
28356
|
} catch {
|
|
28676
28357
|
}
|
|
28677
28358
|
}
|
|
28678
28359
|
|
|
28679
28360
|
// src/owner-profile.ts
|
|
28680
|
-
var
|
|
28361
|
+
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
28681
28362
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
28682
|
-
var
|
|
28363
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
28683
28364
|
var PROFILE_FILENAME = "profile.json";
|
|
28684
28365
|
function loadOwnerDisplayName(dataDir) {
|
|
28685
28366
|
const fallback = import_node_os12.default.userInfo().username;
|
|
28686
|
-
const profilePath =
|
|
28367
|
+
const profilePath = import_node_path25.default.join(dataDir, PROFILE_FILENAME);
|
|
28687
28368
|
let raw;
|
|
28688
28369
|
try {
|
|
28689
|
-
raw =
|
|
28370
|
+
raw = import_node_fs23.default.readFileSync(profilePath, "utf8");
|
|
28690
28371
|
} catch {
|
|
28691
28372
|
return fallback;
|
|
28692
28373
|
}
|
|
@@ -28715,12 +28396,12 @@ init_protocol();
|
|
|
28715
28396
|
init_protocol();
|
|
28716
28397
|
|
|
28717
28398
|
// src/session/fork.ts
|
|
28718
|
-
var
|
|
28399
|
+
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
28719
28400
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
28720
|
-
var
|
|
28401
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
28721
28402
|
init_claude_history();
|
|
28722
28403
|
function readJsonlEntries(file) {
|
|
28723
|
-
const raw =
|
|
28404
|
+
const raw = import_node_fs24.default.readFileSync(file, "utf8");
|
|
28724
28405
|
const out = [];
|
|
28725
28406
|
for (const line of raw.split("\n")) {
|
|
28726
28407
|
const t = line.trim();
|
|
@@ -28733,10 +28414,10 @@ function readJsonlEntries(file) {
|
|
|
28733
28414
|
return out;
|
|
28734
28415
|
}
|
|
28735
28416
|
function forkSession(input) {
|
|
28736
|
-
const baseDir = input.baseDir ??
|
|
28737
|
-
const projectDir =
|
|
28738
|
-
const sourceFile =
|
|
28739
|
-
if (!
|
|
28417
|
+
const baseDir = input.baseDir ?? import_node_path26.default.join(import_node_os13.default.homedir(), ".claude");
|
|
28418
|
+
const projectDir = import_node_path26.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
28419
|
+
const sourceFile = import_node_path26.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
28420
|
+
if (!import_node_fs24.default.existsSync(sourceFile)) {
|
|
28740
28421
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
28741
28422
|
}
|
|
28742
28423
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -28766,9 +28447,9 @@ function forkSession(input) {
|
|
|
28766
28447
|
}
|
|
28767
28448
|
forkedLines.push(JSON.stringify(forked));
|
|
28768
28449
|
}
|
|
28769
|
-
const forkedFilePath =
|
|
28770
|
-
|
|
28771
|
-
|
|
28450
|
+
const forkedFilePath = import_node_path26.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
28451
|
+
import_node_fs24.default.mkdirSync(projectDir, { recursive: true });
|
|
28452
|
+
import_node_fs24.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
28772
28453
|
return { forkedToolSessionId, forkedFilePath };
|
|
28773
28454
|
}
|
|
28774
28455
|
|
|
@@ -29124,7 +28805,7 @@ function buildPermissionHandlers(deps) {
|
|
|
29124
28805
|
}
|
|
29125
28806
|
|
|
29126
28807
|
// src/handlers/history.ts
|
|
29127
|
-
var
|
|
28808
|
+
var path36 = __toESM(require("path"), 1);
|
|
29128
28809
|
init_protocol();
|
|
29129
28810
|
|
|
29130
28811
|
// src/session/recent-dirs.ts
|
|
@@ -29142,7 +28823,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
29142
28823
|
}
|
|
29143
28824
|
|
|
29144
28825
|
// src/permission/persona-paths.ts
|
|
29145
|
-
var
|
|
28826
|
+
var path35 = __toESM(require("path"), 1);
|
|
29146
28827
|
function getAllowedPersonaIds(grants, action) {
|
|
29147
28828
|
const ids = /* @__PURE__ */ new Set();
|
|
29148
28829
|
for (const g2 of grants) {
|
|
@@ -29155,26 +28836,26 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
29155
28836
|
return ids;
|
|
29156
28837
|
}
|
|
29157
28838
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read") {
|
|
29158
|
-
const root =
|
|
29159
|
-
const target =
|
|
29160
|
-
const sep3 = root.endsWith(
|
|
28839
|
+
const root = path35.resolve(personaRoot);
|
|
28840
|
+
const target = path35.resolve(absPath);
|
|
28841
|
+
const sep3 = root.endsWith(path35.sep) ? "" : path35.sep;
|
|
29161
28842
|
if (!target.startsWith(root + sep3)) return false;
|
|
29162
|
-
const rel =
|
|
28843
|
+
const rel = path35.relative(root, target);
|
|
29163
28844
|
if (!rel || rel.startsWith("..")) return false;
|
|
29164
|
-
const personaId = rel.split(
|
|
28845
|
+
const personaId = rel.split(path35.sep)[0];
|
|
29165
28846
|
if (!personaId) return false;
|
|
29166
28847
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
29167
28848
|
if (allowed === "*") return true;
|
|
29168
28849
|
return allowed.has(personaId);
|
|
29169
28850
|
}
|
|
29170
28851
|
function personaIdFromPath(absPath, personaRoot) {
|
|
29171
|
-
const root =
|
|
29172
|
-
const target =
|
|
29173
|
-
const sep3 = root.endsWith(
|
|
28852
|
+
const root = path35.resolve(personaRoot);
|
|
28853
|
+
const target = path35.resolve(absPath);
|
|
28854
|
+
const sep3 = root.endsWith(path35.sep) ? "" : path35.sep;
|
|
29174
28855
|
if (!target.startsWith(root + sep3)) return null;
|
|
29175
|
-
const rel =
|
|
28856
|
+
const rel = path35.relative(root, target);
|
|
29176
28857
|
if (!rel || rel.startsWith("..")) return null;
|
|
29177
|
-
const id = rel.split(
|
|
28858
|
+
const id = rel.split(path35.sep)[0];
|
|
29178
28859
|
return id || null;
|
|
29179
28860
|
}
|
|
29180
28861
|
|
|
@@ -29199,7 +28880,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29199
28880
|
if (!pid) return false;
|
|
29200
28881
|
return isGuestPathAllowed(
|
|
29201
28882
|
ctx.grants,
|
|
29202
|
-
|
|
28883
|
+
path36.join(personaRoot, pid),
|
|
29203
28884
|
personaRoot,
|
|
29204
28885
|
"read"
|
|
29205
28886
|
);
|
|
@@ -29210,7 +28891,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29210
28891
|
};
|
|
29211
28892
|
const list = async (frame, _client, ctx) => {
|
|
29212
28893
|
const args = HistoryListArgs.parse(frame);
|
|
29213
|
-
assertGuestPath(ctx,
|
|
28894
|
+
assertGuestPath(ctx, path36.resolve(args.projectPath), personaRoot, "history:list");
|
|
29214
28895
|
const sessions = await history.listSessions(args);
|
|
29215
28896
|
return { response: { type: "history:list", sessions } };
|
|
29216
28897
|
};
|
|
@@ -29242,13 +28923,13 @@ function buildHistoryHandlers(deps) {
|
|
|
29242
28923
|
};
|
|
29243
28924
|
const subagents = async (frame, _client, ctx) => {
|
|
29244
28925
|
const args = HistorySubagentsArgs.parse(frame);
|
|
29245
|
-
assertGuestPath(ctx,
|
|
28926
|
+
assertGuestPath(ctx, path36.resolve(args.cwd), personaRoot, "history:subagents");
|
|
29246
28927
|
const subs = await history.listSubagents(args);
|
|
29247
28928
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
29248
28929
|
};
|
|
29249
28930
|
const subagentRead = async (frame, _client, ctx) => {
|
|
29250
28931
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
29251
|
-
assertGuestPath(ctx,
|
|
28932
|
+
assertGuestPath(ctx, path36.resolve(args.cwd), personaRoot, "history:subagent-read");
|
|
29252
28933
|
const res = await history.readSubagent(args);
|
|
29253
28934
|
return { response: { type: "history:subagent-read", ...res } };
|
|
29254
28935
|
};
|
|
@@ -29256,7 +28937,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29256
28937
|
const dirs = listRecentDirs(store);
|
|
29257
28938
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
29258
28939
|
const filtered = dirs.filter(
|
|
29259
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
28940
|
+
(d) => isGuestPathAllowed(ctx.grants, path36.resolve(d.cwd), personaRoot, "read")
|
|
29260
28941
|
);
|
|
29261
28942
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
29262
28943
|
}
|
|
@@ -29273,7 +28954,7 @@ function buildHistoryHandlers(deps) {
|
|
|
29273
28954
|
}
|
|
29274
28955
|
|
|
29275
28956
|
// src/handlers/workspace.ts
|
|
29276
|
-
var
|
|
28957
|
+
var path37 = __toESM(require("path"), 1);
|
|
29277
28958
|
var os14 = __toESM(require("os"), 1);
|
|
29278
28959
|
init_protocol();
|
|
29279
28960
|
init_protocol();
|
|
@@ -29314,22 +28995,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29314
28995
|
const args = WorkspaceListArgs.parse(frame);
|
|
29315
28996
|
const isGuest = ctx?.principal.kind === "guest";
|
|
29316
28997
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os14.homedir();
|
|
29317
|
-
const resolvedCwd =
|
|
29318
|
-
const target = args.path ?
|
|
28998
|
+
const resolvedCwd = path37.resolve(args.cwd ?? fallbackCwd);
|
|
28999
|
+
const target = args.path ? path37.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
29319
29000
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list");
|
|
29320
29001
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
29321
29002
|
return { response: { type: "workspace:list", ...res } };
|
|
29322
29003
|
};
|
|
29323
29004
|
const read = async (frame, _client, ctx) => {
|
|
29324
29005
|
const args = WorkspaceReadArgs.parse(frame);
|
|
29325
|
-
const target =
|
|
29006
|
+
const target = path37.isAbsolute(args.path) ? path37.resolve(args.path) : path37.resolve(args.cwd, args.path);
|
|
29326
29007
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read");
|
|
29327
29008
|
const res = workspace.read(args);
|
|
29328
29009
|
return { response: { type: "workspace:read", ...res } };
|
|
29329
29010
|
};
|
|
29330
29011
|
const skillsList = async (frame, _client, ctx) => {
|
|
29331
29012
|
const args = SkillsListArgs.parse(frame);
|
|
29332
|
-
const cwdAbs =
|
|
29013
|
+
const cwdAbs = path37.resolve(args.cwd);
|
|
29333
29014
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
|
|
29334
29015
|
const list2 = skills.list(args);
|
|
29335
29016
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -29341,7 +29022,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29341
29022
|
};
|
|
29342
29023
|
const agentsList = async (frame, _client, ctx) => {
|
|
29343
29024
|
const args = AgentsListArgs.parse(frame);
|
|
29344
|
-
const cwdAbs =
|
|
29025
|
+
const cwdAbs = path37.resolve(args.cwd);
|
|
29345
29026
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
|
|
29346
29027
|
const list2 = agents.list(args);
|
|
29347
29028
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -29360,20 +29041,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
29360
29041
|
}
|
|
29361
29042
|
|
|
29362
29043
|
// src/handlers/git.ts
|
|
29363
|
-
var
|
|
29044
|
+
var path39 = __toESM(require("path"), 1);
|
|
29364
29045
|
init_protocol();
|
|
29365
29046
|
init_protocol();
|
|
29366
29047
|
|
|
29367
29048
|
// src/workspace/git.ts
|
|
29368
29049
|
var import_node_child_process6 = require("child_process");
|
|
29369
|
-
var
|
|
29370
|
-
var
|
|
29050
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
29051
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
29371
29052
|
var import_node_util = require("util");
|
|
29372
29053
|
var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
|
|
29373
29054
|
function normalizePath(p2) {
|
|
29374
|
-
const resolved =
|
|
29055
|
+
const resolved = import_node_path27.default.resolve(p2);
|
|
29375
29056
|
try {
|
|
29376
|
-
return
|
|
29057
|
+
return import_node_fs25.default.realpathSync(resolved);
|
|
29377
29058
|
} catch {
|
|
29378
29059
|
return resolved;
|
|
29379
29060
|
}
|
|
@@ -29446,7 +29127,7 @@ async function listGitBranches(cwd) {
|
|
|
29446
29127
|
// src/handlers/git.ts
|
|
29447
29128
|
function assertGuestCwd(ctx, cwd, personaRoot, method) {
|
|
29448
29129
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
29449
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
29130
|
+
if (!isGuestPathAllowed(ctx.grants, path39.resolve(cwd), personaRoot, "read")) {
|
|
29450
29131
|
throw new ClawdError(
|
|
29451
29132
|
ERROR_CODES.UNAUTHORIZED,
|
|
29452
29133
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -29933,7 +29614,7 @@ function buildPersonaHandlers(deps) {
|
|
|
29933
29614
|
}
|
|
29934
29615
|
|
|
29935
29616
|
// src/handlers/attachment.ts
|
|
29936
|
-
var
|
|
29617
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
29937
29618
|
init_protocol();
|
|
29938
29619
|
init_protocol();
|
|
29939
29620
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -29987,12 +29668,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
29987
29668
|
`session ${args.sessionId} scope unresolved`
|
|
29988
29669
|
);
|
|
29989
29670
|
}
|
|
29990
|
-
const cwdAbs =
|
|
29991
|
-
const candidateAbs =
|
|
29671
|
+
const cwdAbs = import_node_path28.default.resolve(sessionFile.cwd);
|
|
29672
|
+
const candidateAbs = import_node_path28.default.isAbsolute(args.relPath) ? import_node_path28.default.resolve(args.relPath) : import_node_path28.default.resolve(cwdAbs, args.relPath);
|
|
29992
29673
|
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
|
|
29993
29674
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
29994
29675
|
const entry = entries.find((e) => {
|
|
29995
|
-
const storedAbs =
|
|
29676
|
+
const storedAbs = import_node_path28.default.isAbsolute(e.relPath) ? import_node_path28.default.resolve(e.relPath) : import_node_path28.default.resolve(cwdAbs, e.relPath);
|
|
29996
29677
|
return storedAbs === candidateAbs && !e.stale;
|
|
29997
29678
|
});
|
|
29998
29679
|
if (!entry) {
|
|
@@ -30016,7 +29697,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
30016
29697
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
30017
29698
|
const f = deps.sessionStore.read(sessionId);
|
|
30018
29699
|
if (!f) return;
|
|
30019
|
-
assertGuestAttachmentPath(ctx,
|
|
29700
|
+
assertGuestAttachmentPath(ctx, import_node_path28.default.resolve(f.cwd), deps.personaRoot, method);
|
|
30020
29701
|
}
|
|
30021
29702
|
const groupAdd = async (frame, _client, ctx) => {
|
|
30022
29703
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -30057,7 +29738,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
30057
29738
|
}
|
|
30058
29739
|
const entries = deps.groupFileStore.list(scope, parsed.data.sessionId);
|
|
30059
29740
|
const target = entries.find((e) => e.relPath === parsed.data.relPath);
|
|
30060
|
-
if (target?.from === "owner"
|
|
29741
|
+
if (target?.from === "owner") {
|
|
30061
29742
|
deps.groupFileStore.remove(scope, parsed.data.sessionId, parsed.data.relPath);
|
|
30062
29743
|
} else {
|
|
30063
29744
|
deps.groupFileStore.markStale(scope, parsed.data.sessionId, parsed.data.relPath);
|
|
@@ -30258,7 +29939,7 @@ function computeGrantForFrame(method, frame) {
|
|
|
30258
29939
|
async function startDaemon(config) {
|
|
30259
29940
|
const logger = createLogger({
|
|
30260
29941
|
level: config.logLevel,
|
|
30261
|
-
file:
|
|
29942
|
+
file: import_node_path29.default.join(config.dataDir, "clawd.log")
|
|
30262
29943
|
});
|
|
30263
29944
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
30264
29945
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -30345,7 +30026,7 @@ async function startDaemon(config) {
|
|
|
30345
30026
|
const agents = new AgentsScanner();
|
|
30346
30027
|
const history = new ClaudeHistoryReader();
|
|
30347
30028
|
let transport = null;
|
|
30348
|
-
const personaStore = new PersonaStore(
|
|
30029
|
+
const personaStore = new PersonaStore(import_node_path29.default.join(config.dataDir, "personas"));
|
|
30349
30030
|
const defaultsRoot = findDefaultsRoot();
|
|
30350
30031
|
if (defaultsRoot) {
|
|
30351
30032
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -30362,7 +30043,7 @@ async function startDaemon(config) {
|
|
|
30362
30043
|
getAdapter,
|
|
30363
30044
|
historyReader: history,
|
|
30364
30045
|
dataDir: config.dataDir,
|
|
30365
|
-
personaRoot:
|
|
30046
|
+
personaRoot: import_node_path29.default.join(config.dataDir, "personas"),
|
|
30366
30047
|
personaStore,
|
|
30367
30048
|
ownerDisplayName,
|
|
30368
30049
|
ownerPrincipalId,
|
|
@@ -30386,10 +30067,10 @@ async function startDaemon(config) {
|
|
|
30386
30067
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
30387
30068
|
attachmentGroup: {
|
|
30388
30069
|
onFileEdit: (input) => {
|
|
30389
|
-
const absPath =
|
|
30070
|
+
const absPath = import_node_path29.default.isAbsolute(input.relPath) ? input.relPath : import_node_path29.default.join(input.cwd, input.relPath);
|
|
30390
30071
|
let size = 0;
|
|
30391
30072
|
try {
|
|
30392
|
-
size =
|
|
30073
|
+
size = import_node_fs26.default.statSync(absPath).size;
|
|
30393
30074
|
} catch (err) {
|
|
30394
30075
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
30395
30076
|
sessionId: input.sessionId,
|
|
@@ -30507,10 +30188,10 @@ async function startDaemon(config) {
|
|
|
30507
30188
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
30508
30189
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
30509
30190
|
// guest path guard:candidate 必须在 personaRoot 子树下
|
|
30510
|
-
personaRoot:
|
|
30191
|
+
personaRoot: import_node_path29.default.join(config.dataDir, "personas")
|
|
30511
30192
|
},
|
|
30512
30193
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
30513
|
-
personaRoot:
|
|
30194
|
+
personaRoot: import_node_path29.default.join(config.dataDir, "personas"),
|
|
30514
30195
|
// capability:list / delete handler 依赖
|
|
30515
30196
|
capabilityManager,
|
|
30516
30197
|
// personal-cap:get 返回的 shareBaseUrl 用此 base URL:
|
|
@@ -30546,19 +30227,7 @@ async function startDaemon(config) {
|
|
|
30546
30227
|
sessionStore: store,
|
|
30547
30228
|
// /files HMAC verify 用 auth.json 的 signSecret 字段(与 attachment.signUrl 同源)。
|
|
30548
30229
|
// --auth-token CLI 模式没 signSecret → 路由返 501,sign URL 功能整体禁用。
|
|
30549
|
-
getSignSecret: () => authFile?.signSecret ?? null
|
|
30550
|
-
// chatinput 附件上传(POST /attachments/upload,spec §6.1)。upload pipeline
|
|
30551
|
-
// 在 session.cwd 下的 .attachments/ 落盘;signSecret 与 /files HMAC 同源;
|
|
30552
|
-
// tunnel 未启时返 503 TUNNEL_NOT_READY 让前端显式提示。
|
|
30553
|
-
attachmentUpload: {
|
|
30554
|
-
groupFileStore,
|
|
30555
|
-
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
30556
|
-
getSessionDir: (sid) => {
|
|
30557
|
-
const f = manager.findOwnedSession(sid);
|
|
30558
|
-
return f ? f.cwd : null;
|
|
30559
|
-
},
|
|
30560
|
-
getHttpBaseUrl: () => currentTunnelUrl ? getHttpBaseUrl() : null
|
|
30561
|
-
}
|
|
30230
|
+
getSignSecret: () => authFile?.signSecret ?? null
|
|
30562
30231
|
});
|
|
30563
30232
|
wsServer = new LocalWsServer({
|
|
30564
30233
|
host: config.host,
|
|
@@ -30723,8 +30392,8 @@ async function startDaemon(config) {
|
|
|
30723
30392
|
const lines = [
|
|
30724
30393
|
`Tunnel: ${r.url}`,
|
|
30725
30394
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
30726
|
-
`Frpc config: ${
|
|
30727
|
-
`Frpc log: ${
|
|
30395
|
+
`Frpc config: ${import_node_path29.default.join(config.dataDir, "frpc.toml")}`,
|
|
30396
|
+
`Frpc log: ${import_node_path29.default.join(config.dataDir, "frpc.log")}`
|
|
30728
30397
|
];
|
|
30729
30398
|
const width = Math.max(...lines.map((l) => l.length));
|
|
30730
30399
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -30737,8 +30406,8 @@ ${bar}
|
|
|
30737
30406
|
|
|
30738
30407
|
`);
|
|
30739
30408
|
try {
|
|
30740
|
-
const connectPath =
|
|
30741
|
-
|
|
30409
|
+
const connectPath = import_node_path29.default.join(config.dataDir, "connect.txt");
|
|
30410
|
+
import_node_fs26.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
30742
30411
|
} catch {
|
|
30743
30412
|
}
|
|
30744
30413
|
} catch (err) {
|
|
@@ -30763,29 +30432,8 @@ ${bar}
|
|
|
30763
30432
|
logger.warn("tunnel unavailable, degraded to local mode", { reason: tunnelError });
|
|
30764
30433
|
}
|
|
30765
30434
|
}
|
|
30766
|
-
const tickAttachmentGc = () => {
|
|
30767
|
-
try {
|
|
30768
|
-
runAttachmentGc({
|
|
30769
|
-
dataDir: config.dataDir,
|
|
30770
|
-
groupFileStore,
|
|
30771
|
-
sessionScopes: manager.listOwnedSessionScopes().map(({ scope, sessionId }) => ({
|
|
30772
|
-
scope,
|
|
30773
|
-
sessionId
|
|
30774
|
-
})),
|
|
30775
|
-
// 注入 cwd 让 GC 直接定位 .attachments 目录(与 upload 落盘点一致)
|
|
30776
|
-
getSessionCwd: (sid) => manager.findOwnedSession(sid)?.cwd ?? null,
|
|
30777
|
-
logger
|
|
30778
|
-
});
|
|
30779
|
-
} catch (err) {
|
|
30780
|
-
logger.warn("attachment gc tick failed", { err: err.message });
|
|
30781
|
-
}
|
|
30782
|
-
};
|
|
30783
|
-
setImmediate(tickAttachmentGc);
|
|
30784
|
-
const attachmentGcInterval = setInterval(tickAttachmentGc, 24 * 3600 * 1e3);
|
|
30785
|
-
attachmentGcInterval.unref();
|
|
30786
30435
|
const shutdown = async () => {
|
|
30787
30436
|
logger.info("stopping clawd");
|
|
30788
|
-
clearInterval(attachmentGcInterval);
|
|
30789
30437
|
observer.stopAll();
|
|
30790
30438
|
manager.stopAll();
|
|
30791
30439
|
if (tunnelMgr) {
|
|
@@ -30803,9 +30451,9 @@ ${bar}
|
|
|
30803
30451
|
};
|
|
30804
30452
|
}
|
|
30805
30453
|
function migrateDropPersonsDir(dataDir) {
|
|
30806
|
-
const dir =
|
|
30454
|
+
const dir = import_node_path29.default.join(dataDir, "persons");
|
|
30807
30455
|
try {
|
|
30808
|
-
|
|
30456
|
+
import_node_fs26.default.rmSync(dir, { recursive: true, force: true });
|
|
30809
30457
|
} catch {
|
|
30810
30458
|
}
|
|
30811
30459
|
}
|