@clawos-dev/clawd 0.2.81 → 0.2.82-beta.153.5114ee6
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 +419 -459
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -119,18 +119,15 @@ var init_methods = __esm({
|
|
|
119
119
|
"attachment.groupRemove",
|
|
120
120
|
"attachment.groupList",
|
|
121
121
|
// ---- capability:* (capability platform 鉴权底座) ----
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
// personas/<pid>/.clawd/sessions/guests/<capId>/ guest sessions 目录。
|
|
127
|
-
"capability:issue",
|
|
122
|
+
// global personal token 模型 (2026-05-25): UI 不再调 capability:issue —— daemon 启动时
|
|
123
|
+
// loadOrCreatePersonalCapability 自动创建 1 张 fixed-grants 的 personal capability,
|
|
124
|
+
// 所有联系人共用 personal token。capability:list / capability:delete 保留 (供调试 /
|
|
125
|
+
// 老板手动清旧 cap);capability:issue / capability:bindPeer 已下线。
|
|
128
126
|
"capability:list",
|
|
129
127
|
"capability:delete",
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
"capability:bindPeer",
|
|
128
|
+
// global personal token (2026-05-25): UI invite/accept dialog 挂载即调,拿 personal
|
|
129
|
+
// token + capability + shareBaseUrl 用于拼 inviteUrl / autoAttach 反向推。owner-only。
|
|
130
|
+
"personal-cap:get",
|
|
134
131
|
// ---- inbox:* (capability platform Phase 3 跨用户通知 + Phase 4 DM) ----
|
|
135
132
|
// owner 接 guest 的 cross-principal 消息事件 + DM 双向私聊.
|
|
136
133
|
// inbox:list / markRead: admin-only (Phase 3); inbox:postMessage: DM 自带能力,
|
|
@@ -646,8 +643,8 @@ var init_parseUtil = __esm({
|
|
|
646
643
|
init_errors2();
|
|
647
644
|
init_en();
|
|
648
645
|
makeIssue = (params) => {
|
|
649
|
-
const { data, path:
|
|
650
|
-
const fullPath = [...
|
|
646
|
+
const { data, path: path43, errorMaps, issueData } = params;
|
|
647
|
+
const fullPath = [...path43, ...issueData.path || []];
|
|
651
648
|
const fullIssue = {
|
|
652
649
|
...issueData,
|
|
653
650
|
path: fullPath
|
|
@@ -958,11 +955,11 @@ var init_types = __esm({
|
|
|
958
955
|
init_parseUtil();
|
|
959
956
|
init_util();
|
|
960
957
|
ParseInputLazyPath = class {
|
|
961
|
-
constructor(parent, value,
|
|
958
|
+
constructor(parent, value, path43, key) {
|
|
962
959
|
this._cachedPath = [];
|
|
963
960
|
this.parent = parent;
|
|
964
961
|
this.data = value;
|
|
965
|
-
this._path =
|
|
962
|
+
this._path = path43;
|
|
966
963
|
this._key = key;
|
|
967
964
|
}
|
|
968
965
|
get path() {
|
|
@@ -5109,7 +5106,7 @@ function stripSecretHash(cap) {
|
|
|
5109
5106
|
const { secretHash: _hash, ...wire } = cap;
|
|
5110
5107
|
return wire;
|
|
5111
5108
|
}
|
|
5112
|
-
var ResourceSchema, ActionSchema, GrantSchema, CapabilitySchema, CapabilityWireSchema, CapabilityErrorCodeSchema, WhoamiResponseSchema,
|
|
5109
|
+
var ResourceSchema, ActionSchema, GrantSchema, CapabilitySchema, CapabilityWireSchema, CapabilityErrorCodeSchema, WhoamiResponseSchema, PERSONAL_CAP_GRANTS, PersonalCapGetResponseSchema;
|
|
5113
5110
|
var init_capability = __esm({
|
|
5114
5111
|
"../protocol/src/capability.ts"() {
|
|
5115
5112
|
"use strict";
|
|
@@ -5171,16 +5168,18 @@ var init_capability = __esm({
|
|
|
5171
5168
|
}).strict()
|
|
5172
5169
|
)
|
|
5173
5170
|
}).strict();
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5171
|
+
PERSONAL_CAP_GRANTS = Object.freeze([
|
|
5172
|
+
Object.freeze({
|
|
5173
|
+
resource: Object.freeze({ type: "persona", id: "*" }),
|
|
5174
|
+
actions: Object.freeze(["read", "send"])
|
|
5175
|
+
})
|
|
5176
|
+
]);
|
|
5177
|
+
PersonalCapGetResponseSchema = external_exports.object({
|
|
5178
|
+
type: external_exports.literal("personal-cap:get:ok"),
|
|
5179
|
+
token: external_exports.string().min(1),
|
|
5180
|
+
capability: CapabilityWireSchema,
|
|
5181
|
+
/** ws/wss base URL,UI deriveInviteBase 用来拼 inviteUrl(tunnel 优先 / 否则本机 ws) */
|
|
5182
|
+
shareBaseUrl: external_exports.string().min(1)
|
|
5184
5183
|
}).strict();
|
|
5185
5184
|
}
|
|
5186
5185
|
});
|
|
@@ -5564,8 +5563,8 @@ var require_req = __commonJS({
|
|
|
5564
5563
|
if (req.originalUrl) {
|
|
5565
5564
|
_req.url = req.originalUrl;
|
|
5566
5565
|
} else {
|
|
5567
|
-
const
|
|
5568
|
-
_req.url = typeof
|
|
5566
|
+
const path43 = req.path;
|
|
5567
|
+
_req.url = typeof path43 === "string" ? path43 : req.url ? req.url.path || req.url : void 0;
|
|
5569
5568
|
}
|
|
5570
5569
|
if (req.query) {
|
|
5571
5570
|
_req.query = req.query;
|
|
@@ -5730,14 +5729,14 @@ var require_redact = __commonJS({
|
|
|
5730
5729
|
}
|
|
5731
5730
|
return obj;
|
|
5732
5731
|
}
|
|
5733
|
-
function parsePath(
|
|
5732
|
+
function parsePath(path43) {
|
|
5734
5733
|
const parts = [];
|
|
5735
5734
|
let current = "";
|
|
5736
5735
|
let inBrackets = false;
|
|
5737
5736
|
let inQuotes = false;
|
|
5738
5737
|
let quoteChar = "";
|
|
5739
|
-
for (let i = 0; i <
|
|
5740
|
-
const char =
|
|
5738
|
+
for (let i = 0; i < path43.length; i++) {
|
|
5739
|
+
const char = path43[i];
|
|
5741
5740
|
if (!inBrackets && char === ".") {
|
|
5742
5741
|
if (current) {
|
|
5743
5742
|
parts.push(current);
|
|
@@ -5868,10 +5867,10 @@ var require_redact = __commonJS({
|
|
|
5868
5867
|
return current;
|
|
5869
5868
|
}
|
|
5870
5869
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
5871
|
-
for (const
|
|
5872
|
-
const parts = parsePath(
|
|
5870
|
+
for (const path43 of paths) {
|
|
5871
|
+
const parts = parsePath(path43);
|
|
5873
5872
|
if (parts.includes("*")) {
|
|
5874
|
-
redactWildcardPath(obj, parts, censor,
|
|
5873
|
+
redactWildcardPath(obj, parts, censor, path43, remove);
|
|
5875
5874
|
} else {
|
|
5876
5875
|
if (remove) {
|
|
5877
5876
|
removeKey(obj, parts);
|
|
@@ -5956,8 +5955,8 @@ var require_redact = __commonJS({
|
|
|
5956
5955
|
}
|
|
5957
5956
|
} else {
|
|
5958
5957
|
if (afterWildcard.includes("*")) {
|
|
5959
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
5960
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
5958
|
+
const wrappedCensor = typeof censor === "function" ? (value, path43) => {
|
|
5959
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path43];
|
|
5961
5960
|
return censor(value, fullPath);
|
|
5962
5961
|
} : censor;
|
|
5963
5962
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -5992,8 +5991,8 @@ var require_redact = __commonJS({
|
|
|
5992
5991
|
return null;
|
|
5993
5992
|
}
|
|
5994
5993
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
5995
|
-
for (const
|
|
5996
|
-
const parts = parsePath(
|
|
5994
|
+
for (const path43 of pathsToClone) {
|
|
5995
|
+
const parts = parsePath(path43);
|
|
5997
5996
|
let current = pathStructure;
|
|
5998
5997
|
for (let i = 0; i < parts.length; i++) {
|
|
5999
5998
|
const part = parts[i];
|
|
@@ -6045,24 +6044,24 @@ var require_redact = __commonJS({
|
|
|
6045
6044
|
}
|
|
6046
6045
|
return cloneSelectively(obj, pathStructure);
|
|
6047
6046
|
}
|
|
6048
|
-
function validatePath(
|
|
6049
|
-
if (typeof
|
|
6047
|
+
function validatePath(path43) {
|
|
6048
|
+
if (typeof path43 !== "string") {
|
|
6050
6049
|
throw new Error("Paths must be (non-empty) strings");
|
|
6051
6050
|
}
|
|
6052
|
-
if (
|
|
6051
|
+
if (path43 === "") {
|
|
6053
6052
|
throw new Error("Invalid redaction path ()");
|
|
6054
6053
|
}
|
|
6055
|
-
if (
|
|
6056
|
-
throw new Error(`Invalid redaction path (${
|
|
6054
|
+
if (path43.includes("..")) {
|
|
6055
|
+
throw new Error(`Invalid redaction path (${path43})`);
|
|
6057
6056
|
}
|
|
6058
|
-
if (
|
|
6059
|
-
throw new Error(`Invalid redaction path (${
|
|
6057
|
+
if (path43.includes(",")) {
|
|
6058
|
+
throw new Error(`Invalid redaction path (${path43})`);
|
|
6060
6059
|
}
|
|
6061
6060
|
let bracketCount = 0;
|
|
6062
6061
|
let inQuotes = false;
|
|
6063
6062
|
let quoteChar = "";
|
|
6064
|
-
for (let i = 0; i <
|
|
6065
|
-
const char =
|
|
6063
|
+
for (let i = 0; i < path43.length; i++) {
|
|
6064
|
+
const char = path43[i];
|
|
6066
6065
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6067
6066
|
if (!inQuotes) {
|
|
6068
6067
|
inQuotes = true;
|
|
@@ -6076,20 +6075,20 @@ var require_redact = __commonJS({
|
|
|
6076
6075
|
} else if (char === "]" && !inQuotes) {
|
|
6077
6076
|
bracketCount--;
|
|
6078
6077
|
if (bracketCount < 0) {
|
|
6079
|
-
throw new Error(`Invalid redaction path (${
|
|
6078
|
+
throw new Error(`Invalid redaction path (${path43})`);
|
|
6080
6079
|
}
|
|
6081
6080
|
}
|
|
6082
6081
|
}
|
|
6083
6082
|
if (bracketCount !== 0) {
|
|
6084
|
-
throw new Error(`Invalid redaction path (${
|
|
6083
|
+
throw new Error(`Invalid redaction path (${path43})`);
|
|
6085
6084
|
}
|
|
6086
6085
|
}
|
|
6087
6086
|
function validatePaths(paths) {
|
|
6088
6087
|
if (!Array.isArray(paths)) {
|
|
6089
6088
|
throw new TypeError("paths must be an array");
|
|
6090
6089
|
}
|
|
6091
|
-
for (const
|
|
6092
|
-
validatePath(
|
|
6090
|
+
for (const path43 of paths) {
|
|
6091
|
+
validatePath(path43);
|
|
6093
6092
|
}
|
|
6094
6093
|
}
|
|
6095
6094
|
function slowRedact(options = {}) {
|
|
@@ -6257,8 +6256,8 @@ var require_redaction = __commonJS({
|
|
|
6257
6256
|
if (shape[k2] === null) {
|
|
6258
6257
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6259
6258
|
} else {
|
|
6260
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6261
|
-
return censor(value, [k2, ...
|
|
6259
|
+
const wrappedCensor = typeof censor === "function" ? (value, path43) => {
|
|
6260
|
+
return censor(value, [k2, ...path43]);
|
|
6262
6261
|
} : censor;
|
|
6263
6262
|
o[k2] = Redact({
|
|
6264
6263
|
paths: shape[k2],
|
|
@@ -6476,10 +6475,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
6476
6475
|
var require_sonic_boom = __commonJS({
|
|
6477
6476
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
6478
6477
|
"use strict";
|
|
6479
|
-
var
|
|
6478
|
+
var fs34 = require("fs");
|
|
6480
6479
|
var EventEmitter2 = require("events");
|
|
6481
6480
|
var inherits = require("util").inherits;
|
|
6482
|
-
var
|
|
6481
|
+
var path43 = require("path");
|
|
6483
6482
|
var sleep = require_atomic_sleep();
|
|
6484
6483
|
var assert = require("assert");
|
|
6485
6484
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6533,20 +6532,20 @@ var require_sonic_boom = __commonJS({
|
|
|
6533
6532
|
const mode = sonic.mode;
|
|
6534
6533
|
if (sonic.sync) {
|
|
6535
6534
|
try {
|
|
6536
|
-
if (sonic.mkdir)
|
|
6537
|
-
const fd =
|
|
6535
|
+
if (sonic.mkdir) fs34.mkdirSync(path43.dirname(file), { recursive: true });
|
|
6536
|
+
const fd = fs34.openSync(file, flags, mode);
|
|
6538
6537
|
fileOpened(null, fd);
|
|
6539
6538
|
} catch (err) {
|
|
6540
6539
|
fileOpened(err);
|
|
6541
6540
|
throw err;
|
|
6542
6541
|
}
|
|
6543
6542
|
} else if (sonic.mkdir) {
|
|
6544
|
-
|
|
6543
|
+
fs34.mkdir(path43.dirname(file), { recursive: true }, (err) => {
|
|
6545
6544
|
if (err) return fileOpened(err);
|
|
6546
|
-
|
|
6545
|
+
fs34.open(file, flags, mode, fileOpened);
|
|
6547
6546
|
});
|
|
6548
6547
|
} else {
|
|
6549
|
-
|
|
6548
|
+
fs34.open(file, flags, mode, fileOpened);
|
|
6550
6549
|
}
|
|
6551
6550
|
}
|
|
6552
6551
|
function SonicBoom(opts) {
|
|
@@ -6587,8 +6586,8 @@ var require_sonic_boom = __commonJS({
|
|
|
6587
6586
|
this.flush = flushBuffer;
|
|
6588
6587
|
this.flushSync = flushBufferSync;
|
|
6589
6588
|
this._actualWrite = actualWriteBuffer;
|
|
6590
|
-
fsWriteSync = () =>
|
|
6591
|
-
fsWrite = () =>
|
|
6589
|
+
fsWriteSync = () => fs34.writeSync(this.fd, this._writingBuf);
|
|
6590
|
+
fsWrite = () => fs34.write(this.fd, this._writingBuf, this.release);
|
|
6592
6591
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
6593
6592
|
this._writingBuf = "";
|
|
6594
6593
|
this.write = write;
|
|
@@ -6597,15 +6596,15 @@ var require_sonic_boom = __commonJS({
|
|
|
6597
6596
|
this._actualWrite = actualWrite;
|
|
6598
6597
|
fsWriteSync = () => {
|
|
6599
6598
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6600
|
-
return
|
|
6599
|
+
return fs34.writeSync(this.fd, this._writingBuf);
|
|
6601
6600
|
}
|
|
6602
|
-
return
|
|
6601
|
+
return fs34.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6603
6602
|
};
|
|
6604
6603
|
fsWrite = () => {
|
|
6605
6604
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6606
|
-
return
|
|
6605
|
+
return fs34.write(this.fd, this._writingBuf, this.release);
|
|
6607
6606
|
}
|
|
6608
|
-
return
|
|
6607
|
+
return fs34.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
6609
6608
|
};
|
|
6610
6609
|
} else {
|
|
6611
6610
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -6662,7 +6661,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6662
6661
|
}
|
|
6663
6662
|
}
|
|
6664
6663
|
if (this._fsync) {
|
|
6665
|
-
|
|
6664
|
+
fs34.fsyncSync(this.fd);
|
|
6666
6665
|
}
|
|
6667
6666
|
const len = this._len;
|
|
6668
6667
|
if (this._reopening) {
|
|
@@ -6776,7 +6775,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6776
6775
|
const onDrain = () => {
|
|
6777
6776
|
if (!this._fsync) {
|
|
6778
6777
|
try {
|
|
6779
|
-
|
|
6778
|
+
fs34.fsync(this.fd, (err) => {
|
|
6780
6779
|
this._flushPending = false;
|
|
6781
6780
|
cb(err);
|
|
6782
6781
|
});
|
|
@@ -6878,7 +6877,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6878
6877
|
const fd = this.fd;
|
|
6879
6878
|
this.once("ready", () => {
|
|
6880
6879
|
if (fd !== this.fd) {
|
|
6881
|
-
|
|
6880
|
+
fs34.close(fd, (err) => {
|
|
6882
6881
|
if (err) {
|
|
6883
6882
|
return this.emit("error", err);
|
|
6884
6883
|
}
|
|
@@ -6927,7 +6926,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6927
6926
|
buf = this._bufs[0];
|
|
6928
6927
|
}
|
|
6929
6928
|
try {
|
|
6930
|
-
const n = Buffer.isBuffer(buf) ?
|
|
6929
|
+
const n = Buffer.isBuffer(buf) ? fs34.writeSync(this.fd, buf) : fs34.writeSync(this.fd, buf, "utf8");
|
|
6931
6930
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
6932
6931
|
buf = releasedBufObj.writingBuf;
|
|
6933
6932
|
this._len = releasedBufObj.len;
|
|
@@ -6943,7 +6942,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6943
6942
|
}
|
|
6944
6943
|
}
|
|
6945
6944
|
try {
|
|
6946
|
-
|
|
6945
|
+
fs34.fsyncSync(this.fd);
|
|
6947
6946
|
} catch {
|
|
6948
6947
|
}
|
|
6949
6948
|
}
|
|
@@ -6964,7 +6963,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6964
6963
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
6965
6964
|
}
|
|
6966
6965
|
try {
|
|
6967
|
-
const n =
|
|
6966
|
+
const n = fs34.writeSync(this.fd, buf);
|
|
6968
6967
|
buf = buf.subarray(n);
|
|
6969
6968
|
this._len = Math.max(this._len - n, 0);
|
|
6970
6969
|
if (buf.length <= 0) {
|
|
@@ -6992,13 +6991,13 @@ var require_sonic_boom = __commonJS({
|
|
|
6992
6991
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
6993
6992
|
if (this.sync) {
|
|
6994
6993
|
try {
|
|
6995
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
6994
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs34.writeSync(this.fd, this._writingBuf) : fs34.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6996
6995
|
release(null, written);
|
|
6997
6996
|
} catch (err) {
|
|
6998
6997
|
release(err);
|
|
6999
6998
|
}
|
|
7000
6999
|
} else {
|
|
7001
|
-
|
|
7000
|
+
fs34.write(this.fd, this._writingBuf, release);
|
|
7002
7001
|
}
|
|
7003
7002
|
}
|
|
7004
7003
|
function actualWriteBuffer() {
|
|
@@ -7007,7 +7006,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7007
7006
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
7008
7007
|
if (this.sync) {
|
|
7009
7008
|
try {
|
|
7010
|
-
const written =
|
|
7009
|
+
const written = fs34.writeSync(this.fd, this._writingBuf);
|
|
7011
7010
|
release(null, written);
|
|
7012
7011
|
} catch (err) {
|
|
7013
7012
|
release(err);
|
|
@@ -7016,7 +7015,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7016
7015
|
if (kCopyBuffer) {
|
|
7017
7016
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
7018
7017
|
}
|
|
7019
|
-
|
|
7018
|
+
fs34.write(this.fd, this._writingBuf, release);
|
|
7020
7019
|
}
|
|
7021
7020
|
}
|
|
7022
7021
|
function actualClose(sonic) {
|
|
@@ -7032,12 +7031,12 @@ var require_sonic_boom = __commonJS({
|
|
|
7032
7031
|
sonic._lens = [];
|
|
7033
7032
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
7034
7033
|
try {
|
|
7035
|
-
|
|
7034
|
+
fs34.fsync(sonic.fd, closeWrapped);
|
|
7036
7035
|
} catch {
|
|
7037
7036
|
}
|
|
7038
7037
|
function closeWrapped() {
|
|
7039
7038
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
7040
|
-
|
|
7039
|
+
fs34.close(sonic.fd, done);
|
|
7041
7040
|
} else {
|
|
7042
7041
|
done();
|
|
7043
7042
|
}
|
|
@@ -10172,11 +10171,11 @@ var init_lib = __esm({
|
|
|
10172
10171
|
}
|
|
10173
10172
|
}
|
|
10174
10173
|
},
|
|
10175
|
-
addToPath: function addToPath(
|
|
10176
|
-
var last =
|
|
10174
|
+
addToPath: function addToPath(path43, added, removed, oldPosInc, options) {
|
|
10175
|
+
var last = path43.lastComponent;
|
|
10177
10176
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10178
10177
|
return {
|
|
10179
|
-
oldPos:
|
|
10178
|
+
oldPos: path43.oldPos + oldPosInc,
|
|
10180
10179
|
lastComponent: {
|
|
10181
10180
|
count: last.count + 1,
|
|
10182
10181
|
added,
|
|
@@ -10186,7 +10185,7 @@ var init_lib = __esm({
|
|
|
10186
10185
|
};
|
|
10187
10186
|
} else {
|
|
10188
10187
|
return {
|
|
10189
|
-
oldPos:
|
|
10188
|
+
oldPos: path43.oldPos + oldPosInc,
|
|
10190
10189
|
lastComponent: {
|
|
10191
10190
|
count: 1,
|
|
10192
10191
|
added,
|
|
@@ -10617,10 +10616,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10617
10616
|
const memories = raw.map((m2) => {
|
|
10618
10617
|
if (!m2 || typeof m2 !== "object") return null;
|
|
10619
10618
|
const rec = m2;
|
|
10620
|
-
const
|
|
10619
|
+
const path43 = typeof rec.path === "string" ? rec.path : null;
|
|
10621
10620
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
10622
|
-
if (!
|
|
10623
|
-
const entry = { path:
|
|
10621
|
+
if (!path43 || content == null) return null;
|
|
10622
|
+
const entry = { path: path43, content };
|
|
10624
10623
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
10625
10624
|
return entry;
|
|
10626
10625
|
}).filter((m2) => m2 !== null);
|
|
@@ -11446,10 +11445,10 @@ function parseAttachment(obj) {
|
|
|
11446
11445
|
const memories = raw.map((m2) => {
|
|
11447
11446
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11448
11447
|
const rec = m2;
|
|
11449
|
-
const
|
|
11448
|
+
const path43 = typeof rec.path === "string" ? rec.path : null;
|
|
11450
11449
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11451
|
-
if (!
|
|
11452
|
-
const out = { path:
|
|
11450
|
+
if (!path43 || content == null) return null;
|
|
11451
|
+
const out = { path: path43, content };
|
|
11453
11452
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11454
11453
|
return out;
|
|
11455
11454
|
}).filter((m2) => m2 !== null);
|
|
@@ -18948,7 +18947,7 @@ var require_websocket = __commonJS({
|
|
|
18948
18947
|
var http2 = require("http");
|
|
18949
18948
|
var net = require("net");
|
|
18950
18949
|
var tls = require("tls");
|
|
18951
|
-
var { randomBytes
|
|
18950
|
+
var { randomBytes, createHash: createHash2 } = require("crypto");
|
|
18952
18951
|
var { Duplex, Readable: Readable3 } = require("stream");
|
|
18953
18952
|
var { URL: URL2 } = require("url");
|
|
18954
18953
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -19478,7 +19477,7 @@ var require_websocket = __commonJS({
|
|
|
19478
19477
|
}
|
|
19479
19478
|
}
|
|
19480
19479
|
const defaultPort = isSecure ? 443 : 80;
|
|
19481
|
-
const key =
|
|
19480
|
+
const key = randomBytes(16).toString("base64");
|
|
19482
19481
|
const request = isSecure ? https.request : http2.request;
|
|
19483
19482
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
19484
19483
|
let perMessageDeflate;
|
|
@@ -19608,7 +19607,7 @@ var require_websocket = __commonJS({
|
|
|
19608
19607
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
19609
19608
|
return;
|
|
19610
19609
|
}
|
|
19611
|
-
const digest =
|
|
19610
|
+
const digest = createHash2("sha1").update(key + GUID).digest("base64");
|
|
19612
19611
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
19613
19612
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
19614
19613
|
return;
|
|
@@ -19975,7 +19974,7 @@ var require_websocket_server = __commonJS({
|
|
|
19975
19974
|
var EventEmitter2 = require("events");
|
|
19976
19975
|
var http2 = require("http");
|
|
19977
19976
|
var { Duplex } = require("stream");
|
|
19978
|
-
var { createHash:
|
|
19977
|
+
var { createHash: createHash2 } = require("crypto");
|
|
19979
19978
|
var extension2 = require_extension();
|
|
19980
19979
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
19981
19980
|
var subprotocol2 = require_subprotocol();
|
|
@@ -20276,7 +20275,7 @@ var require_websocket_server = __commonJS({
|
|
|
20276
20275
|
);
|
|
20277
20276
|
}
|
|
20278
20277
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
20279
|
-
const digest =
|
|
20278
|
+
const digest = createHash2("sha1").update(key + GUID).digest("base64");
|
|
20280
20279
|
const headers = [
|
|
20281
20280
|
"HTTP/1.1 101 Switching Protocols",
|
|
20282
20281
|
"Upgrade: websocket",
|
|
@@ -20364,7 +20363,7 @@ var require_websocket_server = __commonJS({
|
|
|
20364
20363
|
// src/run-case/recorder.ts
|
|
20365
20364
|
function startRunCaseRecorder(opts) {
|
|
20366
20365
|
const now = opts.now ?? Date.now;
|
|
20367
|
-
const dir =
|
|
20366
|
+
const dir = import_node_path29.default.dirname(opts.recordPath);
|
|
20368
20367
|
let stream = null;
|
|
20369
20368
|
let closing = false;
|
|
20370
20369
|
let closedSettled = false;
|
|
@@ -20378,8 +20377,8 @@ function startRunCaseRecorder(opts) {
|
|
|
20378
20377
|
});
|
|
20379
20378
|
const ensureStream = () => {
|
|
20380
20379
|
if (stream) return stream;
|
|
20381
|
-
|
|
20382
|
-
stream =
|
|
20380
|
+
import_node_fs26.default.mkdirSync(dir, { recursive: true });
|
|
20381
|
+
stream = import_node_fs26.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
20383
20382
|
stream.on("close", () => closedResolve());
|
|
20384
20383
|
return stream;
|
|
20385
20384
|
};
|
|
@@ -20404,12 +20403,12 @@ function startRunCaseRecorder(opts) {
|
|
|
20404
20403
|
};
|
|
20405
20404
|
return { tap, close, closed };
|
|
20406
20405
|
}
|
|
20407
|
-
var
|
|
20406
|
+
var import_node_fs26, import_node_path29;
|
|
20408
20407
|
var init_recorder = __esm({
|
|
20409
20408
|
"src/run-case/recorder.ts"() {
|
|
20410
20409
|
"use strict";
|
|
20411
|
-
|
|
20412
|
-
|
|
20410
|
+
import_node_fs26 = __toESM(require("fs"), 1);
|
|
20411
|
+
import_node_path29 = __toESM(require("path"), 1);
|
|
20413
20412
|
}
|
|
20414
20413
|
});
|
|
20415
20414
|
|
|
@@ -20452,7 +20451,7 @@ var init_wire = __esm({
|
|
|
20452
20451
|
// src/run-case/controller.ts
|
|
20453
20452
|
async function runController(opts) {
|
|
20454
20453
|
const now = opts.now ?? Date.now;
|
|
20455
|
-
const cwd = opts.cwd ?? (0,
|
|
20454
|
+
const cwd = opts.cwd ?? (0, import_node_fs27.mkdtempSync)(import_node_path30.default.join(import_node_os14.default.tmpdir(), "clawd-runcase-"));
|
|
20456
20455
|
const ownsCwd = opts.cwd === void 0;
|
|
20457
20456
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
20458
20457
|
const spawnCtx = { cwd };
|
|
@@ -20613,19 +20612,19 @@ async function runController(opts) {
|
|
|
20613
20612
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
20614
20613
|
if (ownsCwd) {
|
|
20615
20614
|
try {
|
|
20616
|
-
(0,
|
|
20615
|
+
(0, import_node_fs27.rmSync)(cwd, { recursive: true, force: true });
|
|
20617
20616
|
} catch {
|
|
20618
20617
|
}
|
|
20619
20618
|
}
|
|
20620
20619
|
return exitCode ?? 0;
|
|
20621
20620
|
}
|
|
20622
|
-
var
|
|
20621
|
+
var import_node_fs27, import_node_os14, import_node_path30;
|
|
20623
20622
|
var init_controller = __esm({
|
|
20624
20623
|
"src/run-case/controller.ts"() {
|
|
20625
20624
|
"use strict";
|
|
20626
|
-
|
|
20625
|
+
import_node_fs27 = require("fs");
|
|
20627
20626
|
import_node_os14 = __toESM(require("os"), 1);
|
|
20628
|
-
|
|
20627
|
+
import_node_path30 = __toESM(require("path"), 1);
|
|
20629
20628
|
init_claude();
|
|
20630
20629
|
init_stdout_splitter();
|
|
20631
20630
|
init_permission_stdio();
|
|
@@ -20857,8 +20856,8 @@ Env (advanced):
|
|
|
20857
20856
|
`;
|
|
20858
20857
|
|
|
20859
20858
|
// src/index.ts
|
|
20860
|
-
var
|
|
20861
|
-
var
|
|
20859
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
20860
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
20862
20861
|
|
|
20863
20862
|
// src/logger.ts
|
|
20864
20863
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
@@ -26233,11 +26232,12 @@ function ownerContext(ownerPrincipalId, displayName) {
|
|
|
26233
26232
|
grants: [{ resource: { type: "*" }, actions: ["admin"] }]
|
|
26234
26233
|
};
|
|
26235
26234
|
}
|
|
26236
|
-
function guestContext(cap) {
|
|
26235
|
+
function guestContext(cap, peerOwnerPrincipalId) {
|
|
26237
26236
|
return {
|
|
26238
26237
|
principal: { id: cap.id, kind: "guest", displayName: cap.displayName },
|
|
26239
26238
|
grants: cap.grants,
|
|
26240
|
-
capabilityId: cap.id
|
|
26239
|
+
capabilityId: cap.id,
|
|
26240
|
+
...peerOwnerPrincipalId ? { peerOwnerPrincipalId } : {}
|
|
26241
26241
|
};
|
|
26242
26242
|
}
|
|
26243
26243
|
function authenticate(token, deps) {
|
|
@@ -26251,17 +26251,7 @@ function authenticate(token, deps) {
|
|
|
26251
26251
|
if (v2.code === "TOKEN_INVALID") return { ok: false, code: "BAD_TOKEN" };
|
|
26252
26252
|
return { ok: false, code: v2.code };
|
|
26253
26253
|
}
|
|
26254
|
-
|
|
26255
|
-
try {
|
|
26256
|
-
deps.onGuestHello(v2.capability.id, deps.selfPrincipalId, deps.selfDisplayName);
|
|
26257
|
-
} catch (e) {
|
|
26258
|
-
if (e.message === "TOKEN_SHARED_LEAK") {
|
|
26259
|
-
return { ok: false, code: "TOKEN_REVOKED" };
|
|
26260
|
-
}
|
|
26261
|
-
throw e;
|
|
26262
|
-
}
|
|
26263
|
-
}
|
|
26264
|
-
return { ok: true, context: guestContext(v2.capability) };
|
|
26254
|
+
return { ok: true, context: guestContext(v2.capability, deps.selfPrincipalId) };
|
|
26265
26255
|
}
|
|
26266
26256
|
|
|
26267
26257
|
// src/permission/capability-store.ts
|
|
@@ -26397,7 +26387,6 @@ function sha256Hex(s) {
|
|
|
26397
26387
|
}
|
|
26398
26388
|
|
|
26399
26389
|
// src/permission/capability-manager.ts
|
|
26400
|
-
var crypto5 = __toESM(require("crypto"), 1);
|
|
26401
26390
|
var CapabilityManager = class {
|
|
26402
26391
|
constructor(registry2, hooks = {}) {
|
|
26403
26392
|
this.registry = registry2;
|
|
@@ -26413,54 +26402,6 @@ var CapabilityManager = class {
|
|
|
26413
26402
|
findById(id) {
|
|
26414
26403
|
return this.registry.findById(id);
|
|
26415
26404
|
}
|
|
26416
|
-
issue(args) {
|
|
26417
|
-
if (!args.displayName.trim()) {
|
|
26418
|
-
throw new Error("CapabilityManager.issue: displayName must be non-empty");
|
|
26419
|
-
}
|
|
26420
|
-
const token = (this.hooks.generateToken ?? defaultGenerateToken)();
|
|
26421
|
-
const id = (this.hooks.generateId ?? defaultGenerateId)();
|
|
26422
|
-
const now = (this.hooks.now ?? Date.now)();
|
|
26423
|
-
const cap = {
|
|
26424
|
-
id,
|
|
26425
|
-
secretHash: sha256Hex2(token),
|
|
26426
|
-
displayName: args.displayName,
|
|
26427
|
-
grants: args.grants,
|
|
26428
|
-
issuedAt: now,
|
|
26429
|
-
usedCount: 0,
|
|
26430
|
-
...args.expiresAt !== void 0 ? { expiresAt: args.expiresAt } : {},
|
|
26431
|
-
...args.maxUses !== void 0 ? { maxUses: args.maxUses } : {}
|
|
26432
|
-
};
|
|
26433
|
-
this.registry.upsertCapability(cap);
|
|
26434
|
-
this.hooks.onIssued?.(cap, token);
|
|
26435
|
-
return { token, capability: cap };
|
|
26436
|
-
}
|
|
26437
|
-
/**
|
|
26438
|
-
* guest 端 auth 帧捎带 selfPrincipalId/selfDisplayName 时,AuthGate.authenticate
|
|
26439
|
-
* 校验 cap token 通过后调本方法把 peer 字段写回 cap:
|
|
26440
|
-
* - 首次(cap.firstUsedByPeerAt 未设)→ 写盘 + 触发 onIssued 复用 push 频道
|
|
26441
|
-
* 让 owner UI 通过 capability:updated 实时拿到 peer 字段
|
|
26442
|
-
* - 重复(同 peerOwnerId)→ noop
|
|
26443
|
-
* - 冲突(不同 peerOwnerId)→ throw TOKEN_SHARED_LEAK,AuthGate 转 close 4401
|
|
26444
|
-
*/
|
|
26445
|
-
recordPeerHello(capId, args) {
|
|
26446
|
-
const cap = this.registry.findById(capId);
|
|
26447
|
-
if (!cap) return { changed: false };
|
|
26448
|
-
if (cap.firstUsedByPeerAt != null) {
|
|
26449
|
-
if (cap.peerOwnerId !== args.ownerPrincipalId) {
|
|
26450
|
-
throw new Error("TOKEN_SHARED_LEAK");
|
|
26451
|
-
}
|
|
26452
|
-
return { changed: false };
|
|
26453
|
-
}
|
|
26454
|
-
const updated = {
|
|
26455
|
-
...cap,
|
|
26456
|
-
peerOwnerId: args.ownerPrincipalId,
|
|
26457
|
-
firstUsedByPeerAt: args.now,
|
|
26458
|
-
peerDisplayName: args.displayName
|
|
26459
|
-
};
|
|
26460
|
-
this.registry.upsertCapability(updated);
|
|
26461
|
-
this.hooks.onIssued?.(updated, "__peer_hello__");
|
|
26462
|
-
return { changed: true };
|
|
26463
|
-
}
|
|
26464
26405
|
/**
|
|
26465
26406
|
* Hard delete:从 registry / store 物理移除 capability。
|
|
26466
26407
|
* idempotent:不存在 → null(handler 翻译成 VALIDATION_ERROR)
|
|
@@ -26473,15 +26414,6 @@ var CapabilityManager = class {
|
|
|
26473
26414
|
return { capability: removed };
|
|
26474
26415
|
}
|
|
26475
26416
|
};
|
|
26476
|
-
function defaultGenerateToken() {
|
|
26477
|
-
return crypto5.randomBytes(24).toString("base64url");
|
|
26478
|
-
}
|
|
26479
|
-
function defaultGenerateId() {
|
|
26480
|
-
return "cap_" + crypto5.randomBytes(6).toString("base64url");
|
|
26481
|
-
}
|
|
26482
|
-
function sha256Hex2(s) {
|
|
26483
|
-
return crypto5.createHash("sha256").update(s).digest("hex");
|
|
26484
|
-
}
|
|
26485
26417
|
|
|
26486
26418
|
// src/permission/cleanup.ts
|
|
26487
26419
|
var fs16 = __toESM(require("fs"), 1);
|
|
@@ -26499,14 +26431,89 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
26499
26431
|
return { removed };
|
|
26500
26432
|
}
|
|
26501
26433
|
|
|
26434
|
+
// src/permission/personal-capability.ts
|
|
26435
|
+
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
26436
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
26437
|
+
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
26438
|
+
var PERSONAL_CAP_FILE_NAME = "personal-capability.json";
|
|
26439
|
+
var PERSONAL_CAP_DISPLAY_NAME = "personal";
|
|
26440
|
+
function personalCapFilePath(dataDir) {
|
|
26441
|
+
return import_node_path14.default.join(dataDir, PERSONAL_CAP_FILE_NAME);
|
|
26442
|
+
}
|
|
26443
|
+
function loadOrCreatePersonalCapability(opts) {
|
|
26444
|
+
const file = personalCapFilePath(opts.dataDir);
|
|
26445
|
+
const generateToken = opts.generateToken ?? defaultGenerateToken;
|
|
26446
|
+
const generateId = opts.generateId ?? defaultGenerateId;
|
|
26447
|
+
const now = opts.now ?? Date.now;
|
|
26448
|
+
const existing = readFile(file);
|
|
26449
|
+
if (existing) return existing;
|
|
26450
|
+
const token = generateToken();
|
|
26451
|
+
const id = generateId();
|
|
26452
|
+
const capability = {
|
|
26453
|
+
id,
|
|
26454
|
+
secretHash: sha256Hex2(token),
|
|
26455
|
+
displayName: PERSONAL_CAP_DISPLAY_NAME,
|
|
26456
|
+
// CapabilitySchema 期待 mutable Grant[],protocol 常量是 readonly,落盘前拷一份
|
|
26457
|
+
grants: PERSONAL_CAP_GRANTS.map((g2) => ({
|
|
26458
|
+
resource: { ...g2.resource },
|
|
26459
|
+
actions: [...g2.actions]
|
|
26460
|
+
})),
|
|
26461
|
+
issuedAt: now(),
|
|
26462
|
+
usedCount: 0
|
|
26463
|
+
};
|
|
26464
|
+
const content = { token, capability };
|
|
26465
|
+
writeFile(file, content);
|
|
26466
|
+
return content;
|
|
26467
|
+
}
|
|
26468
|
+
function readFile(file) {
|
|
26469
|
+
let raw;
|
|
26470
|
+
try {
|
|
26471
|
+
raw = import_node_fs13.default.readFileSync(file, "utf8");
|
|
26472
|
+
} catch (err) {
|
|
26473
|
+
const code = err?.code;
|
|
26474
|
+
if (code === "ENOENT") return null;
|
|
26475
|
+
return null;
|
|
26476
|
+
}
|
|
26477
|
+
let parsed;
|
|
26478
|
+
try {
|
|
26479
|
+
parsed = JSON.parse(raw);
|
|
26480
|
+
} catch {
|
|
26481
|
+
return null;
|
|
26482
|
+
}
|
|
26483
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
26484
|
+
const obj = parsed;
|
|
26485
|
+
if (typeof obj.token !== "string" || obj.token.length === 0) return null;
|
|
26486
|
+
const capParsed = CapabilitySchema.safeParse(obj.capability);
|
|
26487
|
+
if (!capParsed.success) return null;
|
|
26488
|
+
if (sha256Hex2(obj.token) !== capParsed.data.secretHash) return null;
|
|
26489
|
+
return { token: obj.token, capability: capParsed.data };
|
|
26490
|
+
}
|
|
26491
|
+
function writeFile(file, content) {
|
|
26492
|
+
import_node_fs13.default.mkdirSync(import_node_path14.default.dirname(file), { recursive: true });
|
|
26493
|
+
import_node_fs13.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
26494
|
+
try {
|
|
26495
|
+
import_node_fs13.default.chmodSync(file, 384);
|
|
26496
|
+
} catch {
|
|
26497
|
+
}
|
|
26498
|
+
}
|
|
26499
|
+
function defaultGenerateToken() {
|
|
26500
|
+
return import_node_crypto4.default.randomBytes(24).toString("base64url");
|
|
26501
|
+
}
|
|
26502
|
+
function defaultGenerateId() {
|
|
26503
|
+
return "personal_" + import_node_crypto4.default.randomBytes(6).toString("base64url");
|
|
26504
|
+
}
|
|
26505
|
+
function sha256Hex2(s) {
|
|
26506
|
+
return import_node_crypto4.default.createHash("sha256").update(s).digest("hex");
|
|
26507
|
+
}
|
|
26508
|
+
|
|
26502
26509
|
// src/inbox/inbox-store.ts
|
|
26503
|
-
var
|
|
26504
|
-
var
|
|
26510
|
+
var fs18 = __toESM(require("fs"), 1);
|
|
26511
|
+
var path20 = __toESM(require("path"), 1);
|
|
26505
26512
|
var INBOX_SUBDIR = "inbox";
|
|
26506
26513
|
var InboxStore = class {
|
|
26507
26514
|
constructor(dataDir) {
|
|
26508
26515
|
this.dataDir = dataDir;
|
|
26509
|
-
|
|
26516
|
+
fs18.mkdirSync(this.dirPath(), { recursive: true });
|
|
26510
26517
|
}
|
|
26511
26518
|
dataDir;
|
|
26512
26519
|
/**
|
|
@@ -26518,7 +26525,7 @@ var InboxStore = class {
|
|
|
26518
26525
|
const file = this.filePath(peerOwnerId);
|
|
26519
26526
|
let raw;
|
|
26520
26527
|
try {
|
|
26521
|
-
raw =
|
|
26528
|
+
raw = fs18.readFileSync(file, "utf8");
|
|
26522
26529
|
} catch (err) {
|
|
26523
26530
|
if (err?.code === "ENOENT") return [];
|
|
26524
26531
|
return [];
|
|
@@ -26534,7 +26541,7 @@ var InboxStore = class {
|
|
|
26534
26541
|
const dir = this.dirPath();
|
|
26535
26542
|
let entries;
|
|
26536
26543
|
try {
|
|
26537
|
-
entries =
|
|
26544
|
+
entries = fs18.readdirSync(dir);
|
|
26538
26545
|
} catch (err) {
|
|
26539
26546
|
if (err?.code === "ENOENT") return [];
|
|
26540
26547
|
return [];
|
|
@@ -26550,9 +26557,9 @@ var InboxStore = class {
|
|
|
26550
26557
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
26551
26558
|
const file = this.filePath(message.peerOwnerId);
|
|
26552
26559
|
const line = JSON.stringify(message) + "\n";
|
|
26553
|
-
|
|
26560
|
+
fs18.appendFileSync(file, line, { mode: 384 });
|
|
26554
26561
|
try {
|
|
26555
|
-
|
|
26562
|
+
fs18.chmodSync(file, 384);
|
|
26556
26563
|
} catch {
|
|
26557
26564
|
}
|
|
26558
26565
|
}
|
|
@@ -26582,7 +26589,7 @@ var InboxStore = class {
|
|
|
26582
26589
|
removeByPeerOwnerId(peerOwnerId) {
|
|
26583
26590
|
const file = this.filePath(peerOwnerId);
|
|
26584
26591
|
try {
|
|
26585
|
-
|
|
26592
|
+
fs18.unlinkSync(file);
|
|
26586
26593
|
} catch (err) {
|
|
26587
26594
|
if (err?.code === "ENOENT") return;
|
|
26588
26595
|
}
|
|
@@ -26591,18 +26598,18 @@ var InboxStore = class {
|
|
|
26591
26598
|
const file = this.filePath(peerOwnerId);
|
|
26592
26599
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
26593
26600
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
26594
|
-
|
|
26595
|
-
|
|
26601
|
+
fs18.writeFileSync(tmp, content, { mode: 384 });
|
|
26602
|
+
fs18.renameSync(tmp, file);
|
|
26596
26603
|
try {
|
|
26597
|
-
|
|
26604
|
+
fs18.chmodSync(file, 384);
|
|
26598
26605
|
} catch {
|
|
26599
26606
|
}
|
|
26600
26607
|
}
|
|
26601
26608
|
dirPath() {
|
|
26602
|
-
return
|
|
26609
|
+
return path20.join(this.dataDir, INBOX_SUBDIR);
|
|
26603
26610
|
}
|
|
26604
26611
|
filePath(peerOwnerId) {
|
|
26605
|
-
return
|
|
26612
|
+
return path20.join(this.dirPath(), `${peerOwnerId}.jsonl`);
|
|
26606
26613
|
}
|
|
26607
26614
|
};
|
|
26608
26615
|
function parseAllLines(raw) {
|
|
@@ -26689,8 +26696,8 @@ var InboxManager = class {
|
|
|
26689
26696
|
};
|
|
26690
26697
|
|
|
26691
26698
|
// src/state/received-capability-store.ts
|
|
26692
|
-
var
|
|
26693
|
-
var
|
|
26699
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
26700
|
+
var path21 = __toESM(require("path"), 1);
|
|
26694
26701
|
var FILE_NAME = "received-capabilities.json";
|
|
26695
26702
|
var ReceivedCapabilityStore = class {
|
|
26696
26703
|
constructor(dataDir) {
|
|
@@ -26700,10 +26707,10 @@ var ReceivedCapabilityStore = class {
|
|
|
26700
26707
|
caps = /* @__PURE__ */ new Map();
|
|
26701
26708
|
load() {
|
|
26702
26709
|
this.caps.clear();
|
|
26703
|
-
const file =
|
|
26710
|
+
const file = path21.join(this.dataDir, FILE_NAME);
|
|
26704
26711
|
let raw;
|
|
26705
26712
|
try {
|
|
26706
|
-
raw =
|
|
26713
|
+
raw = fs19.readFileSync(file, "utf8");
|
|
26707
26714
|
} catch (err) {
|
|
26708
26715
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
26709
26716
|
return;
|
|
@@ -26740,20 +26747,20 @@ var ReceivedCapabilityStore = class {
|
|
|
26740
26747
|
this.flush();
|
|
26741
26748
|
}
|
|
26742
26749
|
flush() {
|
|
26743
|
-
const file =
|
|
26750
|
+
const file = path21.join(this.dataDir, FILE_NAME);
|
|
26744
26751
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
26745
26752
|
const content = JSON.stringify(
|
|
26746
26753
|
{ receivedCaps: Array.from(this.caps.values()) },
|
|
26747
26754
|
null,
|
|
26748
26755
|
2
|
|
26749
26756
|
);
|
|
26750
|
-
|
|
26751
|
-
|
|
26752
|
-
|
|
26757
|
+
fs19.mkdirSync(this.dataDir, { recursive: true });
|
|
26758
|
+
fs19.writeFileSync(tmp, content, { mode: 384 });
|
|
26759
|
+
fs19.renameSync(tmp, file);
|
|
26753
26760
|
}
|
|
26754
26761
|
renameBak(file) {
|
|
26755
26762
|
try {
|
|
26756
|
-
|
|
26763
|
+
fs19.renameSync(file, `${file}.bak`);
|
|
26757
26764
|
} catch {
|
|
26758
26765
|
}
|
|
26759
26766
|
}
|
|
@@ -26851,61 +26858,61 @@ async function connectRemote(args) {
|
|
|
26851
26858
|
}
|
|
26852
26859
|
|
|
26853
26860
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
26854
|
-
var
|
|
26855
|
-
var
|
|
26861
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
26862
|
+
var path22 = __toESM(require("path"), 1);
|
|
26856
26863
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
26857
26864
|
function migrateFlattenSessions(opts) {
|
|
26858
26865
|
const dataDir = opts.dataDir;
|
|
26859
26866
|
const now = opts.now ?? Date.now;
|
|
26860
|
-
const sessionsDir =
|
|
26861
|
-
const flagPath =
|
|
26867
|
+
const sessionsDir = path22.join(dataDir, "sessions");
|
|
26868
|
+
const flagPath = path22.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
26862
26869
|
if (existsSync3(flagPath)) {
|
|
26863
26870
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
26864
26871
|
}
|
|
26865
26872
|
let movedBare = 0;
|
|
26866
26873
|
let movedVmOwner = 0;
|
|
26867
26874
|
let archivedListener = 0;
|
|
26868
|
-
const defaultDir =
|
|
26875
|
+
const defaultDir = path22.join(sessionsDir, "default");
|
|
26869
26876
|
if (existsSync3(defaultDir)) {
|
|
26870
26877
|
for (const entry of readdirSafe(defaultDir)) {
|
|
26871
26878
|
if (!entry.endsWith(".json")) continue;
|
|
26872
|
-
const src =
|
|
26873
|
-
const dst =
|
|
26874
|
-
|
|
26879
|
+
const src = path22.join(defaultDir, entry);
|
|
26880
|
+
const dst = path22.join(sessionsDir, entry);
|
|
26881
|
+
fs20.renameSync(src, dst);
|
|
26875
26882
|
movedBare += 1;
|
|
26876
26883
|
}
|
|
26877
26884
|
rmdirIfEmpty(defaultDir);
|
|
26878
26885
|
}
|
|
26879
26886
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
26880
|
-
const personaDir =
|
|
26887
|
+
const personaDir = path22.join(sessionsDir, pid);
|
|
26881
26888
|
if (!isDir(personaDir)) continue;
|
|
26882
26889
|
if (pid === "default") continue;
|
|
26883
|
-
const ownerSrc =
|
|
26890
|
+
const ownerSrc = path22.join(personaDir, "owner");
|
|
26884
26891
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
26885
|
-
const ownerDst =
|
|
26886
|
-
|
|
26892
|
+
const ownerDst = path22.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
26893
|
+
fs20.mkdirSync(ownerDst, { recursive: true });
|
|
26887
26894
|
for (const file of readdirSafe(ownerSrc)) {
|
|
26888
26895
|
if (!file.endsWith(".json")) continue;
|
|
26889
|
-
|
|
26896
|
+
fs20.renameSync(path22.join(ownerSrc, file), path22.join(ownerDst, file));
|
|
26890
26897
|
movedVmOwner += 1;
|
|
26891
26898
|
}
|
|
26892
26899
|
rmdirIfEmpty(ownerSrc);
|
|
26893
26900
|
}
|
|
26894
|
-
const listenerSrc =
|
|
26901
|
+
const listenerSrc = path22.join(personaDir, "listener");
|
|
26895
26902
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
26896
|
-
const archiveDst =
|
|
26897
|
-
|
|
26903
|
+
const archiveDst = path22.join(dataDir, ".legacy", `listener-${pid}`);
|
|
26904
|
+
fs20.mkdirSync(archiveDst, { recursive: true });
|
|
26898
26905
|
for (const file of readdirSafe(listenerSrc)) {
|
|
26899
26906
|
if (!file.endsWith(".json")) continue;
|
|
26900
|
-
|
|
26907
|
+
fs20.renameSync(path22.join(listenerSrc, file), path22.join(archiveDst, file));
|
|
26901
26908
|
archivedListener += 1;
|
|
26902
26909
|
}
|
|
26903
26910
|
rmdirIfEmpty(listenerSrc);
|
|
26904
26911
|
}
|
|
26905
26912
|
rmdirIfEmpty(personaDir);
|
|
26906
26913
|
}
|
|
26907
|
-
|
|
26908
|
-
|
|
26914
|
+
fs20.mkdirSync(sessionsDir, { recursive: true });
|
|
26915
|
+
fs20.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
26909
26916
|
return {
|
|
26910
26917
|
skipped: false,
|
|
26911
26918
|
flagWritten: true,
|
|
@@ -26916,7 +26923,7 @@ function migrateFlattenSessions(opts) {
|
|
|
26916
26923
|
}
|
|
26917
26924
|
function existsSync3(p2) {
|
|
26918
26925
|
try {
|
|
26919
|
-
|
|
26926
|
+
fs20.statSync(p2);
|
|
26920
26927
|
return true;
|
|
26921
26928
|
} catch {
|
|
26922
26929
|
return false;
|
|
@@ -26924,31 +26931,31 @@ function existsSync3(p2) {
|
|
|
26924
26931
|
}
|
|
26925
26932
|
function isDir(p2) {
|
|
26926
26933
|
try {
|
|
26927
|
-
return
|
|
26934
|
+
return fs20.statSync(p2).isDirectory();
|
|
26928
26935
|
} catch {
|
|
26929
26936
|
return false;
|
|
26930
26937
|
}
|
|
26931
26938
|
}
|
|
26932
26939
|
function readdirSafe(p2) {
|
|
26933
26940
|
try {
|
|
26934
|
-
return
|
|
26941
|
+
return fs20.readdirSync(p2);
|
|
26935
26942
|
} catch {
|
|
26936
26943
|
return [];
|
|
26937
26944
|
}
|
|
26938
26945
|
}
|
|
26939
26946
|
function rmdirIfEmpty(p2) {
|
|
26940
26947
|
try {
|
|
26941
|
-
|
|
26948
|
+
fs20.rmdirSync(p2);
|
|
26942
26949
|
} catch {
|
|
26943
26950
|
}
|
|
26944
26951
|
}
|
|
26945
26952
|
|
|
26946
26953
|
// src/transport/http-router.ts
|
|
26947
|
-
var
|
|
26948
|
-
var
|
|
26954
|
+
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
26955
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
26949
26956
|
|
|
26950
26957
|
// src/attachment/mime.ts
|
|
26951
|
-
var
|
|
26958
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
26952
26959
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
26953
26960
|
var EXT_TO_NATIVE_MIME = {
|
|
26954
26961
|
// 图片
|
|
@@ -27055,14 +27062,14 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
27055
27062
|
".mk"
|
|
27056
27063
|
]);
|
|
27057
27064
|
function lookupMime(filePathOrName) {
|
|
27058
|
-
const ext =
|
|
27065
|
+
const ext = import_node_path15.default.extname(filePathOrName).toLowerCase();
|
|
27059
27066
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
27060
27067
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
27061
27068
|
return "application/octet-stream";
|
|
27062
27069
|
}
|
|
27063
27070
|
|
|
27064
27071
|
// src/attachment/sign-url.ts
|
|
27065
|
-
var
|
|
27072
|
+
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
27066
27073
|
var HMAC_ALGO = "sha256";
|
|
27067
27074
|
function base64urlEncode(buf) {
|
|
27068
27075
|
const b2 = typeof buf === "string" ? Buffer.from(buf, "utf8") : buf;
|
|
@@ -27079,7 +27086,7 @@ function decodeAbsPathFromUrl(encoded) {
|
|
|
27079
27086
|
}
|
|
27080
27087
|
function computeSig(secret, absPath, e) {
|
|
27081
27088
|
const msg = e === null ? absPath : `${absPath}|${e}`;
|
|
27082
|
-
return
|
|
27089
|
+
return import_node_crypto5.default.createHmac(HMAC_ALGO, secret).update(msg).digest();
|
|
27083
27090
|
}
|
|
27084
27091
|
function signUrlParts(secret, absPath, ttlSeconds, now = Date.now) {
|
|
27085
27092
|
const e = ttlSeconds === null ? null : Math.floor(now() / 1e3) + ttlSeconds;
|
|
@@ -27114,7 +27121,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
27114
27121
|
if (provided.length !== expected.length) {
|
|
27115
27122
|
return { ok: false, code: "BAD_SIG" };
|
|
27116
27123
|
}
|
|
27117
|
-
if (!
|
|
27124
|
+
if (!import_node_crypto5.default.timingSafeEqual(provided, expected)) {
|
|
27118
27125
|
return { ok: false, code: "BAD_SIG" };
|
|
27119
27126
|
}
|
|
27120
27127
|
if (e !== null && now() / 1e3 > e) {
|
|
@@ -27132,9 +27139,7 @@ function createHttpRouter(deps) {
|
|
|
27132
27139
|
return true;
|
|
27133
27140
|
}
|
|
27134
27141
|
if (url.pathname === "/healthz" && req.method === "GET") {
|
|
27135
|
-
sendJson(res, 200, { ok: true, version: deps.daemonVersion }
|
|
27136
|
-
"Access-Control-Allow-Origin": "*"
|
|
27137
|
-
});
|
|
27142
|
+
sendJson(res, 200, { ok: true, version: deps.daemonVersion });
|
|
27138
27143
|
return true;
|
|
27139
27144
|
}
|
|
27140
27145
|
if (!url.pathname.startsWith("/session/") && !url.pathname.startsWith("/files/")) {
|
|
@@ -27186,7 +27191,7 @@ function createHttpRouter(deps) {
|
|
|
27186
27191
|
return true;
|
|
27187
27192
|
}
|
|
27188
27193
|
let absPath;
|
|
27189
|
-
if (
|
|
27194
|
+
if (import_node_path16.default.isAbsolute(pathParam)) {
|
|
27190
27195
|
absPath = pathParam;
|
|
27191
27196
|
} else if (deps.sessionStore) {
|
|
27192
27197
|
const file = deps.sessionStore.read(sid);
|
|
@@ -27194,7 +27199,7 @@ function createHttpRouter(deps) {
|
|
|
27194
27199
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
27195
27200
|
return true;
|
|
27196
27201
|
}
|
|
27197
|
-
absPath =
|
|
27202
|
+
absPath = import_node_path16.default.join(file.cwd, pathParam);
|
|
27198
27203
|
} else {
|
|
27199
27204
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
27200
27205
|
return true;
|
|
@@ -27214,11 +27219,8 @@ function parseUrl(rawUrl) {
|
|
|
27214
27219
|
return null;
|
|
27215
27220
|
}
|
|
27216
27221
|
}
|
|
27217
|
-
function sendJson(res, status, body
|
|
27218
|
-
res.writeHead(status, {
|
|
27219
|
-
"Content-Type": "application/json; charset=utf-8",
|
|
27220
|
-
...extraHeaders ?? {}
|
|
27221
|
-
});
|
|
27222
|
+
function sendJson(res, status, body) {
|
|
27223
|
+
res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
|
|
27222
27224
|
res.end(JSON.stringify(body));
|
|
27223
27225
|
}
|
|
27224
27226
|
function withCtx(ctx, body) {
|
|
@@ -27227,7 +27229,7 @@ function withCtx(ctx, body) {
|
|
|
27227
27229
|
function streamFile(res, absPath, logger) {
|
|
27228
27230
|
let stat;
|
|
27229
27231
|
try {
|
|
27230
|
-
stat =
|
|
27232
|
+
stat = import_node_fs14.default.statSync(absPath);
|
|
27231
27233
|
} catch (err) {
|
|
27232
27234
|
const code = err?.code;
|
|
27233
27235
|
if (code === "ENOENT") {
|
|
@@ -27242,7 +27244,7 @@ function streamFile(res, absPath, logger) {
|
|
|
27242
27244
|
return;
|
|
27243
27245
|
}
|
|
27244
27246
|
const mime = lookupMime(absPath);
|
|
27245
|
-
const basename =
|
|
27247
|
+
const basename = import_node_path16.default.basename(absPath);
|
|
27246
27248
|
res.writeHead(200, {
|
|
27247
27249
|
"Content-Type": mime,
|
|
27248
27250
|
"Content-Length": String(stat.size),
|
|
@@ -27250,7 +27252,7 @@ function streamFile(res, absPath, logger) {
|
|
|
27250
27252
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
27251
27253
|
"X-Content-Type-Options": "nosniff"
|
|
27252
27254
|
});
|
|
27253
|
-
const stream =
|
|
27255
|
+
const stream = import_node_fs14.default.createReadStream(absPath);
|
|
27254
27256
|
stream.on("error", (err) => {
|
|
27255
27257
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
27256
27258
|
res.destroy();
|
|
@@ -27259,9 +27261,9 @@ function streamFile(res, absPath, logger) {
|
|
|
27259
27261
|
}
|
|
27260
27262
|
|
|
27261
27263
|
// src/attachment/group.ts
|
|
27262
|
-
var
|
|
27263
|
-
var
|
|
27264
|
-
var
|
|
27264
|
+
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
27265
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
27266
|
+
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
27265
27267
|
init_protocol();
|
|
27266
27268
|
var GroupFileStore = class {
|
|
27267
27269
|
dataDir;
|
|
@@ -27272,11 +27274,11 @@ var GroupFileStore = class {
|
|
|
27272
27274
|
this.logger = opts.logger;
|
|
27273
27275
|
}
|
|
27274
27276
|
rootForScope(scope) {
|
|
27275
|
-
return
|
|
27277
|
+
return import_node_path17.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
27276
27278
|
}
|
|
27277
27279
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
27278
27280
|
filePath(scope, sessionId) {
|
|
27279
|
-
return
|
|
27281
|
+
return import_node_path17.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
27280
27282
|
}
|
|
27281
27283
|
cacheKey(scope, sessionId) {
|
|
27282
27284
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -27285,7 +27287,7 @@ var GroupFileStore = class {
|
|
|
27285
27287
|
readFile(scope, sessionId) {
|
|
27286
27288
|
const file = this.filePath(scope, sessionId);
|
|
27287
27289
|
try {
|
|
27288
|
-
const raw =
|
|
27290
|
+
const raw = import_node_fs15.default.readFileSync(file, "utf8");
|
|
27289
27291
|
const parsed = JSON.parse(raw);
|
|
27290
27292
|
if (!Array.isArray(parsed)) {
|
|
27291
27293
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -27311,10 +27313,10 @@ var GroupFileStore = class {
|
|
|
27311
27313
|
}
|
|
27312
27314
|
writeFile(scope, sessionId, entries) {
|
|
27313
27315
|
const file = this.filePath(scope, sessionId);
|
|
27314
|
-
|
|
27316
|
+
import_node_fs15.default.mkdirSync(import_node_path17.default.dirname(file), { recursive: true });
|
|
27315
27317
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
27316
|
-
|
|
27317
|
-
|
|
27318
|
+
import_node_fs15.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
27319
|
+
import_node_fs15.default.renameSync(tmp, file);
|
|
27318
27320
|
}
|
|
27319
27321
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
27320
27322
|
list(scope, sessionId) {
|
|
@@ -27350,7 +27352,7 @@ var GroupFileStore = class {
|
|
|
27350
27352
|
entries[idx] = next;
|
|
27351
27353
|
} else {
|
|
27352
27354
|
next = {
|
|
27353
|
-
id: `gf-${
|
|
27355
|
+
id: `gf-${import_node_crypto6.default.randomBytes(6).toString("base64url")}`,
|
|
27354
27356
|
relPath: input.relPath,
|
|
27355
27357
|
from: input.from,
|
|
27356
27358
|
label: input.label,
|
|
@@ -27400,10 +27402,10 @@ var GroupFileStore = class {
|
|
|
27400
27402
|
};
|
|
27401
27403
|
|
|
27402
27404
|
// src/discovery/state-file.ts
|
|
27403
|
-
var
|
|
27404
|
-
var
|
|
27405
|
+
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
27406
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
27405
27407
|
function defaultStateFilePath(dataDir) {
|
|
27406
|
-
return
|
|
27408
|
+
return import_node_path18.default.join(dataDir, "state.json");
|
|
27407
27409
|
}
|
|
27408
27410
|
function isPidAlive(pid) {
|
|
27409
27411
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -27425,7 +27427,7 @@ var StateFileManager = class {
|
|
|
27425
27427
|
}
|
|
27426
27428
|
read() {
|
|
27427
27429
|
try {
|
|
27428
|
-
const raw =
|
|
27430
|
+
const raw = import_node_fs16.default.readFileSync(this.file, "utf8");
|
|
27429
27431
|
const parsed = JSON.parse(raw);
|
|
27430
27432
|
return parsed;
|
|
27431
27433
|
} catch {
|
|
@@ -27439,34 +27441,34 @@ var StateFileManager = class {
|
|
|
27439
27441
|
return { status: "stale", existing };
|
|
27440
27442
|
}
|
|
27441
27443
|
write(state) {
|
|
27442
|
-
|
|
27444
|
+
import_node_fs16.default.mkdirSync(import_node_path18.default.dirname(this.file), { recursive: true });
|
|
27443
27445
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
27444
|
-
|
|
27445
|
-
|
|
27446
|
+
import_node_fs16.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
27447
|
+
import_node_fs16.default.renameSync(tmp, this.file);
|
|
27446
27448
|
if (process.platform !== "win32") {
|
|
27447
27449
|
try {
|
|
27448
|
-
|
|
27450
|
+
import_node_fs16.default.chmodSync(this.file, 384);
|
|
27449
27451
|
} catch {
|
|
27450
27452
|
}
|
|
27451
27453
|
}
|
|
27452
27454
|
}
|
|
27453
27455
|
delete() {
|
|
27454
27456
|
try {
|
|
27455
|
-
|
|
27457
|
+
import_node_fs16.default.unlinkSync(this.file);
|
|
27456
27458
|
} catch {
|
|
27457
27459
|
}
|
|
27458
27460
|
}
|
|
27459
27461
|
};
|
|
27460
27462
|
|
|
27461
27463
|
// src/tunnel/tunnel-manager.ts
|
|
27462
|
-
var
|
|
27463
|
-
var
|
|
27464
|
-
var
|
|
27464
|
+
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
27465
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
27466
|
+
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
27465
27467
|
var import_node_child_process5 = require("child_process");
|
|
27466
27468
|
|
|
27467
27469
|
// src/tunnel/tunnel-store.ts
|
|
27468
|
-
var
|
|
27469
|
-
var
|
|
27470
|
+
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
27471
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
27470
27472
|
var TunnelStore = class {
|
|
27471
27473
|
constructor(filePath) {
|
|
27472
27474
|
this.filePath = filePath;
|
|
@@ -27474,7 +27476,7 @@ var TunnelStore = class {
|
|
|
27474
27476
|
filePath;
|
|
27475
27477
|
async get() {
|
|
27476
27478
|
try {
|
|
27477
|
-
const raw = await
|
|
27479
|
+
const raw = await import_node_fs17.default.promises.readFile(this.filePath, "utf8");
|
|
27478
27480
|
const obj = JSON.parse(raw);
|
|
27479
27481
|
if (!isPersistedTunnel(obj)) return null;
|
|
27480
27482
|
return obj;
|
|
@@ -27485,22 +27487,22 @@ var TunnelStore = class {
|
|
|
27485
27487
|
}
|
|
27486
27488
|
}
|
|
27487
27489
|
async set(v2) {
|
|
27488
|
-
const dir =
|
|
27489
|
-
await
|
|
27490
|
+
const dir = import_node_path19.default.dirname(this.filePath);
|
|
27491
|
+
await import_node_fs17.default.promises.mkdir(dir, { recursive: true });
|
|
27490
27492
|
const data = JSON.stringify(v2, null, 2);
|
|
27491
27493
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
27492
|
-
await
|
|
27494
|
+
await import_node_fs17.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
27493
27495
|
if (process.platform !== "win32") {
|
|
27494
27496
|
try {
|
|
27495
|
-
await
|
|
27497
|
+
await import_node_fs17.default.promises.chmod(tmp, 384);
|
|
27496
27498
|
} catch {
|
|
27497
27499
|
}
|
|
27498
27500
|
}
|
|
27499
|
-
await
|
|
27501
|
+
await import_node_fs17.default.promises.rename(tmp, this.filePath);
|
|
27500
27502
|
}
|
|
27501
27503
|
async clear() {
|
|
27502
27504
|
try {
|
|
27503
|
-
await
|
|
27505
|
+
await import_node_fs17.default.promises.unlink(this.filePath);
|
|
27504
27506
|
} catch (err) {
|
|
27505
27507
|
const code = err?.code;
|
|
27506
27508
|
if (code !== "ENOENT") throw err;
|
|
@@ -27595,9 +27597,9 @@ function escape(v2) {
|
|
|
27595
27597
|
}
|
|
27596
27598
|
|
|
27597
27599
|
// src/tunnel/frpc-binary.ts
|
|
27598
|
-
var
|
|
27600
|
+
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
27599
27601
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
27600
|
-
var
|
|
27602
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
27601
27603
|
var import_node_child_process3 = require("child_process");
|
|
27602
27604
|
var import_node_stream2 = require("stream");
|
|
27603
27605
|
var import_promises = require("stream/promises");
|
|
@@ -27629,20 +27631,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
27629
27631
|
}
|
|
27630
27632
|
async function ensureFrpcBinary(opts) {
|
|
27631
27633
|
if (opts.override) {
|
|
27632
|
-
if (!
|
|
27634
|
+
if (!import_node_fs18.default.existsSync(opts.override)) {
|
|
27633
27635
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
27634
27636
|
}
|
|
27635
27637
|
return opts.override;
|
|
27636
27638
|
}
|
|
27637
27639
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
27638
27640
|
const platform = opts.platform ?? detectPlatform();
|
|
27639
|
-
const binDir =
|
|
27640
|
-
|
|
27641
|
+
const binDir = import_node_path20.default.join(opts.dataDir, "bin");
|
|
27642
|
+
import_node_fs18.default.mkdirSync(binDir, { recursive: true });
|
|
27641
27643
|
cleanupStaleArtifacts(binDir);
|
|
27642
|
-
const stableBin =
|
|
27643
|
-
if (
|
|
27644
|
+
const stableBin = import_node_path20.default.join(binDir, "frpc");
|
|
27645
|
+
if (import_node_fs18.default.existsSync(stableBin)) return stableBin;
|
|
27644
27646
|
const partialBin = `${stableBin}.partial`;
|
|
27645
|
-
const tarballPath =
|
|
27647
|
+
const tarballPath = import_node_path20.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
27646
27648
|
try {
|
|
27647
27649
|
const url = frpcDownloadUrl(version2, platform);
|
|
27648
27650
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -27651,8 +27653,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
27651
27653
|
} else {
|
|
27652
27654
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
27653
27655
|
}
|
|
27654
|
-
|
|
27655
|
-
|
|
27656
|
+
import_node_fs18.default.chmodSync(partialBin, 493);
|
|
27657
|
+
import_node_fs18.default.renameSync(partialBin, stableBin);
|
|
27656
27658
|
} finally {
|
|
27657
27659
|
safeUnlink(tarballPath);
|
|
27658
27660
|
safeUnlink(partialBin);
|
|
@@ -27662,15 +27664,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
27662
27664
|
function cleanupStaleArtifacts(binDir) {
|
|
27663
27665
|
let entries;
|
|
27664
27666
|
try {
|
|
27665
|
-
entries =
|
|
27667
|
+
entries = import_node_fs18.default.readdirSync(binDir);
|
|
27666
27668
|
} catch {
|
|
27667
27669
|
return;
|
|
27668
27670
|
}
|
|
27669
27671
|
for (const name of entries) {
|
|
27670
27672
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
27671
|
-
const full =
|
|
27673
|
+
const full = import_node_path20.default.join(binDir, name);
|
|
27672
27674
|
try {
|
|
27673
|
-
|
|
27675
|
+
import_node_fs18.default.rmSync(full, { recursive: true, force: true });
|
|
27674
27676
|
} catch {
|
|
27675
27677
|
}
|
|
27676
27678
|
}
|
|
@@ -27678,7 +27680,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
27678
27680
|
}
|
|
27679
27681
|
function safeUnlink(p2) {
|
|
27680
27682
|
try {
|
|
27681
|
-
|
|
27683
|
+
import_node_fs18.default.unlinkSync(p2);
|
|
27682
27684
|
} catch {
|
|
27683
27685
|
}
|
|
27684
27686
|
}
|
|
@@ -27689,13 +27691,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
27689
27691
|
if (!res.ok || !res.body) {
|
|
27690
27692
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
27691
27693
|
}
|
|
27692
|
-
const out =
|
|
27694
|
+
const out = import_node_fs18.default.createWriteStream(dest);
|
|
27693
27695
|
const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
|
|
27694
27696
|
await (0, import_promises.pipeline)(nodeStream, out);
|
|
27695
27697
|
}
|
|
27696
27698
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
27697
|
-
const work =
|
|
27698
|
-
|
|
27699
|
+
const work = import_node_path20.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
27700
|
+
import_node_fs18.default.mkdirSync(work, { recursive: true });
|
|
27699
27701
|
try {
|
|
27700
27702
|
await new Promise((resolve6, reject) => {
|
|
27701
27703
|
const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -27703,32 +27705,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
27703
27705
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
27704
27706
|
});
|
|
27705
27707
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
27706
|
-
const src =
|
|
27707
|
-
if (!
|
|
27708
|
+
const src = import_node_path20.default.join(work, dirName, "frpc");
|
|
27709
|
+
if (!import_node_fs18.default.existsSync(src)) {
|
|
27708
27710
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
27709
27711
|
}
|
|
27710
|
-
|
|
27712
|
+
import_node_fs18.default.copyFileSync(src, destBin);
|
|
27711
27713
|
} finally {
|
|
27712
|
-
|
|
27714
|
+
import_node_fs18.default.rmSync(work, { recursive: true, force: true });
|
|
27713
27715
|
}
|
|
27714
27716
|
}
|
|
27715
27717
|
|
|
27716
27718
|
// src/tunnel/frpc-process.ts
|
|
27717
|
-
var
|
|
27718
|
-
var
|
|
27719
|
+
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
27720
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
27719
27721
|
var import_node_child_process4 = require("child_process");
|
|
27720
27722
|
function frpcPidFilePath(dataDir) {
|
|
27721
|
-
return
|
|
27723
|
+
return import_node_path21.default.join(dataDir, "frpc.pid");
|
|
27722
27724
|
}
|
|
27723
27725
|
function writeFrpcPid(dataDir, pid) {
|
|
27724
27726
|
try {
|
|
27725
|
-
|
|
27727
|
+
import_node_fs19.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
27726
27728
|
} catch {
|
|
27727
27729
|
}
|
|
27728
27730
|
}
|
|
27729
27731
|
function clearFrpcPid(dataDir) {
|
|
27730
27732
|
try {
|
|
27731
|
-
|
|
27733
|
+
import_node_fs19.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
27732
27734
|
} catch {
|
|
27733
27735
|
}
|
|
27734
27736
|
}
|
|
@@ -27744,7 +27746,7 @@ function defaultIsPidAlive(pid) {
|
|
|
27744
27746
|
}
|
|
27745
27747
|
function defaultReadPidFile(file) {
|
|
27746
27748
|
try {
|
|
27747
|
-
return
|
|
27749
|
+
return import_node_fs19.default.readFileSync(file, "utf8");
|
|
27748
27750
|
} catch {
|
|
27749
27751
|
return null;
|
|
27750
27752
|
}
|
|
@@ -27760,7 +27762,7 @@ function defaultSleep(ms) {
|
|
|
27760
27762
|
}
|
|
27761
27763
|
async function killStaleFrpc(deps) {
|
|
27762
27764
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
27763
|
-
const tomlPath =
|
|
27765
|
+
const tomlPath = import_node_path21.default.join(deps.dataDir, "frpc.toml");
|
|
27764
27766
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
27765
27767
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
27766
27768
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -27784,7 +27786,7 @@ async function killStaleFrpc(deps) {
|
|
|
27784
27786
|
}
|
|
27785
27787
|
if (victims.size === 0) {
|
|
27786
27788
|
try {
|
|
27787
|
-
|
|
27789
|
+
import_node_fs19.default.unlinkSync(pidFile);
|
|
27788
27790
|
} catch {
|
|
27789
27791
|
}
|
|
27790
27792
|
return;
|
|
@@ -27795,7 +27797,7 @@ async function killStaleFrpc(deps) {
|
|
|
27795
27797
|
}
|
|
27796
27798
|
await sleep(deps.reapWaitMs ?? 300);
|
|
27797
27799
|
try {
|
|
27798
|
-
|
|
27800
|
+
import_node_fs19.default.unlinkSync(pidFile);
|
|
27799
27801
|
} catch {
|
|
27800
27802
|
}
|
|
27801
27803
|
}
|
|
@@ -27832,7 +27834,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
27832
27834
|
var TunnelManager = class {
|
|
27833
27835
|
constructor(deps) {
|
|
27834
27836
|
this.deps = deps;
|
|
27835
|
-
this.store = deps.store ?? new TunnelStore(
|
|
27837
|
+
this.store = deps.store ?? new TunnelStore(import_node_path22.default.join(deps.dataDir, "tunnel.json"));
|
|
27836
27838
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
27837
27839
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
27838
27840
|
}
|
|
@@ -27959,8 +27961,8 @@ var TunnelManager = class {
|
|
|
27959
27961
|
dataDir: this.deps.dataDir,
|
|
27960
27962
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
27961
27963
|
});
|
|
27962
|
-
const tomlPath =
|
|
27963
|
-
const proxyName = `clawd-${t.subdomain}-${localPort}-${
|
|
27964
|
+
const tomlPath = import_node_path22.default.join(this.deps.dataDir, "frpc.toml");
|
|
27965
|
+
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
|
|
27964
27966
|
const toml = buildFrpcToml({
|
|
27965
27967
|
serverAddr: t.frpsHost,
|
|
27966
27968
|
serverPort: t.frpsPort,
|
|
@@ -27970,12 +27972,12 @@ var TunnelManager = class {
|
|
|
27970
27972
|
localPort,
|
|
27971
27973
|
logLevel: "info"
|
|
27972
27974
|
});
|
|
27973
|
-
await
|
|
27975
|
+
await import_node_fs20.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
27974
27976
|
const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
|
|
27975
27977
|
stdio: ["ignore", "pipe", "pipe"]
|
|
27976
27978
|
});
|
|
27977
|
-
const logFilePath =
|
|
27978
|
-
const logStream =
|
|
27979
|
+
const logFilePath = import_node_path22.default.join(this.deps.dataDir, "frpc.log");
|
|
27980
|
+
const logStream = import_node_fs20.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
27979
27981
|
logStream.on("error", () => {
|
|
27980
27982
|
});
|
|
27981
27983
|
const tee = (chunk) => {
|
|
@@ -28058,22 +28060,22 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
28058
28060
|
|
|
28059
28061
|
// src/tunnel/device-key.ts
|
|
28060
28062
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
28061
|
-
var
|
|
28063
|
+
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
28062
28064
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
28063
28065
|
function deriveStableDeviceKey(opts = {}) {
|
|
28064
28066
|
const hostname = opts.hostname ?? import_node_os10.default.hostname();
|
|
28065
28067
|
const uid = opts.uid ?? (typeof import_node_os10.default.userInfo === "function" ? import_node_os10.default.userInfo().uid : 0);
|
|
28066
28068
|
const input = `${hostname}::${uid}`;
|
|
28067
|
-
return
|
|
28069
|
+
return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
28068
28070
|
}
|
|
28069
28071
|
|
|
28070
28072
|
// src/auth-store.ts
|
|
28071
|
-
var
|
|
28072
|
-
var
|
|
28073
|
-
var
|
|
28073
|
+
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
28074
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
28075
|
+
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
28074
28076
|
var AUTH_FILE_NAME = "auth.json";
|
|
28075
28077
|
function authFilePath(dataDir) {
|
|
28076
|
-
return
|
|
28078
|
+
return import_node_path23.default.join(dataDir, AUTH_FILE_NAME);
|
|
28077
28079
|
}
|
|
28078
28080
|
function loadOrCreateAuthFile(opts) {
|
|
28079
28081
|
const file = authFilePath(opts.dataDir);
|
|
@@ -28098,14 +28100,14 @@ function loadOrCreateAuthFile(opts) {
|
|
|
28098
28100
|
return next;
|
|
28099
28101
|
}
|
|
28100
28102
|
function defaultGenerateToken2() {
|
|
28101
|
-
return
|
|
28103
|
+
return import_node_crypto9.default.randomBytes(32).toString("base64url");
|
|
28102
28104
|
}
|
|
28103
28105
|
function defaultGenerateOwnerPrincipalId() {
|
|
28104
|
-
return `owner-${
|
|
28106
|
+
return `owner-${import_node_crypto9.default.randomUUID()}`;
|
|
28105
28107
|
}
|
|
28106
28108
|
function readAuthFile(file) {
|
|
28107
28109
|
try {
|
|
28108
|
-
const raw =
|
|
28110
|
+
const raw = import_node_fs21.default.readFileSync(file, "utf8");
|
|
28109
28111
|
const parsed = JSON.parse(raw);
|
|
28110
28112
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
28111
28113
|
return null;
|
|
@@ -28123,25 +28125,25 @@ function readAuthFile(file) {
|
|
|
28123
28125
|
}
|
|
28124
28126
|
}
|
|
28125
28127
|
function writeAuthFile(file, content) {
|
|
28126
|
-
|
|
28127
|
-
|
|
28128
|
+
import_node_fs21.default.mkdirSync(import_node_path23.default.dirname(file), { recursive: true });
|
|
28129
|
+
import_node_fs21.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
28128
28130
|
try {
|
|
28129
|
-
|
|
28131
|
+
import_node_fs21.default.chmodSync(file, 384);
|
|
28130
28132
|
} catch {
|
|
28131
28133
|
}
|
|
28132
28134
|
}
|
|
28133
28135
|
|
|
28134
28136
|
// src/owner-profile.ts
|
|
28135
|
-
var
|
|
28137
|
+
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
28136
28138
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
28137
|
-
var
|
|
28139
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
28138
28140
|
var PROFILE_FILENAME = "profile.json";
|
|
28139
28141
|
function loadOwnerDisplayName(dataDir) {
|
|
28140
28142
|
const fallback = import_node_os11.default.userInfo().username;
|
|
28141
|
-
const profilePath =
|
|
28143
|
+
const profilePath = import_node_path24.default.join(dataDir, PROFILE_FILENAME);
|
|
28142
28144
|
let raw;
|
|
28143
28145
|
try {
|
|
28144
|
-
raw =
|
|
28146
|
+
raw = import_node_fs22.default.readFileSync(profilePath, "utf8");
|
|
28145
28147
|
} catch {
|
|
28146
28148
|
return fallback;
|
|
28147
28149
|
}
|
|
@@ -28170,12 +28172,12 @@ init_protocol();
|
|
|
28170
28172
|
init_protocol();
|
|
28171
28173
|
|
|
28172
28174
|
// src/session/fork.ts
|
|
28173
|
-
var
|
|
28175
|
+
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
28174
28176
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
28175
|
-
var
|
|
28177
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
28176
28178
|
init_claude_history();
|
|
28177
28179
|
function readJsonlEntries(file) {
|
|
28178
|
-
const raw =
|
|
28180
|
+
const raw = import_node_fs23.default.readFileSync(file, "utf8");
|
|
28179
28181
|
const out = [];
|
|
28180
28182
|
for (const line of raw.split("\n")) {
|
|
28181
28183
|
const t = line.trim();
|
|
@@ -28188,10 +28190,10 @@ function readJsonlEntries(file) {
|
|
|
28188
28190
|
return out;
|
|
28189
28191
|
}
|
|
28190
28192
|
function forkSession(input) {
|
|
28191
|
-
const baseDir = input.baseDir ??
|
|
28192
|
-
const projectDir =
|
|
28193
|
-
const sourceFile =
|
|
28194
|
-
if (!
|
|
28193
|
+
const baseDir = input.baseDir ?? import_node_path25.default.join(import_node_os12.default.homedir(), ".claude");
|
|
28194
|
+
const projectDir = import_node_path25.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
28195
|
+
const sourceFile = import_node_path25.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
28196
|
+
if (!import_node_fs23.default.existsSync(sourceFile)) {
|
|
28195
28197
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
28196
28198
|
}
|
|
28197
28199
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -28221,9 +28223,9 @@ function forkSession(input) {
|
|
|
28221
28223
|
}
|
|
28222
28224
|
forkedLines.push(JSON.stringify(forked));
|
|
28223
28225
|
}
|
|
28224
|
-
const forkedFilePath =
|
|
28225
|
-
|
|
28226
|
-
|
|
28226
|
+
const forkedFilePath = import_node_path25.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
28227
|
+
import_node_fs23.default.mkdirSync(projectDir, { recursive: true });
|
|
28228
|
+
import_node_fs23.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
28227
28229
|
return { forkedToolSessionId, forkedFilePath };
|
|
28228
28230
|
}
|
|
28229
28231
|
|
|
@@ -28544,7 +28546,7 @@ function buildPermissionHandlers(deps) {
|
|
|
28544
28546
|
}
|
|
28545
28547
|
|
|
28546
28548
|
// src/handlers/history.ts
|
|
28547
|
-
var
|
|
28549
|
+
var path35 = __toESM(require("path"), 1);
|
|
28548
28550
|
init_protocol();
|
|
28549
28551
|
|
|
28550
28552
|
// src/session/recent-dirs.ts
|
|
@@ -28562,7 +28564,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
28562
28564
|
}
|
|
28563
28565
|
|
|
28564
28566
|
// src/permission/persona-paths.ts
|
|
28565
|
-
var
|
|
28567
|
+
var path34 = __toESM(require("path"), 1);
|
|
28566
28568
|
function getAllowedPersonaIds(grants, action) {
|
|
28567
28569
|
const ids = /* @__PURE__ */ new Set();
|
|
28568
28570
|
for (const g2 of grants) {
|
|
@@ -28575,26 +28577,26 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
28575
28577
|
return ids;
|
|
28576
28578
|
}
|
|
28577
28579
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read") {
|
|
28578
|
-
const root =
|
|
28579
|
-
const target =
|
|
28580
|
-
const sep3 = root.endsWith(
|
|
28580
|
+
const root = path34.resolve(personaRoot);
|
|
28581
|
+
const target = path34.resolve(absPath);
|
|
28582
|
+
const sep3 = root.endsWith(path34.sep) ? "" : path34.sep;
|
|
28581
28583
|
if (!target.startsWith(root + sep3)) return false;
|
|
28582
|
-
const rel =
|
|
28584
|
+
const rel = path34.relative(root, target);
|
|
28583
28585
|
if (!rel || rel.startsWith("..")) return false;
|
|
28584
|
-
const personaId = rel.split(
|
|
28586
|
+
const personaId = rel.split(path34.sep)[0];
|
|
28585
28587
|
if (!personaId) return false;
|
|
28586
28588
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
28587
28589
|
if (allowed === "*") return true;
|
|
28588
28590
|
return allowed.has(personaId);
|
|
28589
28591
|
}
|
|
28590
28592
|
function personaIdFromPath(absPath, personaRoot) {
|
|
28591
|
-
const root =
|
|
28592
|
-
const target =
|
|
28593
|
-
const sep3 = root.endsWith(
|
|
28593
|
+
const root = path34.resolve(personaRoot);
|
|
28594
|
+
const target = path34.resolve(absPath);
|
|
28595
|
+
const sep3 = root.endsWith(path34.sep) ? "" : path34.sep;
|
|
28594
28596
|
if (!target.startsWith(root + sep3)) return null;
|
|
28595
|
-
const rel =
|
|
28597
|
+
const rel = path34.relative(root, target);
|
|
28596
28598
|
if (!rel || rel.startsWith("..")) return null;
|
|
28597
|
-
const id = rel.split(
|
|
28599
|
+
const id = rel.split(path34.sep)[0];
|
|
28598
28600
|
return id || null;
|
|
28599
28601
|
}
|
|
28600
28602
|
|
|
@@ -28619,7 +28621,7 @@ function buildHistoryHandlers(deps) {
|
|
|
28619
28621
|
if (!pid) return false;
|
|
28620
28622
|
return isGuestPathAllowed(
|
|
28621
28623
|
ctx.grants,
|
|
28622
|
-
|
|
28624
|
+
path35.join(personaRoot, pid),
|
|
28623
28625
|
personaRoot,
|
|
28624
28626
|
"read"
|
|
28625
28627
|
);
|
|
@@ -28630,7 +28632,7 @@ function buildHistoryHandlers(deps) {
|
|
|
28630
28632
|
};
|
|
28631
28633
|
const list = async (frame, _client, ctx) => {
|
|
28632
28634
|
const args = HistoryListArgs.parse(frame);
|
|
28633
|
-
assertGuestPath(ctx,
|
|
28635
|
+
assertGuestPath(ctx, path35.resolve(args.projectPath), personaRoot, "history:list");
|
|
28634
28636
|
const sessions = await history.listSessions(args);
|
|
28635
28637
|
return { response: { type: "history:list", sessions } };
|
|
28636
28638
|
};
|
|
@@ -28662,13 +28664,13 @@ function buildHistoryHandlers(deps) {
|
|
|
28662
28664
|
};
|
|
28663
28665
|
const subagents = async (frame, _client, ctx) => {
|
|
28664
28666
|
const args = HistorySubagentsArgs.parse(frame);
|
|
28665
|
-
assertGuestPath(ctx,
|
|
28667
|
+
assertGuestPath(ctx, path35.resolve(args.cwd), personaRoot, "history:subagents");
|
|
28666
28668
|
const subs = await history.listSubagents(args);
|
|
28667
28669
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
28668
28670
|
};
|
|
28669
28671
|
const subagentRead = async (frame, _client, ctx) => {
|
|
28670
28672
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
28671
|
-
assertGuestPath(ctx,
|
|
28673
|
+
assertGuestPath(ctx, path35.resolve(args.cwd), personaRoot, "history:subagent-read");
|
|
28672
28674
|
const res = await history.readSubagent(args);
|
|
28673
28675
|
return { response: { type: "history:subagent-read", ...res } };
|
|
28674
28676
|
};
|
|
@@ -28676,7 +28678,7 @@ function buildHistoryHandlers(deps) {
|
|
|
28676
28678
|
const dirs = listRecentDirs(store);
|
|
28677
28679
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
28678
28680
|
const filtered = dirs.filter(
|
|
28679
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
28681
|
+
(d) => isGuestPathAllowed(ctx.grants, path35.resolve(d.cwd), personaRoot, "read")
|
|
28680
28682
|
);
|
|
28681
28683
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
28682
28684
|
}
|
|
@@ -28693,7 +28695,7 @@ function buildHistoryHandlers(deps) {
|
|
|
28693
28695
|
}
|
|
28694
28696
|
|
|
28695
28697
|
// src/handlers/workspace.ts
|
|
28696
|
-
var
|
|
28698
|
+
var path36 = __toESM(require("path"), 1);
|
|
28697
28699
|
var os13 = __toESM(require("os"), 1);
|
|
28698
28700
|
init_protocol();
|
|
28699
28701
|
init_protocol();
|
|
@@ -28734,22 +28736,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
28734
28736
|
const args = WorkspaceListArgs.parse(frame);
|
|
28735
28737
|
const isGuest = ctx?.principal.kind === "guest";
|
|
28736
28738
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os13.homedir();
|
|
28737
|
-
const resolvedCwd =
|
|
28738
|
-
const target = args.path ?
|
|
28739
|
+
const resolvedCwd = path36.resolve(args.cwd ?? fallbackCwd);
|
|
28740
|
+
const target = args.path ? path36.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
28739
28741
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list");
|
|
28740
28742
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
28741
28743
|
return { response: { type: "workspace:list", ...res } };
|
|
28742
28744
|
};
|
|
28743
28745
|
const read = async (frame, _client, ctx) => {
|
|
28744
28746
|
const args = WorkspaceReadArgs.parse(frame);
|
|
28745
|
-
const target =
|
|
28747
|
+
const target = path36.isAbsolute(args.path) ? path36.resolve(args.path) : path36.resolve(args.cwd, args.path);
|
|
28746
28748
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read");
|
|
28747
28749
|
const res = workspace.read(args);
|
|
28748
28750
|
return { response: { type: "workspace:read", ...res } };
|
|
28749
28751
|
};
|
|
28750
28752
|
const skillsList = async (frame, _client, ctx) => {
|
|
28751
28753
|
const args = SkillsListArgs.parse(frame);
|
|
28752
|
-
const cwdAbs =
|
|
28754
|
+
const cwdAbs = path36.resolve(args.cwd);
|
|
28753
28755
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list");
|
|
28754
28756
|
const list2 = skills.list(args);
|
|
28755
28757
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -28761,7 +28763,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
28761
28763
|
};
|
|
28762
28764
|
const agentsList = async (frame, _client, ctx) => {
|
|
28763
28765
|
const args = AgentsListArgs.parse(frame);
|
|
28764
|
-
const cwdAbs =
|
|
28766
|
+
const cwdAbs = path36.resolve(args.cwd);
|
|
28765
28767
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list");
|
|
28766
28768
|
const list2 = agents.list(args);
|
|
28767
28769
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -28780,20 +28782,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
28780
28782
|
}
|
|
28781
28783
|
|
|
28782
28784
|
// src/handlers/git.ts
|
|
28783
|
-
var
|
|
28785
|
+
var path38 = __toESM(require("path"), 1);
|
|
28784
28786
|
init_protocol();
|
|
28785
28787
|
init_protocol();
|
|
28786
28788
|
|
|
28787
28789
|
// src/workspace/git.ts
|
|
28788
28790
|
var import_node_child_process6 = require("child_process");
|
|
28789
|
-
var
|
|
28790
|
-
var
|
|
28791
|
+
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
28792
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
28791
28793
|
var import_node_util = require("util");
|
|
28792
28794
|
var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
|
|
28793
28795
|
function normalizePath(p2) {
|
|
28794
|
-
const resolved =
|
|
28796
|
+
const resolved = import_node_path26.default.resolve(p2);
|
|
28795
28797
|
try {
|
|
28796
|
-
return
|
|
28798
|
+
return import_node_fs24.default.realpathSync(resolved);
|
|
28797
28799
|
} catch {
|
|
28798
28800
|
return resolved;
|
|
28799
28801
|
}
|
|
@@ -28866,7 +28868,7 @@ async function listGitBranches(cwd) {
|
|
|
28866
28868
|
// src/handlers/git.ts
|
|
28867
28869
|
function assertGuestCwd(ctx, cwd, personaRoot, method) {
|
|
28868
28870
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
28869
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
28871
|
+
if (!isGuestPathAllowed(ctx.grants, path38.resolve(cwd), personaRoot, "read")) {
|
|
28870
28872
|
throw new ClawdError(
|
|
28871
28873
|
ERROR_CODES.UNAUTHORIZED,
|
|
28872
28874
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -28921,27 +28923,7 @@ var DeleteArgsSchema = external_exports.object({
|
|
|
28921
28923
|
capabilityId: external_exports.string().min(1)
|
|
28922
28924
|
}).strict();
|
|
28923
28925
|
function buildCapabilityHandlers(deps) {
|
|
28924
|
-
const { manager, getShareBaseUrl } = deps;
|
|
28925
|
-
const issue = async (frame) => {
|
|
28926
|
-
const { type: _type, requestId: _requestId, ...rest } = frame;
|
|
28927
|
-
const args = CapabilityIssueArgsSchema.parse(rest);
|
|
28928
|
-
const { token, capability } = manager.issue({
|
|
28929
|
-
displayName: args.displayName,
|
|
28930
|
-
grants: args.grants,
|
|
28931
|
-
...args.expiresAt !== void 0 ? { expiresAt: args.expiresAt } : {},
|
|
28932
|
-
...args.maxUses !== void 0 ? { maxUses: args.maxUses } : {}
|
|
28933
|
-
});
|
|
28934
|
-
const base = getShareBaseUrl().replace(/\/$/, "");
|
|
28935
|
-
const shareUrl = `${base}/?token=${encodeURIComponent(token)}`;
|
|
28936
|
-
return {
|
|
28937
|
-
response: {
|
|
28938
|
-
type: "capability:issued",
|
|
28939
|
-
token,
|
|
28940
|
-
shareUrl,
|
|
28941
|
-
capability: stripSecretHash(capability)
|
|
28942
|
-
}
|
|
28943
|
-
};
|
|
28944
|
-
};
|
|
28926
|
+
const { manager, getShareBaseUrl, getPersonalCapability } = deps;
|
|
28945
28927
|
const list = async () => {
|
|
28946
28928
|
return {
|
|
28947
28929
|
response: {
|
|
@@ -28967,30 +28949,21 @@ function buildCapabilityHandlers(deps) {
|
|
|
28967
28949
|
}
|
|
28968
28950
|
};
|
|
28969
28951
|
};
|
|
28970
|
-
const
|
|
28971
|
-
const {
|
|
28972
|
-
const args = CapabilityBindPeerArgsSchema.parse(rest);
|
|
28973
|
-
try {
|
|
28974
|
-
manager.recordPeerHello(args.capabilityId, {
|
|
28975
|
-
ownerPrincipalId: args.peerOwnerId,
|
|
28976
|
-
displayName: args.peerDisplayName,
|
|
28977
|
-
now: Date.now()
|
|
28978
|
-
});
|
|
28979
|
-
} catch (e) {
|
|
28980
|
-
throw new ClawdError(
|
|
28981
|
-
ERROR_CODES.VALIDATION_ERROR,
|
|
28982
|
-
`capability:bindPeer: ${e.message}`
|
|
28983
|
-
);
|
|
28984
|
-
}
|
|
28952
|
+
const personalCapGet = async () => {
|
|
28953
|
+
const { token, capability } = getPersonalCapability();
|
|
28985
28954
|
return {
|
|
28986
|
-
response: {
|
|
28955
|
+
response: {
|
|
28956
|
+
type: "personal-cap:get:ok",
|
|
28957
|
+
token,
|
|
28958
|
+
capability: stripSecretHash(capability),
|
|
28959
|
+
shareBaseUrl: getShareBaseUrl()
|
|
28960
|
+
}
|
|
28987
28961
|
};
|
|
28988
28962
|
};
|
|
28989
28963
|
return {
|
|
28990
|
-
"capability:issue": issue,
|
|
28991
28964
|
"capability:list": list,
|
|
28992
28965
|
"capability:delete": del,
|
|
28993
|
-
"
|
|
28966
|
+
"personal-cap:get": personalCapGet
|
|
28994
28967
|
};
|
|
28995
28968
|
}
|
|
28996
28969
|
|
|
@@ -29009,20 +28982,24 @@ function resolvePeerOwnerId(ctx, argsPeerOwnerId, capManager) {
|
|
|
29009
28982
|
if (!ctx.capabilityId) {
|
|
29010
28983
|
throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "inbox: guest ctx missing capabilityId");
|
|
29011
28984
|
}
|
|
29012
|
-
|
|
29013
|
-
if (!
|
|
28985
|
+
let resolved = ctx.peerOwnerPrincipalId;
|
|
28986
|
+
if (!resolved) {
|
|
28987
|
+
const cap = capManager.findById(ctx.capabilityId);
|
|
28988
|
+
resolved = cap?.peerOwnerId;
|
|
28989
|
+
}
|
|
28990
|
+
if (!resolved) {
|
|
29014
28991
|
throw new ClawdError(
|
|
29015
28992
|
ERROR_CODES.UNAUTHORIZED,
|
|
29016
|
-
`inbox: guest cap ${ctx.capabilityId} has no
|
|
28993
|
+
`inbox: guest cap ${ctx.capabilityId} has no peerOwnerPrincipalId (auth frame missing selfPrincipalId)`
|
|
29017
28994
|
);
|
|
29018
28995
|
}
|
|
29019
|
-
if (argsPeerOwnerId && argsPeerOwnerId !==
|
|
28996
|
+
if (argsPeerOwnerId && argsPeerOwnerId !== resolved) {
|
|
29020
28997
|
throw new ClawdError(
|
|
29021
28998
|
ERROR_CODES.UNAUTHORIZED,
|
|
29022
|
-
`inbox: guest args.peerOwnerId mismatch (
|
|
28999
|
+
`inbox: guest args.peerOwnerId mismatch (resolved=${resolved}, args=${argsPeerOwnerId})`
|
|
29023
29000
|
);
|
|
29024
29001
|
}
|
|
29025
|
-
return
|
|
29002
|
+
return resolved;
|
|
29026
29003
|
}
|
|
29027
29004
|
function buildInboxHandlers(deps) {
|
|
29028
29005
|
const { manager, capManager } = deps;
|
|
@@ -29378,7 +29355,7 @@ function buildPersonaHandlers(deps) {
|
|
|
29378
29355
|
}
|
|
29379
29356
|
|
|
29380
29357
|
// src/handlers/attachment.ts
|
|
29381
|
-
var
|
|
29358
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
29382
29359
|
init_protocol();
|
|
29383
29360
|
init_protocol();
|
|
29384
29361
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -29432,12 +29409,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
29432
29409
|
`session ${args.sessionId} scope unresolved`
|
|
29433
29410
|
);
|
|
29434
29411
|
}
|
|
29435
|
-
const cwdAbs =
|
|
29436
|
-
const candidateAbs =
|
|
29412
|
+
const cwdAbs = import_node_path27.default.resolve(sessionFile.cwd);
|
|
29413
|
+
const candidateAbs = import_node_path27.default.isAbsolute(args.relPath) ? import_node_path27.default.resolve(args.relPath) : import_node_path27.default.resolve(cwdAbs, args.relPath);
|
|
29437
29414
|
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl");
|
|
29438
29415
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
29439
29416
|
const entry = entries.find((e) => {
|
|
29440
|
-
const storedAbs =
|
|
29417
|
+
const storedAbs = import_node_path27.default.isAbsolute(e.relPath) ? import_node_path27.default.resolve(e.relPath) : import_node_path27.default.resolve(cwdAbs, e.relPath);
|
|
29441
29418
|
return storedAbs === candidateAbs && !e.stale;
|
|
29442
29419
|
});
|
|
29443
29420
|
if (!entry) {
|
|
@@ -29461,7 +29438,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
29461
29438
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
29462
29439
|
const f = deps.sessionStore.read(sessionId);
|
|
29463
29440
|
if (!f) return;
|
|
29464
|
-
assertGuestAttachmentPath(ctx,
|
|
29441
|
+
assertGuestAttachmentPath(ctx, import_node_path27.default.resolve(f.cwd), deps.personaRoot, method);
|
|
29465
29442
|
}
|
|
29466
29443
|
const groupAdd = async (frame, _client, ctx) => {
|
|
29467
29444
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -29547,7 +29524,8 @@ function buildMethodHandlers(deps) {
|
|
|
29547
29524
|
}),
|
|
29548
29525
|
...buildCapabilityHandlers({
|
|
29549
29526
|
manager: deps.capabilityManager,
|
|
29550
|
-
getShareBaseUrl: deps.getShareBaseUrl
|
|
29527
|
+
getShareBaseUrl: deps.getShareBaseUrl,
|
|
29528
|
+
getPersonalCapability: deps.getPersonalCapability
|
|
29551
29529
|
}),
|
|
29552
29530
|
...buildInboxHandlers({
|
|
29553
29531
|
manager: deps.inboxManager,
|
|
@@ -29585,11 +29563,12 @@ var METHOD_GRANT_MAP = {
|
|
|
29585
29563
|
// handler 内部按 ctx.principal.kind 决定返回 "合成 owner self capability" 还是
|
|
29586
29564
|
// "查 capabilityManager 拿 caller 的 guest capability"。
|
|
29587
29565
|
"whoami": { kind: "public" },
|
|
29588
|
-
// ---- capability platform(admin-only
|
|
29589
|
-
|
|
29566
|
+
// ---- capability platform(admin-only) ----
|
|
29567
|
+
// global personal token (2026-05-25): capability:issue / bindPeer 已下线;
|
|
29568
|
+
// personal capability 由 daemon 启动时自动创建,personal-cap:get 是 owner-only 拿 token + shareBaseUrl
|
|
29590
29569
|
"capability:list": ADMIN_ANY,
|
|
29591
29570
|
"capability:delete": ADMIN_ANY,
|
|
29592
|
-
"
|
|
29571
|
+
"personal-cap:get": ADMIN_ANY,
|
|
29593
29572
|
// ---- inbox: channel-based IM (capability platform v3) ----
|
|
29594
29573
|
// 三条都 'public' — capability 本身就是授权凭证. handler 内额外校验
|
|
29595
29574
|
// guest ctx.capabilityId === args.capabilityId, 防 guest 越权操作别的 channel.
|
|
@@ -29690,7 +29669,7 @@ function computeGrantForFrame(method, frame) {
|
|
|
29690
29669
|
async function startDaemon(config) {
|
|
29691
29670
|
const logger = createLogger({
|
|
29692
29671
|
level: config.logLevel,
|
|
29693
|
-
file:
|
|
29672
|
+
file: import_node_path28.default.join(config.dataDir, "clawd.log")
|
|
29694
29673
|
});
|
|
29695
29674
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
29696
29675
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -29719,14 +29698,9 @@ async function startDaemon(config) {
|
|
|
29719
29698
|
receivedCapabilityStore.load();
|
|
29720
29699
|
const capabilityStore = new CapabilityStore(config.dataDir);
|
|
29721
29700
|
const capabilityRegistry = new CapabilityRegistry(capabilityStore);
|
|
29701
|
+
const personalCapability = loadOrCreatePersonalCapability({ dataDir: config.dataDir });
|
|
29702
|
+
capabilityRegistry.upsertCapability(personalCapability.capability);
|
|
29722
29703
|
const capabilityManager = new CapabilityManager(capabilityRegistry, {
|
|
29723
|
-
onIssued: (cap, token) => {
|
|
29724
|
-
wsServer?.broadcastToOwners({
|
|
29725
|
-
type: "capability:tokenIssued",
|
|
29726
|
-
capability: stripSecretHash(cap),
|
|
29727
|
-
token
|
|
29728
|
-
});
|
|
29729
|
-
},
|
|
29730
29704
|
onDeleted: (cap) => {
|
|
29731
29705
|
const deletedAt = Date.now();
|
|
29732
29706
|
wsServer?.broadcastToOwners({
|
|
@@ -29758,14 +29732,7 @@ async function startDaemon(config) {
|
|
|
29758
29732
|
ownerDisplayName,
|
|
29759
29733
|
capabilityRegistry,
|
|
29760
29734
|
selfPrincipalId,
|
|
29761
|
-
selfDisplayName
|
|
29762
|
-
onGuestHello: (capId, ownerId, name) => {
|
|
29763
|
-
capabilityManager.recordPeerHello(capId, {
|
|
29764
|
-
ownerPrincipalId: ownerId,
|
|
29765
|
-
displayName: name,
|
|
29766
|
-
now: Date.now()
|
|
29767
|
-
});
|
|
29768
|
-
}
|
|
29735
|
+
selfDisplayName
|
|
29769
29736
|
});
|
|
29770
29737
|
},
|
|
29771
29738
|
onAuthed: (h, ctx) => wsServer?.attachClientContext(h.id, ctx),
|
|
@@ -29789,7 +29756,7 @@ async function startDaemon(config) {
|
|
|
29789
29756
|
const agents = new AgentsScanner();
|
|
29790
29757
|
const history = new ClaudeHistoryReader();
|
|
29791
29758
|
let transport = null;
|
|
29792
|
-
const personaStore = new PersonaStore(
|
|
29759
|
+
const personaStore = new PersonaStore(import_node_path28.default.join(config.dataDir, "personas"));
|
|
29793
29760
|
const defaultsRoot = findDefaultsRoot();
|
|
29794
29761
|
if (defaultsRoot) {
|
|
29795
29762
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -29806,7 +29773,7 @@ async function startDaemon(config) {
|
|
|
29806
29773
|
getAdapter,
|
|
29807
29774
|
historyReader: history,
|
|
29808
29775
|
dataDir: config.dataDir,
|
|
29809
|
-
personaRoot:
|
|
29776
|
+
personaRoot: import_node_path28.default.join(config.dataDir, "personas"),
|
|
29810
29777
|
personaStore,
|
|
29811
29778
|
ownerDisplayName,
|
|
29812
29779
|
ownerPrincipalId,
|
|
@@ -29830,10 +29797,10 @@ async function startDaemon(config) {
|
|
|
29830
29797
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
29831
29798
|
attachmentGroup: {
|
|
29832
29799
|
onFileEdit: (input) => {
|
|
29833
|
-
const absPath =
|
|
29800
|
+
const absPath = import_node_path28.default.isAbsolute(input.relPath) ? input.relPath : import_node_path28.default.join(input.cwd, input.relPath);
|
|
29834
29801
|
let size = 0;
|
|
29835
29802
|
try {
|
|
29836
|
-
size =
|
|
29803
|
+
size = import_node_fs25.default.statSync(absPath).size;
|
|
29837
29804
|
} catch (err) {
|
|
29838
29805
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
29839
29806
|
sessionId: input.sessionId,
|
|
@@ -29946,15 +29913,17 @@ async function startDaemon(config) {
|
|
|
29946
29913
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
29947
29914
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
29948
29915
|
// guest path guard:candidate 必须在 personaRoot 子树下
|
|
29949
|
-
personaRoot:
|
|
29916
|
+
personaRoot: import_node_path28.default.join(config.dataDir, "personas")
|
|
29950
29917
|
},
|
|
29951
29918
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
29952
|
-
personaRoot:
|
|
29953
|
-
//
|
|
29919
|
+
personaRoot: import_node_path28.default.join(config.dataDir, "personas"),
|
|
29920
|
+
// capability:list / delete handler 依赖
|
|
29954
29921
|
capabilityManager,
|
|
29955
|
-
//
|
|
29922
|
+
// personal-cap:get 返回的 shareBaseUrl 用此 base URL:
|
|
29956
29923
|
// tunnel 拉起后切到反代 wss://... 地址;否则本机 ws://host:port。
|
|
29957
29924
|
getShareBaseUrl: () => currentTunnelUrl ?? `ws://${config.host}:${config.port}`,
|
|
29925
|
+
// global personal token (2026-05-25): personal-cap:get handler 直接返回此 token + cap
|
|
29926
|
+
getPersonalCapability: () => personalCapability,
|
|
29958
29927
|
// v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
|
|
29959
29928
|
ownerDisplayName,
|
|
29960
29929
|
// owner-id stabilization: whoami 用稳定 ownerPrincipalId 替代 'owner' 字面量
|
|
@@ -30010,23 +29979,14 @@ async function startDaemon(config) {
|
|
|
30010
29979
|
// 用 cap token 连 noAuth daemon 时若无此 hook 会 fallback owner ctx, whoami 错返
|
|
30011
29980
|
// capability.id = ownerPrincipalId, 导致 myCapabilityId 写错 → inbox channel 写错.
|
|
30012
29981
|
// 命中 cap → attach guest ctx; 空 token / 未命中 → 保持 noAuth 行为 (handler fallback owner).
|
|
30013
|
-
tryVerifyCapabilityToken: (token, selfPrincipalId,
|
|
29982
|
+
tryVerifyCapabilityToken: (token, selfPrincipalId, _selfDisplayName) => {
|
|
30014
29983
|
const v2 = capabilityRegistry.verifyToken(token);
|
|
30015
29984
|
if (!v2.ok) return null;
|
|
30016
|
-
if (selfPrincipalId && selfDisplayName) {
|
|
30017
|
-
try {
|
|
30018
|
-
capabilityManager.recordPeerHello(v2.capability.id, {
|
|
30019
|
-
ownerPrincipalId: selfPrincipalId,
|
|
30020
|
-
displayName: selfDisplayName,
|
|
30021
|
-
now: Date.now()
|
|
30022
|
-
});
|
|
30023
|
-
} catch {
|
|
30024
|
-
}
|
|
30025
|
-
}
|
|
30026
29985
|
return {
|
|
30027
29986
|
principal: { id: v2.capability.id, kind: "guest", displayName: v2.capability.displayName },
|
|
30028
29987
|
grants: v2.capability.grants,
|
|
30029
|
-
capabilityId: v2.capability.id
|
|
29988
|
+
capabilityId: v2.capability.id,
|
|
29989
|
+
...selfPrincipalId ? { peerOwnerPrincipalId: selfPrincipalId } : {}
|
|
30030
29990
|
};
|
|
30031
29991
|
},
|
|
30032
29992
|
// file-sharing HTTP 路由复用 daemon 同端口(spec §5 第 3 条);router 自己处理 auth + 404
|
|
@@ -30157,8 +30117,8 @@ async function startDaemon(config) {
|
|
|
30157
30117
|
const lines = [
|
|
30158
30118
|
`Tunnel: ${r.url}`,
|
|
30159
30119
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
30160
|
-
`Frpc config: ${
|
|
30161
|
-
`Frpc log: ${
|
|
30120
|
+
`Frpc config: ${import_node_path28.default.join(config.dataDir, "frpc.toml")}`,
|
|
30121
|
+
`Frpc log: ${import_node_path28.default.join(config.dataDir, "frpc.log")}`
|
|
30162
30122
|
];
|
|
30163
30123
|
const width = Math.max(...lines.map((l) => l.length));
|
|
30164
30124
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -30171,8 +30131,8 @@ ${bar}
|
|
|
30171
30131
|
|
|
30172
30132
|
`);
|
|
30173
30133
|
try {
|
|
30174
|
-
const connectPath =
|
|
30175
|
-
|
|
30134
|
+
const connectPath = import_node_path28.default.join(config.dataDir, "connect.txt");
|
|
30135
|
+
import_node_fs25.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
30176
30136
|
} catch {
|
|
30177
30137
|
}
|
|
30178
30138
|
} catch (err) {
|
|
@@ -30216,9 +30176,9 @@ ${bar}
|
|
|
30216
30176
|
};
|
|
30217
30177
|
}
|
|
30218
30178
|
function migrateDropPersonsDir(dataDir) {
|
|
30219
|
-
const dir =
|
|
30179
|
+
const dir = import_node_path28.default.join(dataDir, "persons");
|
|
30220
30180
|
try {
|
|
30221
|
-
|
|
30181
|
+
import_node_fs25.default.rmSync(dir, { recursive: true, force: true });
|
|
30222
30182
|
} catch {
|
|
30223
30183
|
}
|
|
30224
30184
|
}
|