@clawos-dev/clawd 0.2.128 → 0.2.129
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 +485 -387
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -720,8 +720,8 @@ var init_parseUtil = __esm({
|
|
|
720
720
|
init_errors2();
|
|
721
721
|
init_en();
|
|
722
722
|
makeIssue = (params) => {
|
|
723
|
-
const { data, path:
|
|
724
|
-
const fullPath = [...
|
|
723
|
+
const { data, path: path59, errorMaps, issueData } = params;
|
|
724
|
+
const fullPath = [...path59, ...issueData.path || []];
|
|
725
725
|
const fullIssue = {
|
|
726
726
|
...issueData,
|
|
727
727
|
path: fullPath
|
|
@@ -1032,11 +1032,11 @@ var init_types = __esm({
|
|
|
1032
1032
|
init_parseUtil();
|
|
1033
1033
|
init_util();
|
|
1034
1034
|
ParseInputLazyPath = class {
|
|
1035
|
-
constructor(parent, value,
|
|
1035
|
+
constructor(parent, value, path59, key) {
|
|
1036
1036
|
this._cachedPath = [];
|
|
1037
1037
|
this.parent = parent;
|
|
1038
1038
|
this.data = value;
|
|
1039
|
-
this._path =
|
|
1039
|
+
this._path = path59;
|
|
1040
1040
|
this._key = key;
|
|
1041
1041
|
}
|
|
1042
1042
|
get path() {
|
|
@@ -4523,7 +4523,11 @@ var init_persona_schemas = __esm({
|
|
|
4523
4523
|
});
|
|
4524
4524
|
PersonaSandboxSettingsSchema = external_exports.object({
|
|
4525
4525
|
permissions: external_exports.object({
|
|
4526
|
-
defaultMode: external_exports.string().optional()
|
|
4526
|
+
defaultMode: external_exports.string().optional(),
|
|
4527
|
+
// CC 工具 allowlist('Bash'/'Read'/...)。per-persona profile 在最严格 base 上追加放开。
|
|
4528
|
+
allow: external_exports.array(external_exports.string()).optional(),
|
|
4529
|
+
// deny 优先级最高;强制底座(persona 私密区)由 daemon compose 强制 union,owner 删不掉。
|
|
4530
|
+
deny: external_exports.array(external_exports.string()).optional()
|
|
4527
4531
|
}).optional(),
|
|
4528
4532
|
sandbox: external_exports.object({
|
|
4529
4533
|
enabled: external_exports.boolean().optional(),
|
|
@@ -4534,6 +4538,11 @@ var init_persona_schemas = __esm({
|
|
|
4534
4538
|
allowRead: external_exports.array(external_exports.string()).optional(),
|
|
4535
4539
|
denyWrite: external_exports.array(external_exports.string()).optional(),
|
|
4536
4540
|
allowWrite: external_exports.array(external_exports.string()).optional()
|
|
4541
|
+
}).optional(),
|
|
4542
|
+
// 出站网络 + 本机端口。base 不放(空),profile 按需追加域名(app-builder = ['*'])。
|
|
4543
|
+
network: external_exports.object({
|
|
4544
|
+
allowedDomains: external_exports.array(external_exports.string()).optional(),
|
|
4545
|
+
allowLocalBinding: external_exports.boolean().optional()
|
|
4537
4546
|
}).optional()
|
|
4538
4547
|
}).optional()
|
|
4539
4548
|
});
|
|
@@ -6181,8 +6190,8 @@ var require_req = __commonJS({
|
|
|
6181
6190
|
if (req.originalUrl) {
|
|
6182
6191
|
_req.url = req.originalUrl;
|
|
6183
6192
|
} else {
|
|
6184
|
-
const
|
|
6185
|
-
_req.url = typeof
|
|
6193
|
+
const path59 = req.path;
|
|
6194
|
+
_req.url = typeof path59 === "string" ? path59 : req.url ? req.url.path || req.url : void 0;
|
|
6186
6195
|
}
|
|
6187
6196
|
if (req.query) {
|
|
6188
6197
|
_req.query = req.query;
|
|
@@ -6347,14 +6356,14 @@ var require_redact = __commonJS({
|
|
|
6347
6356
|
}
|
|
6348
6357
|
return obj;
|
|
6349
6358
|
}
|
|
6350
|
-
function parsePath(
|
|
6359
|
+
function parsePath(path59) {
|
|
6351
6360
|
const parts = [];
|
|
6352
6361
|
let current = "";
|
|
6353
6362
|
let inBrackets = false;
|
|
6354
6363
|
let inQuotes = false;
|
|
6355
6364
|
let quoteChar = "";
|
|
6356
|
-
for (let i = 0; i <
|
|
6357
|
-
const char =
|
|
6365
|
+
for (let i = 0; i < path59.length; i++) {
|
|
6366
|
+
const char = path59[i];
|
|
6358
6367
|
if (!inBrackets && char === ".") {
|
|
6359
6368
|
if (current) {
|
|
6360
6369
|
parts.push(current);
|
|
@@ -6485,10 +6494,10 @@ var require_redact = __commonJS({
|
|
|
6485
6494
|
return current;
|
|
6486
6495
|
}
|
|
6487
6496
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
6488
|
-
for (const
|
|
6489
|
-
const parts = parsePath(
|
|
6497
|
+
for (const path59 of paths) {
|
|
6498
|
+
const parts = parsePath(path59);
|
|
6490
6499
|
if (parts.includes("*")) {
|
|
6491
|
-
redactWildcardPath(obj, parts, censor,
|
|
6500
|
+
redactWildcardPath(obj, parts, censor, path59, remove);
|
|
6492
6501
|
} else {
|
|
6493
6502
|
if (remove) {
|
|
6494
6503
|
removeKey(obj, parts);
|
|
@@ -6573,8 +6582,8 @@ var require_redact = __commonJS({
|
|
|
6573
6582
|
}
|
|
6574
6583
|
} else {
|
|
6575
6584
|
if (afterWildcard.includes("*")) {
|
|
6576
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6577
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
6585
|
+
const wrappedCensor = typeof censor === "function" ? (value, path59) => {
|
|
6586
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path59];
|
|
6578
6587
|
return censor(value, fullPath);
|
|
6579
6588
|
} : censor;
|
|
6580
6589
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6609,8 +6618,8 @@ var require_redact = __commonJS({
|
|
|
6609
6618
|
return null;
|
|
6610
6619
|
}
|
|
6611
6620
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6612
|
-
for (const
|
|
6613
|
-
const parts = parsePath(
|
|
6621
|
+
for (const path59 of pathsToClone) {
|
|
6622
|
+
const parts = parsePath(path59);
|
|
6614
6623
|
let current = pathStructure;
|
|
6615
6624
|
for (let i = 0; i < parts.length; i++) {
|
|
6616
6625
|
const part = parts[i];
|
|
@@ -6662,24 +6671,24 @@ var require_redact = __commonJS({
|
|
|
6662
6671
|
}
|
|
6663
6672
|
return cloneSelectively(obj, pathStructure);
|
|
6664
6673
|
}
|
|
6665
|
-
function validatePath(
|
|
6666
|
-
if (typeof
|
|
6674
|
+
function validatePath(path59) {
|
|
6675
|
+
if (typeof path59 !== "string") {
|
|
6667
6676
|
throw new Error("Paths must be (non-empty) strings");
|
|
6668
6677
|
}
|
|
6669
|
-
if (
|
|
6678
|
+
if (path59 === "") {
|
|
6670
6679
|
throw new Error("Invalid redaction path ()");
|
|
6671
6680
|
}
|
|
6672
|
-
if (
|
|
6673
|
-
throw new Error(`Invalid redaction path (${
|
|
6681
|
+
if (path59.includes("..")) {
|
|
6682
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6674
6683
|
}
|
|
6675
|
-
if (
|
|
6676
|
-
throw new Error(`Invalid redaction path (${
|
|
6684
|
+
if (path59.includes(",")) {
|
|
6685
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6677
6686
|
}
|
|
6678
6687
|
let bracketCount = 0;
|
|
6679
6688
|
let inQuotes = false;
|
|
6680
6689
|
let quoteChar = "";
|
|
6681
|
-
for (let i = 0; i <
|
|
6682
|
-
const char =
|
|
6690
|
+
for (let i = 0; i < path59.length; i++) {
|
|
6691
|
+
const char = path59[i];
|
|
6683
6692
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6684
6693
|
if (!inQuotes) {
|
|
6685
6694
|
inQuotes = true;
|
|
@@ -6693,20 +6702,20 @@ var require_redact = __commonJS({
|
|
|
6693
6702
|
} else if (char === "]" && !inQuotes) {
|
|
6694
6703
|
bracketCount--;
|
|
6695
6704
|
if (bracketCount < 0) {
|
|
6696
|
-
throw new Error(`Invalid redaction path (${
|
|
6705
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6697
6706
|
}
|
|
6698
6707
|
}
|
|
6699
6708
|
}
|
|
6700
6709
|
if (bracketCount !== 0) {
|
|
6701
|
-
throw new Error(`Invalid redaction path (${
|
|
6710
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6702
6711
|
}
|
|
6703
6712
|
}
|
|
6704
6713
|
function validatePaths(paths) {
|
|
6705
6714
|
if (!Array.isArray(paths)) {
|
|
6706
6715
|
throw new TypeError("paths must be an array");
|
|
6707
6716
|
}
|
|
6708
|
-
for (const
|
|
6709
|
-
validatePath(
|
|
6717
|
+
for (const path59 of paths) {
|
|
6718
|
+
validatePath(path59);
|
|
6710
6719
|
}
|
|
6711
6720
|
}
|
|
6712
6721
|
function slowRedact(options = {}) {
|
|
@@ -6874,8 +6883,8 @@ var require_redaction = __commonJS({
|
|
|
6874
6883
|
if (shape[k2] === null) {
|
|
6875
6884
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6876
6885
|
} else {
|
|
6877
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6878
|
-
return censor(value, [k2, ...
|
|
6886
|
+
const wrappedCensor = typeof censor === "function" ? (value, path59) => {
|
|
6887
|
+
return censor(value, [k2, ...path59]);
|
|
6879
6888
|
} : censor;
|
|
6880
6889
|
o[k2] = Redact({
|
|
6881
6890
|
paths: shape[k2],
|
|
@@ -7096,7 +7105,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7096
7105
|
var fs50 = require("fs");
|
|
7097
7106
|
var EventEmitter3 = require("events");
|
|
7098
7107
|
var inherits = require("util").inherits;
|
|
7099
|
-
var
|
|
7108
|
+
var path59 = require("path");
|
|
7100
7109
|
var sleep = require_atomic_sleep();
|
|
7101
7110
|
var assert = require("assert");
|
|
7102
7111
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -7150,7 +7159,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7150
7159
|
const mode = sonic.mode;
|
|
7151
7160
|
if (sonic.sync) {
|
|
7152
7161
|
try {
|
|
7153
|
-
if (sonic.mkdir) fs50.mkdirSync(
|
|
7162
|
+
if (sonic.mkdir) fs50.mkdirSync(path59.dirname(file), { recursive: true });
|
|
7154
7163
|
const fd = fs50.openSync(file, flags, mode);
|
|
7155
7164
|
fileOpened(null, fd);
|
|
7156
7165
|
} catch (err) {
|
|
@@ -7158,7 +7167,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7158
7167
|
throw err;
|
|
7159
7168
|
}
|
|
7160
7169
|
} else if (sonic.mkdir) {
|
|
7161
|
-
fs50.mkdir(
|
|
7170
|
+
fs50.mkdir(path59.dirname(file), { recursive: true }, (err) => {
|
|
7162
7171
|
if (err) return fileOpened(err);
|
|
7163
7172
|
fs50.open(file, flags, mode, fileOpened);
|
|
7164
7173
|
});
|
|
@@ -10789,11 +10798,11 @@ var init_lib = __esm({
|
|
|
10789
10798
|
}
|
|
10790
10799
|
}
|
|
10791
10800
|
},
|
|
10792
|
-
addToPath: function addToPath(
|
|
10793
|
-
var last =
|
|
10801
|
+
addToPath: function addToPath(path59, added, removed, oldPosInc, options) {
|
|
10802
|
+
var last = path59.lastComponent;
|
|
10794
10803
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10795
10804
|
return {
|
|
10796
|
-
oldPos:
|
|
10805
|
+
oldPos: path59.oldPos + oldPosInc,
|
|
10797
10806
|
lastComponent: {
|
|
10798
10807
|
count: last.count + 1,
|
|
10799
10808
|
added,
|
|
@@ -10803,7 +10812,7 @@ var init_lib = __esm({
|
|
|
10803
10812
|
};
|
|
10804
10813
|
} else {
|
|
10805
10814
|
return {
|
|
10806
|
-
oldPos:
|
|
10815
|
+
oldPos: path59.oldPos + oldPosInc,
|
|
10807
10816
|
lastComponent: {
|
|
10808
10817
|
count: 1,
|
|
10809
10818
|
added,
|
|
@@ -11249,10 +11258,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
11249
11258
|
const memories = raw.map((m2) => {
|
|
11250
11259
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11251
11260
|
const rec = m2;
|
|
11252
|
-
const
|
|
11261
|
+
const path59 = typeof rec.path === "string" ? rec.path : null;
|
|
11253
11262
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11254
|
-
if (!
|
|
11255
|
-
const entry = { path:
|
|
11263
|
+
if (!path59 || content == null) return null;
|
|
11264
|
+
const entry = { path: path59, content };
|
|
11256
11265
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
11257
11266
|
return entry;
|
|
11258
11267
|
}).filter((m2) => m2 !== null);
|
|
@@ -11289,7 +11298,7 @@ function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
|
|
|
11289
11298
|
if (backupFileName === null) return null;
|
|
11290
11299
|
try {
|
|
11291
11300
|
return import_node_fs8.default.readFileSync(
|
|
11292
|
-
|
|
11301
|
+
import_node_path8.default.join(fileHistoryRoot, toolSessionId, backupFileName),
|
|
11293
11302
|
"utf8"
|
|
11294
11303
|
);
|
|
11295
11304
|
} catch {
|
|
@@ -11304,13 +11313,13 @@ function readCurrentContent(filePath) {
|
|
|
11304
11313
|
return null;
|
|
11305
11314
|
}
|
|
11306
11315
|
}
|
|
11307
|
-
var import_node_fs8, import_node_os3,
|
|
11316
|
+
var import_node_fs8, import_node_os3, import_node_path8, TASK_NOTIFICATION_RE, TASK_ID_RE, TOOL_USE_ID_RE, SLASH_COMMAND_RE, LOCAL_COMMAND_RE, SYSTEM_REMINDER_RE, OPENSPEC_BLOCK_RE, SKILL_HINT_RE, ATTACHMENT_SILENT_SUBTYPES, ClaudeHistoryReader;
|
|
11308
11317
|
var init_claude_history = __esm({
|
|
11309
11318
|
"src/tools/claude-history.ts"() {
|
|
11310
11319
|
"use strict";
|
|
11311
11320
|
import_node_fs8 = __toESM(require("fs"), 1);
|
|
11312
11321
|
import_node_os3 = __toESM(require("os"), 1);
|
|
11313
|
-
|
|
11322
|
+
import_node_path8 = __toESM(require("path"), 1);
|
|
11314
11323
|
init_lib();
|
|
11315
11324
|
init_tool_result_extra();
|
|
11316
11325
|
TASK_NOTIFICATION_RE = /<task-notification\b[\s\S]*?<\/task-notification>/i;
|
|
@@ -11334,9 +11343,9 @@ var init_claude_history = __esm({
|
|
|
11334
11343
|
// 每次 user 提交前 trackEdit 拷一份,作为 rewind 回退目标
|
|
11335
11344
|
fileHistoryRoot;
|
|
11336
11345
|
constructor(opts = {}) {
|
|
11337
|
-
const base = opts.baseDir ??
|
|
11338
|
-
this.projectsRoot =
|
|
11339
|
-
this.fileHistoryRoot =
|
|
11346
|
+
const base = opts.baseDir ?? import_node_path8.default.join(import_node_os3.default.homedir(), ".claude");
|
|
11347
|
+
this.projectsRoot = import_node_path8.default.join(base, "projects");
|
|
11348
|
+
this.fileHistoryRoot = import_node_path8.default.join(base, "file-history");
|
|
11340
11349
|
}
|
|
11341
11350
|
async listProjects() {
|
|
11342
11351
|
let entries;
|
|
@@ -11349,9 +11358,9 @@ var init_claude_history = __esm({
|
|
|
11349
11358
|
const out = [];
|
|
11350
11359
|
for (const ent of entries) {
|
|
11351
11360
|
if (!ent.isDirectory()) continue;
|
|
11352
|
-
const dir =
|
|
11361
|
+
const dir = import_node_path8.default.join(this.projectsRoot, ent.name);
|
|
11353
11362
|
const files = import_node_fs8.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
11354
|
-
const updatedAtMs = files.reduce((m2, f) => Math.max(m2, safeStatMtime(
|
|
11363
|
+
const updatedAtMs = files.reduce((m2, f) => Math.max(m2, safeStatMtime(import_node_path8.default.join(dir, f))), 0);
|
|
11355
11364
|
out.push({
|
|
11356
11365
|
projectPath: hashDirToCwd(ent.name),
|
|
11357
11366
|
hashDir: ent.name,
|
|
@@ -11363,7 +11372,7 @@ var init_claude_history = __esm({
|
|
|
11363
11372
|
return out;
|
|
11364
11373
|
}
|
|
11365
11374
|
async listSessions(args) {
|
|
11366
|
-
const dir =
|
|
11375
|
+
const dir = import_node_path8.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
|
|
11367
11376
|
let files;
|
|
11368
11377
|
try {
|
|
11369
11378
|
files = import_node_fs8.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
@@ -11373,7 +11382,7 @@ var init_claude_history = __esm({
|
|
|
11373
11382
|
}
|
|
11374
11383
|
const out = [];
|
|
11375
11384
|
for (const f of files) {
|
|
11376
|
-
const full =
|
|
11385
|
+
const full = import_node_path8.default.join(dir, f);
|
|
11377
11386
|
const toolSessionId = f.slice(0, -".jsonl".length);
|
|
11378
11387
|
const lines = readJsonlLines(full);
|
|
11379
11388
|
let summary = "";
|
|
@@ -11428,7 +11437,7 @@ var init_claude_history = __esm({
|
|
|
11428
11437
|
return out;
|
|
11429
11438
|
}
|
|
11430
11439
|
async read(args) {
|
|
11431
|
-
const file =
|
|
11440
|
+
const file = import_node_path8.default.join(
|
|
11432
11441
|
this.projectsRoot,
|
|
11433
11442
|
cwdToHashDir(args.cwd),
|
|
11434
11443
|
`${args.toolSessionId}.jsonl`
|
|
@@ -11465,7 +11474,7 @@ var init_claude_history = __esm({
|
|
|
11465
11474
|
// 独立目录路径:<projectsRoot>/<cwdHash>/<toolSessionId>/subagents/*.jsonl
|
|
11466
11475
|
// 返回 null 表示目录不存在(调用方回退旧实现);返回空数组表示目录存在但无 jsonl
|
|
11467
11476
|
listSubagentsFromDirectory(cwd, toolSessionId) {
|
|
11468
|
-
const dir =
|
|
11477
|
+
const dir = import_node_path8.default.join(
|
|
11469
11478
|
this.projectsRoot,
|
|
11470
11479
|
cwdToHashDir(cwd),
|
|
11471
11480
|
toolSessionId,
|
|
@@ -11483,7 +11492,7 @@ var init_claude_history = __esm({
|
|
|
11483
11492
|
if (!e.isFile()) continue;
|
|
11484
11493
|
if (!e.name.startsWith("agent-") || !e.name.endsWith(".jsonl")) continue;
|
|
11485
11494
|
const subagentId = e.name.slice("agent-".length, -".jsonl".length);
|
|
11486
|
-
const filePath =
|
|
11495
|
+
const filePath = import_node_path8.default.join(dir, e.name);
|
|
11487
11496
|
const lines = readJsonlLines(filePath);
|
|
11488
11497
|
let firstText = "";
|
|
11489
11498
|
let messageCount = 0;
|
|
@@ -11500,7 +11509,7 @@ var init_claude_history = __esm({
|
|
|
11500
11509
|
return out;
|
|
11501
11510
|
}
|
|
11502
11511
|
listSubagentsFromMainJsonl(cwd, toolSessionId) {
|
|
11503
|
-
const file =
|
|
11512
|
+
const file = import_node_path8.default.join(
|
|
11504
11513
|
this.projectsRoot,
|
|
11505
11514
|
cwdToHashDir(cwd),
|
|
11506
11515
|
`${toolSessionId}.jsonl`
|
|
@@ -11535,7 +11544,7 @@ var init_claude_history = __esm({
|
|
|
11535
11544
|
}
|
|
11536
11545
|
// 独立文件路径:agent-<subagentId>.jsonl;文件不存在返回 null 让调用方回退旧实现
|
|
11537
11546
|
readSubagentFromFile(cwd, toolSessionId, subagentId) {
|
|
11538
|
-
const file =
|
|
11547
|
+
const file = import_node_path8.default.join(
|
|
11539
11548
|
this.projectsRoot,
|
|
11540
11549
|
cwdToHashDir(cwd),
|
|
11541
11550
|
toolSessionId,
|
|
@@ -11563,7 +11572,7 @@ var init_claude_history = __esm({
|
|
|
11563
11572
|
* "那一刻每个 tracked 文件对应的 backup 文件名"
|
|
11564
11573
|
*/
|
|
11565
11574
|
readFileHistorySnapshots(args) {
|
|
11566
|
-
const file =
|
|
11575
|
+
const file = import_node_path8.default.join(
|
|
11567
11576
|
this.projectsRoot,
|
|
11568
11577
|
cwdToHashDir(args.cwd),
|
|
11569
11578
|
`${args.toolSessionId}.jsonl`
|
|
@@ -11608,7 +11617,7 @@ var init_claude_history = __esm({
|
|
|
11608
11617
|
for (const [anchorId, target] of snapshots) {
|
|
11609
11618
|
let hasAny = false;
|
|
11610
11619
|
for (const [rawPath, backup] of Object.entries(target)) {
|
|
11611
|
-
const absPath =
|
|
11620
|
+
const absPath = import_node_path8.default.isAbsolute(rawPath) ? rawPath : import_node_path8.default.join(args.cwd, rawPath);
|
|
11612
11621
|
const backupContent = readBackupContent(
|
|
11613
11622
|
this.fileHistoryRoot,
|
|
11614
11623
|
args.toolSessionId,
|
|
@@ -11648,7 +11657,7 @@ var init_claude_history = __esm({
|
|
|
11648
11657
|
let totalInsertions = 0;
|
|
11649
11658
|
let totalDeletions = 0;
|
|
11650
11659
|
for (const [rawPath, backup] of Object.entries(target)) {
|
|
11651
|
-
const absPath =
|
|
11660
|
+
const absPath = import_node_path8.default.isAbsolute(rawPath) ? rawPath : import_node_path8.default.join(args.cwd, rawPath);
|
|
11652
11661
|
const backupContent = readBackupContent(
|
|
11653
11662
|
this.fileHistoryRoot,
|
|
11654
11663
|
args.toolSessionId,
|
|
@@ -11695,7 +11704,7 @@ var init_claude_history = __esm({
|
|
|
11695
11704
|
};
|
|
11696
11705
|
}
|
|
11697
11706
|
readSubagentFromMainJsonl(cwd, toolSessionId, subagentId) {
|
|
11698
|
-
const file =
|
|
11707
|
+
const file = import_node_path8.default.join(
|
|
11699
11708
|
this.projectsRoot,
|
|
11700
11709
|
cwdToHashDir(cwd),
|
|
11701
11710
|
`${toolSessionId}.jsonl`
|
|
@@ -11719,7 +11728,7 @@ var init_claude_history = __esm({
|
|
|
11719
11728
|
// src/tools/claude.ts
|
|
11720
11729
|
function macOSDesktopCandidates(home) {
|
|
11721
11730
|
return [
|
|
11722
|
-
|
|
11731
|
+
import_node_path9.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
|
|
11723
11732
|
"/Applications/Claude.app/Contents/Resources/app.asar.unpacked/node_modules/@anthropic-ai/claude-code/cli.js"
|
|
11724
11733
|
];
|
|
11725
11734
|
}
|
|
@@ -12064,10 +12073,10 @@ function parseAttachment(obj) {
|
|
|
12064
12073
|
const memories = raw.map((m2) => {
|
|
12065
12074
|
if (!m2 || typeof m2 !== "object") return null;
|
|
12066
12075
|
const rec = m2;
|
|
12067
|
-
const
|
|
12076
|
+
const path59 = typeof rec.path === "string" ? rec.path : null;
|
|
12068
12077
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
12069
|
-
if (!
|
|
12070
|
-
const out = { path:
|
|
12078
|
+
if (!path59 || content == null) return null;
|
|
12079
|
+
const out = { path: path59, content };
|
|
12071
12080
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
12072
12081
|
return out;
|
|
12073
12082
|
}).filter((m2) => m2 !== null);
|
|
@@ -12171,7 +12180,7 @@ function encodeClaudeStdin(text) {
|
|
|
12171
12180
|
};
|
|
12172
12181
|
return JSON.stringify(frame) + "\n";
|
|
12173
12182
|
}
|
|
12174
|
-
var import_node_child_process, import_node_child_process2, import_node_fs9, import_node_os4,
|
|
12183
|
+
var import_node_child_process, import_node_child_process2, import_node_fs9, import_node_os4, import_node_path9, ATTACHMENT_SILENT_SUBTYPES2, unknownTypeHandler, ATTACHMENT_RE, IMAGE_EXT_MIME, CLAUDE_MODELS, CLAUDE_PERMISSION_MODES, CLAUDE_CAPABILITIES, ClaudeAdapter;
|
|
12175
12184
|
var init_claude = __esm({
|
|
12176
12185
|
"src/tools/claude.ts"() {
|
|
12177
12186
|
"use strict";
|
|
@@ -12179,7 +12188,7 @@ var init_claude = __esm({
|
|
|
12179
12188
|
import_node_child_process2 = require("child_process");
|
|
12180
12189
|
import_node_fs9 = __toESM(require("fs"), 1);
|
|
12181
12190
|
import_node_os4 = __toESM(require("os"), 1);
|
|
12182
|
-
|
|
12191
|
+
import_node_path9 = __toESM(require("path"), 1);
|
|
12183
12192
|
init_protocol();
|
|
12184
12193
|
init_claude_history();
|
|
12185
12194
|
init_tool_result_extra();
|
|
@@ -23855,8 +23864,8 @@ var require_utils = __commonJS({
|
|
|
23855
23864
|
var result = transform[inputType][outputType](input);
|
|
23856
23865
|
return result;
|
|
23857
23866
|
};
|
|
23858
|
-
exports2.resolve = function(
|
|
23859
|
-
var parts =
|
|
23867
|
+
exports2.resolve = function(path59) {
|
|
23868
|
+
var parts = path59.split("/");
|
|
23860
23869
|
var result = [];
|
|
23861
23870
|
for (var index = 0; index < parts.length; index++) {
|
|
23862
23871
|
var part = parts[index];
|
|
@@ -29709,18 +29718,18 @@ var require_object = __commonJS({
|
|
|
29709
29718
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
29710
29719
|
this.files[name] = object;
|
|
29711
29720
|
};
|
|
29712
|
-
var parentFolder = function(
|
|
29713
|
-
if (
|
|
29714
|
-
|
|
29721
|
+
var parentFolder = function(path59) {
|
|
29722
|
+
if (path59.slice(-1) === "/") {
|
|
29723
|
+
path59 = path59.substring(0, path59.length - 1);
|
|
29715
29724
|
}
|
|
29716
|
-
var lastSlash =
|
|
29717
|
-
return lastSlash > 0 ?
|
|
29725
|
+
var lastSlash = path59.lastIndexOf("/");
|
|
29726
|
+
return lastSlash > 0 ? path59.substring(0, lastSlash) : "";
|
|
29718
29727
|
};
|
|
29719
|
-
var forceTrailingSlash = function(
|
|
29720
|
-
if (
|
|
29721
|
-
|
|
29728
|
+
var forceTrailingSlash = function(path59) {
|
|
29729
|
+
if (path59.slice(-1) !== "/") {
|
|
29730
|
+
path59 += "/";
|
|
29722
29731
|
}
|
|
29723
|
-
return
|
|
29732
|
+
return path59;
|
|
29724
29733
|
};
|
|
29725
29734
|
var folderAdd = function(name, createFolders) {
|
|
29726
29735
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -30722,7 +30731,7 @@ var require_lib3 = __commonJS({
|
|
|
30722
30731
|
// src/run-case/recorder.ts
|
|
30723
30732
|
function startRunCaseRecorder(opts) {
|
|
30724
30733
|
const now = opts.now ?? Date.now;
|
|
30725
|
-
const dir =
|
|
30734
|
+
const dir = import_node_path47.default.dirname(opts.recordPath);
|
|
30726
30735
|
let stream = null;
|
|
30727
30736
|
let closing = false;
|
|
30728
30737
|
let closedSettled = false;
|
|
@@ -30762,12 +30771,12 @@ function startRunCaseRecorder(opts) {
|
|
|
30762
30771
|
};
|
|
30763
30772
|
return { tap, close, closed };
|
|
30764
30773
|
}
|
|
30765
|
-
var import_node_fs33,
|
|
30774
|
+
var import_node_fs33, import_node_path47;
|
|
30766
30775
|
var init_recorder = __esm({
|
|
30767
30776
|
"src/run-case/recorder.ts"() {
|
|
30768
30777
|
"use strict";
|
|
30769
30778
|
import_node_fs33 = __toESM(require("fs"), 1);
|
|
30770
|
-
|
|
30779
|
+
import_node_path47 = __toESM(require("path"), 1);
|
|
30771
30780
|
}
|
|
30772
30781
|
});
|
|
30773
30782
|
|
|
@@ -30810,7 +30819,7 @@ var init_wire = __esm({
|
|
|
30810
30819
|
// src/run-case/controller.ts
|
|
30811
30820
|
async function runController(opts) {
|
|
30812
30821
|
const now = opts.now ?? Date.now;
|
|
30813
|
-
const cwd = opts.cwd ?? (0, import_node_fs34.mkdtempSync)(
|
|
30822
|
+
const cwd = opts.cwd ?? (0, import_node_fs34.mkdtempSync)(import_node_path48.default.join(import_node_os19.default.tmpdir(), "clawd-runcase-"));
|
|
30814
30823
|
const ownsCwd = opts.cwd === void 0;
|
|
30815
30824
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
30816
30825
|
const spawnCtx = { cwd };
|
|
@@ -30977,13 +30986,13 @@ async function runController(opts) {
|
|
|
30977
30986
|
}
|
|
30978
30987
|
return exitCode ?? 0;
|
|
30979
30988
|
}
|
|
30980
|
-
var import_node_fs34, import_node_os19,
|
|
30989
|
+
var import_node_fs34, import_node_os19, import_node_path48;
|
|
30981
30990
|
var init_controller = __esm({
|
|
30982
30991
|
"src/run-case/controller.ts"() {
|
|
30983
30992
|
"use strict";
|
|
30984
30993
|
import_node_fs34 = require("fs");
|
|
30985
30994
|
import_node_os19 = __toESM(require("os"), 1);
|
|
30986
|
-
|
|
30995
|
+
import_node_path48 = __toESM(require("path"), 1);
|
|
30987
30996
|
init_claude();
|
|
30988
30997
|
init_stdout_splitter();
|
|
30989
30998
|
init_permission_stdio();
|
|
@@ -31218,7 +31227,7 @@ Env (advanced):
|
|
|
31218
31227
|
`;
|
|
31219
31228
|
|
|
31220
31229
|
// src/index.ts
|
|
31221
|
-
var
|
|
31230
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
31222
31231
|
var import_node_fs32 = __toESM(require("fs"), 1);
|
|
31223
31232
|
|
|
31224
31233
|
// src/logger.ts
|
|
@@ -31257,15 +31266,12 @@ function createLogger(opts = {}) {
|
|
|
31257
31266
|
}
|
|
31258
31267
|
|
|
31259
31268
|
// src/session/store-factory.ts
|
|
31260
|
-
var
|
|
31269
|
+
var path5 = __toESM(require("path"), 1);
|
|
31261
31270
|
|
|
31262
31271
|
// src/session/store.ts
|
|
31263
31272
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
31264
|
-
var import_node_path4 = __toESM(require("path"), 1);
|
|
31265
|
-
init_protocol();
|
|
31266
|
-
|
|
31267
|
-
// src/session/scope.ts
|
|
31268
31273
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
31274
|
+
init_protocol();
|
|
31269
31275
|
|
|
31270
31276
|
// src/session/user-workdir.ts
|
|
31271
31277
|
var path3 = __toESM(require("path"), 1);
|
|
@@ -31301,7 +31307,6 @@ function metaFromScope(scope, personaRoot, usersRoot) {
|
|
|
31301
31307
|
return {
|
|
31302
31308
|
idleKillEnabled: true,
|
|
31303
31309
|
personaMode: "guest",
|
|
31304
|
-
extraSettings: import_node_path3.default.join(personaRoot, scope.personaId, ".clawd", "sandbox-settings.json"),
|
|
31305
31310
|
userWorkDir,
|
|
31306
31311
|
addDirs: [userWorkDir]
|
|
31307
31312
|
};
|
|
@@ -31331,7 +31336,7 @@ var SessionStore = class {
|
|
|
31331
31336
|
this.root = opts.root;
|
|
31332
31337
|
} else {
|
|
31333
31338
|
const scope = opts.scope ?? { kind: "default" };
|
|
31334
|
-
this.root =
|
|
31339
|
+
this.root = import_node_path3.default.join(
|
|
31335
31340
|
opts.dataDir,
|
|
31336
31341
|
"sessions",
|
|
31337
31342
|
...scopeSubPath(scope).map(safeFileName)
|
|
@@ -31339,7 +31344,7 @@ var SessionStore = class {
|
|
|
31339
31344
|
}
|
|
31340
31345
|
}
|
|
31341
31346
|
filePath(sessionId) {
|
|
31342
|
-
return
|
|
31347
|
+
return import_node_path3.default.join(this.root, `${safeFileName(sessionId)}.json`);
|
|
31343
31348
|
}
|
|
31344
31349
|
ensureDir() {
|
|
31345
31350
|
import_node_fs3.default.mkdirSync(this.root, { recursive: true });
|
|
@@ -31387,7 +31392,7 @@ var SessionStore = class {
|
|
|
31387
31392
|
for (const name of entries) {
|
|
31388
31393
|
if (!name.endsWith(".json")) continue;
|
|
31389
31394
|
if (name.includes(".tmp-")) continue;
|
|
31390
|
-
const full =
|
|
31395
|
+
const full = import_node_path3.default.join(this.root, name);
|
|
31391
31396
|
try {
|
|
31392
31397
|
const raw = import_node_fs3.default.readFileSync(full, "utf8");
|
|
31393
31398
|
const parsed = JSON.parse(raw);
|
|
@@ -31413,10 +31418,10 @@ var SessionStoreFactory = class {
|
|
|
31413
31418
|
}
|
|
31414
31419
|
// ---- root path 派生(暴露给 migration / revoke cascade 等外部消费方) ----
|
|
31415
31420
|
bareRoot() {
|
|
31416
|
-
return
|
|
31421
|
+
return path5.join(this.dataDir, "sessions");
|
|
31417
31422
|
}
|
|
31418
31423
|
vmOwnerRoot(personaId) {
|
|
31419
|
-
return
|
|
31424
|
+
return path5.join(
|
|
31420
31425
|
this.dataDir,
|
|
31421
31426
|
"personas",
|
|
31422
31427
|
safeFileName(personaId),
|
|
@@ -31426,7 +31431,7 @@ var SessionStoreFactory = class {
|
|
|
31426
31431
|
);
|
|
31427
31432
|
}
|
|
31428
31433
|
vmGuestRoot(personaId, capId) {
|
|
31429
|
-
return
|
|
31434
|
+
return path5.join(
|
|
31430
31435
|
this.dataDir,
|
|
31431
31436
|
"personas",
|
|
31432
31437
|
safeFileName(personaId),
|
|
@@ -31463,7 +31468,7 @@ var SessionStoreFactory = class {
|
|
|
31463
31468
|
|
|
31464
31469
|
// src/session/manager.ts
|
|
31465
31470
|
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
31466
|
-
var
|
|
31471
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
31467
31472
|
|
|
31468
31473
|
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
31469
31474
|
var byteToHex = [];
|
|
@@ -31515,6 +31520,78 @@ var v4_default = v4;
|
|
|
31515
31520
|
// src/session/manager.ts
|
|
31516
31521
|
init_protocol();
|
|
31517
31522
|
|
|
31523
|
+
// src/tools/guest-settings.ts
|
|
31524
|
+
var FORCED_DENY_READ = ["~/"];
|
|
31525
|
+
var FORCED_TOOL_DENY = ["Edit(./**)"];
|
|
31526
|
+
function unionArr(a, b2) {
|
|
31527
|
+
const out = [...a ?? []];
|
|
31528
|
+
for (const x of b2) if (!out.includes(x)) out.push(x);
|
|
31529
|
+
return out;
|
|
31530
|
+
}
|
|
31531
|
+
function isGuestSettingsLike(v2) {
|
|
31532
|
+
if (!v2 || typeof v2 !== "object") return false;
|
|
31533
|
+
const sb = v2.sandbox;
|
|
31534
|
+
return !!sb && typeof sb === "object";
|
|
31535
|
+
}
|
|
31536
|
+
function buildGuestSettingsV1() {
|
|
31537
|
+
return {
|
|
31538
|
+
permissions: {
|
|
31539
|
+
defaultMode: "dontAsk",
|
|
31540
|
+
deny: [...FORCED_TOOL_DENY]
|
|
31541
|
+
// 保留 persona 限制:挡 CC 工具改/读 persona(cwd=persona)
|
|
31542
|
+
},
|
|
31543
|
+
sandbox: {
|
|
31544
|
+
enabled: true,
|
|
31545
|
+
autoAllowBashIfSandboxed: true,
|
|
31546
|
+
// Bash 自动过沙箱;文件工具 dontAsk 自动拒(最严格只 Bash)
|
|
31547
|
+
allowUnsandboxedCommands: false,
|
|
31548
|
+
// 关 dangerouslyDisableSandbox 逃逸口
|
|
31549
|
+
filesystem: {
|
|
31550
|
+
denyRead: ["~/"],
|
|
31551
|
+
denyWrite: [],
|
|
31552
|
+
// **不放 '~/'**(写是白名单制,home 自动不可写);persona(cwd) 由 compose 强制 deny
|
|
31553
|
+
allowRead: [],
|
|
31554
|
+
// 不放 cwd(persona);userWorkDir 由 compose 注入,profile 加工具链精确路径
|
|
31555
|
+
allowWrite: []
|
|
31556
|
+
}
|
|
31557
|
+
}
|
|
31558
|
+
};
|
|
31559
|
+
}
|
|
31560
|
+
function applyProfile(base, profile) {
|
|
31561
|
+
if (profile.permissions?.defaultMode) base.permissions.defaultMode = profile.permissions.defaultMode;
|
|
31562
|
+
if (profile.permissions?.allow) base.permissions.allow = unionArr(base.permissions.allow, profile.permissions.allow);
|
|
31563
|
+
if (profile.permissions?.deny) base.permissions.deny = unionArr(base.permissions.deny, profile.permissions.deny);
|
|
31564
|
+
const pf = profile.sandbox?.filesystem;
|
|
31565
|
+
if (pf) {
|
|
31566
|
+
const f = base.sandbox.filesystem ?? (base.sandbox.filesystem = {});
|
|
31567
|
+
if (pf.allowRead) f.allowRead = unionArr(f.allowRead, pf.allowRead);
|
|
31568
|
+
if (pf.allowWrite) f.allowWrite = unionArr(f.allowWrite, pf.allowWrite);
|
|
31569
|
+
if (pf.denyRead) f.denyRead = unionArr(f.denyRead, pf.denyRead);
|
|
31570
|
+
if (pf.denyWrite) f.denyWrite = unionArr(f.denyWrite, pf.denyWrite);
|
|
31571
|
+
}
|
|
31572
|
+
const pn = profile.sandbox?.network;
|
|
31573
|
+
if (pn) {
|
|
31574
|
+
const n = base.sandbox.network ?? (base.sandbox.network = {});
|
|
31575
|
+
if (pn.allowedDomains) n.allowedDomains = unionArr(n.allowedDomains, pn.allowedDomains);
|
|
31576
|
+
if (pn.allowLocalBinding !== void 0) n.allowLocalBinding = pn.allowLocalBinding;
|
|
31577
|
+
}
|
|
31578
|
+
return base;
|
|
31579
|
+
}
|
|
31580
|
+
function composeGuestSandbox(base, userWorkDir, spawnCwd) {
|
|
31581
|
+
const s = isGuestSettingsLike(base) ? base : buildGuestSettingsV1();
|
|
31582
|
+
s.permissions = s.permissions ?? { defaultMode: "dontAsk" };
|
|
31583
|
+
const fsv = s.sandbox.filesystem ?? (s.sandbox.filesystem = {});
|
|
31584
|
+
s.sandbox.enabled = true;
|
|
31585
|
+
s.sandbox.autoAllowBashIfSandboxed = true;
|
|
31586
|
+
s.sandbox.allowUnsandboxedCommands = false;
|
|
31587
|
+
fsv.denyRead = unionArr(fsv.denyRead, FORCED_DENY_READ);
|
|
31588
|
+
fsv.denyWrite = unionArr((fsv.denyWrite ?? []).filter((p2) => p2 !== "~/"), [spawnCwd]);
|
|
31589
|
+
s.permissions.deny = unionArr(s.permissions.deny, FORCED_TOOL_DENY);
|
|
31590
|
+
fsv.allowRead = unionArr(fsv.allowRead, [userWorkDir]);
|
|
31591
|
+
fsv.allowWrite = unionArr(fsv.allowWrite, [userWorkDir]);
|
|
31592
|
+
return s;
|
|
31593
|
+
}
|
|
31594
|
+
|
|
31518
31595
|
// src/session/reducer.ts
|
|
31519
31596
|
init_runtime();
|
|
31520
31597
|
|
|
@@ -32282,7 +32359,7 @@ init_stdout_splitter();
|
|
|
32282
32359
|
|
|
32283
32360
|
// src/ipc-recorder.ts
|
|
32284
32361
|
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
32285
|
-
var
|
|
32362
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
32286
32363
|
function tsForFilename(ms) {
|
|
32287
32364
|
return new Date(ms).toISOString().replace(/[:.]/g, "-");
|
|
32288
32365
|
}
|
|
@@ -32293,8 +32370,8 @@ function startRecorder(opts) {
|
|
|
32293
32370
|
return null;
|
|
32294
32371
|
}
|
|
32295
32372
|
const now = opts.now ?? Date.now;
|
|
32296
|
-
const dir =
|
|
32297
|
-
const filePath =
|
|
32373
|
+
const dir = import_node_path4.default.join(opts.dataDir, "ipc-recordings", opts.sessionId);
|
|
32374
|
+
const filePath = import_node_path4.default.join(dir, `${tsForFilename(now())}.jsonl`);
|
|
32298
32375
|
let stream = null;
|
|
32299
32376
|
let closedResolve;
|
|
32300
32377
|
const closed = new Promise((resolve6) => {
|
|
@@ -32746,9 +32823,9 @@ function extractEditPath(input) {
|
|
|
32746
32823
|
|
|
32747
32824
|
// src/debug/pty-probe.ts
|
|
32748
32825
|
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
32749
|
-
var
|
|
32826
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
32750
32827
|
var PROBE_DIR = "/tmp/clawd-probe";
|
|
32751
|
-
var EVENTS_FILE =
|
|
32828
|
+
var EVENTS_FILE = import_node_path5.default.join(PROBE_DIR, "events.jsonl");
|
|
32752
32829
|
var inited = false;
|
|
32753
32830
|
function ensureDir() {
|
|
32754
32831
|
if (inited) return true;
|
|
@@ -32771,7 +32848,7 @@ function probeEvent(event, data = {}) {
|
|
|
32771
32848
|
function probeDumpReplay(sessionId, payload) {
|
|
32772
32849
|
try {
|
|
32773
32850
|
if (!ensureDir()) return "";
|
|
32774
|
-
const file =
|
|
32851
|
+
const file = import_node_path5.default.join(PROBE_DIR, `replay-${sessionId}-${Date.now()}.ans`);
|
|
32775
32852
|
import_node_fs5.default.writeFileSync(file, payload, "utf8");
|
|
32776
32853
|
return file;
|
|
32777
32854
|
} catch {
|
|
@@ -32863,7 +32940,7 @@ function derivePersonaSpawnCwd(file, personaRoot) {
|
|
|
32863
32940
|
`derivePersonaSpawnCwd: personaRoot missing for owner session ${file.sessionId} (ownerPersonaId=${personaId})`
|
|
32864
32941
|
);
|
|
32865
32942
|
}
|
|
32866
|
-
return
|
|
32943
|
+
return import_node_path6.default.join(personaRoot, safeFileName(personaId));
|
|
32867
32944
|
}
|
|
32868
32945
|
function makeInitialState(file, subSessionMeta) {
|
|
32869
32946
|
return {
|
|
@@ -32980,7 +33057,7 @@ var SessionManager = class {
|
|
|
32980
33057
|
// <dataDir>/sessions/ 列子目录 (排除 'default').
|
|
32981
33058
|
listPersonaIdsOnDisk() {
|
|
32982
33059
|
if (!this.deps.dataDir) return [];
|
|
32983
|
-
const root = this.deps.storeFactory ?
|
|
33060
|
+
const root = this.deps.storeFactory ? import_node_path6.default.join(this.deps.dataDir, "personas") : import_node_path6.default.join(this.deps.dataDir, "sessions");
|
|
32984
33061
|
let entries;
|
|
32985
33062
|
try {
|
|
32986
33063
|
entries = import_node_fs6.default.readdirSync(root, { withFileTypes: true });
|
|
@@ -32996,7 +33073,7 @@ var SessionManager = class {
|
|
|
32996
33073
|
// 只在 storeFactory 注入 (新布局) 下生效, 老布局无 guest 目录.
|
|
32997
33074
|
listGuestCapIdsForPersona(personaId) {
|
|
32998
33075
|
if (!this.deps.dataDir || !this.deps.storeFactory) return [];
|
|
32999
|
-
const root =
|
|
33076
|
+
const root = import_node_path6.default.join(
|
|
33000
33077
|
this.deps.dataDir,
|
|
33001
33078
|
"personas",
|
|
33002
33079
|
personaId,
|
|
@@ -33117,6 +33194,16 @@ var SessionManager = class {
|
|
|
33117
33194
|
const adapter = this.deps.getAdapter(file.tool ?? "claude");
|
|
33118
33195
|
const store = this.storeFor(scope);
|
|
33119
33196
|
const subSessionMeta = metaFromScope(scope, this.deps.personaRoot ?? "", this.deps.usersRoot ?? "");
|
|
33197
|
+
if (scope.kind === "persona" && scope.mode === "guest") {
|
|
33198
|
+
if (!this.deps.personaRoot || !subSessionMeta?.userWorkDir) {
|
|
33199
|
+
throw new Error(
|
|
33200
|
+
`newRunner: guest session ${file.sessionId} \u7F3A personaRoot/userWorkDir\uFF0C\u65E0\u6CD5\u7269\u5316 OS \u6C99\u7BB1\uFF08\u62D2\u7EDD\u521B\u5EFA\u65E0\u6C99\u7BB1 guest\uFF09`
|
|
33201
|
+
);
|
|
33202
|
+
}
|
|
33203
|
+
const base = this.deps.personaStore?.readSandboxSettings(scope.personaId) ?? null;
|
|
33204
|
+
const settings = composeGuestSandbox(base, subSessionMeta.userWorkDir, file.cwd);
|
|
33205
|
+
subSessionMeta.extraSettings = JSON.stringify(settings);
|
|
33206
|
+
}
|
|
33120
33207
|
const attachmentGroup = this.deps.attachmentGroup;
|
|
33121
33208
|
const runner = new SessionRunner(makeInitialState(file, subSessionMeta), {
|
|
33122
33209
|
broadcastFrame: (frame, target) => this.routeFromRunner(frame, target),
|
|
@@ -34313,24 +34400,8 @@ var SessionManager = class {
|
|
|
34313
34400
|
|
|
34314
34401
|
// src/persona/store.ts
|
|
34315
34402
|
var fs7 = __toESM(require("fs"), 1);
|
|
34316
|
-
var
|
|
34403
|
+
var path9 = __toESM(require("path"), 1);
|
|
34317
34404
|
init_protocol();
|
|
34318
|
-
|
|
34319
|
-
// src/tools/guest-settings.ts
|
|
34320
|
-
function buildGuestSettingsV1(paths) {
|
|
34321
|
-
const p2 = (dir) => dir.replace(/^\//, "");
|
|
34322
|
-
return {
|
|
34323
|
-
permissions: {
|
|
34324
|
-
defaultMode: "dontAsk",
|
|
34325
|
-
allow: ["Bash"],
|
|
34326
|
-
deny: [`Edit(//${p2(paths.personaDir)}/**)`, `Read(//${p2(paths.personaDir)}/.clawd/**)`]
|
|
34327
|
-
},
|
|
34328
|
-
// 先不加 OS 沙箱(见文件头说明);目录隔离靠 user-dir 分配 + --add-dir + RPC 守卫。
|
|
34329
|
-
sandbox: { enabled: false }
|
|
34330
|
-
};
|
|
34331
|
-
}
|
|
34332
|
-
|
|
34333
|
-
// src/persona/store.ts
|
|
34334
34405
|
var PersonaStore = class {
|
|
34335
34406
|
constructor(root) {
|
|
34336
34407
|
this.root = root;
|
|
@@ -34338,31 +34409,30 @@ var PersonaStore = class {
|
|
|
34338
34409
|
}
|
|
34339
34410
|
root;
|
|
34340
34411
|
personaDir(personaId) {
|
|
34341
|
-
return
|
|
34412
|
+
return path9.join(this.root, safeFileName(personaId));
|
|
34342
34413
|
}
|
|
34343
34414
|
metaPath(personaId) {
|
|
34344
|
-
return
|
|
34415
|
+
return path9.join(this.personaDir(personaId), ".clawd", "persona.json");
|
|
34345
34416
|
}
|
|
34346
34417
|
claudeMdPath(personaId) {
|
|
34347
|
-
return
|
|
34418
|
+
return path9.join(this.personaDir(personaId), "CLAUDE.md");
|
|
34348
34419
|
}
|
|
34349
34420
|
/**
|
|
34350
|
-
*
|
|
34351
|
-
*
|
|
34352
|
-
*
|
|
34353
|
-
*
|
|
34354
|
-
* 加载 persona 人格,只有 listener 多一层 OS sandbox。
|
|
34421
|
+
* persona 级 sandbox 模板落盘路径 —— 故意放 `.clawd/` 而非 `.claude/`,让 CC 的 project
|
|
34422
|
+
* source 自动发现扫不到(owner `--setting-sources user,project,local` 不会顺手带进来)。
|
|
34423
|
+
* 这份是 **UI 展示用模板**(readSandboxSettings);guest 真正加载的沙箱文件由 manager 在
|
|
34424
|
+
* spawn 前 per-guest 动态拼到各自 session 目录(含本 guest userWorkDir carve),不是这份。
|
|
34355
34425
|
*/
|
|
34356
34426
|
sandboxSettingsPath(personaId) {
|
|
34357
|
-
return
|
|
34427
|
+
return path9.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
|
|
34358
34428
|
}
|
|
34359
34429
|
write(persona, personality) {
|
|
34360
34430
|
const dir = this.personaDir(persona.personaId);
|
|
34361
|
-
fs7.mkdirSync(
|
|
34431
|
+
fs7.mkdirSync(path9.join(dir, ".clawd"), { recursive: true });
|
|
34362
34432
|
this.atomicWrite(this.claudeMdPath(persona.personaId), personality);
|
|
34363
34433
|
this.atomicWrite(
|
|
34364
34434
|
this.sandboxSettingsPath(persona.personaId),
|
|
34365
|
-
JSON.stringify(buildGuestSettingsV1(
|
|
34435
|
+
JSON.stringify(buildGuestSettingsV1(), null, 2)
|
|
34366
34436
|
);
|
|
34367
34437
|
this.atomicWrite(this.metaPath(persona.personaId), JSON.stringify(persona, null, 2));
|
|
34368
34438
|
}
|
|
@@ -34370,10 +34440,9 @@ var PersonaStore = class {
|
|
|
34370
34440
|
this.atomicWrite(this.claudeMdPath(personaId), personality);
|
|
34371
34441
|
}
|
|
34372
34442
|
/**
|
|
34373
|
-
* 覆盖式写 sandbox
|
|
34374
|
-
*
|
|
34375
|
-
*
|
|
34376
|
-
* 想同步默认值,老板手动 cat 写一次即可。
|
|
34443
|
+
* 覆盖式写 persona 级 sandbox 配置(seed 给有 profile 的 persona 写 base⊕profile;owner 之后可手编)。
|
|
34444
|
+
* 这份是 guest 沙箱的 **base 真源**:manager spawn 时 composeGuestSandbox 读它 + 叠强制底座
|
|
34445
|
+
* (enabled/denyRead/persona-deny owner 削弱不了)+ 注入本 guest userWorkDir → 写 per-guest 文件给 CC。
|
|
34377
34446
|
*/
|
|
34378
34447
|
writeSandboxSettings(personaId, settings) {
|
|
34379
34448
|
this.atomicWrite(
|
|
@@ -34417,14 +34486,14 @@ var PersonaStore = class {
|
|
|
34417
34486
|
}
|
|
34418
34487
|
/** Persona 私有 skills 目录路径:<personaDir>/.claude/skills */
|
|
34419
34488
|
skillsDir(personaId) {
|
|
34420
|
-
return
|
|
34489
|
+
return path9.join(this.personaDir(personaId), ".claude", "skills");
|
|
34421
34490
|
}
|
|
34422
34491
|
/**
|
|
34423
34492
|
* Claude Code 项目级 settings 路径:`<personaDir>/.claude/settings.json`。
|
|
34424
34493
|
* 这里只读 `enabledPlugins` 字段,由 owner 通过 CC `/plugin` 之类命令维护,daemon 不写。
|
|
34425
34494
|
*/
|
|
34426
34495
|
claudeSettingsPath(personaId) {
|
|
34427
|
-
return
|
|
34496
|
+
return path9.join(this.personaDir(personaId), ".claude", "settings.json");
|
|
34428
34497
|
}
|
|
34429
34498
|
/**
|
|
34430
34499
|
* 读取 persona 的 `.claude/settings.json` 中 `enabledPlugins` map,把 value === true
|
|
@@ -34458,7 +34527,7 @@ var PersonaStore = class {
|
|
|
34458
34527
|
list() {
|
|
34459
34528
|
if (!fs7.existsSync(this.root)) return [];
|
|
34460
34529
|
return fs7.readdirSync(this.root).filter((name) => {
|
|
34461
|
-
return fs7.existsSync(
|
|
34530
|
+
return fs7.existsSync(path9.join(this.root, name, ".clawd", "persona.json"));
|
|
34462
34531
|
});
|
|
34463
34532
|
}
|
|
34464
34533
|
remove(personaId) {
|
|
@@ -34519,7 +34588,7 @@ var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
|
34519
34588
|
// src/skills/scanner.ts
|
|
34520
34589
|
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
34521
34590
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
34522
|
-
var
|
|
34591
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
34523
34592
|
|
|
34524
34593
|
// src/skills/frontmatter.ts
|
|
34525
34594
|
var STRIP_QUOTES = /^["']|["']$/g;
|
|
@@ -34641,14 +34710,14 @@ function scanSkillDir(dir, source, seen, out, pluginName) {
|
|
|
34641
34710
|
return;
|
|
34642
34711
|
}
|
|
34643
34712
|
for (const ent of entries) {
|
|
34644
|
-
const entryPath =
|
|
34713
|
+
const entryPath = import_node_path7.default.join(dir, ent.name);
|
|
34645
34714
|
if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
|
|
34646
34715
|
let content;
|
|
34647
34716
|
try {
|
|
34648
|
-
content = import_node_fs7.default.readFileSync(
|
|
34717
|
+
content = import_node_fs7.default.readFileSync(import_node_path7.default.join(entryPath, "SKILL.md"), "utf8");
|
|
34649
34718
|
} catch {
|
|
34650
34719
|
try {
|
|
34651
|
-
content = import_node_fs7.default.readFileSync(
|
|
34720
|
+
content = import_node_fs7.default.readFileSync(import_node_path7.default.join(entryPath, "skill.md"), "utf8");
|
|
34652
34721
|
} catch {
|
|
34653
34722
|
continue;
|
|
34654
34723
|
}
|
|
@@ -34677,7 +34746,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
34677
34746
|
return;
|
|
34678
34747
|
}
|
|
34679
34748
|
for (const ent of entries) {
|
|
34680
|
-
const entryPath =
|
|
34749
|
+
const entryPath = import_node_path7.default.join(dir, ent.name);
|
|
34681
34750
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
|
|
34682
34751
|
const ns = ent.name;
|
|
34683
34752
|
let subEntries;
|
|
@@ -34688,7 +34757,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
34688
34757
|
}
|
|
34689
34758
|
for (const se of subEntries) {
|
|
34690
34759
|
if (!se.name.endsWith(".md")) continue;
|
|
34691
|
-
const sePath =
|
|
34760
|
+
const sePath = import_node_path7.default.join(entryPath, se.name);
|
|
34692
34761
|
let content;
|
|
34693
34762
|
try {
|
|
34694
34763
|
content = import_node_fs7.default.readFileSync(sePath, "utf8");
|
|
@@ -34724,7 +34793,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
34724
34793
|
}
|
|
34725
34794
|
}
|
|
34726
34795
|
function readInstalledPlugins(home) {
|
|
34727
|
-
const file =
|
|
34796
|
+
const file = import_node_path7.default.join(home, ".claude", "plugins", "installed_plugins.json");
|
|
34728
34797
|
let raw;
|
|
34729
34798
|
try {
|
|
34730
34799
|
raw = import_node_fs7.default.readFileSync(file, "utf8");
|
|
@@ -34775,14 +34844,14 @@ var SkillsScanner = class {
|
|
|
34775
34844
|
});
|
|
34776
34845
|
}
|
|
34777
34846
|
const fsBlock = [];
|
|
34778
|
-
scanSkillDir(
|
|
34779
|
-
scanCommandDir(
|
|
34780
|
-
scanSkillDir(
|
|
34781
|
-
scanCommandDir(
|
|
34847
|
+
scanSkillDir(import_node_path7.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
|
|
34848
|
+
scanCommandDir(import_node_path7.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
|
|
34849
|
+
scanSkillDir(import_node_path7.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
|
|
34850
|
+
scanCommandDir(import_node_path7.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
|
|
34782
34851
|
const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
|
|
34783
34852
|
for (const { name, root } of plugins) {
|
|
34784
|
-
scanSkillDir(
|
|
34785
|
-
scanCommandDir(
|
|
34853
|
+
scanSkillDir(import_node_path7.default.join(root, "skills"), "plugin", seen, fsBlock, name);
|
|
34854
|
+
scanCommandDir(import_node_path7.default.join(root, "commands"), "plugin", seen, fsBlock, name);
|
|
34786
34855
|
}
|
|
34787
34856
|
fsBlock.sort((a, b2) => a.name < b2.name ? -1 : a.name > b2.name ? 1 : 0);
|
|
34788
34857
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -34888,7 +34957,7 @@ var PersonaManager = class {
|
|
|
34888
34957
|
|
|
34889
34958
|
// src/persona/seed.ts
|
|
34890
34959
|
var fs9 = __toESM(require("fs"), 1);
|
|
34891
|
-
var
|
|
34960
|
+
var path11 = __toESM(require("path"), 1);
|
|
34892
34961
|
var import_node_url = require("url");
|
|
34893
34962
|
var import_meta = {};
|
|
34894
34963
|
var DEFAULT_PERSONAS = [
|
|
@@ -34928,9 +34997,37 @@ var DEFAULT_PERSONAS = [
|
|
|
34928
34997
|
label: "App Builder",
|
|
34929
34998
|
model: "opus",
|
|
34930
34999
|
iconKey: "assist",
|
|
34931
|
-
public: false
|
|
34932
|
-
//
|
|
34933
|
-
//
|
|
35000
|
+
public: false,
|
|
35001
|
+
// 开发型 profile:在最严格 base(已含 Bash+文件工具)上追加 web 工具 + node/pnpm 工具链精确路径
|
|
35002
|
+
// + 出站全放。工具链只列精确目录(~/.nvm / pnpm store / ~/.npm),**不放宽 dot 目录**(~/.config 含
|
|
35003
|
+
// gh/gcloud 凭证、~/.local/bin 在 PATH 可被植入),避免 secrets 暴露 + 提权。mac/linux 两套 pnpm store 都列。
|
|
35004
|
+
sandboxProfile: {
|
|
35005
|
+
// base 只 Bash,开发型在此放开文件工具 + web 工具(OS 沙箱 carve 兜底文件边界)。
|
|
35006
|
+
// .secrets 只 app-builder 有 → 这里加 deny(其余 persona base 不默认带 .secrets)。
|
|
35007
|
+
// defaultMode bypassPermissions:开发流频繁用工具,免逐次审批;deny 规则仍生效、OS 沙箱照管(已验证)。
|
|
35008
|
+
permissions: {
|
|
35009
|
+
defaultMode: "bypassPermissions",
|
|
35010
|
+
allow: ["Read", "Edit", "Write", "Glob", "Grep", "WebFetch", "WebSearch"],
|
|
35011
|
+
deny: ["Read(./.secrets/**)"]
|
|
35012
|
+
},
|
|
35013
|
+
sandbox: {
|
|
35014
|
+
filesystem: {
|
|
35015
|
+
// ~/.npmrc:registry 认证配置(私有源 token),不读会 pnpm install 403;单文件精确放行。
|
|
35016
|
+
// ~/Library/Preferences/pnpm:mac 上 pnpm 全局 rc 目录(env-paths config),不读会 WARN EPERM。
|
|
35017
|
+
allowRead: ["~/.npmrc", "~/Library/Preferences/pnpm", "~/.nvm", "~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store"],
|
|
35018
|
+
allowWrite: ["~/Library/pnpm", "~/.local/share/pnpm", "~/.local/state/pnpm", "~/.npm", "~/.pnpm-store"]
|
|
35019
|
+
},
|
|
35020
|
+
// 网络:CC 沙箱出站强制走它自管的 MITM proxy 按 allowedDomains 过滤,**没有全开档**——'*' 或空白名单
|
|
35021
|
+
// 都被全拦(matcher JL8:plain 域名只精确匹配,'*.xxx' 是 host.endsWith('.xxx'),且对裸 IP 返回 false)。
|
|
35022
|
+
// 用一组常见顶级域通配近似"全放行",几乎零维护即可覆盖 npm/pnpm/git 全生态(registry.npmjs.org→*.org、
|
|
35023
|
+
// npm.jsr.io→*.io、github/githubusercontent→*.com…)。代价:仍挡掉直连 IP 外联(正常包安装都走域名,
|
|
35024
|
+
// 反而是一道防裸 IP 外泄的兜底)。需要别的 TLD 往这里加。allowLocalBinding 控本机 bind,与出站正交。
|
|
35025
|
+
network: {
|
|
35026
|
+
allowedDomains: ["*.com", "*.org", "*.io", "*.net", "*.dev", "*.app", "*.cn", "*.co", "*.chat", "*.ai"],
|
|
35027
|
+
allowLocalBinding: true
|
|
35028
|
+
}
|
|
35029
|
+
}
|
|
35030
|
+
}
|
|
34934
35031
|
},
|
|
34935
35032
|
{
|
|
34936
35033
|
personaId: "persona-developer",
|
|
@@ -34950,14 +35047,14 @@ var DEFAULT_PERSONAS = [
|
|
|
34950
35047
|
function findDefaultsRoot() {
|
|
34951
35048
|
const candidates = [];
|
|
34952
35049
|
try {
|
|
34953
|
-
const here =
|
|
34954
|
-
candidates.push(
|
|
34955
|
-
candidates.push(
|
|
35050
|
+
const here = path11.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
35051
|
+
candidates.push(path11.resolve(here, "defaults"));
|
|
35052
|
+
candidates.push(path11.resolve(here, "persona-defaults"));
|
|
34956
35053
|
} catch {
|
|
34957
35054
|
}
|
|
34958
35055
|
if (process.argv[1]) {
|
|
34959
|
-
const argvDir =
|
|
34960
|
-
candidates.push(
|
|
35056
|
+
const argvDir = path11.dirname(process.argv[1]);
|
|
35057
|
+
candidates.push(path11.resolve(argvDir, "persona-defaults"));
|
|
34961
35058
|
}
|
|
34962
35059
|
for (const c of candidates) {
|
|
34963
35060
|
try {
|
|
@@ -34974,7 +35071,7 @@ function seedDefaultPersonas(args) {
|
|
|
34974
35071
|
args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
|
|
34975
35072
|
continue;
|
|
34976
35073
|
}
|
|
34977
|
-
const bundleDir =
|
|
35074
|
+
const bundleDir = path11.join(args.defaultsRoot, entry.personaId);
|
|
34978
35075
|
if (!fs9.existsSync(bundleDir)) {
|
|
34979
35076
|
args.logger.warn("persona.seed.skip", {
|
|
34980
35077
|
personaId: entry.personaId,
|
|
@@ -34983,7 +35080,7 @@ function seedDefaultPersonas(args) {
|
|
|
34983
35080
|
});
|
|
34984
35081
|
continue;
|
|
34985
35082
|
}
|
|
34986
|
-
const claudeMdPath =
|
|
35083
|
+
const claudeMdPath = path11.join(bundleDir, "CLAUDE.md");
|
|
34987
35084
|
if (!fs9.existsSync(claudeMdPath)) {
|
|
34988
35085
|
args.logger.warn("persona.seed.skip", {
|
|
34989
35086
|
personaId: entry.personaId,
|
|
@@ -35004,9 +35101,10 @@ function seedDefaultPersonas(args) {
|
|
|
35004
35101
|
updatedAt: now
|
|
35005
35102
|
};
|
|
35006
35103
|
args.store.write(persona, personality);
|
|
35007
|
-
if (entry.
|
|
35008
|
-
|
|
35009
|
-
args.
|
|
35104
|
+
if (entry.sandboxProfile) {
|
|
35105
|
+
const settings = applyProfile(buildGuestSettingsV1(), entry.sandboxProfile);
|
|
35106
|
+
args.store.writeSandboxSettings(entry.personaId, settings);
|
|
35107
|
+
args.logger.info("persona.seed.sandbox-profile", { personaId: entry.personaId });
|
|
35010
35108
|
}
|
|
35011
35109
|
copyBundleExtras(bundleDir, args.store.personaDirPath(entry.personaId));
|
|
35012
35110
|
args.logger.info("persona.seed.created", { personaId: entry.personaId });
|
|
@@ -35015,8 +35113,8 @@ function seedDefaultPersonas(args) {
|
|
|
35015
35113
|
function copyBundleExtras(srcDir, dstDir) {
|
|
35016
35114
|
for (const entry of fs9.readdirSync(srcDir, { withFileTypes: true })) {
|
|
35017
35115
|
if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
|
|
35018
|
-
const srcPath =
|
|
35019
|
-
const dstPath =
|
|
35116
|
+
const srcPath = path11.join(srcDir, entry.name);
|
|
35117
|
+
const dstPath = path11.join(dstDir, entry.name);
|
|
35020
35118
|
if (entry.isDirectory()) {
|
|
35021
35119
|
fs9.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
|
|
35022
35120
|
} else if (entry.isFile()) {
|
|
@@ -35028,14 +35126,14 @@ var DAEMON_MANAGED_PATHS = ["extension-kit", "CLAUDE.md", ".mcp.json"];
|
|
|
35028
35126
|
function refreshDaemonManagedDirs(args) {
|
|
35029
35127
|
const entries = args.entries ?? DEFAULT_PERSONAS;
|
|
35030
35128
|
for (const entry of entries) {
|
|
35031
|
-
const bundleDir =
|
|
35129
|
+
const bundleDir = path11.join(args.defaultsRoot, entry.personaId);
|
|
35032
35130
|
if (!fs9.existsSync(bundleDir)) continue;
|
|
35033
35131
|
const personaDir = args.store.personaDirPath(entry.personaId);
|
|
35034
35132
|
if (!fs9.existsSync(personaDir)) continue;
|
|
35035
35133
|
for (const relPath of DAEMON_MANAGED_PATHS) {
|
|
35036
|
-
const srcPath =
|
|
35134
|
+
const srcPath = path11.join(bundleDir, relPath);
|
|
35037
35135
|
if (!fs9.existsSync(srcPath)) continue;
|
|
35038
|
-
const dstPath =
|
|
35136
|
+
const dstPath = path11.join(personaDir, relPath);
|
|
35039
35137
|
try {
|
|
35040
35138
|
fs9.cpSync(srcPath, dstPath, { recursive: true, force: true, dereference: true });
|
|
35041
35139
|
args.logger.info("persona.refresh.synced", {
|
|
@@ -35059,7 +35157,7 @@ init_claude();
|
|
|
35059
35157
|
// src/tools/claude-tui.ts
|
|
35060
35158
|
var import_node_fs10 = __toESM(require("fs"), 1);
|
|
35061
35159
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
35062
|
-
var
|
|
35160
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
35063
35161
|
var import_headless = __toESM(require_xterm_headless(), 1);
|
|
35064
35162
|
|
|
35065
35163
|
// ../node_modules/.pnpm/@xterm+addon-serialize@0.14.0/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs
|
|
@@ -36039,7 +36137,7 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
|
|
|
36039
36137
|
function jsonlExistsForCtx(ctx) {
|
|
36040
36138
|
if (!ctx.toolSessionId) return false;
|
|
36041
36139
|
const home = import_node_os5.default.homedir();
|
|
36042
|
-
const file =
|
|
36140
|
+
const file = import_node_path10.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
|
|
36043
36141
|
try {
|
|
36044
36142
|
return import_node_fs10.default.statSync(file).isFile();
|
|
36045
36143
|
} catch {
|
|
@@ -36053,14 +36151,14 @@ init_claude_history();
|
|
|
36053
36151
|
// src/workspace/browser.ts
|
|
36054
36152
|
var import_node_fs11 = __toESM(require("fs"), 1);
|
|
36055
36153
|
var import_node_os6 = __toESM(require("os"), 1);
|
|
36056
|
-
var
|
|
36154
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
36057
36155
|
init_protocol();
|
|
36058
36156
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
36059
36157
|
function resolveInsideCwd(cwd, subpath) {
|
|
36060
|
-
const absCwd =
|
|
36061
|
-
const joined =
|
|
36062
|
-
const rel =
|
|
36063
|
-
if (rel.startsWith("..") ||
|
|
36158
|
+
const absCwd = import_node_path11.default.resolve(cwd);
|
|
36159
|
+
const joined = import_node_path11.default.resolve(absCwd, subpath ?? ".");
|
|
36160
|
+
const rel = import_node_path11.default.relative(absCwd, joined);
|
|
36161
|
+
if (rel.startsWith("..") || import_node_path11.default.isAbsolute(rel)) {
|
|
36064
36162
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
36065
36163
|
}
|
|
36066
36164
|
return joined;
|
|
@@ -36091,7 +36189,7 @@ var WorkspaceBrowser = class {
|
|
|
36091
36189
|
mtime: ""
|
|
36092
36190
|
};
|
|
36093
36191
|
try {
|
|
36094
|
-
const st = import_node_fs11.default.statSync(
|
|
36192
|
+
const st = import_node_fs11.default.statSync(import_node_path11.default.join(full, d.name));
|
|
36095
36193
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
36096
36194
|
if (d.isFile()) entry.size = st.size;
|
|
36097
36195
|
} catch {
|
|
@@ -36138,7 +36236,7 @@ var WorkspaceBrowser = class {
|
|
|
36138
36236
|
// src/skills/agents-scanner.ts
|
|
36139
36237
|
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
36140
36238
|
var import_node_os7 = __toESM(require("os"), 1);
|
|
36141
|
-
var
|
|
36239
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
36142
36240
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
36143
36241
|
function isDirLikeSync2(p2) {
|
|
36144
36242
|
try {
|
|
@@ -36176,10 +36274,10 @@ function scanAgentsDir(dir, source, seen, out) {
|
|
|
36176
36274
|
}
|
|
36177
36275
|
for (const ent of entries) {
|
|
36178
36276
|
if (!ent.name.endsWith(".md")) continue;
|
|
36179
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
36277
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path12.default.join(dir, ent.name)))) {
|
|
36180
36278
|
continue;
|
|
36181
36279
|
}
|
|
36182
|
-
const filePath =
|
|
36280
|
+
const filePath = import_node_path12.default.join(dir, ent.name);
|
|
36183
36281
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
36184
36282
|
if (seen.has(baseName)) continue;
|
|
36185
36283
|
seen.add(baseName);
|
|
@@ -36202,7 +36300,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
36202
36300
|
return;
|
|
36203
36301
|
}
|
|
36204
36302
|
for (const ent of entries) {
|
|
36205
|
-
const childPath =
|
|
36303
|
+
const childPath = import_node_path12.default.join(dir, ent.name);
|
|
36206
36304
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
36207
36305
|
walk2(childPath, [...namespaces, ent.name]);
|
|
36208
36306
|
continue;
|
|
@@ -36227,9 +36325,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
36227
36325
|
walk2(root, []);
|
|
36228
36326
|
}
|
|
36229
36327
|
function readInstalledPlugins2(home) {
|
|
36230
|
-
const pluginsDir =
|
|
36231
|
-
const v2 =
|
|
36232
|
-
const v1 =
|
|
36328
|
+
const pluginsDir = import_node_path12.default.join(home, ".claude", "plugins");
|
|
36329
|
+
const v2 = import_node_path12.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
36330
|
+
const v1 = import_node_path12.default.join(pluginsDir, "installed_plugins.json");
|
|
36233
36331
|
let raw = null;
|
|
36234
36332
|
for (const candidate of [v2, v1]) {
|
|
36235
36333
|
try {
|
|
@@ -36258,19 +36356,19 @@ function readInstalledPlugins2(home) {
|
|
|
36258
36356
|
return out;
|
|
36259
36357
|
}
|
|
36260
36358
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
36261
|
-
let cur =
|
|
36262
|
-
const fsRoot =
|
|
36359
|
+
let cur = import_node_path12.default.resolve(startCwd);
|
|
36360
|
+
const fsRoot = import_node_path12.default.parse(cur).root;
|
|
36263
36361
|
while (true) {
|
|
36264
|
-
scanAgentsDir(
|
|
36362
|
+
scanAgentsDir(import_node_path12.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
36265
36363
|
let hasGit = false;
|
|
36266
36364
|
try {
|
|
36267
|
-
hasGit = import_node_fs12.default.existsSync(
|
|
36365
|
+
hasGit = import_node_fs12.default.existsSync(import_node_path12.default.join(cur, ".git"));
|
|
36268
36366
|
} catch {
|
|
36269
36367
|
}
|
|
36270
36368
|
if (hasGit) return;
|
|
36271
36369
|
if (cur === home) return;
|
|
36272
36370
|
if (cur === fsRoot) return;
|
|
36273
|
-
const parent =
|
|
36371
|
+
const parent = import_node_path12.default.dirname(cur);
|
|
36274
36372
|
if (parent === cur) return;
|
|
36275
36373
|
cur = parent;
|
|
36276
36374
|
}
|
|
@@ -36305,7 +36403,7 @@ var AgentsScanner = class {
|
|
|
36305
36403
|
}
|
|
36306
36404
|
const fsBlock = [];
|
|
36307
36405
|
scanAgentsDir(
|
|
36308
|
-
|
|
36406
|
+
import_node_path12.default.join(this.home, ".claude", "agents"),
|
|
36309
36407
|
"global",
|
|
36310
36408
|
seen,
|
|
36311
36409
|
fsBlock
|
|
@@ -36319,7 +36417,7 @@ var AgentsScanner = class {
|
|
|
36319
36417
|
...this.extraPluginRoots
|
|
36320
36418
|
];
|
|
36321
36419
|
for (const { name, root } of plugins) {
|
|
36322
|
-
const agentsRoot =
|
|
36420
|
+
const agentsRoot = import_node_path12.default.join(root, "agents");
|
|
36323
36421
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
36324
36422
|
}
|
|
36325
36423
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -36329,13 +36427,13 @@ var AgentsScanner = class {
|
|
|
36329
36427
|
// src/observer/session-observer.ts
|
|
36330
36428
|
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
36331
36429
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
36332
|
-
var
|
|
36430
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
36333
36431
|
init_claude_history();
|
|
36334
36432
|
|
|
36335
36433
|
// src/observer/subagent-meta-observer.ts
|
|
36336
36434
|
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
36337
36435
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
36338
|
-
var
|
|
36436
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
36339
36437
|
init_claude_history();
|
|
36340
36438
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
36341
36439
|
var SubagentMetaObserver = class {
|
|
@@ -36348,7 +36446,7 @@ var SubagentMetaObserver = class {
|
|
|
36348
36446
|
watches = /* @__PURE__ */ new Map();
|
|
36349
36447
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
36350
36448
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
36351
|
-
return
|
|
36449
|
+
return import_node_path13.default.join(
|
|
36352
36450
|
this.home,
|
|
36353
36451
|
".claude",
|
|
36354
36452
|
"projects",
|
|
@@ -36404,7 +36502,7 @@ var SubagentMetaObserver = class {
|
|
|
36404
36502
|
if (!m2) return;
|
|
36405
36503
|
const agentId = m2[1];
|
|
36406
36504
|
if (w2.emitted.has(agentId)) return;
|
|
36407
|
-
const file =
|
|
36505
|
+
const file = import_node_path13.default.join(w2.dirPath, name);
|
|
36408
36506
|
let raw;
|
|
36409
36507
|
try {
|
|
36410
36508
|
raw = import_node_fs13.default.readFileSync(file, "utf8");
|
|
@@ -36464,7 +36562,7 @@ var SessionObserver = class {
|
|
|
36464
36562
|
metaObserver;
|
|
36465
36563
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
36466
36564
|
if (override) return override;
|
|
36467
|
-
return
|
|
36565
|
+
return import_node_path14.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
36468
36566
|
}
|
|
36469
36567
|
start(args) {
|
|
36470
36568
|
this.stop(args.sessionId);
|
|
@@ -36485,10 +36583,10 @@ var SessionObserver = class {
|
|
|
36485
36583
|
prevIsRejectSentinel: false
|
|
36486
36584
|
};
|
|
36487
36585
|
try {
|
|
36488
|
-
import_node_fs14.default.mkdirSync(
|
|
36586
|
+
import_node_fs14.default.mkdirSync(import_node_path14.default.dirname(filePath), { recursive: true });
|
|
36489
36587
|
} catch {
|
|
36490
36588
|
}
|
|
36491
|
-
w2.watcher = import_node_fs14.default.watch(
|
|
36589
|
+
w2.watcher = import_node_fs14.default.watch(import_node_path14.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
36492
36590
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
36493
36591
|
this.poll(w2);
|
|
36494
36592
|
});
|
|
@@ -37295,7 +37393,7 @@ async function authenticate(token, deps) {
|
|
|
37295
37393
|
|
|
37296
37394
|
// src/permission/capability-store.ts
|
|
37297
37395
|
var fs17 = __toESM(require("fs"), 1);
|
|
37298
|
-
var
|
|
37396
|
+
var path19 = __toESM(require("path"), 1);
|
|
37299
37397
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
37300
37398
|
var FILE_VERSION = 1;
|
|
37301
37399
|
var CapabilityStore = class {
|
|
@@ -37325,7 +37423,7 @@ var CapabilityStore = class {
|
|
|
37325
37423
|
this.flush();
|
|
37326
37424
|
}
|
|
37327
37425
|
filePath() {
|
|
37328
|
-
return
|
|
37426
|
+
return path19.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
37329
37427
|
}
|
|
37330
37428
|
readFromDisk() {
|
|
37331
37429
|
const file = this.filePath();
|
|
@@ -37472,7 +37570,7 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
37472
37570
|
|
|
37473
37571
|
// src/inbox/inbox-store.ts
|
|
37474
37572
|
var fs19 = __toESM(require("fs"), 1);
|
|
37475
|
-
var
|
|
37573
|
+
var path20 = __toESM(require("path"), 1);
|
|
37476
37574
|
var INBOX_SUBDIR = "inbox";
|
|
37477
37575
|
var InboxStore = class {
|
|
37478
37576
|
constructor(dataDir) {
|
|
@@ -37570,10 +37668,10 @@ var InboxStore = class {
|
|
|
37570
37668
|
}
|
|
37571
37669
|
}
|
|
37572
37670
|
dirPath() {
|
|
37573
|
-
return
|
|
37671
|
+
return path20.join(this.dataDir, INBOX_SUBDIR);
|
|
37574
37672
|
}
|
|
37575
37673
|
filePath(peerDeviceId) {
|
|
37576
|
-
return
|
|
37674
|
+
return path20.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
37577
37675
|
}
|
|
37578
37676
|
};
|
|
37579
37677
|
function parseAllLines(raw) {
|
|
@@ -37661,7 +37759,7 @@ var InboxManager = class {
|
|
|
37661
37759
|
|
|
37662
37760
|
// src/state/contact-store.ts
|
|
37663
37761
|
var fs20 = __toESM(require("fs"), 1);
|
|
37664
|
-
var
|
|
37762
|
+
var path21 = __toESM(require("path"), 1);
|
|
37665
37763
|
var FILE_NAME = "contacts.json";
|
|
37666
37764
|
var ContactStore = class {
|
|
37667
37765
|
constructor(dataDir) {
|
|
@@ -37671,7 +37769,7 @@ var ContactStore = class {
|
|
|
37671
37769
|
contacts = /* @__PURE__ */ new Map();
|
|
37672
37770
|
load() {
|
|
37673
37771
|
this.contacts.clear();
|
|
37674
|
-
const file =
|
|
37772
|
+
const file = path21.join(this.dataDir, FILE_NAME);
|
|
37675
37773
|
let raw;
|
|
37676
37774
|
try {
|
|
37677
37775
|
raw = fs20.readFileSync(file, "utf8");
|
|
@@ -37717,7 +37815,7 @@ var ContactStore = class {
|
|
|
37717
37815
|
return existed;
|
|
37718
37816
|
}
|
|
37719
37817
|
flush() {
|
|
37720
|
-
const file =
|
|
37818
|
+
const file = path21.join(this.dataDir, FILE_NAME);
|
|
37721
37819
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
37722
37820
|
const content = JSON.stringify(
|
|
37723
37821
|
{ contacts: Array.from(this.contacts.values()) },
|
|
@@ -37866,52 +37964,52 @@ async function autoReverseContact(args) {
|
|
|
37866
37964
|
|
|
37867
37965
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
37868
37966
|
var fs21 = __toESM(require("fs"), 1);
|
|
37869
|
-
var
|
|
37967
|
+
var path22 = __toESM(require("path"), 1);
|
|
37870
37968
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
37871
37969
|
function migrateFlattenSessions(opts) {
|
|
37872
37970
|
const dataDir = opts.dataDir;
|
|
37873
37971
|
const now = opts.now ?? Date.now;
|
|
37874
|
-
const sessionsDir =
|
|
37875
|
-
const flagPath =
|
|
37972
|
+
const sessionsDir = path22.join(dataDir, "sessions");
|
|
37973
|
+
const flagPath = path22.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
37876
37974
|
if (existsSync3(flagPath)) {
|
|
37877
37975
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
37878
37976
|
}
|
|
37879
37977
|
let movedBare = 0;
|
|
37880
37978
|
let movedVmOwner = 0;
|
|
37881
37979
|
let archivedListener = 0;
|
|
37882
|
-
const defaultDir =
|
|
37980
|
+
const defaultDir = path22.join(sessionsDir, "default");
|
|
37883
37981
|
if (existsSync3(defaultDir)) {
|
|
37884
37982
|
for (const entry of readdirSafe(defaultDir)) {
|
|
37885
37983
|
if (!entry.endsWith(".json")) continue;
|
|
37886
|
-
const src =
|
|
37887
|
-
const dst =
|
|
37984
|
+
const src = path22.join(defaultDir, entry);
|
|
37985
|
+
const dst = path22.join(sessionsDir, entry);
|
|
37888
37986
|
fs21.renameSync(src, dst);
|
|
37889
37987
|
movedBare += 1;
|
|
37890
37988
|
}
|
|
37891
37989
|
rmdirIfEmpty(defaultDir);
|
|
37892
37990
|
}
|
|
37893
37991
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
37894
|
-
const personaDir =
|
|
37992
|
+
const personaDir = path22.join(sessionsDir, pid);
|
|
37895
37993
|
if (!isDir(personaDir)) continue;
|
|
37896
37994
|
if (pid === "default") continue;
|
|
37897
|
-
const ownerSrc =
|
|
37995
|
+
const ownerSrc = path22.join(personaDir, "owner");
|
|
37898
37996
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
37899
|
-
const ownerDst =
|
|
37997
|
+
const ownerDst = path22.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
37900
37998
|
fs21.mkdirSync(ownerDst, { recursive: true });
|
|
37901
37999
|
for (const file of readdirSafe(ownerSrc)) {
|
|
37902
38000
|
if (!file.endsWith(".json")) continue;
|
|
37903
|
-
fs21.renameSync(
|
|
38001
|
+
fs21.renameSync(path22.join(ownerSrc, file), path22.join(ownerDst, file));
|
|
37904
38002
|
movedVmOwner += 1;
|
|
37905
38003
|
}
|
|
37906
38004
|
rmdirIfEmpty(ownerSrc);
|
|
37907
38005
|
}
|
|
37908
|
-
const listenerSrc =
|
|
38006
|
+
const listenerSrc = path22.join(personaDir, "listener");
|
|
37909
38007
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
37910
|
-
const archiveDst =
|
|
38008
|
+
const archiveDst = path22.join(dataDir, ".legacy", `listener-${pid}`);
|
|
37911
38009
|
fs21.mkdirSync(archiveDst, { recursive: true });
|
|
37912
38010
|
for (const file of readdirSafe(listenerSrc)) {
|
|
37913
38011
|
if (!file.endsWith(".json")) continue;
|
|
37914
|
-
fs21.renameSync(
|
|
38012
|
+
fs21.renameSync(path22.join(listenerSrc, file), path22.join(archiveDst, file));
|
|
37915
38013
|
archivedListener += 1;
|
|
37916
38014
|
}
|
|
37917
38015
|
rmdirIfEmpty(listenerSrc);
|
|
@@ -37959,10 +38057,10 @@ function rmdirIfEmpty(p2) {
|
|
|
37959
38057
|
|
|
37960
38058
|
// src/transport/http-router.ts
|
|
37961
38059
|
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
37962
|
-
var
|
|
38060
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
37963
38061
|
|
|
37964
38062
|
// src/attachment/mime.ts
|
|
37965
|
-
var
|
|
38063
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
37966
38064
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
37967
38065
|
var EXT_TO_NATIVE_MIME = {
|
|
37968
38066
|
// 图片
|
|
@@ -38069,7 +38167,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
38069
38167
|
".mk"
|
|
38070
38168
|
]);
|
|
38071
38169
|
function lookupMime(filePathOrName) {
|
|
38072
|
-
const ext =
|
|
38170
|
+
const ext = import_node_path15.default.extname(filePathOrName).toLowerCase();
|
|
38073
38171
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
38074
38172
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
38075
38173
|
return "application/octet-stream";
|
|
@@ -38139,7 +38237,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
38139
38237
|
|
|
38140
38238
|
// src/attachment/upload.ts
|
|
38141
38239
|
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
38142
|
-
var
|
|
38240
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
38143
38241
|
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
38144
38242
|
var import_promises = require("stream/promises");
|
|
38145
38243
|
var UploadError = class extends Error {
|
|
@@ -38151,14 +38249,14 @@ var UploadError = class extends Error {
|
|
|
38151
38249
|
code;
|
|
38152
38250
|
};
|
|
38153
38251
|
function assertValidFileName(fileName) {
|
|
38154
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
38252
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path16.default.basename(fileName)) {
|
|
38155
38253
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
38156
38254
|
}
|
|
38157
38255
|
}
|
|
38158
38256
|
var HASH_PREFIX_LEN = 16;
|
|
38159
38257
|
async function writeUploadedAttachment(args) {
|
|
38160
38258
|
assertValidFileName(args.fileName);
|
|
38161
|
-
const attachmentsRoot =
|
|
38259
|
+
const attachmentsRoot = import_node_path16.default.join(args.sessionDir, ".attachments");
|
|
38162
38260
|
try {
|
|
38163
38261
|
import_node_fs15.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
38164
38262
|
} catch (err) {
|
|
@@ -38166,7 +38264,7 @@ async function writeUploadedAttachment(args) {
|
|
|
38166
38264
|
}
|
|
38167
38265
|
const hasher = import_node_crypto5.default.createHash("sha256");
|
|
38168
38266
|
let actualSize = 0;
|
|
38169
|
-
const tmpPath =
|
|
38267
|
+
const tmpPath = import_node_path16.default.join(
|
|
38170
38268
|
attachmentsRoot,
|
|
38171
38269
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto5.default.randomBytes(4).toString("hex")}`
|
|
38172
38270
|
);
|
|
@@ -38201,7 +38299,7 @@ async function writeUploadedAttachment(args) {
|
|
|
38201
38299
|
);
|
|
38202
38300
|
}
|
|
38203
38301
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
38204
|
-
const hashDir =
|
|
38302
|
+
const hashDir = import_node_path16.default.join(attachmentsRoot, attachmentId);
|
|
38205
38303
|
let finalFileName;
|
|
38206
38304
|
let hashDirExists = false;
|
|
38207
38305
|
try {
|
|
@@ -38219,7 +38317,7 @@ async function writeUploadedAttachment(args) {
|
|
|
38219
38317
|
try {
|
|
38220
38318
|
import_node_fs15.default.mkdirSync(hashDir, { recursive: true });
|
|
38221
38319
|
finalFileName = args.fileName;
|
|
38222
|
-
import_node_fs15.default.renameSync(tmpPath,
|
|
38320
|
+
import_node_fs15.default.renameSync(tmpPath, import_node_path16.default.join(hashDir, finalFileName));
|
|
38223
38321
|
} catch (err) {
|
|
38224
38322
|
try {
|
|
38225
38323
|
import_node_fs15.default.unlinkSync(tmpPath);
|
|
@@ -38228,8 +38326,8 @@ async function writeUploadedAttachment(args) {
|
|
|
38228
38326
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
38229
38327
|
}
|
|
38230
38328
|
}
|
|
38231
|
-
const absPath =
|
|
38232
|
-
const relPath =
|
|
38329
|
+
const absPath = import_node_path16.default.join(hashDir, finalFileName);
|
|
38330
|
+
const relPath = import_node_path16.default.relative(args.sessionDir, absPath);
|
|
38233
38331
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
38234
38332
|
relPath: absPath,
|
|
38235
38333
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -38243,7 +38341,7 @@ async function writeUploadedAttachment(args) {
|
|
|
38243
38341
|
|
|
38244
38342
|
// src/extension/import.ts
|
|
38245
38343
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
38246
|
-
var
|
|
38344
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
38247
38345
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
38248
38346
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
38249
38347
|
var ImportError = class extends Error {
|
|
@@ -38261,7 +38359,7 @@ async function importZip(buf, root) {
|
|
|
38261
38359
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
38262
38360
|
}
|
|
38263
38361
|
for (const name of Object.keys(zip.files)) {
|
|
38264
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
38362
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path17.default.isAbsolute(name)) {
|
|
38265
38363
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
38266
38364
|
}
|
|
38267
38365
|
}
|
|
@@ -38294,7 +38392,7 @@ async function importZip(buf, root) {
|
|
|
38294
38392
|
);
|
|
38295
38393
|
}
|
|
38296
38394
|
}
|
|
38297
|
-
const destDir =
|
|
38395
|
+
const destDir = import_node_path17.default.join(root, manifest.id);
|
|
38298
38396
|
let destExists = false;
|
|
38299
38397
|
try {
|
|
38300
38398
|
await import_promises2.default.access(destDir);
|
|
@@ -38304,15 +38402,15 @@ async function importZip(buf, root) {
|
|
|
38304
38402
|
if (destExists) {
|
|
38305
38403
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
38306
38404
|
}
|
|
38307
|
-
const stage = await import_promises2.default.mkdtemp(
|
|
38405
|
+
const stage = await import_promises2.default.mkdtemp(import_node_path17.default.join(import_node_os10.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
38308
38406
|
try {
|
|
38309
38407
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
38310
|
-
const dest =
|
|
38408
|
+
const dest = import_node_path17.default.join(stage, name);
|
|
38311
38409
|
if (entry.dir) {
|
|
38312
38410
|
await import_promises2.default.mkdir(dest, { recursive: true });
|
|
38313
38411
|
continue;
|
|
38314
38412
|
}
|
|
38315
|
-
await import_promises2.default.mkdir(
|
|
38413
|
+
await import_promises2.default.mkdir(import_node_path17.default.dirname(dest), { recursive: true });
|
|
38316
38414
|
const content = await entry.async("nodebuffer");
|
|
38317
38415
|
await import_promises2.default.writeFile(dest, content);
|
|
38318
38416
|
}
|
|
@@ -38426,7 +38524,7 @@ function isValidUploadFileName(fileName) {
|
|
|
38426
38524
|
if (fileName === "." || fileName === "..") return false;
|
|
38427
38525
|
if (fileName.startsWith(".")) return false;
|
|
38428
38526
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
38429
|
-
return fileName ===
|
|
38527
|
+
return fileName === import_node_path18.default.basename(fileName);
|
|
38430
38528
|
}
|
|
38431
38529
|
function createHttpRouter(deps) {
|
|
38432
38530
|
return async (req, res) => {
|
|
@@ -38655,7 +38753,7 @@ function createHttpRouter(deps) {
|
|
|
38655
38753
|
return true;
|
|
38656
38754
|
}
|
|
38657
38755
|
let absPath;
|
|
38658
|
-
if (
|
|
38756
|
+
if (import_node_path18.default.isAbsolute(pathParam)) {
|
|
38659
38757
|
absPath = pathParam;
|
|
38660
38758
|
} else if (deps.sessionStore) {
|
|
38661
38759
|
const file = deps.sessionStore.read(sid);
|
|
@@ -38663,7 +38761,7 @@ function createHttpRouter(deps) {
|
|
|
38663
38761
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
38664
38762
|
return true;
|
|
38665
38763
|
}
|
|
38666
|
-
absPath =
|
|
38764
|
+
absPath = import_node_path18.default.join(file.cwd, pathParam);
|
|
38667
38765
|
} else {
|
|
38668
38766
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
38669
38767
|
return true;
|
|
@@ -38761,7 +38859,7 @@ function streamFile(res, absPath, logger) {
|
|
|
38761
38859
|
return;
|
|
38762
38860
|
}
|
|
38763
38861
|
const mime = lookupMime(absPath);
|
|
38764
|
-
const basename =
|
|
38862
|
+
const basename = import_node_path18.default.basename(absPath);
|
|
38765
38863
|
res.writeHead(200, {
|
|
38766
38864
|
"Content-Type": mime,
|
|
38767
38865
|
"Content-Length": String(stat.size),
|
|
@@ -38779,7 +38877,7 @@ function streamFile(res, absPath, logger) {
|
|
|
38779
38877
|
|
|
38780
38878
|
// src/attachment/gc.ts
|
|
38781
38879
|
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
38782
|
-
var
|
|
38880
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
38783
38881
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
38784
38882
|
function runAttachmentGc(args) {
|
|
38785
38883
|
const now = (args.now ?? Date.now)();
|
|
@@ -38788,17 +38886,17 @@ function runAttachmentGc(args) {
|
|
|
38788
38886
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
38789
38887
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
38790
38888
|
if (entry.stale) continue;
|
|
38791
|
-
if (
|
|
38889
|
+
if (import_node_path19.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
38792
38890
|
}
|
|
38793
38891
|
}
|
|
38794
38892
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
38795
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
38893
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path19.default.join(
|
|
38796
38894
|
args.dataDir,
|
|
38797
38895
|
"sessions",
|
|
38798
38896
|
...scopeSubPath(scope).map(safeFileName),
|
|
38799
38897
|
safeFileName(sessionId)
|
|
38800
38898
|
);
|
|
38801
|
-
const attRoot =
|
|
38899
|
+
const attRoot = import_node_path19.default.join(sessionDir, ".attachments");
|
|
38802
38900
|
let hashDirs;
|
|
38803
38901
|
try {
|
|
38804
38902
|
hashDirs = import_node_fs17.default.readdirSync(attRoot);
|
|
@@ -38808,7 +38906,7 @@ function runAttachmentGc(args) {
|
|
|
38808
38906
|
continue;
|
|
38809
38907
|
}
|
|
38810
38908
|
for (const hashDir of hashDirs) {
|
|
38811
|
-
const hashDirAbs =
|
|
38909
|
+
const hashDirAbs = import_node_path19.default.join(attRoot, hashDir);
|
|
38812
38910
|
let files;
|
|
38813
38911
|
try {
|
|
38814
38912
|
files = import_node_fs17.default.readdirSync(hashDirAbs);
|
|
@@ -38816,7 +38914,7 @@ function runAttachmentGc(args) {
|
|
|
38816
38914
|
continue;
|
|
38817
38915
|
}
|
|
38818
38916
|
for (const name of files) {
|
|
38819
|
-
const file =
|
|
38917
|
+
const file = import_node_path19.default.join(hashDirAbs, name);
|
|
38820
38918
|
let stat;
|
|
38821
38919
|
try {
|
|
38822
38920
|
stat = import_node_fs17.default.statSync(file);
|
|
@@ -38847,7 +38945,7 @@ function runAttachmentGc(args) {
|
|
|
38847
38945
|
|
|
38848
38946
|
// src/attachment/group.ts
|
|
38849
38947
|
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
38850
|
-
var
|
|
38948
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
38851
38949
|
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
38852
38950
|
init_protocol();
|
|
38853
38951
|
var GroupFileStore = class {
|
|
@@ -38859,11 +38957,11 @@ var GroupFileStore = class {
|
|
|
38859
38957
|
this.logger = opts.logger;
|
|
38860
38958
|
}
|
|
38861
38959
|
rootForScope(scope) {
|
|
38862
|
-
return
|
|
38960
|
+
return import_node_path20.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
38863
38961
|
}
|
|
38864
38962
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
38865
38963
|
filePath(scope, sessionId) {
|
|
38866
|
-
return
|
|
38964
|
+
return import_node_path20.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
38867
38965
|
}
|
|
38868
38966
|
cacheKey(scope, sessionId) {
|
|
38869
38967
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -38898,7 +38996,7 @@ var GroupFileStore = class {
|
|
|
38898
38996
|
}
|
|
38899
38997
|
writeFile(scope, sessionId, entries) {
|
|
38900
38998
|
const file = this.filePath(scope, sessionId);
|
|
38901
|
-
import_node_fs18.default.mkdirSync(
|
|
38999
|
+
import_node_fs18.default.mkdirSync(import_node_path20.default.dirname(file), { recursive: true });
|
|
38902
39000
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
38903
39001
|
import_node_fs18.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
38904
39002
|
import_node_fs18.default.renameSync(tmp, file);
|
|
@@ -38988,9 +39086,9 @@ var GroupFileStore = class {
|
|
|
38988
39086
|
|
|
38989
39087
|
// src/discovery/state-file.ts
|
|
38990
39088
|
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
38991
|
-
var
|
|
39089
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
38992
39090
|
function defaultStateFilePath(dataDir) {
|
|
38993
|
-
return
|
|
39091
|
+
return import_node_path21.default.join(dataDir, "state.json");
|
|
38994
39092
|
}
|
|
38995
39093
|
function isPidAlive(pid) {
|
|
38996
39094
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -39026,7 +39124,7 @@ var StateFileManager = class {
|
|
|
39026
39124
|
return { status: "stale", existing };
|
|
39027
39125
|
}
|
|
39028
39126
|
write(state) {
|
|
39029
|
-
import_node_fs19.default.mkdirSync(
|
|
39127
|
+
import_node_fs19.default.mkdirSync(import_node_path21.default.dirname(this.file), { recursive: true });
|
|
39030
39128
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
39031
39129
|
import_node_fs19.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
39032
39130
|
import_node_fs19.default.renameSync(tmp, this.file);
|
|
@@ -39047,13 +39145,13 @@ var StateFileManager = class {
|
|
|
39047
39145
|
|
|
39048
39146
|
// src/tunnel/tunnel-manager.ts
|
|
39049
39147
|
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
39050
|
-
var
|
|
39148
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
39051
39149
|
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
39052
39150
|
var import_node_child_process5 = require("child_process");
|
|
39053
39151
|
|
|
39054
39152
|
// src/tunnel/tunnel-store.ts
|
|
39055
39153
|
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
39056
|
-
var
|
|
39154
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
39057
39155
|
var TunnelStore = class {
|
|
39058
39156
|
constructor(filePath) {
|
|
39059
39157
|
this.filePath = filePath;
|
|
@@ -39072,7 +39170,7 @@ var TunnelStore = class {
|
|
|
39072
39170
|
}
|
|
39073
39171
|
}
|
|
39074
39172
|
async set(v2) {
|
|
39075
|
-
const dir =
|
|
39173
|
+
const dir = import_node_path22.default.dirname(this.filePath);
|
|
39076
39174
|
await import_node_fs20.default.promises.mkdir(dir, { recursive: true });
|
|
39077
39175
|
const data = JSON.stringify(v2, null, 2);
|
|
39078
39176
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
@@ -39184,7 +39282,7 @@ function escape(v2) {
|
|
|
39184
39282
|
// src/tunnel/frpc-binary.ts
|
|
39185
39283
|
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
39186
39284
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
39187
|
-
var
|
|
39285
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
39188
39286
|
var import_node_child_process3 = require("child_process");
|
|
39189
39287
|
var import_node_stream2 = require("stream");
|
|
39190
39288
|
var import_promises3 = require("stream/promises");
|
|
@@ -39223,13 +39321,13 @@ async function ensureFrpcBinary(opts) {
|
|
|
39223
39321
|
}
|
|
39224
39322
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
39225
39323
|
const platform = opts.platform ?? detectPlatform();
|
|
39226
|
-
const binDir =
|
|
39324
|
+
const binDir = import_node_path23.default.join(opts.dataDir, "bin");
|
|
39227
39325
|
import_node_fs21.default.mkdirSync(binDir, { recursive: true });
|
|
39228
39326
|
cleanupStaleArtifacts(binDir);
|
|
39229
|
-
const stableBin =
|
|
39327
|
+
const stableBin = import_node_path23.default.join(binDir, "frpc");
|
|
39230
39328
|
if (import_node_fs21.default.existsSync(stableBin)) return stableBin;
|
|
39231
39329
|
const partialBin = `${stableBin}.partial`;
|
|
39232
|
-
const tarballPath =
|
|
39330
|
+
const tarballPath = import_node_path23.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
39233
39331
|
try {
|
|
39234
39332
|
const url = frpcDownloadUrl(version2, platform);
|
|
39235
39333
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -39255,7 +39353,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
39255
39353
|
}
|
|
39256
39354
|
for (const name of entries) {
|
|
39257
39355
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
39258
|
-
const full =
|
|
39356
|
+
const full = import_node_path23.default.join(binDir, name);
|
|
39259
39357
|
try {
|
|
39260
39358
|
import_node_fs21.default.rmSync(full, { recursive: true, force: true });
|
|
39261
39359
|
} catch {
|
|
@@ -39281,7 +39379,7 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
39281
39379
|
await (0, import_promises3.pipeline)(nodeStream, out);
|
|
39282
39380
|
}
|
|
39283
39381
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
39284
|
-
const work =
|
|
39382
|
+
const work = import_node_path23.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
39285
39383
|
import_node_fs21.default.mkdirSync(work, { recursive: true });
|
|
39286
39384
|
try {
|
|
39287
39385
|
await new Promise((resolve6, reject) => {
|
|
@@ -39290,7 +39388,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
39290
39388
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
39291
39389
|
});
|
|
39292
39390
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
39293
|
-
const src =
|
|
39391
|
+
const src = import_node_path23.default.join(work, dirName, "frpc");
|
|
39294
39392
|
if (!import_node_fs21.default.existsSync(src)) {
|
|
39295
39393
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
39296
39394
|
}
|
|
@@ -39302,10 +39400,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
39302
39400
|
|
|
39303
39401
|
// src/tunnel/frpc-process.ts
|
|
39304
39402
|
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
39305
|
-
var
|
|
39403
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
39306
39404
|
var import_node_child_process4 = require("child_process");
|
|
39307
39405
|
function frpcPidFilePath(dataDir) {
|
|
39308
|
-
return
|
|
39406
|
+
return import_node_path24.default.join(dataDir, "frpc.pid");
|
|
39309
39407
|
}
|
|
39310
39408
|
function writeFrpcPid(dataDir, pid) {
|
|
39311
39409
|
try {
|
|
@@ -39347,7 +39445,7 @@ function defaultSleep(ms) {
|
|
|
39347
39445
|
}
|
|
39348
39446
|
async function killStaleFrpc(deps) {
|
|
39349
39447
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
39350
|
-
const tomlPath =
|
|
39448
|
+
const tomlPath = import_node_path24.default.join(deps.dataDir, "frpc.toml");
|
|
39351
39449
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
39352
39450
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
39353
39451
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -39419,7 +39517,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
39419
39517
|
var TunnelManager = class {
|
|
39420
39518
|
constructor(deps) {
|
|
39421
39519
|
this.deps = deps;
|
|
39422
|
-
this.store = deps.store ?? new TunnelStore(
|
|
39520
|
+
this.store = deps.store ?? new TunnelStore(import_node_path25.default.join(deps.dataDir, "tunnel.json"));
|
|
39423
39521
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
39424
39522
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
39425
39523
|
}
|
|
@@ -39546,7 +39644,7 @@ var TunnelManager = class {
|
|
|
39546
39644
|
dataDir: this.deps.dataDir,
|
|
39547
39645
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
39548
39646
|
});
|
|
39549
|
-
const tomlPath =
|
|
39647
|
+
const tomlPath = import_node_path25.default.join(this.deps.dataDir, "frpc.toml");
|
|
39550
39648
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
|
|
39551
39649
|
const toml = buildFrpcToml({
|
|
39552
39650
|
serverAddr: t.frpsHost,
|
|
@@ -39561,7 +39659,7 @@ var TunnelManager = class {
|
|
|
39561
39659
|
const proc = (this.deps.spawnImpl ?? import_node_child_process5.spawn)(frpcBin, ["-c", tomlPath], {
|
|
39562
39660
|
stdio: ["ignore", "pipe", "pipe"]
|
|
39563
39661
|
});
|
|
39564
|
-
const logFilePath =
|
|
39662
|
+
const logFilePath = import_node_path25.default.join(this.deps.dataDir, "frpc.log");
|
|
39565
39663
|
const logStream = import_node_fs23.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
39566
39664
|
logStream.on("error", () => {
|
|
39567
39665
|
});
|
|
@@ -39645,15 +39743,15 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
39645
39743
|
|
|
39646
39744
|
// src/tunnel/device-key.ts
|
|
39647
39745
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
39648
|
-
var
|
|
39746
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
39649
39747
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
39650
39748
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
39651
39749
|
function deriveStableDeviceKey(opts = {}) {
|
|
39652
39750
|
const hostname = opts.hostname ?? import_node_os12.default.hostname();
|
|
39653
39751
|
const uid = opts.uid ?? (typeof import_node_os12.default.userInfo === "function" ? import_node_os12.default.userInfo().uid : 0);
|
|
39654
39752
|
const home = opts.home ?? import_node_os12.default.homedir();
|
|
39655
|
-
const defaultDataDir =
|
|
39656
|
-
const normalizedDataDir = opts.dataDir ?
|
|
39753
|
+
const defaultDataDir = import_node_path26.default.resolve(import_node_path26.default.join(home, ".clawd"));
|
|
39754
|
+
const normalizedDataDir = opts.dataDir ? import_node_path26.default.resolve(opts.dataDir) : null;
|
|
39657
39755
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
39658
39756
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
39659
39757
|
return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
@@ -39661,11 +39759,11 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
39661
39759
|
|
|
39662
39760
|
// src/auth-store.ts
|
|
39663
39761
|
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
39664
|
-
var
|
|
39762
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
39665
39763
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
39666
39764
|
var AUTH_FILE_NAME = "auth.json";
|
|
39667
39765
|
function authFilePath(dataDir) {
|
|
39668
|
-
return
|
|
39766
|
+
return import_node_path27.default.join(dataDir, AUTH_FILE_NAME);
|
|
39669
39767
|
}
|
|
39670
39768
|
function loadOrCreateAuthFile(opts) {
|
|
39671
39769
|
const file = authFilePath(opts.dataDir);
|
|
@@ -39718,7 +39816,7 @@ function readAuthFile(file) {
|
|
|
39718
39816
|
}
|
|
39719
39817
|
}
|
|
39720
39818
|
function writeAuthFile(file, content) {
|
|
39721
|
-
import_node_fs24.default.mkdirSync(
|
|
39819
|
+
import_node_fs24.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
|
|
39722
39820
|
import_node_fs24.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
39723
39821
|
try {
|
|
39724
39822
|
import_node_fs24.default.chmodSync(file, 384);
|
|
@@ -39729,11 +39827,11 @@ function writeAuthFile(file, content) {
|
|
|
39729
39827
|
// src/owner-profile.ts
|
|
39730
39828
|
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
39731
39829
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
39732
|
-
var
|
|
39830
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
39733
39831
|
var PROFILE_FILENAME = "profile.json";
|
|
39734
39832
|
function loadOwnerDisplayName(dataDir) {
|
|
39735
39833
|
const fallback = import_node_os13.default.userInfo().username;
|
|
39736
|
-
const profilePath =
|
|
39834
|
+
const profilePath = import_node_path28.default.join(dataDir, PROFILE_FILENAME);
|
|
39737
39835
|
let raw;
|
|
39738
39836
|
try {
|
|
39739
39837
|
raw = import_node_fs25.default.readFileSync(profilePath, "utf8");
|
|
@@ -39760,12 +39858,12 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
39760
39858
|
|
|
39761
39859
|
// src/feishu-auth/owner-identity-store.ts
|
|
39762
39860
|
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
39763
|
-
var
|
|
39861
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
39764
39862
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
39765
39863
|
var OwnerIdentityStore = class {
|
|
39766
39864
|
file;
|
|
39767
39865
|
constructor(dataDir) {
|
|
39768
|
-
this.file =
|
|
39866
|
+
this.file = import_node_path29.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
39769
39867
|
}
|
|
39770
39868
|
read() {
|
|
39771
39869
|
let raw;
|
|
@@ -39797,7 +39895,7 @@ var OwnerIdentityStore = class {
|
|
|
39797
39895
|
};
|
|
39798
39896
|
}
|
|
39799
39897
|
write(record) {
|
|
39800
|
-
import_node_fs26.default.mkdirSync(
|
|
39898
|
+
import_node_fs26.default.mkdirSync(import_node_path29.default.dirname(this.file), { recursive: true });
|
|
39801
39899
|
import_node_fs26.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
39802
39900
|
try {
|
|
39803
39901
|
import_node_fs26.default.chmodSync(this.file, 384);
|
|
@@ -39925,9 +40023,9 @@ var CentralClientError = class extends Error {
|
|
|
39925
40023
|
code;
|
|
39926
40024
|
cause;
|
|
39927
40025
|
};
|
|
39928
|
-
async function centralRequest(opts,
|
|
40026
|
+
async function centralRequest(opts, path59, init) {
|
|
39929
40027
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
39930
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
40028
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path59}`;
|
|
39931
40029
|
const ctrl = new AbortController();
|
|
39932
40030
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
39933
40031
|
let res;
|
|
@@ -40070,7 +40168,7 @@ function verifyConnectToken(args) {
|
|
|
40070
40168
|
|
|
40071
40169
|
// src/feishu-auth/server-key.ts
|
|
40072
40170
|
var fs35 = __toESM(require("fs"), 1);
|
|
40073
|
-
var
|
|
40171
|
+
var path38 = __toESM(require("path"), 1);
|
|
40074
40172
|
var FILE_NAME2 = "server-signing-key.json";
|
|
40075
40173
|
var ServerKeyStore = class {
|
|
40076
40174
|
constructor(dataDir) {
|
|
@@ -40078,7 +40176,7 @@ var ServerKeyStore = class {
|
|
|
40078
40176
|
}
|
|
40079
40177
|
dataDir;
|
|
40080
40178
|
filePath() {
|
|
40081
|
-
return
|
|
40179
|
+
return path38.join(this.dataDir, FILE_NAME2);
|
|
40082
40180
|
}
|
|
40083
40181
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
40084
40182
|
read() {
|
|
@@ -40118,7 +40216,7 @@ init_protocol();
|
|
|
40118
40216
|
// src/session/fork.ts
|
|
40119
40217
|
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
40120
40218
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
40121
|
-
var
|
|
40219
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
40122
40220
|
init_claude_history();
|
|
40123
40221
|
function readJsonlEntries(file) {
|
|
40124
40222
|
const raw = import_node_fs27.default.readFileSync(file, "utf8");
|
|
@@ -40134,9 +40232,9 @@ function readJsonlEntries(file) {
|
|
|
40134
40232
|
return out;
|
|
40135
40233
|
}
|
|
40136
40234
|
function forkSession(input) {
|
|
40137
|
-
const baseDir = input.baseDir ??
|
|
40138
|
-
const projectDir =
|
|
40139
|
-
const sourceFile =
|
|
40235
|
+
const baseDir = input.baseDir ?? import_node_path30.default.join(import_node_os14.default.homedir(), ".claude");
|
|
40236
|
+
const projectDir = import_node_path30.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
40237
|
+
const sourceFile = import_node_path30.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
40140
40238
|
if (!import_node_fs27.default.existsSync(sourceFile)) {
|
|
40141
40239
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
40142
40240
|
}
|
|
@@ -40167,7 +40265,7 @@ function forkSession(input) {
|
|
|
40167
40265
|
}
|
|
40168
40266
|
forkedLines.push(JSON.stringify(forked));
|
|
40169
40267
|
}
|
|
40170
|
-
const forkedFilePath =
|
|
40268
|
+
const forkedFilePath = import_node_path30.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
40171
40269
|
import_node_fs27.default.mkdirSync(projectDir, { recursive: true });
|
|
40172
40270
|
import_node_fs27.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
40173
40271
|
return { forkedToolSessionId, forkedFilePath };
|
|
@@ -40536,7 +40634,7 @@ function buildPermissionHandlers(deps) {
|
|
|
40536
40634
|
}
|
|
40537
40635
|
|
|
40538
40636
|
// src/handlers/history.ts
|
|
40539
|
-
var
|
|
40637
|
+
var path41 = __toESM(require("path"), 1);
|
|
40540
40638
|
init_protocol();
|
|
40541
40639
|
|
|
40542
40640
|
// src/session/recent-dirs.ts
|
|
@@ -40554,7 +40652,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
40554
40652
|
}
|
|
40555
40653
|
|
|
40556
40654
|
// src/permission/persona-paths.ts
|
|
40557
|
-
var
|
|
40655
|
+
var path40 = __toESM(require("path"), 1);
|
|
40558
40656
|
function getAllowedPersonaIds(grants, action) {
|
|
40559
40657
|
const ids = /* @__PURE__ */ new Set();
|
|
40560
40658
|
for (const g2 of grants) {
|
|
@@ -40567,31 +40665,31 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
40567
40665
|
return ids;
|
|
40568
40666
|
}
|
|
40569
40667
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
40570
|
-
const target =
|
|
40668
|
+
const target = path40.resolve(absPath);
|
|
40571
40669
|
if (userWorkDir) {
|
|
40572
|
-
const u =
|
|
40573
|
-
const usep = u.endsWith(
|
|
40670
|
+
const u = path40.resolve(userWorkDir);
|
|
40671
|
+
const usep = u.endsWith(path40.sep) ? "" : path40.sep;
|
|
40574
40672
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
40575
40673
|
}
|
|
40576
|
-
const root =
|
|
40577
|
-
const sep2 = root.endsWith(
|
|
40674
|
+
const root = path40.resolve(personaRoot);
|
|
40675
|
+
const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
|
|
40578
40676
|
if (!target.startsWith(root + sep2)) return false;
|
|
40579
|
-
const rel =
|
|
40677
|
+
const rel = path40.relative(root, target);
|
|
40580
40678
|
if (!rel || rel.startsWith("..")) return false;
|
|
40581
|
-
const personaId = rel.split(
|
|
40679
|
+
const personaId = rel.split(path40.sep)[0];
|
|
40582
40680
|
if (!personaId) return false;
|
|
40583
40681
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
40584
40682
|
if (allowed === "*") return true;
|
|
40585
40683
|
return allowed.has(personaId);
|
|
40586
40684
|
}
|
|
40587
40685
|
function personaIdFromPath(absPath, personaRoot) {
|
|
40588
|
-
const root =
|
|
40589
|
-
const target =
|
|
40590
|
-
const sep2 = root.endsWith(
|
|
40686
|
+
const root = path40.resolve(personaRoot);
|
|
40687
|
+
const target = path40.resolve(absPath);
|
|
40688
|
+
const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
|
|
40591
40689
|
if (!target.startsWith(root + sep2)) return null;
|
|
40592
|
-
const rel =
|
|
40690
|
+
const rel = path40.relative(root, target);
|
|
40593
40691
|
if (!rel || rel.startsWith("..")) return null;
|
|
40594
|
-
const id = rel.split(
|
|
40692
|
+
const id = rel.split(path40.sep)[0];
|
|
40595
40693
|
return id || null;
|
|
40596
40694
|
}
|
|
40597
40695
|
|
|
@@ -40618,7 +40716,7 @@ function buildHistoryHandlers(deps) {
|
|
|
40618
40716
|
if (!pid) return false;
|
|
40619
40717
|
return isGuestPathAllowed(
|
|
40620
40718
|
ctx.grants,
|
|
40621
|
-
|
|
40719
|
+
path41.join(personaRoot, pid),
|
|
40622
40720
|
personaRoot,
|
|
40623
40721
|
"read",
|
|
40624
40722
|
userWorkDir
|
|
@@ -40630,7 +40728,7 @@ function buildHistoryHandlers(deps) {
|
|
|
40630
40728
|
};
|
|
40631
40729
|
const list = async (frame, _client, ctx) => {
|
|
40632
40730
|
const args = HistoryListArgs.parse(frame);
|
|
40633
|
-
assertGuestPath(ctx,
|
|
40731
|
+
assertGuestPath(ctx, path41.resolve(args.projectPath), personaRoot, "history:list");
|
|
40634
40732
|
const sessions = await history.listSessions(args);
|
|
40635
40733
|
return { response: { type: "history:list", sessions } };
|
|
40636
40734
|
};
|
|
@@ -40662,13 +40760,13 @@ function buildHistoryHandlers(deps) {
|
|
|
40662
40760
|
};
|
|
40663
40761
|
const subagents = async (frame, _client, ctx) => {
|
|
40664
40762
|
const args = HistorySubagentsArgs.parse(frame);
|
|
40665
|
-
assertGuestPath(ctx,
|
|
40763
|
+
assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
40666
40764
|
const subs = await history.listSubagents(args);
|
|
40667
40765
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
40668
40766
|
};
|
|
40669
40767
|
const subagentRead = async (frame, _client, ctx) => {
|
|
40670
40768
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
40671
|
-
assertGuestPath(ctx,
|
|
40769
|
+
assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
40672
40770
|
const res = await history.readSubagent(args);
|
|
40673
40771
|
return { response: { type: "history:subagent-read", ...res } };
|
|
40674
40772
|
};
|
|
@@ -40677,7 +40775,7 @@ function buildHistoryHandlers(deps) {
|
|
|
40677
40775
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
40678
40776
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
40679
40777
|
const filtered = dirs.filter(
|
|
40680
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
40778
|
+
(d) => isGuestPathAllowed(ctx.grants, path41.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
40681
40779
|
);
|
|
40682
40780
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
40683
40781
|
}
|
|
@@ -40694,7 +40792,7 @@ function buildHistoryHandlers(deps) {
|
|
|
40694
40792
|
}
|
|
40695
40793
|
|
|
40696
40794
|
// src/handlers/workspace.ts
|
|
40697
|
-
var
|
|
40795
|
+
var path42 = __toESM(require("path"), 1);
|
|
40698
40796
|
var os15 = __toESM(require("os"), 1);
|
|
40699
40797
|
init_protocol();
|
|
40700
40798
|
init_protocol();
|
|
@@ -40736,22 +40834,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
40736
40834
|
const args = WorkspaceListArgs.parse(frame);
|
|
40737
40835
|
const isGuest = ctx?.principal.kind === "guest";
|
|
40738
40836
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os15.homedir();
|
|
40739
|
-
const resolvedCwd =
|
|
40740
|
-
const target = args.path ?
|
|
40837
|
+
const resolvedCwd = path42.resolve(args.cwd ?? fallbackCwd);
|
|
40838
|
+
const target = args.path ? path42.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
40741
40839
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
40742
40840
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
40743
40841
|
return { response: { type: "workspace:list", ...res } };
|
|
40744
40842
|
};
|
|
40745
40843
|
const read = async (frame, _client, ctx) => {
|
|
40746
40844
|
const args = WorkspaceReadArgs.parse(frame);
|
|
40747
|
-
const target =
|
|
40845
|
+
const target = path42.isAbsolute(args.path) ? path42.resolve(args.path) : path42.resolve(args.cwd, args.path);
|
|
40748
40846
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
40749
40847
|
const res = workspace.read(args);
|
|
40750
40848
|
return { response: { type: "workspace:read", ...res } };
|
|
40751
40849
|
};
|
|
40752
40850
|
const skillsList = async (frame, _client, ctx) => {
|
|
40753
40851
|
const args = SkillsListArgs.parse(frame);
|
|
40754
|
-
const cwdAbs =
|
|
40852
|
+
const cwdAbs = path42.resolve(args.cwd);
|
|
40755
40853
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
40756
40854
|
const list2 = skills.list(args);
|
|
40757
40855
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -40763,7 +40861,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
40763
40861
|
};
|
|
40764
40862
|
const agentsList = async (frame, _client, ctx) => {
|
|
40765
40863
|
const args = AgentsListArgs.parse(frame);
|
|
40766
|
-
const cwdAbs =
|
|
40864
|
+
const cwdAbs = path42.resolve(args.cwd);
|
|
40767
40865
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
40768
40866
|
const list2 = agents.list(args);
|
|
40769
40867
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -40782,18 +40880,18 @@ function buildWorkspaceHandlers(deps) {
|
|
|
40782
40880
|
}
|
|
40783
40881
|
|
|
40784
40882
|
// src/handlers/git.ts
|
|
40785
|
-
var
|
|
40883
|
+
var path44 = __toESM(require("path"), 1);
|
|
40786
40884
|
init_protocol();
|
|
40787
40885
|
init_protocol();
|
|
40788
40886
|
|
|
40789
40887
|
// src/workspace/git.ts
|
|
40790
40888
|
var import_node_child_process6 = require("child_process");
|
|
40791
40889
|
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
40792
|
-
var
|
|
40890
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
40793
40891
|
var import_node_util = require("util");
|
|
40794
40892
|
var pexec = (0, import_node_util.promisify)(import_node_child_process6.execFile);
|
|
40795
40893
|
function normalizePath(p2) {
|
|
40796
|
-
const resolved =
|
|
40894
|
+
const resolved = import_node_path31.default.resolve(p2);
|
|
40797
40895
|
try {
|
|
40798
40896
|
return import_node_fs28.default.realpathSync(resolved);
|
|
40799
40897
|
} catch {
|
|
@@ -40869,7 +40967,7 @@ async function listGitBranches(cwd) {
|
|
|
40869
40967
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
40870
40968
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
40871
40969
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
40872
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
40970
|
+
if (!isGuestPathAllowed(ctx.grants, path44.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
40873
40971
|
throw new ClawdError(
|
|
40874
40972
|
ERROR_CODES.UNAUTHORIZED,
|
|
40875
40973
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -41382,7 +41480,7 @@ function buildPersonaHandlers(deps) {
|
|
|
41382
41480
|
}
|
|
41383
41481
|
|
|
41384
41482
|
// src/handlers/attachment.ts
|
|
41385
|
-
var
|
|
41483
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
41386
41484
|
init_protocol();
|
|
41387
41485
|
init_protocol();
|
|
41388
41486
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -41437,12 +41535,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
41437
41535
|
`session ${args.sessionId} scope unresolved`
|
|
41438
41536
|
);
|
|
41439
41537
|
}
|
|
41440
|
-
const cwdAbs =
|
|
41441
|
-
const candidateAbs =
|
|
41538
|
+
const cwdAbs = import_node_path32.default.resolve(sessionFile.cwd);
|
|
41539
|
+
const candidateAbs = import_node_path32.default.isAbsolute(args.relPath) ? import_node_path32.default.resolve(args.relPath) : import_node_path32.default.resolve(cwdAbs, args.relPath);
|
|
41442
41540
|
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl", deps.usersRoot);
|
|
41443
41541
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
41444
41542
|
const entry = entries.find((e) => {
|
|
41445
|
-
const storedAbs =
|
|
41543
|
+
const storedAbs = import_node_path32.default.isAbsolute(e.relPath) ? import_node_path32.default.resolve(e.relPath) : import_node_path32.default.resolve(cwdAbs, e.relPath);
|
|
41446
41544
|
return storedAbs === candidateAbs && !e.stale;
|
|
41447
41545
|
});
|
|
41448
41546
|
if (!entry) {
|
|
@@ -41466,7 +41564,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
41466
41564
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
41467
41565
|
const f = deps.sessionStore.read(sessionId);
|
|
41468
41566
|
if (!f) return;
|
|
41469
|
-
assertGuestAttachmentPath(ctx,
|
|
41567
|
+
assertGuestAttachmentPath(ctx, import_node_path32.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
41470
41568
|
}
|
|
41471
41569
|
const groupAdd = async (frame, _client, ctx) => {
|
|
41472
41570
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -41538,19 +41636,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
41538
41636
|
|
|
41539
41637
|
// src/handlers/extension.ts
|
|
41540
41638
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
41541
|
-
var
|
|
41639
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
41542
41640
|
init_protocol();
|
|
41543
41641
|
|
|
41544
41642
|
// src/extension/bundle-zip.ts
|
|
41545
41643
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
41546
|
-
var
|
|
41644
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
41547
41645
|
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
41548
41646
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
41549
41647
|
async function bundleExtensionDir(dir) {
|
|
41550
41648
|
const entries = await listFilesSorted(dir);
|
|
41551
41649
|
const zip = new import_jszip2.default();
|
|
41552
41650
|
for (const rel of entries) {
|
|
41553
|
-
const abs =
|
|
41651
|
+
const abs = import_node_path33.default.join(dir, rel);
|
|
41554
41652
|
const content = await import_promises4.default.readFile(abs);
|
|
41555
41653
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
41556
41654
|
}
|
|
@@ -41571,7 +41669,7 @@ async function listFilesSorted(rootDir) {
|
|
|
41571
41669
|
return out;
|
|
41572
41670
|
}
|
|
41573
41671
|
async function walk(absRoot, relPrefix, out) {
|
|
41574
|
-
const dirAbs =
|
|
41672
|
+
const dirAbs = import_node_path33.default.join(absRoot, relPrefix);
|
|
41575
41673
|
const entries = await import_promises4.default.readdir(dirAbs, { withFileTypes: true });
|
|
41576
41674
|
for (const e of entries) {
|
|
41577
41675
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -41625,25 +41723,25 @@ function computePublishCheck(args) {
|
|
|
41625
41723
|
|
|
41626
41724
|
// src/extension/install-flow.ts
|
|
41627
41725
|
var import_promises5 = __toESM(require("fs/promises"), 1);
|
|
41628
|
-
var
|
|
41726
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
41629
41727
|
var import_node_os17 = __toESM(require("os"), 1);
|
|
41630
41728
|
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
41631
41729
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
41632
41730
|
|
|
41633
41731
|
// src/extension/paths.ts
|
|
41634
41732
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
41635
|
-
var
|
|
41733
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
41636
41734
|
function clawdHomeRoot(override) {
|
|
41637
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
41735
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path34.default.join(import_node_os16.default.homedir(), ".clawd");
|
|
41638
41736
|
}
|
|
41639
41737
|
function extensionsRoot(override) {
|
|
41640
|
-
return
|
|
41738
|
+
return import_node_path34.default.join(clawdHomeRoot(override), "extensions");
|
|
41641
41739
|
}
|
|
41642
41740
|
function publishedChannelsFile(override) {
|
|
41643
|
-
return
|
|
41741
|
+
return import_node_path34.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
41644
41742
|
}
|
|
41645
41743
|
function bundleCacheRoot(override) {
|
|
41646
|
-
return
|
|
41744
|
+
return import_node_path34.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
41647
41745
|
}
|
|
41648
41746
|
|
|
41649
41747
|
// src/extension/install-flow.ts
|
|
@@ -41670,7 +41768,7 @@ async function installFromChannel(args, deps) {
|
|
|
41670
41768
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
41671
41769
|
}
|
|
41672
41770
|
for (const name of Object.keys(zip.files)) {
|
|
41673
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
41771
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
|
|
41674
41772
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
41675
41773
|
}
|
|
41676
41774
|
}
|
|
@@ -41702,7 +41800,7 @@ async function installFromChannel(args, deps) {
|
|
|
41702
41800
|
);
|
|
41703
41801
|
}
|
|
41704
41802
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
41705
|
-
const destDir =
|
|
41803
|
+
const destDir = import_node_path35.default.join(deps.extensionsRoot, localExtId);
|
|
41706
41804
|
let destExists = false;
|
|
41707
41805
|
try {
|
|
41708
41806
|
await import_promises5.default.access(destDir);
|
|
@@ -41716,16 +41814,16 @@ async function installFromChannel(args, deps) {
|
|
|
41716
41814
|
);
|
|
41717
41815
|
}
|
|
41718
41816
|
const stage = await import_promises5.default.mkdtemp(
|
|
41719
|
-
|
|
41817
|
+
import_node_path35.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
41720
41818
|
);
|
|
41721
41819
|
try {
|
|
41722
41820
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
41723
|
-
const dest =
|
|
41821
|
+
const dest = import_node_path35.default.join(stage, name);
|
|
41724
41822
|
if (entry.dir) {
|
|
41725
41823
|
await import_promises5.default.mkdir(dest, { recursive: true });
|
|
41726
41824
|
continue;
|
|
41727
41825
|
}
|
|
41728
|
-
await import_promises5.default.mkdir(
|
|
41826
|
+
await import_promises5.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
|
|
41729
41827
|
if (name === "manifest.json") {
|
|
41730
41828
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
41731
41829
|
await import_promises5.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -41746,7 +41844,7 @@ async function installFromChannel(args, deps) {
|
|
|
41746
41844
|
|
|
41747
41845
|
// src/extension/update-flow.ts
|
|
41748
41846
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
41749
|
-
var
|
|
41847
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
41750
41848
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
41751
41849
|
var import_node_crypto13 = __toESM(require("crypto"), 1);
|
|
41752
41850
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
@@ -41763,11 +41861,11 @@ async function updateFromChannel(args, deps) {
|
|
|
41763
41861
|
channelRef.extId,
|
|
41764
41862
|
channelRef.ownerPrincipalId
|
|
41765
41863
|
);
|
|
41766
|
-
const liveDir =
|
|
41864
|
+
const liveDir = import_node_path36.default.join(deps.extensionsRoot, localExtId);
|
|
41767
41865
|
const prevDir = `${liveDir}.prev`;
|
|
41768
41866
|
let existingVersion;
|
|
41769
41867
|
try {
|
|
41770
|
-
const raw = await import_promises6.default.readFile(
|
|
41868
|
+
const raw = await import_promises6.default.readFile(import_node_path36.default.join(liveDir, "manifest.json"), "utf8");
|
|
41771
41869
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
41772
41870
|
if (!parsed2.success) {
|
|
41773
41871
|
throw new UpdateError(
|
|
@@ -41800,7 +41898,7 @@ async function updateFromChannel(args, deps) {
|
|
|
41800
41898
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
41801
41899
|
}
|
|
41802
41900
|
for (const name of Object.keys(zip.files)) {
|
|
41803
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
41901
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
|
|
41804
41902
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
41805
41903
|
}
|
|
41806
41904
|
}
|
|
@@ -41835,16 +41933,16 @@ async function updateFromChannel(args, deps) {
|
|
|
41835
41933
|
await import_promises6.default.rm(prevDir, { recursive: true, force: true });
|
|
41836
41934
|
await import_promises6.default.rename(liveDir, prevDir);
|
|
41837
41935
|
const stage = await import_promises6.default.mkdtemp(
|
|
41838
|
-
|
|
41936
|
+
import_node_path36.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
41839
41937
|
);
|
|
41840
41938
|
try {
|
|
41841
41939
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
41842
|
-
const dest =
|
|
41940
|
+
const dest = import_node_path36.default.join(stage, name);
|
|
41843
41941
|
if (entry.dir) {
|
|
41844
41942
|
await import_promises6.default.mkdir(dest, { recursive: true });
|
|
41845
41943
|
continue;
|
|
41846
41944
|
}
|
|
41847
|
-
await import_promises6.default.mkdir(
|
|
41945
|
+
await import_promises6.default.mkdir(import_node_path36.default.dirname(dest), { recursive: true });
|
|
41848
41946
|
if (name === "manifest.json") {
|
|
41849
41947
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
41850
41948
|
await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -41937,7 +42035,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
41937
42035
|
);
|
|
41938
42036
|
}
|
|
41939
42037
|
}
|
|
41940
|
-
const manifestPath =
|
|
42038
|
+
const manifestPath = import_node_path37.default.join(root, extId, "manifest.json");
|
|
41941
42039
|
const manifest = await readManifest(root, extId);
|
|
41942
42040
|
const next = { ...manifest, version: newVersion };
|
|
41943
42041
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -41945,7 +42043,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
41945
42043
|
await import_promises7.default.rename(tmp, manifestPath);
|
|
41946
42044
|
}
|
|
41947
42045
|
async function readManifest(root, extId) {
|
|
41948
|
-
const file =
|
|
42046
|
+
const file = import_node_path37.default.join(root, extId, "manifest.json");
|
|
41949
42047
|
let raw;
|
|
41950
42048
|
try {
|
|
41951
42049
|
raw = await import_promises7.default.readFile(file, "utf8");
|
|
@@ -42036,7 +42134,7 @@ function buildExtensionHandlers(deps) {
|
|
|
42036
42134
|
};
|
|
42037
42135
|
async function buildSnapshotMeta(extId) {
|
|
42038
42136
|
const manifest = await readManifest(deps.root, extId);
|
|
42039
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
42137
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path37.default.join(deps.root, extId));
|
|
42040
42138
|
return { manifest, contentHash: sha256, buffer };
|
|
42041
42139
|
}
|
|
42042
42140
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -42333,7 +42431,7 @@ var PublishJobRegistry = class {
|
|
|
42333
42431
|
// src/app-builder/publish-job-runner.ts
|
|
42334
42432
|
var import_node_child_process8 = require("child_process");
|
|
42335
42433
|
var import_node_fs29 = require("fs");
|
|
42336
|
-
var
|
|
42434
|
+
var import_node_path38 = require("path");
|
|
42337
42435
|
|
|
42338
42436
|
// src/app-builder/publish-stage-parser.ts
|
|
42339
42437
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -42365,7 +42463,7 @@ async function startPublishJob(deps, args) {
|
|
|
42365
42463
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
42366
42464
|
}
|
|
42367
42465
|
const projDir = projectDir(args.name);
|
|
42368
|
-
const logPath = (0,
|
|
42466
|
+
const logPath = (0, import_node_path38.join)(projDir, ".publish.log");
|
|
42369
42467
|
let logStream = null;
|
|
42370
42468
|
try {
|
|
42371
42469
|
logStream = (0, import_node_fs29.createWriteStream)(logPath, { flags: "w" });
|
|
@@ -42625,7 +42723,7 @@ async function recoverInterruptedJobs(deps) {
|
|
|
42625
42723
|
|
|
42626
42724
|
// src/handlers/app-builder.ts
|
|
42627
42725
|
init_protocol();
|
|
42628
|
-
var
|
|
42726
|
+
var import_node_path39 = require("path");
|
|
42629
42727
|
var import_node_fs30 = require("fs");
|
|
42630
42728
|
var APP_BUILDER_PERSONAS = ["persona-app-builder"];
|
|
42631
42729
|
var PUBLISH_SCRIPT_REL = "extension-kit/scripts/publish.sh";
|
|
@@ -43000,7 +43098,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
43000
43098
|
});
|
|
43001
43099
|
await userStore.clearPublishJob(args.name);
|
|
43002
43100
|
}
|
|
43003
|
-
const scriptPath = (0,
|
|
43101
|
+
const scriptPath = (0, import_node_path39.join)(deps.personaRoot, PUBLISH_SCRIPT_REL);
|
|
43004
43102
|
deps.logger?.info("app-builder.publish.start", {
|
|
43005
43103
|
name: args.name,
|
|
43006
43104
|
sessionId: boundSession.sessionId,
|
|
@@ -43094,7 +43192,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
43094
43192
|
|
|
43095
43193
|
// src/extension/registry.ts
|
|
43096
43194
|
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
43097
|
-
var
|
|
43195
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
43098
43196
|
async function loadAll(root) {
|
|
43099
43197
|
let entries;
|
|
43100
43198
|
try {
|
|
@@ -43107,13 +43205,13 @@ async function loadAll(root) {
|
|
|
43107
43205
|
for (const ent of entries) {
|
|
43108
43206
|
if (!ent.isDirectory()) continue;
|
|
43109
43207
|
if (ent.name.startsWith(".")) continue;
|
|
43110
|
-
records.push(await loadOne(
|
|
43208
|
+
records.push(await loadOne(import_node_path40.default.join(root, ent.name), ent.name));
|
|
43111
43209
|
}
|
|
43112
43210
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
43113
43211
|
return records;
|
|
43114
43212
|
}
|
|
43115
43213
|
async function loadOne(dir, dirName) {
|
|
43116
|
-
const manifestPath =
|
|
43214
|
+
const manifestPath = import_node_path40.default.join(dir, "manifest.json");
|
|
43117
43215
|
let raw;
|
|
43118
43216
|
try {
|
|
43119
43217
|
raw = await import_promises8.default.readFile(manifestPath, "utf8");
|
|
@@ -43158,7 +43256,7 @@ async function loadOne(dir, dirName) {
|
|
|
43158
43256
|
|
|
43159
43257
|
// src/extension/uninstall.ts
|
|
43160
43258
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
43161
|
-
var
|
|
43259
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
43162
43260
|
var UninstallError = class extends Error {
|
|
43163
43261
|
constructor(code, message) {
|
|
43164
43262
|
super(message);
|
|
@@ -43167,7 +43265,7 @@ var UninstallError = class extends Error {
|
|
|
43167
43265
|
code;
|
|
43168
43266
|
};
|
|
43169
43267
|
async function uninstall(deps) {
|
|
43170
|
-
const dir =
|
|
43268
|
+
const dir = import_node_path41.default.join(deps.root, deps.extId);
|
|
43171
43269
|
try {
|
|
43172
43270
|
await import_promises9.default.access(dir);
|
|
43173
43271
|
} catch {
|
|
@@ -43248,7 +43346,7 @@ function buildMethodHandlers(deps) {
|
|
|
43248
43346
|
// src/app-builder/project-store.ts
|
|
43249
43347
|
var import_node_fs31 = require("fs");
|
|
43250
43348
|
var import_node_child_process9 = require("child_process");
|
|
43251
|
-
var
|
|
43349
|
+
var import_node_path42 = require("path");
|
|
43252
43350
|
init_protocol();
|
|
43253
43351
|
var PROJECTS_DIR = "projects";
|
|
43254
43352
|
var META_FILE = ".clawd-project.json";
|
|
@@ -43263,14 +43361,14 @@ var ProjectStore = class {
|
|
|
43263
43361
|
root;
|
|
43264
43362
|
/** projects/<name>/.clawd-project.json 路径 */
|
|
43265
43363
|
metaPath(name) {
|
|
43266
|
-
return (0,
|
|
43364
|
+
return (0, import_node_path42.join)(this.projectsRoot(), name, META_FILE);
|
|
43267
43365
|
}
|
|
43268
43366
|
/** projects/<name>/ 目录路径(cwd 用) */
|
|
43269
43367
|
projectDir(name) {
|
|
43270
|
-
return (0,
|
|
43368
|
+
return (0, import_node_path42.join)(this.projectsRoot(), name);
|
|
43271
43369
|
}
|
|
43272
43370
|
projectsRoot() {
|
|
43273
|
-
return (0,
|
|
43371
|
+
return (0, import_node_path42.join)(this.root, PROJECTS_DIR);
|
|
43274
43372
|
}
|
|
43275
43373
|
async list() {
|
|
43276
43374
|
let entries;
|
|
@@ -43351,7 +43449,7 @@ var ProjectStore = class {
|
|
|
43351
43449
|
* 代码再参考"。assistant 进 project 时目录已是完整模板,直接 pnpm install 即可。
|
|
43352
43450
|
*/
|
|
43353
43451
|
async scaffold(name, template = DEFAULT_TEMPLATE, personaRoot = this.root) {
|
|
43354
|
-
const scriptPath = (0,
|
|
43452
|
+
const scriptPath = (0, import_node_path42.join)(personaRoot, SCAFFOLD_SCRIPT_REL);
|
|
43355
43453
|
const destDir = this.projectDir(name);
|
|
43356
43454
|
return await new Promise((resolve6, reject) => {
|
|
43357
43455
|
const child = (0, import_node_child_process9.spawn)("bash", [scriptPath, name, template, destDir], {
|
|
@@ -43889,7 +43987,7 @@ function computeGrantForFrame(method, frame) {
|
|
|
43889
43987
|
|
|
43890
43988
|
// src/extension/runtime.ts
|
|
43891
43989
|
var import_node_child_process11 = require("child_process");
|
|
43892
|
-
var
|
|
43990
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
43893
43991
|
var import_promises10 = require("timers/promises");
|
|
43894
43992
|
|
|
43895
43993
|
// src/extension/port-allocator.ts
|
|
@@ -43990,7 +44088,7 @@ var Runtime = class {
|
|
|
43990
44088
|
/\$CLAWOS_EXT_PORT/g,
|
|
43991
44089
|
String(port)
|
|
43992
44090
|
);
|
|
43993
|
-
const dir =
|
|
44091
|
+
const dir = import_node_path43.default.join(this.root, extId);
|
|
43994
44092
|
const env = {
|
|
43995
44093
|
...process.env,
|
|
43996
44094
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -44102,7 +44200,7 @@ ${handle.stderrTail}`
|
|
|
44102
44200
|
|
|
44103
44201
|
// src/extension/published-channels.ts
|
|
44104
44202
|
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
44105
|
-
var
|
|
44203
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
44106
44204
|
init_zod();
|
|
44107
44205
|
var PublishedChannelsError = class extends Error {
|
|
44108
44206
|
constructor(code, message) {
|
|
@@ -44201,7 +44299,7 @@ var PublishedChannelStore = class {
|
|
|
44201
44299
|
)
|
|
44202
44300
|
};
|
|
44203
44301
|
const tmp = `${this.filePath}.tmp`;
|
|
44204
|
-
await import_promises11.default.mkdir(
|
|
44302
|
+
await import_promises11.default.mkdir(import_node_path44.default.dirname(this.filePath), { recursive: true });
|
|
44205
44303
|
await import_promises11.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
44206
44304
|
await import_promises11.default.rename(tmp, this.filePath);
|
|
44207
44305
|
}
|
|
@@ -44209,7 +44307,7 @@ var PublishedChannelStore = class {
|
|
|
44209
44307
|
|
|
44210
44308
|
// src/extension/bundle-cache.ts
|
|
44211
44309
|
var import_promises12 = __toESM(require("fs/promises"), 1);
|
|
44212
|
-
var
|
|
44310
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
44213
44311
|
var BundleCache = class {
|
|
44214
44312
|
constructor(rootDir) {
|
|
44215
44313
|
this.rootDir = rootDir;
|
|
@@ -44218,14 +44316,14 @@ var BundleCache = class {
|
|
|
44218
44316
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
44219
44317
|
async write(snapshotHash, buffer) {
|
|
44220
44318
|
await import_promises12.default.mkdir(this.rootDir, { recursive: true });
|
|
44221
|
-
const file =
|
|
44319
|
+
const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
44222
44320
|
const tmp = `${file}.tmp`;
|
|
44223
44321
|
await import_promises12.default.writeFile(tmp, buffer, { mode: 384 });
|
|
44224
44322
|
await import_promises12.default.rename(tmp, file);
|
|
44225
44323
|
}
|
|
44226
44324
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
44227
44325
|
async read(snapshotHash) {
|
|
44228
|
-
const file =
|
|
44326
|
+
const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
44229
44327
|
try {
|
|
44230
44328
|
return await import_promises12.default.readFile(file);
|
|
44231
44329
|
} catch (e) {
|
|
@@ -44235,7 +44333,7 @@ var BundleCache = class {
|
|
|
44235
44333
|
}
|
|
44236
44334
|
/** Idempotent — missing file is not an error. */
|
|
44237
44335
|
async delete(snapshotHash) {
|
|
44238
|
-
const file =
|
|
44336
|
+
const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
44239
44337
|
await import_promises12.default.rm(file, { force: true });
|
|
44240
44338
|
}
|
|
44241
44339
|
};
|
|
@@ -44244,7 +44342,7 @@ var BundleCache = class {
|
|
|
44244
44342
|
async function startDaemon(config) {
|
|
44245
44343
|
const logger = createLogger({
|
|
44246
44344
|
level: config.logLevel,
|
|
44247
|
-
file:
|
|
44345
|
+
file: import_node_path46.default.join(config.dataDir, "clawd.log")
|
|
44248
44346
|
});
|
|
44249
44347
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
44250
44348
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -44380,8 +44478,8 @@ async function startDaemon(config) {
|
|
|
44380
44478
|
const agents = new AgentsScanner();
|
|
44381
44479
|
const history = new ClaudeHistoryReader();
|
|
44382
44480
|
let transport = null;
|
|
44383
|
-
const personaStore = new PersonaStore(
|
|
44384
|
-
const usersRoot =
|
|
44481
|
+
const personaStore = new PersonaStore(import_node_path46.default.join(config.dataDir, "personas"));
|
|
44482
|
+
const usersRoot = import_node_path46.default.join(config.dataDir, "users");
|
|
44385
44483
|
const defaultsRoot = findDefaultsRoot();
|
|
44386
44484
|
if (defaultsRoot) {
|
|
44387
44485
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -44399,7 +44497,7 @@ async function startDaemon(config) {
|
|
|
44399
44497
|
getAdapter,
|
|
44400
44498
|
historyReader: history,
|
|
44401
44499
|
dataDir: config.dataDir,
|
|
44402
|
-
personaRoot:
|
|
44500
|
+
personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
|
|
44403
44501
|
usersRoot,
|
|
44404
44502
|
personaStore,
|
|
44405
44503
|
ownerDisplayName,
|
|
@@ -44429,7 +44527,7 @@ async function startDaemon(config) {
|
|
|
44429
44527
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
44430
44528
|
attachmentGroup: {
|
|
44431
44529
|
onFileEdit: (input) => {
|
|
44432
|
-
const absPath =
|
|
44530
|
+
const absPath = import_node_path46.default.isAbsolute(input.relPath) ? input.relPath : import_node_path46.default.join(input.cwd, input.relPath);
|
|
44433
44531
|
let size = 0;
|
|
44434
44532
|
try {
|
|
44435
44533
|
size = import_node_fs32.default.statSync(absPath).size;
|
|
@@ -44614,11 +44712,11 @@ async function startDaemon(config) {
|
|
|
44614
44712
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
44615
44713
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
44616
44714
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
44617
|
-
personaRoot:
|
|
44715
|
+
personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
|
|
44618
44716
|
usersRoot
|
|
44619
44717
|
},
|
|
44620
44718
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
44621
|
-
personaRoot:
|
|
44719
|
+
personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
|
|
44622
44720
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
44623
44721
|
usersRoot,
|
|
44624
44722
|
// capability:list / delete handler 依赖
|
|
@@ -44707,7 +44805,7 @@ async function startDaemon(config) {
|
|
|
44707
44805
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
44708
44806
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
44709
44807
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
44710
|
-
appBuilderPersonaRoot:
|
|
44808
|
+
appBuilderPersonaRoot: import_node_path46.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
44711
44809
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
44712
44810
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
44713
44811
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -44955,8 +45053,8 @@ async function startDaemon(config) {
|
|
|
44955
45053
|
const lines = [
|
|
44956
45054
|
`Tunnel: ${r.url}`,
|
|
44957
45055
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
44958
|
-
`Frpc config: ${
|
|
44959
|
-
`Frpc log: ${
|
|
45056
|
+
`Frpc config: ${import_node_path46.default.join(config.dataDir, "frpc.toml")}`,
|
|
45057
|
+
`Frpc log: ${import_node_path46.default.join(config.dataDir, "frpc.log")}`
|
|
44960
45058
|
];
|
|
44961
45059
|
const width = Math.max(...lines.map((l) => l.length));
|
|
44962
45060
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -44969,7 +45067,7 @@ ${bar}
|
|
|
44969
45067
|
|
|
44970
45068
|
`);
|
|
44971
45069
|
try {
|
|
44972
|
-
const connectPath =
|
|
45070
|
+
const connectPath = import_node_path46.default.join(config.dataDir, "connect.txt");
|
|
44973
45071
|
import_node_fs32.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
44974
45072
|
} catch {
|
|
44975
45073
|
}
|
|
@@ -45041,7 +45139,7 @@ ${bar}
|
|
|
45041
45139
|
};
|
|
45042
45140
|
}
|
|
45043
45141
|
function migrateDropPersonsDir(dataDir) {
|
|
45044
|
-
const dir =
|
|
45142
|
+
const dir = import_node_path46.default.join(dataDir, "persons");
|
|
45045
45143
|
try {
|
|
45046
45144
|
import_node_fs32.default.rmSync(dir, { recursive: true, force: true });
|
|
45047
45145
|
} catch {
|