@clawos-dev/clawd 0.2.69-beta.120.2a41cd5 → 0.2.69-beta.121.dbda41c
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 +173 -90
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -605,8 +605,8 @@ var init_parseUtil = __esm({
|
|
|
605
605
|
init_errors2();
|
|
606
606
|
init_en();
|
|
607
607
|
makeIssue = (params) => {
|
|
608
|
-
const { data, path:
|
|
609
|
-
const fullPath = [...
|
|
608
|
+
const { data, path: path32, errorMaps, issueData } = params;
|
|
609
|
+
const fullPath = [...path32, ...issueData.path || []];
|
|
610
610
|
const fullIssue = {
|
|
611
611
|
...issueData,
|
|
612
612
|
path: fullPath
|
|
@@ -917,11 +917,11 @@ var init_types = __esm({
|
|
|
917
917
|
init_parseUtil();
|
|
918
918
|
init_util();
|
|
919
919
|
ParseInputLazyPath = class {
|
|
920
|
-
constructor(parent, value,
|
|
920
|
+
constructor(parent, value, path32, key) {
|
|
921
921
|
this._cachedPath = [];
|
|
922
922
|
this.parent = parent;
|
|
923
923
|
this.data = value;
|
|
924
|
-
this._path =
|
|
924
|
+
this._path = path32;
|
|
925
925
|
this._key = key;
|
|
926
926
|
}
|
|
927
927
|
get path() {
|
|
@@ -4331,9 +4331,11 @@ var init_attachment_schemas = __esm({
|
|
|
4331
4331
|
stale: external_exports.boolean().optional()
|
|
4332
4332
|
});
|
|
4333
4333
|
AttachmentSignUrlArgs = external_exports.object({
|
|
4334
|
-
/**
|
|
4335
|
-
|
|
4336
|
-
/**
|
|
4334
|
+
/** 群文件所属的 session */
|
|
4335
|
+
sessionId: external_exports.string().min(1),
|
|
4336
|
+
/** 相对 session.cwd 的路径;允许传绝对路径,daemon 端会归一化(必须在 cwd 内) */
|
|
4337
|
+
relPath: external_exports.string().min(1),
|
|
4338
|
+
/** TTL 秒数;缺省 24h;null 走永久 URL(不带 exp 字段) */
|
|
4337
4339
|
ttlSeconds: external_exports.number().int().positive().nullable().optional()
|
|
4338
4340
|
});
|
|
4339
4341
|
AttachmentSignUrlResponseSchema = external_exports.object({
|
|
@@ -5333,8 +5335,8 @@ var require_req = __commonJS({
|
|
|
5333
5335
|
if (req.originalUrl) {
|
|
5334
5336
|
_req.url = req.originalUrl;
|
|
5335
5337
|
} else {
|
|
5336
|
-
const
|
|
5337
|
-
_req.url = typeof
|
|
5338
|
+
const path32 = req.path;
|
|
5339
|
+
_req.url = typeof path32 === "string" ? path32 : req.url ? req.url.path || req.url : void 0;
|
|
5338
5340
|
}
|
|
5339
5341
|
if (req.query) {
|
|
5340
5342
|
_req.query = req.query;
|
|
@@ -5499,14 +5501,14 @@ var require_redact = __commonJS({
|
|
|
5499
5501
|
}
|
|
5500
5502
|
return obj;
|
|
5501
5503
|
}
|
|
5502
|
-
function parsePath(
|
|
5504
|
+
function parsePath(path32) {
|
|
5503
5505
|
const parts = [];
|
|
5504
5506
|
let current = "";
|
|
5505
5507
|
let inBrackets = false;
|
|
5506
5508
|
let inQuotes = false;
|
|
5507
5509
|
let quoteChar = "";
|
|
5508
|
-
for (let i = 0; i <
|
|
5509
|
-
const char =
|
|
5510
|
+
for (let i = 0; i < path32.length; i++) {
|
|
5511
|
+
const char = path32[i];
|
|
5510
5512
|
if (!inBrackets && char === ".") {
|
|
5511
5513
|
if (current) {
|
|
5512
5514
|
parts.push(current);
|
|
@@ -5637,10 +5639,10 @@ var require_redact = __commonJS({
|
|
|
5637
5639
|
return current;
|
|
5638
5640
|
}
|
|
5639
5641
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
5640
|
-
for (const
|
|
5641
|
-
const parts = parsePath(
|
|
5642
|
+
for (const path32 of paths) {
|
|
5643
|
+
const parts = parsePath(path32);
|
|
5642
5644
|
if (parts.includes("*")) {
|
|
5643
|
-
redactWildcardPath(obj, parts, censor,
|
|
5645
|
+
redactWildcardPath(obj, parts, censor, path32, remove);
|
|
5644
5646
|
} else {
|
|
5645
5647
|
if (remove) {
|
|
5646
5648
|
removeKey(obj, parts);
|
|
@@ -5725,8 +5727,8 @@ var require_redact = __commonJS({
|
|
|
5725
5727
|
}
|
|
5726
5728
|
} else {
|
|
5727
5729
|
if (afterWildcard.includes("*")) {
|
|
5728
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
5729
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
5730
|
+
const wrappedCensor = typeof censor === "function" ? (value, path32) => {
|
|
5731
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path32];
|
|
5730
5732
|
return censor(value, fullPath);
|
|
5731
5733
|
} : censor;
|
|
5732
5734
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -5761,8 +5763,8 @@ var require_redact = __commonJS({
|
|
|
5761
5763
|
return null;
|
|
5762
5764
|
}
|
|
5763
5765
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
5764
|
-
for (const
|
|
5765
|
-
const parts = parsePath(
|
|
5766
|
+
for (const path32 of pathsToClone) {
|
|
5767
|
+
const parts = parsePath(path32);
|
|
5766
5768
|
let current = pathStructure;
|
|
5767
5769
|
for (let i = 0; i < parts.length; i++) {
|
|
5768
5770
|
const part = parts[i];
|
|
@@ -5814,24 +5816,24 @@ var require_redact = __commonJS({
|
|
|
5814
5816
|
}
|
|
5815
5817
|
return cloneSelectively(obj, pathStructure);
|
|
5816
5818
|
}
|
|
5817
|
-
function validatePath(
|
|
5818
|
-
if (typeof
|
|
5819
|
+
function validatePath(path32) {
|
|
5820
|
+
if (typeof path32 !== "string") {
|
|
5819
5821
|
throw new Error("Paths must be (non-empty) strings");
|
|
5820
5822
|
}
|
|
5821
|
-
if (
|
|
5823
|
+
if (path32 === "") {
|
|
5822
5824
|
throw new Error("Invalid redaction path ()");
|
|
5823
5825
|
}
|
|
5824
|
-
if (
|
|
5825
|
-
throw new Error(`Invalid redaction path (${
|
|
5826
|
+
if (path32.includes("..")) {
|
|
5827
|
+
throw new Error(`Invalid redaction path (${path32})`);
|
|
5826
5828
|
}
|
|
5827
|
-
if (
|
|
5828
|
-
throw new Error(`Invalid redaction path (${
|
|
5829
|
+
if (path32.includes(",")) {
|
|
5830
|
+
throw new Error(`Invalid redaction path (${path32})`);
|
|
5829
5831
|
}
|
|
5830
5832
|
let bracketCount = 0;
|
|
5831
5833
|
let inQuotes = false;
|
|
5832
5834
|
let quoteChar = "";
|
|
5833
|
-
for (let i = 0; i <
|
|
5834
|
-
const char =
|
|
5835
|
+
for (let i = 0; i < path32.length; i++) {
|
|
5836
|
+
const char = path32[i];
|
|
5835
5837
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
5836
5838
|
if (!inQuotes) {
|
|
5837
5839
|
inQuotes = true;
|
|
@@ -5845,20 +5847,20 @@ var require_redact = __commonJS({
|
|
|
5845
5847
|
} else if (char === "]" && !inQuotes) {
|
|
5846
5848
|
bracketCount--;
|
|
5847
5849
|
if (bracketCount < 0) {
|
|
5848
|
-
throw new Error(`Invalid redaction path (${
|
|
5850
|
+
throw new Error(`Invalid redaction path (${path32})`);
|
|
5849
5851
|
}
|
|
5850
5852
|
}
|
|
5851
5853
|
}
|
|
5852
5854
|
if (bracketCount !== 0) {
|
|
5853
|
-
throw new Error(`Invalid redaction path (${
|
|
5855
|
+
throw new Error(`Invalid redaction path (${path32})`);
|
|
5854
5856
|
}
|
|
5855
5857
|
}
|
|
5856
5858
|
function validatePaths(paths) {
|
|
5857
5859
|
if (!Array.isArray(paths)) {
|
|
5858
5860
|
throw new TypeError("paths must be an array");
|
|
5859
5861
|
}
|
|
5860
|
-
for (const
|
|
5861
|
-
validatePath(
|
|
5862
|
+
for (const path32 of paths) {
|
|
5863
|
+
validatePath(path32);
|
|
5862
5864
|
}
|
|
5863
5865
|
}
|
|
5864
5866
|
function slowRedact(options = {}) {
|
|
@@ -6026,8 +6028,8 @@ var require_redaction = __commonJS({
|
|
|
6026
6028
|
if (shape[k2] === null) {
|
|
6027
6029
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6028
6030
|
} else {
|
|
6029
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6030
|
-
return censor(value, [k2, ...
|
|
6031
|
+
const wrappedCensor = typeof censor === "function" ? (value, path32) => {
|
|
6032
|
+
return censor(value, [k2, ...path32]);
|
|
6031
6033
|
} : censor;
|
|
6032
6034
|
o[k2] = Redact({
|
|
6033
6035
|
paths: shape[k2],
|
|
@@ -6248,7 +6250,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6248
6250
|
var fs28 = require("fs");
|
|
6249
6251
|
var EventEmitter2 = require("events");
|
|
6250
6252
|
var inherits = require("util").inherits;
|
|
6251
|
-
var
|
|
6253
|
+
var path32 = require("path");
|
|
6252
6254
|
var sleep = require_atomic_sleep();
|
|
6253
6255
|
var assert = require("assert");
|
|
6254
6256
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6302,7 +6304,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6302
6304
|
const mode = sonic.mode;
|
|
6303
6305
|
if (sonic.sync) {
|
|
6304
6306
|
try {
|
|
6305
|
-
if (sonic.mkdir) fs28.mkdirSync(
|
|
6307
|
+
if (sonic.mkdir) fs28.mkdirSync(path32.dirname(file), { recursive: true });
|
|
6306
6308
|
const fd = fs28.openSync(file, flags, mode);
|
|
6307
6309
|
fileOpened(null, fd);
|
|
6308
6310
|
} catch (err) {
|
|
@@ -6310,7 +6312,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6310
6312
|
throw err;
|
|
6311
6313
|
}
|
|
6312
6314
|
} else if (sonic.mkdir) {
|
|
6313
|
-
fs28.mkdir(
|
|
6315
|
+
fs28.mkdir(path32.dirname(file), { recursive: true }, (err) => {
|
|
6314
6316
|
if (err) return fileOpened(err);
|
|
6315
6317
|
fs28.open(file, flags, mode, fileOpened);
|
|
6316
6318
|
});
|
|
@@ -9941,11 +9943,11 @@ var init_lib = __esm({
|
|
|
9941
9943
|
}
|
|
9942
9944
|
}
|
|
9943
9945
|
},
|
|
9944
|
-
addToPath: function addToPath(
|
|
9945
|
-
var last =
|
|
9946
|
+
addToPath: function addToPath(path32, added, removed, oldPosInc, options) {
|
|
9947
|
+
var last = path32.lastComponent;
|
|
9946
9948
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
9947
9949
|
return {
|
|
9948
|
-
oldPos:
|
|
9950
|
+
oldPos: path32.oldPos + oldPosInc,
|
|
9949
9951
|
lastComponent: {
|
|
9950
9952
|
count: last.count + 1,
|
|
9951
9953
|
added,
|
|
@@ -9955,7 +9957,7 @@ var init_lib = __esm({
|
|
|
9955
9957
|
};
|
|
9956
9958
|
} else {
|
|
9957
9959
|
return {
|
|
9958
|
-
oldPos:
|
|
9960
|
+
oldPos: path32.oldPos + oldPosInc,
|
|
9959
9961
|
lastComponent: {
|
|
9960
9962
|
count: 1,
|
|
9961
9963
|
added,
|
|
@@ -10386,10 +10388,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10386
10388
|
const memories = raw.map((m2) => {
|
|
10387
10389
|
if (!m2 || typeof m2 !== "object") return null;
|
|
10388
10390
|
const rec = m2;
|
|
10389
|
-
const
|
|
10391
|
+
const path32 = typeof rec.path === "string" ? rec.path : null;
|
|
10390
10392
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
10391
|
-
if (!
|
|
10392
|
-
const entry = { path:
|
|
10393
|
+
if (!path32 || content == null) return null;
|
|
10394
|
+
const entry = { path: path32, content };
|
|
10393
10395
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
10394
10396
|
return entry;
|
|
10395
10397
|
}).filter((m2) => m2 !== null);
|
|
@@ -11193,10 +11195,10 @@ function parseAttachment(obj) {
|
|
|
11193
11195
|
const memories = raw.map((m2) => {
|
|
11194
11196
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11195
11197
|
const rec = m2;
|
|
11196
|
-
const
|
|
11198
|
+
const path32 = typeof rec.path === "string" ? rec.path : null;
|
|
11197
11199
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11198
|
-
if (!
|
|
11199
|
-
const out = { path:
|
|
11200
|
+
if (!path32 || content == null) return null;
|
|
11201
|
+
const out = { path: path32, content };
|
|
11200
11202
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11201
11203
|
return out;
|
|
11202
11204
|
}).filter((m2) => m2 !== null);
|
|
@@ -20110,7 +20112,7 @@ var require_websocket_server = __commonJS({
|
|
|
20110
20112
|
// src/run-case/recorder.ts
|
|
20111
20113
|
function startRunCaseRecorder(opts) {
|
|
20112
20114
|
const now = opts.now ?? Date.now;
|
|
20113
|
-
const dir =
|
|
20115
|
+
const dir = import_node_path28.default.dirname(opts.recordPath);
|
|
20114
20116
|
let stream = null;
|
|
20115
20117
|
let closing = false;
|
|
20116
20118
|
let closedSettled = false;
|
|
@@ -20150,12 +20152,12 @@ function startRunCaseRecorder(opts) {
|
|
|
20150
20152
|
};
|
|
20151
20153
|
return { tap, close, closed };
|
|
20152
20154
|
}
|
|
20153
|
-
var import_node_fs25,
|
|
20155
|
+
var import_node_fs25, import_node_path28;
|
|
20154
20156
|
var init_recorder = __esm({
|
|
20155
20157
|
"src/run-case/recorder.ts"() {
|
|
20156
20158
|
"use strict";
|
|
20157
20159
|
import_node_fs25 = __toESM(require("fs"), 1);
|
|
20158
|
-
|
|
20160
|
+
import_node_path28 = __toESM(require("path"), 1);
|
|
20159
20161
|
}
|
|
20160
20162
|
});
|
|
20161
20163
|
|
|
@@ -20198,7 +20200,7 @@ var init_wire = __esm({
|
|
|
20198
20200
|
// src/run-case/controller.ts
|
|
20199
20201
|
async function runController(opts) {
|
|
20200
20202
|
const now = opts.now ?? Date.now;
|
|
20201
|
-
const cwd = opts.cwd ?? (0, import_node_fs26.mkdtempSync)(
|
|
20203
|
+
const cwd = opts.cwd ?? (0, import_node_fs26.mkdtempSync)(import_node_path29.default.join(import_node_os14.default.tmpdir(), "clawd-runcase-"));
|
|
20202
20204
|
const ownsCwd = opts.cwd === void 0;
|
|
20203
20205
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
20204
20206
|
const spawnCtx = { cwd };
|
|
@@ -20365,13 +20367,13 @@ async function runController(opts) {
|
|
|
20365
20367
|
}
|
|
20366
20368
|
return exitCode ?? 0;
|
|
20367
20369
|
}
|
|
20368
|
-
var import_node_fs26, import_node_os14,
|
|
20370
|
+
var import_node_fs26, import_node_os14, import_node_path29;
|
|
20369
20371
|
var init_controller = __esm({
|
|
20370
20372
|
"src/run-case/controller.ts"() {
|
|
20371
20373
|
"use strict";
|
|
20372
20374
|
import_node_fs26 = require("fs");
|
|
20373
20375
|
import_node_os14 = __toESM(require("os"), 1);
|
|
20374
|
-
|
|
20376
|
+
import_node_path29 = __toESM(require("path"), 1);
|
|
20375
20377
|
init_claude();
|
|
20376
20378
|
init_stdout_splitter();
|
|
20377
20379
|
init_permission_stdio();
|
|
@@ -20603,7 +20605,7 @@ Env (advanced):
|
|
|
20603
20605
|
`;
|
|
20604
20606
|
|
|
20605
20607
|
// src/index.ts
|
|
20606
|
-
var
|
|
20608
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
20607
20609
|
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
20608
20610
|
|
|
20609
20611
|
// src/logger.ts
|
|
@@ -22104,9 +22106,19 @@ var SessionManager = class {
|
|
|
22104
22106
|
return entries.filter((e) => e.isDirectory() && e.name !== "default").map((e) => e.name);
|
|
22105
22107
|
}
|
|
22106
22108
|
// owner / default 两个分类下按 sessionId 找文件——前端只传 sessionId 不带 scope,
|
|
22107
|
-
// SessionManager
|
|
22109
|
+
// SessionManager 在这里定位。三层快慢路径:
|
|
22110
|
+
// 1) active runner(用户当前在用的 session):runner.state.file 是 SessionFile 内存权威副本,
|
|
22111
|
+
// 直接返回,零磁盘 I/O。覆盖 attachment / file-sharing 等"用户操作 → 紧接着 RPC"的
|
|
22112
|
+
// 绝大多数场景
|
|
22113
|
+
// 2) default scope 磁盘:inactive default session 命中
|
|
22114
|
+
// 3) 所有 persona owner 目录扫盘:inactive persona owner session 命中
|
|
22108
22115
|
// listener sub-session 不走这条——transport 始终明确传 (personaId, sessionId)。
|
|
22116
|
+
//
|
|
22117
|
+
// 公开方法:attachment / file-sharing handler 通过 deps 闭包消费,不应直接持 SessionStore
|
|
22118
|
+
// (持 default-only store 是 file-sharing v1 的预存 bug 根因——见 fix #703)
|
|
22109
22119
|
findOwnedSession(sessionId) {
|
|
22120
|
+
const runner = this.runners.get(sessionId);
|
|
22121
|
+
if (runner) return runner.getState().file;
|
|
22110
22122
|
const dflt = this.deps.store.read(sessionId);
|
|
22111
22123
|
if (dflt) return dflt;
|
|
22112
22124
|
for (const personaId of this.listPersonaIdsOnDisk()) {
|
|
@@ -22116,6 +22128,13 @@ var SessionManager = class {
|
|
|
22116
22128
|
}
|
|
22117
22129
|
return null;
|
|
22118
22130
|
}
|
|
22131
|
+
// findOwnedSession + scopeForFile 收口。把"sessionId → SessionScope"的派生
|
|
22132
|
+
// 集中到 manager(scope 单一来源),调用方拿 scope 不再自己拼 object 也不依赖
|
|
22133
|
+
// ownerPersonaId 字段语义。给 attachment handler 通过 deps.getSessionScope 闭包消费。
|
|
22134
|
+
findOwnedSessionScope(sessionId) {
|
|
22135
|
+
const file = this.findOwnedSession(sessionId);
|
|
22136
|
+
return file ? this.scopeForFile(file) : null;
|
|
22137
|
+
}
|
|
22119
22138
|
// 合并 default + 所有 persona owner 的 SessionFile —— 桌面 App 主 session 列表入口。
|
|
22120
22139
|
// 同样不含 listener sub-session(listener 走 persona:listSubSessions RPC 单独入口)。
|
|
22121
22140
|
listAllOwned() {
|
|
@@ -26850,14 +26869,24 @@ var AUTH_FILE_NAME = "auth.json";
|
|
|
26850
26869
|
function authFilePath(dataDir) {
|
|
26851
26870
|
return import_node_path22.default.join(dataDir, AUTH_FILE_NAME);
|
|
26852
26871
|
}
|
|
26853
|
-
function
|
|
26872
|
+
function loadOrCreateAuthFile(opts) {
|
|
26854
26873
|
const file = authFilePath(opts.dataDir);
|
|
26874
|
+
const generate = opts.generate ?? defaultGenerate;
|
|
26875
|
+
const now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
26855
26876
|
const existing = readAuthFile(file);
|
|
26856
|
-
if (existing && existing.token
|
|
26857
|
-
|
|
26858
|
-
|
|
26859
|
-
|
|
26860
|
-
|
|
26877
|
+
if (existing && existing.token && existing.signSecret) {
|
|
26878
|
+
return {
|
|
26879
|
+
token: existing.token,
|
|
26880
|
+
signSecret: existing.signSecret,
|
|
26881
|
+
createdAt: existing.createdAt ?? (/* @__PURE__ */ new Date(0)).toISOString()
|
|
26882
|
+
};
|
|
26883
|
+
}
|
|
26884
|
+
const token = existing?.token || generate();
|
|
26885
|
+
const signSecret = existing?.signSecret || generate();
|
|
26886
|
+
const createdAt = existing?.createdAt || now().toISOString();
|
|
26887
|
+
const next = { token, signSecret, createdAt };
|
|
26888
|
+
writeAuthFile(file, next);
|
|
26889
|
+
return next;
|
|
26861
26890
|
}
|
|
26862
26891
|
function defaultGenerate() {
|
|
26863
26892
|
return import_node_crypto8.default.randomBytes(32).toString("base64url");
|
|
@@ -26866,13 +26895,14 @@ function readAuthFile(file) {
|
|
|
26866
26895
|
try {
|
|
26867
26896
|
const raw = import_node_fs20.default.readFileSync(file, "utf8");
|
|
26868
26897
|
const parsed = JSON.parse(raw);
|
|
26869
|
-
if (typeof parsed?.token
|
|
26870
|
-
return
|
|
26871
|
-
token: parsed.token,
|
|
26872
|
-
createdAt: typeof parsed.createdAt === "string" ? parsed.createdAt : (/* @__PURE__ */ new Date(0)).toISOString()
|
|
26873
|
-
};
|
|
26898
|
+
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
26899
|
+
return null;
|
|
26874
26900
|
}
|
|
26875
|
-
return
|
|
26901
|
+
return {
|
|
26902
|
+
token: parsed.token,
|
|
26903
|
+
signSecret: typeof parsed.signSecret === "string" && parsed.signSecret.length > 0 ? parsed.signSecret : void 0,
|
|
26904
|
+
createdAt: typeof parsed.createdAt === "string" ? parsed.createdAt : void 0
|
|
26905
|
+
};
|
|
26876
26906
|
} catch (err) {
|
|
26877
26907
|
const code = err?.code;
|
|
26878
26908
|
if (code === "ENOENT") return null;
|
|
@@ -27541,6 +27571,7 @@ function buildPersonaHandlers(deps) {
|
|
|
27541
27571
|
}
|
|
27542
27572
|
|
|
27543
27573
|
// src/handlers/attachment.ts
|
|
27574
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
27544
27575
|
init_protocol();
|
|
27545
27576
|
init_protocol();
|
|
27546
27577
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -27565,8 +27596,51 @@ function buildAttachmentHandlers(deps) {
|
|
|
27565
27596
|
"httpBaseUrl unavailable (daemon HTTP not ready)"
|
|
27566
27597
|
);
|
|
27567
27598
|
}
|
|
27599
|
+
if (!deps.sessionStore || !deps.getSessionScope || !deps.groupFileStore) {
|
|
27600
|
+
throw new ClawdError(
|
|
27601
|
+
ERROR_CODES.METHOD_NOT_IMPLEMENTED,
|
|
27602
|
+
"signUrl requires session/group stores"
|
|
27603
|
+
);
|
|
27604
|
+
}
|
|
27605
|
+
const sessionFile = deps.sessionStore.read(args.sessionId);
|
|
27606
|
+
if (!sessionFile) {
|
|
27607
|
+
throw new ClawdError(
|
|
27608
|
+
ERROR_CODES.VALIDATION_ERROR,
|
|
27609
|
+
`session ${args.sessionId} not found`
|
|
27610
|
+
);
|
|
27611
|
+
}
|
|
27612
|
+
const scope = deps.getSessionScope(args.sessionId);
|
|
27613
|
+
if (!scope) {
|
|
27614
|
+
throw new ClawdError(
|
|
27615
|
+
ERROR_CODES.VALIDATION_ERROR,
|
|
27616
|
+
`session ${args.sessionId} scope unresolved`
|
|
27617
|
+
);
|
|
27618
|
+
}
|
|
27619
|
+
const cwdAbs = import_node_path26.default.resolve(sessionFile.cwd);
|
|
27620
|
+
const candidateAbs = import_node_path26.default.isAbsolute(args.relPath) ? import_node_path26.default.resolve(args.relPath) : import_node_path26.default.resolve(cwdAbs, args.relPath);
|
|
27621
|
+
if (!isContainedIn2(candidateAbs, cwdAbs)) {
|
|
27622
|
+
throw new ClawdError(
|
|
27623
|
+
ERROR_CODES.VALIDATION_ERROR,
|
|
27624
|
+
"relPath escapes session cwd"
|
|
27625
|
+
);
|
|
27626
|
+
}
|
|
27627
|
+
const relPath = import_node_path26.default.relative(cwdAbs, candidateAbs);
|
|
27628
|
+
if (relPath === "" || relPath.startsWith("..")) {
|
|
27629
|
+
throw new ClawdError(
|
|
27630
|
+
ERROR_CODES.VALIDATION_ERROR,
|
|
27631
|
+
"relPath escapes session cwd"
|
|
27632
|
+
);
|
|
27633
|
+
}
|
|
27634
|
+
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
27635
|
+
const entry = entries.find((e) => e.relPath === relPath && !e.stale);
|
|
27636
|
+
if (!entry) {
|
|
27637
|
+
throw new ClawdError(
|
|
27638
|
+
ERROR_CODES.VALIDATION_ERROR,
|
|
27639
|
+
`relPath not in session group files or stale: ${relPath}`
|
|
27640
|
+
);
|
|
27641
|
+
}
|
|
27568
27642
|
const ttl = args.ttlSeconds === null ? null : args.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
27569
|
-
const parts = signUrlParts(secret,
|
|
27643
|
+
const parts = signUrlParts(secret, candidateAbs, ttl);
|
|
27570
27644
|
const url = buildSignedFileUrl(httpBaseUrl, parts);
|
|
27571
27645
|
return {
|
|
27572
27646
|
response: {
|
|
@@ -27652,6 +27726,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
27652
27726
|
"attachment.groupListPersona": groupListPersona
|
|
27653
27727
|
};
|
|
27654
27728
|
}
|
|
27729
|
+
function isContainedIn2(abs, root) {
|
|
27730
|
+
const normalized = import_node_path26.default.resolve(abs);
|
|
27731
|
+
const normalizedRoot = import_node_path26.default.resolve(root);
|
|
27732
|
+
if (normalized === normalizedRoot) return true;
|
|
27733
|
+
return normalized.startsWith(normalizedRoot + import_node_path26.default.sep);
|
|
27734
|
+
}
|
|
27655
27735
|
|
|
27656
27736
|
// src/handlers/index.ts
|
|
27657
27737
|
function buildMethodHandlers(deps) {
|
|
@@ -27675,7 +27755,7 @@ function buildMethodHandlers(deps) {
|
|
|
27675
27755
|
async function startDaemon(config) {
|
|
27676
27756
|
const logger = createLogger({
|
|
27677
27757
|
level: config.logLevel,
|
|
27678
|
-
file:
|
|
27758
|
+
file: import_node_path27.default.join(config.dataDir, "clawd.log")
|
|
27679
27759
|
});
|
|
27680
27760
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
27681
27761
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -27687,10 +27767,12 @@ async function startDaemon(config) {
|
|
|
27687
27767
|
logger.warn("stale state file detected, overwriting", { pid: pre.existing.pid });
|
|
27688
27768
|
}
|
|
27689
27769
|
let resolvedAuthToken = null;
|
|
27770
|
+
let authFile = null;
|
|
27690
27771
|
if (config.authToken && config.authToken.trim()) {
|
|
27691
27772
|
resolvedAuthToken = config.authToken.trim();
|
|
27692
27773
|
} else if (config.tunnel) {
|
|
27693
|
-
|
|
27774
|
+
authFile = loadOrCreateAuthFile({ dataDir: config.dataDir });
|
|
27775
|
+
resolvedAuthToken = authFile.token;
|
|
27694
27776
|
}
|
|
27695
27777
|
const authMode = resolvedAuthToken == null ? "none" : "first-message";
|
|
27696
27778
|
let wsServer = null;
|
|
@@ -27707,7 +27789,7 @@ async function startDaemon(config) {
|
|
|
27707
27789
|
const agents = new AgentsScanner();
|
|
27708
27790
|
const history = new ClaudeHistoryReader();
|
|
27709
27791
|
let transport = null;
|
|
27710
|
-
const personaStore = new PersonaStore(
|
|
27792
|
+
const personaStore = new PersonaStore(import_node_path27.default.join(config.dataDir, "personas"));
|
|
27711
27793
|
const defaultsRoot = findDefaultsRoot();
|
|
27712
27794
|
if (defaultsRoot) {
|
|
27713
27795
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -27722,7 +27804,7 @@ async function startDaemon(config) {
|
|
|
27722
27804
|
getAdapter,
|
|
27723
27805
|
historyReader: history,
|
|
27724
27806
|
dataDir: config.dataDir,
|
|
27725
|
-
personaRoot:
|
|
27807
|
+
personaRoot: import_node_path27.default.join(config.dataDir, "personas"),
|
|
27726
27808
|
personaStore,
|
|
27727
27809
|
ownerDisplayName,
|
|
27728
27810
|
mode: config.mode,
|
|
@@ -27745,7 +27827,7 @@ async function startDaemon(config) {
|
|
|
27745
27827
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
27746
27828
|
attachmentGroup: {
|
|
27747
27829
|
onFileEdit: (input) => {
|
|
27748
|
-
const absPath =
|
|
27830
|
+
const absPath = import_node_path27.default.isAbsolute(input.relPath) ? input.relPath : import_node_path27.default.join(input.cwd, input.relPath);
|
|
27749
27831
|
let size = 0;
|
|
27750
27832
|
try {
|
|
27751
27833
|
size = import_node_fs24.default.statSync(absPath).size;
|
|
@@ -27844,22 +27926,22 @@ async function startDaemon(config) {
|
|
|
27844
27926
|
httpToken: resolvedAuthToken,
|
|
27845
27927
|
// file-sharing attachment.* RPC。signUrl 用 owner token 做 HMAC secret;group RPC
|
|
27846
27928
|
// 根据 sessionId 反查 scope 写盘。
|
|
27929
|
+
//
|
|
27930
|
+
// sessionStore / getSessionScope 都走 manager 的跨 scope 公开 API(findOwnedSession /
|
|
27931
|
+
// findOwnedSessionScope)—— 否则 default-only SessionStore 找不到 persona owner-mode
|
|
27932
|
+
// session,attachment 整套 RPC 对 persona session 都会报 "session not found"。
|
|
27933
|
+
// 详见 fix(daemon) #703:file-sharing v1 预存 wiring bug,#701 把 desktop 默认 --tunnel
|
|
27934
|
+
// 后首次让 desktop 用户用上 file-sharing 才被暴露。
|
|
27847
27935
|
attachment: {
|
|
27848
27936
|
groupFileStore,
|
|
27937
|
+
sessionStore: { read: (sid) => manager.findOwnedSession(sid) },
|
|
27849
27938
|
getHttpBaseUrl,
|
|
27850
|
-
// HMAC sign secret
|
|
27851
|
-
// noAuth 模式
|
|
27852
|
-
getSignSecret: () =>
|
|
27853
|
-
// group RPC
|
|
27939
|
+
// HMAC sign secret:~/.clawd/auth.json signSecret 字段(与 WS Bearer token 独立)。
|
|
27940
|
+
// --auth-token CLI 模式 / noAuth 模式 authFile 为 null → handler 自己返 NOT_IMPLEMENTED。
|
|
27941
|
+
getSignSecret: () => authFile?.signSecret ?? "",
|
|
27942
|
+
// group RPC + sign 都用:根据 sessionId 反查 scope。owner-mode persona session 走
|
|
27854
27943
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
27855
|
-
getSessionScope: (
|
|
27856
|
-
const file = store.read(sessionId);
|
|
27857
|
-
if (!file) return null;
|
|
27858
|
-
if (file.ownerPersonaId) {
|
|
27859
|
-
return { kind: "persona", personaId: file.ownerPersonaId, mode: "owner" };
|
|
27860
|
-
}
|
|
27861
|
-
return { kind: "default" };
|
|
27862
|
-
}
|
|
27944
|
+
getSessionScope: (sid) => manager.findOwnedSessionScope(sid)
|
|
27863
27945
|
}
|
|
27864
27946
|
});
|
|
27865
27947
|
const authResolver = new AuthContextResolver({
|
|
@@ -27873,8 +27955,9 @@ async function startDaemon(config) {
|
|
|
27873
27955
|
personaStore,
|
|
27874
27956
|
groupFileStore,
|
|
27875
27957
|
sessionStore: store,
|
|
27876
|
-
// /files HMAC verify
|
|
27877
|
-
|
|
27958
|
+
// /files HMAC verify 用 auth.json 的 signSecret 字段(与 attachment.signUrl 同源)。
|
|
27959
|
+
// --auth-token CLI 模式没 signSecret → 路由返 501,sign URL 功能整体禁用。
|
|
27960
|
+
getSignSecret: () => authFile?.signSecret ?? null
|
|
27878
27961
|
});
|
|
27879
27962
|
wsServer = new LocalWsServer({
|
|
27880
27963
|
host: config.host,
|
|
@@ -28012,8 +28095,8 @@ async function startDaemon(config) {
|
|
|
28012
28095
|
const lines = [
|
|
28013
28096
|
`Tunnel: ${r.url}`,
|
|
28014
28097
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
28015
|
-
`Frpc config: ${
|
|
28016
|
-
`Frpc log: ${
|
|
28098
|
+
`Frpc config: ${import_node_path27.default.join(config.dataDir, "frpc.toml")}`,
|
|
28099
|
+
`Frpc log: ${import_node_path27.default.join(config.dataDir, "frpc.log")}`
|
|
28017
28100
|
];
|
|
28018
28101
|
const width = Math.max(...lines.map((l) => l.length));
|
|
28019
28102
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -28026,7 +28109,7 @@ ${bar}
|
|
|
28026
28109
|
|
|
28027
28110
|
`);
|
|
28028
28111
|
try {
|
|
28029
|
-
const connectPath =
|
|
28112
|
+
const connectPath = import_node_path27.default.join(config.dataDir, "connect.txt");
|
|
28030
28113
|
import_node_fs24.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
28031
28114
|
} catch {
|
|
28032
28115
|
}
|
package/package.json
CHANGED