@clawos-dev/clawd 0.2.48-beta.74.b742e0f → 0.2.48-beta.76.f411c83
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 +349 -389
- package/dist/persona-defaults/persona-clawd-helper/CLAUDE.md +94 -0
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -296,8 +296,8 @@ var require_req = __commonJS({
|
|
|
296
296
|
if (req.originalUrl) {
|
|
297
297
|
_req.url = req.originalUrl;
|
|
298
298
|
} else {
|
|
299
|
-
const
|
|
300
|
-
_req.url = typeof
|
|
299
|
+
const path25 = req.path;
|
|
300
|
+
_req.url = typeof path25 === "string" ? path25 : req.url ? req.url.path || req.url : void 0;
|
|
301
301
|
}
|
|
302
302
|
if (req.query) {
|
|
303
303
|
_req.query = req.query;
|
|
@@ -462,14 +462,14 @@ var require_redact = __commonJS({
|
|
|
462
462
|
}
|
|
463
463
|
return obj;
|
|
464
464
|
}
|
|
465
|
-
function parsePath(
|
|
465
|
+
function parsePath(path25) {
|
|
466
466
|
const parts = [];
|
|
467
467
|
let current = "";
|
|
468
468
|
let inBrackets = false;
|
|
469
469
|
let inQuotes = false;
|
|
470
470
|
let quoteChar = "";
|
|
471
|
-
for (let i = 0; i <
|
|
472
|
-
const char =
|
|
471
|
+
for (let i = 0; i < path25.length; i++) {
|
|
472
|
+
const char = path25[i];
|
|
473
473
|
if (!inBrackets && char === ".") {
|
|
474
474
|
if (current) {
|
|
475
475
|
parts.push(current);
|
|
@@ -600,10 +600,10 @@ var require_redact = __commonJS({
|
|
|
600
600
|
return current;
|
|
601
601
|
}
|
|
602
602
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
603
|
-
for (const
|
|
604
|
-
const parts = parsePath(
|
|
603
|
+
for (const path25 of paths) {
|
|
604
|
+
const parts = parsePath(path25);
|
|
605
605
|
if (parts.includes("*")) {
|
|
606
|
-
redactWildcardPath(obj, parts, censor,
|
|
606
|
+
redactWildcardPath(obj, parts, censor, path25, remove);
|
|
607
607
|
} else {
|
|
608
608
|
if (remove) {
|
|
609
609
|
removeKey(obj, parts);
|
|
@@ -688,8 +688,8 @@ var require_redact = __commonJS({
|
|
|
688
688
|
}
|
|
689
689
|
} else {
|
|
690
690
|
if (afterWildcard.includes("*")) {
|
|
691
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
692
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
691
|
+
const wrappedCensor = typeof censor === "function" ? (value, path25) => {
|
|
692
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path25];
|
|
693
693
|
return censor(value, fullPath);
|
|
694
694
|
} : censor;
|
|
695
695
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -724,8 +724,8 @@ var require_redact = __commonJS({
|
|
|
724
724
|
return null;
|
|
725
725
|
}
|
|
726
726
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
727
|
-
for (const
|
|
728
|
-
const parts = parsePath(
|
|
727
|
+
for (const path25 of pathsToClone) {
|
|
728
|
+
const parts = parsePath(path25);
|
|
729
729
|
let current = pathStructure;
|
|
730
730
|
for (let i = 0; i < parts.length; i++) {
|
|
731
731
|
const part = parts[i];
|
|
@@ -777,24 +777,24 @@ var require_redact = __commonJS({
|
|
|
777
777
|
}
|
|
778
778
|
return cloneSelectively(obj, pathStructure);
|
|
779
779
|
}
|
|
780
|
-
function validatePath(
|
|
781
|
-
if (typeof
|
|
780
|
+
function validatePath(path25) {
|
|
781
|
+
if (typeof path25 !== "string") {
|
|
782
782
|
throw new Error("Paths must be (non-empty) strings");
|
|
783
783
|
}
|
|
784
|
-
if (
|
|
784
|
+
if (path25 === "") {
|
|
785
785
|
throw new Error("Invalid redaction path ()");
|
|
786
786
|
}
|
|
787
|
-
if (
|
|
788
|
-
throw new Error(`Invalid redaction path (${
|
|
787
|
+
if (path25.includes("..")) {
|
|
788
|
+
throw new Error(`Invalid redaction path (${path25})`);
|
|
789
789
|
}
|
|
790
|
-
if (
|
|
791
|
-
throw new Error(`Invalid redaction path (${
|
|
790
|
+
if (path25.includes(",")) {
|
|
791
|
+
throw new Error(`Invalid redaction path (${path25})`);
|
|
792
792
|
}
|
|
793
793
|
let bracketCount = 0;
|
|
794
794
|
let inQuotes = false;
|
|
795
795
|
let quoteChar = "";
|
|
796
|
-
for (let i = 0; i <
|
|
797
|
-
const char =
|
|
796
|
+
for (let i = 0; i < path25.length; i++) {
|
|
797
|
+
const char = path25[i];
|
|
798
798
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
799
799
|
if (!inQuotes) {
|
|
800
800
|
inQuotes = true;
|
|
@@ -808,20 +808,20 @@ var require_redact = __commonJS({
|
|
|
808
808
|
} else if (char === "]" && !inQuotes) {
|
|
809
809
|
bracketCount--;
|
|
810
810
|
if (bracketCount < 0) {
|
|
811
|
-
throw new Error(`Invalid redaction path (${
|
|
811
|
+
throw new Error(`Invalid redaction path (${path25})`);
|
|
812
812
|
}
|
|
813
813
|
}
|
|
814
814
|
}
|
|
815
815
|
if (bracketCount !== 0) {
|
|
816
|
-
throw new Error(`Invalid redaction path (${
|
|
816
|
+
throw new Error(`Invalid redaction path (${path25})`);
|
|
817
817
|
}
|
|
818
818
|
}
|
|
819
819
|
function validatePaths(paths) {
|
|
820
820
|
if (!Array.isArray(paths)) {
|
|
821
821
|
throw new TypeError("paths must be an array");
|
|
822
822
|
}
|
|
823
|
-
for (const
|
|
824
|
-
validatePath(
|
|
823
|
+
for (const path25 of paths) {
|
|
824
|
+
validatePath(path25);
|
|
825
825
|
}
|
|
826
826
|
}
|
|
827
827
|
function slowRedact(options = {}) {
|
|
@@ -989,8 +989,8 @@ var require_redaction = __commonJS({
|
|
|
989
989
|
if (shape[k] === null) {
|
|
990
990
|
o[k] = (value) => topCensor(value, [k]);
|
|
991
991
|
} else {
|
|
992
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
993
|
-
return censor(value, [k, ...
|
|
992
|
+
const wrappedCensor = typeof censor === "function" ? (value, path25) => {
|
|
993
|
+
return censor(value, [k, ...path25]);
|
|
994
994
|
} : censor;
|
|
995
995
|
o[k] = Redact({
|
|
996
996
|
paths: shape[k],
|
|
@@ -1211,7 +1211,7 @@ var require_sonic_boom = __commonJS({
|
|
|
1211
1211
|
var fs24 = require("fs");
|
|
1212
1212
|
var EventEmitter = require("events");
|
|
1213
1213
|
var inherits = require("util").inherits;
|
|
1214
|
-
var
|
|
1214
|
+
var path25 = require("path");
|
|
1215
1215
|
var sleep = require_atomic_sleep();
|
|
1216
1216
|
var assert = require("assert");
|
|
1217
1217
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -1265,7 +1265,7 @@ var require_sonic_boom = __commonJS({
|
|
|
1265
1265
|
const mode = sonic.mode;
|
|
1266
1266
|
if (sonic.sync) {
|
|
1267
1267
|
try {
|
|
1268
|
-
if (sonic.mkdir) fs24.mkdirSync(
|
|
1268
|
+
if (sonic.mkdir) fs24.mkdirSync(path25.dirname(file), { recursive: true });
|
|
1269
1269
|
const fd = fs24.openSync(file, flags, mode);
|
|
1270
1270
|
fileOpened(null, fd);
|
|
1271
1271
|
} catch (err) {
|
|
@@ -1273,7 +1273,7 @@ var require_sonic_boom = __commonJS({
|
|
|
1273
1273
|
throw err;
|
|
1274
1274
|
}
|
|
1275
1275
|
} else if (sonic.mkdir) {
|
|
1276
|
-
fs24.mkdir(
|
|
1276
|
+
fs24.mkdir(path25.dirname(file), { recursive: true }, (err) => {
|
|
1277
1277
|
if (err) return fileOpened(err);
|
|
1278
1278
|
fs24.open(file, flags, mode, fileOpened);
|
|
1279
1279
|
});
|
|
@@ -4895,8 +4895,8 @@ var init_parseUtil = __esm({
|
|
|
4895
4895
|
init_errors2();
|
|
4896
4896
|
init_en();
|
|
4897
4897
|
makeIssue = (params) => {
|
|
4898
|
-
const { data, path:
|
|
4899
|
-
const fullPath = [...
|
|
4898
|
+
const { data, path: path25, errorMaps, issueData } = params;
|
|
4899
|
+
const fullPath = [...path25, ...issueData.path || []];
|
|
4900
4900
|
const fullIssue = {
|
|
4901
4901
|
...issueData,
|
|
4902
4902
|
path: fullPath
|
|
@@ -5207,11 +5207,11 @@ var init_types = __esm({
|
|
|
5207
5207
|
init_parseUtil();
|
|
5208
5208
|
init_util();
|
|
5209
5209
|
ParseInputLazyPath = class {
|
|
5210
|
-
constructor(parent, value,
|
|
5210
|
+
constructor(parent, value, path25, key) {
|
|
5211
5211
|
this._cachedPath = [];
|
|
5212
5212
|
this.parent = parent;
|
|
5213
5213
|
this.data = value;
|
|
5214
|
-
this._path =
|
|
5214
|
+
this._path = path25;
|
|
5215
5215
|
this._key = key;
|
|
5216
5216
|
}
|
|
5217
5217
|
get path() {
|
|
@@ -9823,11 +9823,11 @@ var init_lib = __esm({
|
|
|
9823
9823
|
}
|
|
9824
9824
|
}
|
|
9825
9825
|
},
|
|
9826
|
-
addToPath: function addToPath(
|
|
9827
|
-
var last =
|
|
9826
|
+
addToPath: function addToPath(path25, added, removed, oldPosInc, options) {
|
|
9827
|
+
var last = path25.lastComponent;
|
|
9828
9828
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
9829
9829
|
return {
|
|
9830
|
-
oldPos:
|
|
9830
|
+
oldPos: path25.oldPos + oldPosInc,
|
|
9831
9831
|
lastComponent: {
|
|
9832
9832
|
count: last.count + 1,
|
|
9833
9833
|
added,
|
|
@@ -9837,7 +9837,7 @@ var init_lib = __esm({
|
|
|
9837
9837
|
};
|
|
9838
9838
|
} else {
|
|
9839
9839
|
return {
|
|
9840
|
-
oldPos:
|
|
9840
|
+
oldPos: path25.oldPos + oldPosInc,
|
|
9841
9841
|
lastComponent: {
|
|
9842
9842
|
count: 1,
|
|
9843
9843
|
added,
|
|
@@ -10268,10 +10268,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10268
10268
|
const memories = raw.map((m) => {
|
|
10269
10269
|
if (!m || typeof m !== "object") return null;
|
|
10270
10270
|
const rec = m;
|
|
10271
|
-
const
|
|
10271
|
+
const path25 = typeof rec.path === "string" ? rec.path : null;
|
|
10272
10272
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
10273
|
-
if (!
|
|
10274
|
-
const entry = { path:
|
|
10273
|
+
if (!path25 || content == null) return null;
|
|
10274
|
+
const entry = { path: path25, content };
|
|
10275
10275
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
10276
10276
|
return entry;
|
|
10277
10277
|
}).filter((m) => m !== null);
|
|
@@ -10308,7 +10308,7 @@ function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
|
|
|
10308
10308
|
if (backupFileName === null) return null;
|
|
10309
10309
|
try {
|
|
10310
10310
|
return import_node_fs6.default.readFileSync(
|
|
10311
|
-
|
|
10311
|
+
import_node_path6.default.join(fileHistoryRoot, toolSessionId, backupFileName),
|
|
10312
10312
|
"utf8"
|
|
10313
10313
|
);
|
|
10314
10314
|
} catch {
|
|
@@ -10323,13 +10323,13 @@ function readCurrentContent(filePath) {
|
|
|
10323
10323
|
return null;
|
|
10324
10324
|
}
|
|
10325
10325
|
}
|
|
10326
|
-
var import_node_fs6, import_node_os2,
|
|
10326
|
+
var import_node_fs6, import_node_os2, import_node_path6, 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;
|
|
10327
10327
|
var init_claude_history = __esm({
|
|
10328
10328
|
"src/tools/claude-history.ts"() {
|
|
10329
10329
|
"use strict";
|
|
10330
10330
|
import_node_fs6 = __toESM(require("fs"), 1);
|
|
10331
10331
|
import_node_os2 = __toESM(require("os"), 1);
|
|
10332
|
-
|
|
10332
|
+
import_node_path6 = __toESM(require("path"), 1);
|
|
10333
10333
|
init_lib();
|
|
10334
10334
|
init_tool_result_extra();
|
|
10335
10335
|
TASK_NOTIFICATION_RE = /<task-notification\b[\s\S]*?<\/task-notification>/i;
|
|
@@ -10353,9 +10353,9 @@ var init_claude_history = __esm({
|
|
|
10353
10353
|
// 每次 user 提交前 trackEdit 拷一份,作为 rewind 回退目标
|
|
10354
10354
|
fileHistoryRoot;
|
|
10355
10355
|
constructor(opts = {}) {
|
|
10356
|
-
const base = opts.baseDir ??
|
|
10357
|
-
this.projectsRoot =
|
|
10358
|
-
this.fileHistoryRoot =
|
|
10356
|
+
const base = opts.baseDir ?? import_node_path6.default.join(import_node_os2.default.homedir(), ".claude");
|
|
10357
|
+
this.projectsRoot = import_node_path6.default.join(base, "projects");
|
|
10358
|
+
this.fileHistoryRoot = import_node_path6.default.join(base, "file-history");
|
|
10359
10359
|
}
|
|
10360
10360
|
async listProjects() {
|
|
10361
10361
|
let entries;
|
|
@@ -10368,9 +10368,9 @@ var init_claude_history = __esm({
|
|
|
10368
10368
|
const out = [];
|
|
10369
10369
|
for (const ent of entries) {
|
|
10370
10370
|
if (!ent.isDirectory()) continue;
|
|
10371
|
-
const dir =
|
|
10371
|
+
const dir = import_node_path6.default.join(this.projectsRoot, ent.name);
|
|
10372
10372
|
const files = import_node_fs6.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
10373
|
-
const updatedAtMs = files.reduce((m, f) => Math.max(m, safeStatMtime(
|
|
10373
|
+
const updatedAtMs = files.reduce((m, f) => Math.max(m, safeStatMtime(import_node_path6.default.join(dir, f))), 0);
|
|
10374
10374
|
out.push({
|
|
10375
10375
|
projectPath: hashDirToCwd(ent.name),
|
|
10376
10376
|
hashDir: ent.name,
|
|
@@ -10382,7 +10382,7 @@ var init_claude_history = __esm({
|
|
|
10382
10382
|
return out;
|
|
10383
10383
|
}
|
|
10384
10384
|
async listSessions(args) {
|
|
10385
|
-
const dir =
|
|
10385
|
+
const dir = import_node_path6.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
|
|
10386
10386
|
let files;
|
|
10387
10387
|
try {
|
|
10388
10388
|
files = import_node_fs6.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
@@ -10392,7 +10392,7 @@ var init_claude_history = __esm({
|
|
|
10392
10392
|
}
|
|
10393
10393
|
const out = [];
|
|
10394
10394
|
for (const f of files) {
|
|
10395
|
-
const full =
|
|
10395
|
+
const full = import_node_path6.default.join(dir, f);
|
|
10396
10396
|
const toolSessionId = f.slice(0, -".jsonl".length);
|
|
10397
10397
|
const lines = readJsonlLines(full);
|
|
10398
10398
|
let summary = "";
|
|
@@ -10447,7 +10447,7 @@ var init_claude_history = __esm({
|
|
|
10447
10447
|
return out;
|
|
10448
10448
|
}
|
|
10449
10449
|
async read(args) {
|
|
10450
|
-
const file =
|
|
10450
|
+
const file = import_node_path6.default.join(
|
|
10451
10451
|
this.projectsRoot,
|
|
10452
10452
|
cwdToHashDir(args.cwd),
|
|
10453
10453
|
`${args.toolSessionId}.jsonl`
|
|
@@ -10480,7 +10480,7 @@ var init_claude_history = __esm({
|
|
|
10480
10480
|
// 独立目录路径:<projectsRoot>/<cwdHash>/<toolSessionId>/subagents/*.jsonl
|
|
10481
10481
|
// 返回 null 表示目录不存在(调用方回退旧实现);返回空数组表示目录存在但无 jsonl
|
|
10482
10482
|
listSubagentsFromDirectory(cwd, toolSessionId) {
|
|
10483
|
-
const dir =
|
|
10483
|
+
const dir = import_node_path6.default.join(
|
|
10484
10484
|
this.projectsRoot,
|
|
10485
10485
|
cwdToHashDir(cwd),
|
|
10486
10486
|
toolSessionId,
|
|
@@ -10498,7 +10498,7 @@ var init_claude_history = __esm({
|
|
|
10498
10498
|
if (!e.isFile()) continue;
|
|
10499
10499
|
if (!e.name.startsWith("agent-") || !e.name.endsWith(".jsonl")) continue;
|
|
10500
10500
|
const subagentId = e.name.slice("agent-".length, -".jsonl".length);
|
|
10501
|
-
const filePath =
|
|
10501
|
+
const filePath = import_node_path6.default.join(dir, e.name);
|
|
10502
10502
|
const lines = readJsonlLines(filePath);
|
|
10503
10503
|
let firstText = "";
|
|
10504
10504
|
let messageCount = 0;
|
|
@@ -10515,7 +10515,7 @@ var init_claude_history = __esm({
|
|
|
10515
10515
|
return out;
|
|
10516
10516
|
}
|
|
10517
10517
|
listSubagentsFromMainJsonl(cwd, toolSessionId) {
|
|
10518
|
-
const file =
|
|
10518
|
+
const file = import_node_path6.default.join(
|
|
10519
10519
|
this.projectsRoot,
|
|
10520
10520
|
cwdToHashDir(cwd),
|
|
10521
10521
|
`${toolSessionId}.jsonl`
|
|
@@ -10550,7 +10550,7 @@ var init_claude_history = __esm({
|
|
|
10550
10550
|
}
|
|
10551
10551
|
// 独立文件路径:agent-<subagentId>.jsonl;文件不存在返回 null 让调用方回退旧实现
|
|
10552
10552
|
readSubagentFromFile(cwd, toolSessionId, subagentId) {
|
|
10553
|
-
const file =
|
|
10553
|
+
const file = import_node_path6.default.join(
|
|
10554
10554
|
this.projectsRoot,
|
|
10555
10555
|
cwdToHashDir(cwd),
|
|
10556
10556
|
toolSessionId,
|
|
@@ -10578,7 +10578,7 @@ var init_claude_history = __esm({
|
|
|
10578
10578
|
* "那一刻每个 tracked 文件对应的 backup 文件名"
|
|
10579
10579
|
*/
|
|
10580
10580
|
readFileHistorySnapshots(args) {
|
|
10581
|
-
const file =
|
|
10581
|
+
const file = import_node_path6.default.join(
|
|
10582
10582
|
this.projectsRoot,
|
|
10583
10583
|
cwdToHashDir(args.cwd),
|
|
10584
10584
|
`${args.toolSessionId}.jsonl`
|
|
@@ -10623,7 +10623,7 @@ var init_claude_history = __esm({
|
|
|
10623
10623
|
for (const [anchorId, target] of snapshots) {
|
|
10624
10624
|
let hasAny = false;
|
|
10625
10625
|
for (const [rawPath, backup] of Object.entries(target)) {
|
|
10626
|
-
const absPath =
|
|
10626
|
+
const absPath = import_node_path6.default.isAbsolute(rawPath) ? rawPath : import_node_path6.default.join(args.cwd, rawPath);
|
|
10627
10627
|
const backupContent = readBackupContent(
|
|
10628
10628
|
this.fileHistoryRoot,
|
|
10629
10629
|
args.toolSessionId,
|
|
@@ -10663,7 +10663,7 @@ var init_claude_history = __esm({
|
|
|
10663
10663
|
let totalInsertions = 0;
|
|
10664
10664
|
let totalDeletions = 0;
|
|
10665
10665
|
for (const [rawPath, backup] of Object.entries(target)) {
|
|
10666
|
-
const absPath =
|
|
10666
|
+
const absPath = import_node_path6.default.isAbsolute(rawPath) ? rawPath : import_node_path6.default.join(args.cwd, rawPath);
|
|
10667
10667
|
const backupContent = readBackupContent(
|
|
10668
10668
|
this.fileHistoryRoot,
|
|
10669
10669
|
args.toolSessionId,
|
|
@@ -10710,7 +10710,7 @@ var init_claude_history = __esm({
|
|
|
10710
10710
|
};
|
|
10711
10711
|
}
|
|
10712
10712
|
readSubagentFromMainJsonl(cwd, toolSessionId, subagentId) {
|
|
10713
|
-
const file =
|
|
10713
|
+
const file = import_node_path6.default.join(
|
|
10714
10714
|
this.projectsRoot,
|
|
10715
10715
|
cwdToHashDir(cwd),
|
|
10716
10716
|
`${toolSessionId}.jsonl`
|
|
@@ -10734,7 +10734,7 @@ var init_claude_history = __esm({
|
|
|
10734
10734
|
// src/tools/claude.ts
|
|
10735
10735
|
function macOSDesktopCandidates(home) {
|
|
10736
10736
|
return [
|
|
10737
|
-
|
|
10737
|
+
import_node_path7.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
|
|
10738
10738
|
"/Applications/Claude.app/Contents/Resources/app.asar.unpacked/node_modules/@anthropic-ai/claude-code/cli.js"
|
|
10739
10739
|
];
|
|
10740
10740
|
}
|
|
@@ -11075,10 +11075,10 @@ function parseAttachment(obj) {
|
|
|
11075
11075
|
const memories = raw.map((m) => {
|
|
11076
11076
|
if (!m || typeof m !== "object") return null;
|
|
11077
11077
|
const rec = m;
|
|
11078
|
-
const
|
|
11078
|
+
const path25 = typeof rec.path === "string" ? rec.path : null;
|
|
11079
11079
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11080
|
-
if (!
|
|
11081
|
-
const out = { path:
|
|
11080
|
+
if (!path25 || content == null) return null;
|
|
11081
|
+
const out = { path: path25, content };
|
|
11082
11082
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11083
11083
|
return out;
|
|
11084
11084
|
}).filter((m) => m !== null);
|
|
@@ -11182,7 +11182,7 @@ function encodeClaudeStdin(text) {
|
|
|
11182
11182
|
};
|
|
11183
11183
|
return JSON.stringify(frame) + "\n";
|
|
11184
11184
|
}
|
|
11185
|
-
var import_node_child_process, import_node_child_process2, import_node_fs7, import_node_os3,
|
|
11185
|
+
var import_node_child_process, import_node_child_process2, import_node_fs7, import_node_os3, import_node_path7, ATTACHMENT_SILENT_SUBTYPES2, unknownTypeHandler, ATTACHMENT_RE, IMAGE_EXT_MIME, CLAUDE_MODELS, CLAUDE_PERMISSION_MODES, CLAUDE_CAPABILITIES, ClaudeAdapter;
|
|
11186
11186
|
var init_claude = __esm({
|
|
11187
11187
|
"src/tools/claude.ts"() {
|
|
11188
11188
|
"use strict";
|
|
@@ -11190,7 +11190,7 @@ var init_claude = __esm({
|
|
|
11190
11190
|
import_node_child_process2 = require("child_process");
|
|
11191
11191
|
import_node_fs7 = __toESM(require("fs"), 1);
|
|
11192
11192
|
import_node_os3 = __toESM(require("os"), 1);
|
|
11193
|
-
|
|
11193
|
+
import_node_path7 = __toESM(require("path"), 1);
|
|
11194
11194
|
init_protocol();
|
|
11195
11195
|
init_claude_history();
|
|
11196
11196
|
init_tool_result_extra();
|
|
@@ -14945,7 +14945,7 @@ var require_websocket_server = __commonJS({
|
|
|
14945
14945
|
// src/run-case/recorder.ts
|
|
14946
14946
|
function startRunCaseRecorder(opts) {
|
|
14947
14947
|
const now = opts.now ?? Date.now;
|
|
14948
|
-
const dir =
|
|
14948
|
+
const dir = import_node_path21.default.dirname(opts.recordPath);
|
|
14949
14949
|
let stream = null;
|
|
14950
14950
|
let closing = false;
|
|
14951
14951
|
let closedSettled = false;
|
|
@@ -14985,12 +14985,12 @@ function startRunCaseRecorder(opts) {
|
|
|
14985
14985
|
};
|
|
14986
14986
|
return { tap, close, closed };
|
|
14987
14987
|
}
|
|
14988
|
-
var import_node_fs21,
|
|
14988
|
+
var import_node_fs21, import_node_path21;
|
|
14989
14989
|
var init_recorder = __esm({
|
|
14990
14990
|
"src/run-case/recorder.ts"() {
|
|
14991
14991
|
"use strict";
|
|
14992
14992
|
import_node_fs21 = __toESM(require("fs"), 1);
|
|
14993
|
-
|
|
14993
|
+
import_node_path21 = __toESM(require("path"), 1);
|
|
14994
14994
|
}
|
|
14995
14995
|
});
|
|
14996
14996
|
|
|
@@ -15033,7 +15033,7 @@ var init_wire = __esm({
|
|
|
15033
15033
|
// src/run-case/controller.ts
|
|
15034
15034
|
async function runController(opts) {
|
|
15035
15035
|
const now = opts.now ?? Date.now;
|
|
15036
|
-
const cwd = opts.cwd ?? (0, import_node_fs22.mkdtempSync)(
|
|
15036
|
+
const cwd = opts.cwd ?? (0, import_node_fs22.mkdtempSync)(import_node_path22.default.join(import_node_os14.default.tmpdir(), "clawd-runcase-"));
|
|
15037
15037
|
const ownsCwd = opts.cwd === void 0;
|
|
15038
15038
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
15039
15039
|
const spawnCtx = { cwd };
|
|
@@ -15200,13 +15200,13 @@ async function runController(opts) {
|
|
|
15200
15200
|
}
|
|
15201
15201
|
return exitCode ?? 0;
|
|
15202
15202
|
}
|
|
15203
|
-
var import_node_fs22, import_node_os14,
|
|
15203
|
+
var import_node_fs22, import_node_os14, import_node_path22;
|
|
15204
15204
|
var init_controller = __esm({
|
|
15205
15205
|
"src/run-case/controller.ts"() {
|
|
15206
15206
|
"use strict";
|
|
15207
15207
|
import_node_fs22 = require("fs");
|
|
15208
15208
|
import_node_os14 = __toESM(require("os"), 1);
|
|
15209
|
-
|
|
15209
|
+
import_node_path22 = __toESM(require("path"), 1);
|
|
15210
15210
|
init_claude();
|
|
15211
15211
|
init_stdout_splitter();
|
|
15212
15212
|
init_permission_stdio();
|
|
@@ -15431,7 +15431,7 @@ Env (advanced):
|
|
|
15431
15431
|
`;
|
|
15432
15432
|
|
|
15433
15433
|
// src/index.ts
|
|
15434
|
-
var
|
|
15434
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
15435
15435
|
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
15436
15436
|
|
|
15437
15437
|
// src/logger.ts
|
|
@@ -15471,30 +15471,9 @@ function createLogger(opts = {}) {
|
|
|
15471
15471
|
|
|
15472
15472
|
// src/session/store.ts
|
|
15473
15473
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
15474
|
-
var import_node_path4 = __toESM(require("path"), 1);
|
|
15475
|
-
init_protocol();
|
|
15476
|
-
|
|
15477
|
-
// src/session/scope.ts
|
|
15478
15474
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
15479
|
-
|
|
15480
|
-
|
|
15481
|
-
}
|
|
15482
|
-
function scopeSubPath(scope) {
|
|
15483
|
-
return scope.kind === "default" ? ["default"] : [scope.personaId, scope.mode];
|
|
15484
|
-
}
|
|
15485
|
-
function metaFromScope(scope, personaRoot) {
|
|
15486
|
-
if (scope.kind === "default") return void 0;
|
|
15487
|
-
if (scope.mode === "owner") {
|
|
15488
|
-
return { idleKillEnabled: false, personaMode: "owner" };
|
|
15489
|
-
}
|
|
15490
|
-
return {
|
|
15491
|
-
idleKillEnabled: true,
|
|
15492
|
-
personaMode: "listener",
|
|
15493
|
-
extraSettings: import_node_path3.default.join(personaRoot, scope.personaId, ".clawd", "sandbox-settings.json")
|
|
15494
|
-
};
|
|
15495
|
-
}
|
|
15496
|
-
|
|
15497
|
-
// src/session/store.ts
|
|
15475
|
+
init_protocol();
|
|
15476
|
+
var DEFAULT_AGENT_ID = "default";
|
|
15498
15477
|
function safeFileName(sessionId) {
|
|
15499
15478
|
const base = sessionId.replace(/[^a-zA-Z0-9_\-.]/g, "_");
|
|
15500
15479
|
const cleaned = base.replace(/^\.+/, (dots) => "_".repeat(dots.length));
|
|
@@ -15506,15 +15485,20 @@ function safeFileName(sessionId) {
|
|
|
15506
15485
|
var SessionStore = class {
|
|
15507
15486
|
root;
|
|
15508
15487
|
constructor(opts) {
|
|
15509
|
-
const
|
|
15510
|
-
|
|
15511
|
-
opts.
|
|
15512
|
-
|
|
15513
|
-
|
|
15514
|
-
|
|
15488
|
+
const agentId = opts.agentId ?? DEFAULT_AGENT_ID;
|
|
15489
|
+
if (agentId !== DEFAULT_AGENT_ID) {
|
|
15490
|
+
if (!opts.personaRoot) {
|
|
15491
|
+
throw new Error(
|
|
15492
|
+
`SessionStore: personaRoot is required for non-default agentId='${agentId}'. Bootstrap must wire personaRoot when constructing SessionStore for persona agents.`
|
|
15493
|
+
);
|
|
15494
|
+
}
|
|
15495
|
+
this.root = import_node_path3.default.join(opts.personaRoot, safeFileName(agentId), ".clawd", "sub-sessions");
|
|
15496
|
+
} else {
|
|
15497
|
+
this.root = import_node_path3.default.join(opts.dataDir, "sessions", agentId);
|
|
15498
|
+
}
|
|
15515
15499
|
}
|
|
15516
15500
|
filePath(sessionId) {
|
|
15517
|
-
return
|
|
15501
|
+
return import_node_path3.default.join(this.root, `${safeFileName(sessionId)}.json`);
|
|
15518
15502
|
}
|
|
15519
15503
|
ensureDir() {
|
|
15520
15504
|
import_node_fs3.default.mkdirSync(this.root, { recursive: true });
|
|
@@ -15562,7 +15546,7 @@ var SessionStore = class {
|
|
|
15562
15546
|
for (const name of entries) {
|
|
15563
15547
|
if (!name.endsWith(".json")) continue;
|
|
15564
15548
|
if (name.includes(".tmp-")) continue;
|
|
15565
|
-
const full =
|
|
15549
|
+
const full = import_node_path3.default.join(this.root, name);
|
|
15566
15550
|
try {
|
|
15567
15551
|
const raw = import_node_fs3.default.readFileSync(full, "utf8");
|
|
15568
15552
|
const parsed = JSON.parse(raw);
|
|
@@ -15578,7 +15562,7 @@ var SessionStore = class {
|
|
|
15578
15562
|
|
|
15579
15563
|
// src/session/manager.ts
|
|
15580
15564
|
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
15581
|
-
var
|
|
15565
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
15582
15566
|
|
|
15583
15567
|
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
15584
15568
|
var byteToHex = [];
|
|
@@ -16306,7 +16290,7 @@ init_stdout_splitter();
|
|
|
16306
16290
|
|
|
16307
16291
|
// src/ipc-recorder.ts
|
|
16308
16292
|
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
16309
|
-
var
|
|
16293
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
16310
16294
|
function tsForFilename(ms) {
|
|
16311
16295
|
return new Date(ms).toISOString().replace(/[:.]/g, "-");
|
|
16312
16296
|
}
|
|
@@ -16317,8 +16301,8 @@ function startRecorder(opts) {
|
|
|
16317
16301
|
return null;
|
|
16318
16302
|
}
|
|
16319
16303
|
const now = opts.now ?? Date.now;
|
|
16320
|
-
const dir =
|
|
16321
|
-
const filePath =
|
|
16304
|
+
const dir = import_node_path4.default.join(opts.dataDir, "ipc-recordings", opts.sessionId);
|
|
16305
|
+
const filePath = import_node_path4.default.join(dir, `${tsForFilename(now())}.jsonl`);
|
|
16322
16306
|
let stream = null;
|
|
16323
16307
|
let closedResolve;
|
|
16324
16308
|
const closed = new Promise((resolve2) => {
|
|
@@ -16760,6 +16744,7 @@ function makeInitialState(file, subSessionMeta) {
|
|
|
16760
16744
|
var SessionManager = class {
|
|
16761
16745
|
constructor(deps) {
|
|
16762
16746
|
this.deps = deps;
|
|
16747
|
+
this.storesByAgent.set(DEFAULT_AGENT_ID, deps.store);
|
|
16763
16748
|
}
|
|
16764
16749
|
deps;
|
|
16765
16750
|
// sessionId → SessionRunner;在 send / ensureSession 时按需创建
|
|
@@ -16775,28 +16760,33 @@ var SessionManager = class {
|
|
|
16775
16760
|
// 由 observer 监听 jsonl user 行后调 recordRealUserUuid 建立映射;rewind 系列 RPC 在
|
|
16776
16761
|
// 入参 / 出参做转译,保证 UI 看到的 uuid 始终是 events 流里的 synth uuid
|
|
16777
16762
|
realUuidBySynth = /* @__PURE__ */ new Map();
|
|
16778
|
-
//
|
|
16779
|
-
// default
|
|
16780
|
-
|
|
16781
|
-
//
|
|
16782
|
-
|
|
16763
|
+
// persona sub-session 路径:按 agentId 派生 SessionStore(root = dataDir/sessions/<agentId>/)。
|
|
16764
|
+
// 'default' 直接复用 deps.store;其它 agentId 第一次访问时按需创建并缓存
|
|
16765
|
+
storesByAgent = /* @__PURE__ */ new Map();
|
|
16766
|
+
// sub-session 创建时记录的 subSessionMeta;ensureSession / runner 创建时塞入 reducer state。
|
|
16767
|
+
// 不进 SessionFile schema(避免破坏现有 zod parse),仅运行时缓存
|
|
16768
|
+
subSessionMetaBySid = /* @__PURE__ */ new Map();
|
|
16783
16769
|
// persona-bound transport 订阅器:sessionId → Set<listener>。
|
|
16784
16770
|
// 透传 owner 路径白名单 EventFrame(routeFromRunner 决定哪些 type 进入),listener 端按
|
|
16785
16771
|
// `frame.type` narrow 出 'session:event'(ParsedEvent)/ 'session:status'(procAlive 同步)等。
|
|
16786
16772
|
// 这样 owner / listener 共用同一组事件字面量,新增跨端信号时只需在 fan-out 白名单里加 type。
|
|
16787
16773
|
eventSubscribers = /* @__PURE__ */ new Map();
|
|
16788
|
-
// 按
|
|
16789
|
-
//
|
|
16790
|
-
|
|
16791
|
-
|
|
16792
|
-
const
|
|
16793
|
-
const cached = this.storesByScope.get(key);
|
|
16774
|
+
// 按 agentId 拿对应的 SessionStore;persona-* agentId 使用 personaRoot 路径。
|
|
16775
|
+
// 'default' 直接复用 deps.store;其它 agentId 第一次访问时按需创建并缓存。
|
|
16776
|
+
// personaRoot 必须与 PersonaStore 同源,两者共享相同的 persona 目录层级
|
|
16777
|
+
storeFor(agentId) {
|
|
16778
|
+
const cached = this.storesByAgent.get(agentId);
|
|
16794
16779
|
if (cached) return cached;
|
|
16795
16780
|
if (!this.deps.dataDir) {
|
|
16796
|
-
throw new Error(`SessionManager: dataDir required to
|
|
16781
|
+
throw new Error(`SessionManager: dataDir required to route agentId='${agentId}'`);
|
|
16782
|
+
}
|
|
16783
|
+
if (!this.deps.personaRoot) {
|
|
16784
|
+
throw new Error(
|
|
16785
|
+
`SessionManager: personaRoot is required to route agentId='${agentId}'. Bootstrap must wire personaRoot when constructing SessionManager for persona sub-sessions.`
|
|
16786
|
+
);
|
|
16797
16787
|
}
|
|
16798
|
-
const st = new SessionStore({ dataDir: this.deps.dataDir,
|
|
16799
|
-
this.
|
|
16788
|
+
const st = new SessionStore({ dataDir: this.deps.dataDir, agentId, personaRoot: this.deps.personaRoot });
|
|
16789
|
+
this.storesByAgent.set(agentId, st);
|
|
16800
16790
|
return st;
|
|
16801
16791
|
}
|
|
16802
16792
|
async getCapabilities(tool) {
|
|
@@ -16807,80 +16797,26 @@ var SessionManager = class {
|
|
|
16807
16797
|
this.capabilitiesCache.set(tool, caps);
|
|
16808
16798
|
return caps;
|
|
16809
16799
|
}
|
|
16810
|
-
//
|
|
16811
|
-
// ownerPersonaId
|
|
16812
|
-
//
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16816
|
-
|
|
16817
|
-
|
|
16818
|
-
// 扫 <dataDir>/sessions/ 列出所有 persona 命名空间(不含 'default')。
|
|
16819
|
-
// 用于 findOwnedSession / listAllOwned 跨 scope 查询。
|
|
16820
|
-
listPersonaIdsOnDisk() {
|
|
16821
|
-
if (!this.deps.dataDir) return [];
|
|
16822
|
-
const root = import_node_path6.default.join(this.deps.dataDir, "sessions");
|
|
16823
|
-
let entries;
|
|
16824
|
-
try {
|
|
16825
|
-
entries = import_node_fs5.default.readdirSync(root, { withFileTypes: true });
|
|
16826
|
-
} catch (err) {
|
|
16827
|
-
const code = err?.code;
|
|
16828
|
-
if (code === "ENOENT") return [];
|
|
16829
|
-
throw err;
|
|
16830
|
-
}
|
|
16831
|
-
return entries.filter((e) => e.isDirectory() && e.name !== "default").map((e) => e.name);
|
|
16832
|
-
}
|
|
16833
|
-
// owner / default 两个分类下按 sessionId 找文件——前端只传 sessionId 不带 scope,
|
|
16834
|
-
// SessionManager 在这里扫盘定位(default 直接试,未命中再轮询所有 persona owner 目录)。
|
|
16835
|
-
// listener sub-session 不走这条——transport 始终明确传 (personaId, sessionId)。
|
|
16836
|
-
findOwnedSession(sessionId) {
|
|
16837
|
-
const dflt = this.deps.store.read(sessionId);
|
|
16838
|
-
if (dflt) return dflt;
|
|
16839
|
-
for (const personaId of this.listPersonaIdsOnDisk()) {
|
|
16840
|
-
const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
|
|
16841
|
-
const file = ownerStore.read(sessionId);
|
|
16842
|
-
if (file) return file;
|
|
16843
|
-
}
|
|
16844
|
-
return null;
|
|
16845
|
-
}
|
|
16846
|
-
// 合并 default + 所有 persona owner 的 SessionFile —— 桌面 App 主 session 列表入口。
|
|
16847
|
-
// 同样不含 listener sub-session(listener 走 persona:listSubSessions RPC 单独入口)。
|
|
16848
|
-
listAllOwned() {
|
|
16849
|
-
const out = [];
|
|
16850
|
-
out.push(...this.deps.store.list());
|
|
16851
|
-
for (const personaId of this.listPersonaIdsOnDisk()) {
|
|
16852
|
-
const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
|
|
16853
|
-
out.push(...ownerStore.list());
|
|
16854
|
-
}
|
|
16855
|
-
return out.sort(
|
|
16856
|
-
(a, b) => a.updatedAt > b.updatedAt ? -1 : a.updatedAt < b.updatedAt ? 1 : 0
|
|
16857
|
-
);
|
|
16858
|
-
}
|
|
16859
|
-
// 写回 SessionFile,自动根据 ownerPersonaId 派生写入 scope。
|
|
16860
|
-
// 调用方原先都是 `deps.store.write(updated)`,全部走这里收口路由。
|
|
16861
|
-
writeOwned(file) {
|
|
16862
|
-
return this.storeFor(this.scopeForFile(file)).write(file);
|
|
16863
|
-
}
|
|
16864
|
-
// 删除 owned SessionFile(default 或 persona/owner),与 findOwnedSession 对称扫盘。
|
|
16865
|
-
deleteOwned(sessionId) {
|
|
16866
|
-
if (this.deps.store.delete(sessionId)) return true;
|
|
16867
|
-
for (const personaId of this.listPersonaIdsOnDisk()) {
|
|
16868
|
-
const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
|
|
16869
|
-
if (ownerStore.delete(sessionId)) return true;
|
|
16800
|
+
// 按优先级解析 SubSessionMeta:subSessionMetaBySid 缓存(内存,首次 create/registerSubSession 写入)
|
|
16801
|
+
// → SessionFile.ownerPersonaId 派生(持久化兜底,daemon 重启后 subSessionMetaBySid 丢失时生效)
|
|
16802
|
+
// → undefined(普通 session)
|
|
16803
|
+
resolveSubSessionMeta(file) {
|
|
16804
|
+
const cached = this.subSessionMetaBySid.get(file.sessionId);
|
|
16805
|
+
if (cached) return cached;
|
|
16806
|
+
if (file.ownerPersonaId) {
|
|
16807
|
+
return { idleKillEnabled: false, personaMode: "owner" };
|
|
16870
16808
|
}
|
|
16871
|
-
return
|
|
16809
|
+
return void 0;
|
|
16872
16810
|
}
|
|
16873
16811
|
// 创建 runner 时包一层 broadcast hook:所有外出 frame 统一走 routeFromRunner,
|
|
16874
|
-
// 经过 compressFrameForWire 后决定是 push collector 还是走 deps.broadcastFrame
|
|
16875
|
-
//
|
|
16876
|
-
//
|
|
16877
|
-
//
|
|
16878
|
-
|
|
16879
|
-
newRunner(file, scope) {
|
|
16812
|
+
// 经过 compressFrameForWire 后决定是 push collector 还是走 deps.broadcastFrame
|
|
16813
|
+
// store:默认 deps.store;persona sub-session 路径下传该 personaId 对应的 SessionStore
|
|
16814
|
+
// subSessionMeta:listener 传 { idleKillEnabled: true, personaMode: 'listener' };
|
|
16815
|
+
// owner 传 { idleKillEnabled: false, personaMode: 'owner' };普通 session 不传
|
|
16816
|
+
newRunner(file, opts = {}) {
|
|
16880
16817
|
const adapter = this.deps.getAdapter(file.tool ?? "claude");
|
|
16881
|
-
const store = this.
|
|
16882
|
-
const
|
|
16883
|
-
const runner = new SessionRunner(makeInitialState(file, subSessionMeta), {
|
|
16818
|
+
const store = opts.store ?? this.deps.store;
|
|
16819
|
+
const runner = new SessionRunner(makeInitialState(file, opts.subSessionMeta), {
|
|
16884
16820
|
broadcastFrame: (frame, target) => this.routeFromRunner(frame, target),
|
|
16885
16821
|
store,
|
|
16886
16822
|
adapter,
|
|
@@ -16941,7 +16877,7 @@ var SessionManager = class {
|
|
|
16941
16877
|
if (!this.deps.personaRoot) {
|
|
16942
16878
|
throw new Error("personaRoot required to derive cwd from ownerPersonaId");
|
|
16943
16879
|
}
|
|
16944
|
-
cwd =
|
|
16880
|
+
cwd = import_node_path5.default.join(this.deps.personaRoot, safeFileName(args.ownerPersonaId));
|
|
16945
16881
|
}
|
|
16946
16882
|
if (!cwd) {
|
|
16947
16883
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, "cwd required when ownerPersonaId is absent");
|
|
@@ -16971,8 +16907,13 @@ var SessionManager = class {
|
|
|
16971
16907
|
createdAt: iso,
|
|
16972
16908
|
updatedAt: iso
|
|
16973
16909
|
};
|
|
16974
|
-
const
|
|
16975
|
-
|
|
16910
|
+
const written = this.deps.store.write(file);
|
|
16911
|
+
if (args.ownerPersonaId) {
|
|
16912
|
+
this.subSessionMetaBySid.set(written.sessionId, {
|
|
16913
|
+
idleKillEnabled: false,
|
|
16914
|
+
personaMode: "owner"
|
|
16915
|
+
});
|
|
16916
|
+
}
|
|
16976
16917
|
return { response: written, broadcast: [] };
|
|
16977
16918
|
}
|
|
16978
16919
|
pin(args) {
|
|
@@ -16987,13 +16928,13 @@ var SessionManager = class {
|
|
|
16987
16928
|
return { response: value, broadcast };
|
|
16988
16929
|
}
|
|
16989
16930
|
const updated = { ...existing, pinnedAt };
|
|
16990
|
-
this.
|
|
16931
|
+
this.deps.store.write(updated);
|
|
16991
16932
|
return { response: updated, broadcast: [] };
|
|
16992
16933
|
}
|
|
16993
16934
|
// sidebar 拖拽完成 → 整体重写 pinned root 的 pinSortOrder(按 orderedIds 下标 0,1,2...)
|
|
16994
16935
|
// orderedIds 必须正好覆盖所有当前 pinned root(既不能漏,也不能含 unpinned id)
|
|
16995
16936
|
reorderPins(args) {
|
|
16996
|
-
const all = this.
|
|
16937
|
+
const all = this.deps.store.list();
|
|
16997
16938
|
const currentPinnedIds = new Set(
|
|
16998
16939
|
all.filter((f) => typeof f.pinnedAt === "number").map((f) => f.sessionId)
|
|
16999
16940
|
);
|
|
@@ -17023,14 +16964,14 @@ var SessionManager = class {
|
|
|
17023
16964
|
} else {
|
|
17024
16965
|
const existing = this.getFile(sessionId);
|
|
17025
16966
|
const updated = { ...existing, pinSortOrder: index };
|
|
17026
|
-
this.
|
|
16967
|
+
this.deps.store.write(updated);
|
|
17027
16968
|
updatedFiles.push(updated);
|
|
17028
16969
|
}
|
|
17029
16970
|
});
|
|
17030
16971
|
return { response: { sessions: updatedFiles }, broadcast };
|
|
17031
16972
|
}
|
|
17032
16973
|
list() {
|
|
17033
|
-
return { response: { sessions: this.
|
|
16974
|
+
return { response: { sessions: this.deps.store.list() }, broadcast: [] };
|
|
17034
16975
|
}
|
|
17035
16976
|
get(args) {
|
|
17036
16977
|
const file = this.getFile(args.sessionId);
|
|
@@ -17083,11 +17024,10 @@ var SessionManager = class {
|
|
|
17083
17024
|
for (const [synth, real] of map) reverse.set(real, synth);
|
|
17084
17025
|
return realUuids.map((r) => reverse.get(r) ?? r);
|
|
17085
17026
|
}
|
|
17086
|
-
// 内部帮手:不走 ManagerResult 的 get,直接拿 SessionFile
|
|
17087
|
-
// 优先 runner cache(hot path);冷态走 findOwnedSession 跨 default + 所有 persona owner 扫盘。
|
|
17027
|
+
// 内部帮手:不走 ManagerResult 的 get,直接拿 SessionFile
|
|
17088
17028
|
getFile(sessionId) {
|
|
17089
17029
|
const runner = this.runners.get(sessionId);
|
|
17090
|
-
const existing = runner?.getState().file ?? this.
|
|
17030
|
+
const existing = runner?.getState().file ?? this.deps.store.read(sessionId);
|
|
17091
17031
|
if (!existing) throw new ClawdError(ERROR_CODES.SESSION_NOT_FOUND, sessionId);
|
|
17092
17032
|
return existing;
|
|
17093
17033
|
}
|
|
@@ -17102,11 +17042,11 @@ var SessionManager = class {
|
|
|
17102
17042
|
return { response: value, broadcast };
|
|
17103
17043
|
}
|
|
17104
17044
|
const updated = { ...existing, ...args.patch, updatedAt: nowIso2(this.deps) };
|
|
17105
|
-
this.
|
|
17045
|
+
this.deps.store.write(updated);
|
|
17106
17046
|
return { response: updated, broadcast: [] };
|
|
17107
17047
|
}
|
|
17108
17048
|
delete(args) {
|
|
17109
|
-
const existing = this.
|
|
17049
|
+
const existing = this.deps.store.read(args.sessionId);
|
|
17110
17050
|
if (!existing) throw new ClawdError(ERROR_CODES.SESSION_NOT_FOUND, args.sessionId);
|
|
17111
17051
|
const runner = this.runners.get(args.sessionId);
|
|
17112
17052
|
if (runner) {
|
|
@@ -17117,7 +17057,7 @@ var SessionManager = class {
|
|
|
17117
17057
|
this.realUuidBySynth.delete(args.sessionId);
|
|
17118
17058
|
return { response: { sessionId: args.sessionId }, broadcast };
|
|
17119
17059
|
}
|
|
17120
|
-
this.
|
|
17060
|
+
this.deps.store.delete(args.sessionId);
|
|
17121
17061
|
return {
|
|
17122
17062
|
response: { sessionId: args.sessionId },
|
|
17123
17063
|
broadcast: [
|
|
@@ -17129,7 +17069,8 @@ var SessionManager = class {
|
|
|
17129
17069
|
const existing = this.getFile(args.sessionId);
|
|
17130
17070
|
let runner = this.runners.get(args.sessionId);
|
|
17131
17071
|
if (!runner) {
|
|
17132
|
-
|
|
17072
|
+
const subSessionMeta = this.resolveSubSessionMeta(existing);
|
|
17073
|
+
runner = this.newRunner(existing, { subSessionMeta });
|
|
17133
17074
|
this.runners.set(args.sessionId, runner);
|
|
17134
17075
|
}
|
|
17135
17076
|
const { broadcast } = this.withCollector(() => {
|
|
@@ -17223,7 +17164,8 @@ var SessionManager = class {
|
|
|
17223
17164
|
const file = this.getFile(args.sessionId);
|
|
17224
17165
|
let runner = this.runners.get(args.sessionId);
|
|
17225
17166
|
if (!runner) {
|
|
17226
|
-
|
|
17167
|
+
const subSessionMeta = this.resolveSubSessionMeta(file);
|
|
17168
|
+
runner = this.newRunner(file, { subSessionMeta });
|
|
17227
17169
|
this.runners.set(args.sessionId, runner);
|
|
17228
17170
|
}
|
|
17229
17171
|
if (!runner.getState().procAlive) {
|
|
@@ -17274,7 +17216,7 @@ var SessionManager = class {
|
|
|
17274
17216
|
});
|
|
17275
17217
|
return { response: value, broadcast };
|
|
17276
17218
|
}
|
|
17277
|
-
const existing = this.
|
|
17219
|
+
const existing = this.deps.store.read(args.sessionId);
|
|
17278
17220
|
const {
|
|
17279
17221
|
toolSessionId: _drop,
|
|
17280
17222
|
contextUsage: _ctx,
|
|
@@ -17289,7 +17231,7 @@ var SessionManager = class {
|
|
|
17289
17231
|
void _branch;
|
|
17290
17232
|
void _model;
|
|
17291
17233
|
const updated = { ...rest, updatedAt: nowIso2(this.deps) };
|
|
17292
|
-
return { response: this.
|
|
17234
|
+
return { response: this.deps.store.write(updated), broadcast: [] };
|
|
17293
17235
|
}
|
|
17294
17236
|
resume(args) {
|
|
17295
17237
|
this.getFile(args.sessionId);
|
|
@@ -17304,13 +17246,13 @@ var SessionManager = class {
|
|
|
17304
17246
|
});
|
|
17305
17247
|
return { response: value, broadcast };
|
|
17306
17248
|
}
|
|
17307
|
-
const existing = this.
|
|
17249
|
+
const existing = this.deps.store.read(args.sessionId);
|
|
17308
17250
|
const updated = {
|
|
17309
17251
|
...existing,
|
|
17310
17252
|
toolSessionId: args.toolSessionId,
|
|
17311
17253
|
updatedAt: nowIso2(this.deps)
|
|
17312
17254
|
};
|
|
17313
|
-
return { response: this.
|
|
17255
|
+
return { response: this.deps.store.write(updated), broadcast: [] };
|
|
17314
17256
|
}
|
|
17315
17257
|
getEvents(args) {
|
|
17316
17258
|
const runner = this.runners.get(args.sessionId);
|
|
@@ -17378,44 +17320,39 @@ var SessionManager = class {
|
|
|
17378
17320
|
if (!runner) return "idle";
|
|
17379
17321
|
return compressStatus(runner.getState().status);
|
|
17380
17322
|
}
|
|
17381
|
-
// 给 observer 用:保证有 runner 但不 spawn(仅创建 state
|
|
17382
|
-
// observer 喂事件路径只走 default + owner(普通 + owner persona session)
|
|
17383
|
-
// ——listener sub-session 的 observer 路径走 ensureRunnerForScope。
|
|
17323
|
+
// 给 observer 用:保证有 runner 但不 spawn(仅创建 state 容器)
|
|
17384
17324
|
ensureSession(file) {
|
|
17385
17325
|
let r = this.runners.get(file.sessionId);
|
|
17386
17326
|
if (r) return r;
|
|
17387
|
-
|
|
17327
|
+
const subSessionMeta = this.resolveSubSessionMeta(file);
|
|
17328
|
+
r = this.newRunner(file, { subSessionMeta });
|
|
17388
17329
|
this.runners.set(file.sessionId, r);
|
|
17389
17330
|
return r;
|
|
17390
17331
|
}
|
|
17391
|
-
// ---------------- persona /
|
|
17332
|
+
// ---------------- persona / sub-session 专用 API ----------------
|
|
17392
17333
|
//
|
|
17393
|
-
// PersonaManager 是 SessionManager 之上的薄编排层,
|
|
17394
|
-
//
|
|
17395
|
-
// - SessionFile 落到 <
|
|
17334
|
+
// PersonaManager 是 SessionManager 之上的薄编排层,sub-session 的持久化(SessionFile)
|
|
17335
|
+
// 仍由 SessionManager 持有。区别于普通 session:
|
|
17336
|
+
// - SessionFile 落到 <personaRoot>/<personaId>/.clawd/sub-sessions/ 而非 sessions/default/
|
|
17396
17337
|
// - reducer state.subSessionMeta.idleKillEnabled = true(turn_end 自动 idle-kill)
|
|
17397
17338
|
// - sessionId 由 PersonaManager 派生(personaId-<tokenHash>),不走自动 newSessionId
|
|
17398
|
-
|
|
17399
|
-
|
|
17400
|
-
|
|
17401
|
-
/** 按 scope 读取 SessionFile;不存在返回 null */
|
|
17402
|
-
readForScope(sessionId, scope) {
|
|
17403
|
-
return this.storeFor(scope).read(sessionId);
|
|
17339
|
+
/** 按 agentId 读取 SessionFile;不存在返回 null */
|
|
17340
|
+
readForAgent(sessionId, agentId) {
|
|
17341
|
+
return this.storeFor(agentId).read(sessionId);
|
|
17404
17342
|
}
|
|
17405
17343
|
/**
|
|
17406
|
-
*
|
|
17407
|
-
*
|
|
17408
|
-
* 路径下还未写过任何 session 时 list() 返回空数组(SessionStore.list 内部 ENOENT 处理)
|
|
17344
|
+
* 按 agentId 列出该命名空间下所有 SessionFile(persona:listSubSessions 入口)。
|
|
17345
|
+
* agentId 还未访问过 → storeFor 第一次创建对应 SessionStore(root 不存在则 list 返回 [])
|
|
17409
17346
|
*/
|
|
17410
|
-
|
|
17411
|
-
return this.storeFor(
|
|
17347
|
+
listForAgent(agentId) {
|
|
17348
|
+
return this.storeFor(agentId).list();
|
|
17412
17349
|
}
|
|
17413
17350
|
/**
|
|
17414
17351
|
* 创建 sub-session 的 SessionFile + 准备 runner(不 spawn)。
|
|
17415
|
-
*
|
|
17416
|
-
* 同一 sessionId 重复调用:抛错(PersonaManager 应先调
|
|
17352
|
+
* subSessionMeta 不进 SessionFile schema,仅缓存进 runner state。
|
|
17353
|
+
* 同一 sessionId 重复调用:抛错(PersonaManager 应先调 readForAgent 命中复用)
|
|
17417
17354
|
*/
|
|
17418
|
-
|
|
17355
|
+
createForAgent(args) {
|
|
17419
17356
|
try {
|
|
17420
17357
|
const stat = import_node_fs5.default.statSync(args.cwd);
|
|
17421
17358
|
if (!stat.isDirectory()) throw new Error("not dir");
|
|
@@ -17424,11 +17361,9 @@ var SessionManager = class {
|
|
|
17424
17361
|
}
|
|
17425
17362
|
const tool = args.tool ?? "claude";
|
|
17426
17363
|
this.deps.getAdapter(tool);
|
|
17427
|
-
const store = this.storeFor(args.
|
|
17364
|
+
const store = this.storeFor(args.agentId);
|
|
17428
17365
|
if (store.read(args.sessionId)) {
|
|
17429
|
-
throw new Error(
|
|
17430
|
-
`session already exists for scope ${scopeKey(args.scope)}: ${args.sessionId}`
|
|
17431
|
-
);
|
|
17366
|
+
throw new Error(`session already exists for agent ${args.agentId}: ${args.sessionId}`);
|
|
17432
17367
|
}
|
|
17433
17368
|
const iso = nowIso2(this.deps);
|
|
17434
17369
|
const file = {
|
|
@@ -17441,7 +17376,11 @@ var SessionManager = class {
|
|
|
17441
17376
|
createdAt: iso,
|
|
17442
17377
|
updatedAt: iso
|
|
17443
17378
|
};
|
|
17444
|
-
|
|
17379
|
+
const written = store.write(file);
|
|
17380
|
+
if (args.subSessionMeta) {
|
|
17381
|
+
this.subSessionMetaBySid.set(args.sessionId, args.subSessionMeta);
|
|
17382
|
+
}
|
|
17383
|
+
return written;
|
|
17445
17384
|
}
|
|
17446
17385
|
/**
|
|
17447
17386
|
* persona-bound transport 用:读取 sub-session 的历史 ParsedEvent[]。
|
|
@@ -17452,21 +17391,22 @@ var SessionManager = class {
|
|
|
17452
17391
|
* 不读 jsonl:
|
|
17453
17392
|
* 1. observer 路径在 spawn 后会自动接管 jsonl 回灌,进 reducer buffer。
|
|
17454
17393
|
* 2. 第一次握手时 sub-session 还没 spawn → toolSessionId 为空 → jsonl 不存在。
|
|
17455
|
-
* sessionFile 不存在抛 SESSION_NOT_FOUND;上层应先调
|
|
17394
|
+
* sessionFile 不存在抛 SESSION_NOT_FOUND;上层应先调 createForAgent。
|
|
17456
17395
|
*/
|
|
17457
|
-
|
|
17458
|
-
const
|
|
17396
|
+
readHistoryEvents(sessionId, agentId) {
|
|
17397
|
+
const store = this.storeFor(agentId);
|
|
17398
|
+
const file = store.read(sessionId);
|
|
17459
17399
|
if (!file) {
|
|
17460
17400
|
throw new ClawdError(
|
|
17461
17401
|
ERROR_CODES.SESSION_NOT_FOUND,
|
|
17462
|
-
`sub-session not found: ${
|
|
17402
|
+
`sub-session not found: ${agentId}/${sessionId}`
|
|
17463
17403
|
);
|
|
17464
17404
|
}
|
|
17465
|
-
const runner = this.
|
|
17405
|
+
const runner = this.ensureRunnerFor(file, agentId);
|
|
17466
17406
|
return runner.getState().buffer.map((e) => e.event);
|
|
17467
17407
|
}
|
|
17468
17408
|
/**
|
|
17469
|
-
* persona-bound transport 用:基于
|
|
17409
|
+
* persona-bound transport 用:基于 readHistoryEvents 的 buffer 切片视图,支持分页。
|
|
17470
17410
|
*
|
|
17471
17411
|
* Why a new method instead of reusing `history:read` RPC handler:
|
|
17472
17412
|
* - `history:read` 走 HandlerDeps.history.read(),读 CC 写盘的 jsonl 文件
|
|
@@ -17474,15 +17414,18 @@ var SessionManager = class {
|
|
|
17474
17414
|
* 两条路径数据形态、时序、字段不同,不能共享 helper。persona-bound 客户端必须
|
|
17475
17415
|
* 走 buffer 路径,才能保证首屏回放和实时帧无 gap、无重复。
|
|
17476
17416
|
*
|
|
17417
|
+
* Why not 改 readHistoryEvents 加 limit/offset:现有 readHistoryEvents 的语义是
|
|
17418
|
+
* "返回 buffer 全部",被其它路径(rewind uuid 转译等)依赖;保留它不动,新加分页方法。
|
|
17419
|
+
*
|
|
17477
17420
|
* 切片语义:clip 安全边界,response.offset 保留请求值便于客户端识别越界请求。
|
|
17478
17421
|
* - offset >= total → events: [], offset: 请求值, total: 当前 buffer 长度
|
|
17479
17422
|
* - offset + limit > total → 返回 tail [offset, total),长度 = total - offset
|
|
17480
17423
|
* - 正常 → 返回 [offset, offset + limit)
|
|
17481
17424
|
*
|
|
17482
|
-
* SESSION_NOT_FOUND 行为继承
|
|
17425
|
+
* SESSION_NOT_FOUND 行为继承 readHistoryEvents(store.read 返回 null 即抛)。
|
|
17483
17426
|
*/
|
|
17484
|
-
|
|
17485
|
-
const all = this.
|
|
17427
|
+
readHistoryPage(sessionId, agentId, limit, offset) {
|
|
17428
|
+
const all = this.readHistoryEvents(sessionId, agentId);
|
|
17486
17429
|
const total = all.length;
|
|
17487
17430
|
const start = Math.min(offset, total);
|
|
17488
17431
|
const end = Math.min(start + limit, total);
|
|
@@ -17495,34 +17438,36 @@ var SessionManager = class {
|
|
|
17495
17438
|
* 返回 unsubscribe;不破坏现有 wire 广播路径——routeFromRunner 同时 fan-out 到
|
|
17496
17439
|
* eventSubscribers 和 deps.broadcastFrame
|
|
17497
17440
|
*/
|
|
17498
|
-
subscribe(
|
|
17499
|
-
|
|
17441
|
+
subscribe(_sessionId, _agentId, listener) {
|
|
17442
|
+
const sid = _sessionId;
|
|
17443
|
+
let subs = this.eventSubscribers.get(sid);
|
|
17500
17444
|
if (!subs) {
|
|
17501
17445
|
subs = /* @__PURE__ */ new Set();
|
|
17502
|
-
this.eventSubscribers.set(
|
|
17446
|
+
this.eventSubscribers.set(sid, subs);
|
|
17503
17447
|
}
|
|
17504
17448
|
subs.add(listener);
|
|
17505
17449
|
return () => {
|
|
17506
|
-
const cur = this.eventSubscribers.get(
|
|
17450
|
+
const cur = this.eventSubscribers.get(sid);
|
|
17507
17451
|
if (!cur) return;
|
|
17508
17452
|
cur.delete(listener);
|
|
17509
|
-
if (cur.size === 0) this.eventSubscribers.delete(
|
|
17453
|
+
if (cur.size === 0) this.eventSubscribers.delete(sid);
|
|
17510
17454
|
};
|
|
17511
17455
|
}
|
|
17512
17456
|
/**
|
|
17513
|
-
* persona-bound transport 用:sub-session 路径的 send(按
|
|
17514
|
-
*
|
|
17515
|
-
*
|
|
17457
|
+
* persona-bound transport 用:sub-session 路径的 send(按 agentId 路由 SessionStore)。
|
|
17458
|
+
* 现状 send(args.sessionId, args.text) 默认 'default' agent;这里按 agentId 拿对应 store
|
|
17459
|
+
* + ensureRunnerFor 保证 runner 用同一个 store 写盘
|
|
17516
17460
|
*/
|
|
17517
|
-
|
|
17518
|
-
const
|
|
17461
|
+
sendForAgent(args) {
|
|
17462
|
+
const store = this.storeFor(args.agentId);
|
|
17463
|
+
const file = store.read(args.sessionId);
|
|
17519
17464
|
if (!file) {
|
|
17520
17465
|
throw new ClawdError(
|
|
17521
17466
|
ERROR_CODES.SESSION_NOT_FOUND,
|
|
17522
|
-
`sub-session not found: ${
|
|
17467
|
+
`sub-session not found: ${args.agentId}/${args.sessionId}`
|
|
17523
17468
|
);
|
|
17524
17469
|
}
|
|
17525
|
-
const runner = this.
|
|
17470
|
+
const runner = this.ensureRunnerFor(file, args.agentId);
|
|
17526
17471
|
const { broadcast } = this.withCollector(() => {
|
|
17527
17472
|
runner.input({ kind: "command", command: { kind: "send", text: args.text } });
|
|
17528
17473
|
});
|
|
@@ -17532,47 +17477,53 @@ var SessionManager = class {
|
|
|
17532
17477
|
* persona-bound transport 用:sub-session reset。
|
|
17533
17478
|
* 复用 reducer 'new' 命令:清 toolSessionId / buffer / nextSeq / pending* + kill proc + emit
|
|
17534
17479
|
* session:cleared。语义上等价 alice 端"清空当前会话上下文"。
|
|
17535
|
-
* 归档已写盘的 jsonl 不在本路径处理(CC 后续 spawn 会写新的 toolSessionId.jsonl
|
|
17480
|
+
* 归档已写盘的 jsonl 不在本路径处理(CC 后续 spawn 会写新的 toolSessionId.jsonl,旧的留盘);
|
|
17481
|
+
* 物理归档可在后续单独 task 加(spec § 6 待 plan 决定项)。
|
|
17536
17482
|
*/
|
|
17537
|
-
|
|
17538
|
-
const
|
|
17483
|
+
resetForAgent(args) {
|
|
17484
|
+
const store = this.storeFor(args.agentId);
|
|
17485
|
+
const file = store.read(args.sessionId);
|
|
17539
17486
|
if (!file) {
|
|
17540
17487
|
throw new ClawdError(
|
|
17541
17488
|
ERROR_CODES.SESSION_NOT_FOUND,
|
|
17542
|
-
`sub-session not found: ${
|
|
17489
|
+
`sub-session not found: ${args.agentId}/${args.sessionId}`
|
|
17543
17490
|
);
|
|
17544
17491
|
}
|
|
17545
|
-
const runner = this.
|
|
17492
|
+
const runner = this.ensureRunnerFor(file, args.agentId);
|
|
17546
17493
|
const { broadcast } = this.withCollector(() => {
|
|
17547
17494
|
runner.input({ kind: "command", command: { kind: "new" } });
|
|
17548
17495
|
});
|
|
17549
17496
|
return { response: { ok: true }, broadcast };
|
|
17550
17497
|
}
|
|
17551
|
-
/** ensureSession 的
|
|
17552
|
-
|
|
17498
|
+
/** ensureSession 的 agentId-aware 版本:复用现有 runner 或按 agentId 派生 store 创建 */
|
|
17499
|
+
ensureRunnerFor(file, agentId) {
|
|
17553
17500
|
const existing = this.runners.get(file.sessionId);
|
|
17554
17501
|
if (existing) return existing;
|
|
17555
|
-
const
|
|
17502
|
+
const store = this.storeFor(agentId);
|
|
17503
|
+
const subSessionMeta = this.resolveSubSessionMeta(file);
|
|
17504
|
+
const runner = this.newRunner(file, { store, subSessionMeta });
|
|
17556
17505
|
this.runners.set(file.sessionId, runner);
|
|
17557
17506
|
return runner;
|
|
17558
17507
|
}
|
|
17559
17508
|
/**
|
|
17560
17509
|
* 老板插话:把 'inject-owner-text' input 喂给对应 runner,
|
|
17561
|
-
* runner 不存在时按
|
|
17510
|
+
* runner 不存在时按 ensureSession 路径懒创建(以 subSessionMeta 缓存为准)。
|
|
17562
17511
|
* frames 走异步路径(broadcastFrame):调用方一般在 PersonaManager.appendOwnerMessage
|
|
17563
17512
|
* 内部走 RPC 处理流,没有同步 collector 上下文
|
|
17564
17513
|
*/
|
|
17565
17514
|
injectOwnerMessage(args) {
|
|
17566
|
-
const
|
|
17515
|
+
const store = this.storeFor(args.agentId);
|
|
17516
|
+
const file = store.read(args.sessionId);
|
|
17567
17517
|
if (!file) {
|
|
17568
17518
|
throw new ClawdError(
|
|
17569
17519
|
ERROR_CODES.SESSION_NOT_FOUND,
|
|
17570
|
-
`sub-session not found: ${
|
|
17520
|
+
`sub-session not found: ${args.agentId}/${args.sessionId}`
|
|
17571
17521
|
);
|
|
17572
17522
|
}
|
|
17573
17523
|
let runner = this.runners.get(args.sessionId);
|
|
17574
17524
|
if (!runner) {
|
|
17575
|
-
|
|
17525
|
+
const subSessionMeta = this.resolveSubSessionMeta(file);
|
|
17526
|
+
runner = this.newRunner(file, { store, subSessionMeta });
|
|
17576
17527
|
this.runners.set(args.sessionId, runner);
|
|
17577
17528
|
}
|
|
17578
17529
|
runner.input({ kind: "inject-owner-text", text: args.text });
|
|
@@ -17668,7 +17619,7 @@ var SessionManager = class {
|
|
|
17668
17619
|
|
|
17669
17620
|
// src/persona/store.ts
|
|
17670
17621
|
var fs6 = __toESM(require("fs"), 1);
|
|
17671
|
-
var
|
|
17622
|
+
var path6 = __toESM(require("path"), 1);
|
|
17672
17623
|
init_protocol();
|
|
17673
17624
|
var DEFAULT_SETTINGS = {
|
|
17674
17625
|
permissions: {
|
|
@@ -17697,13 +17648,13 @@ var PersonaStore = class {
|
|
|
17697
17648
|
}
|
|
17698
17649
|
root;
|
|
17699
17650
|
personaDir(personaId) {
|
|
17700
|
-
return
|
|
17651
|
+
return path6.join(this.root, safeFileName(personaId));
|
|
17701
17652
|
}
|
|
17702
17653
|
metaPath(personaId) {
|
|
17703
|
-
return
|
|
17654
|
+
return path6.join(this.personaDir(personaId), ".clawd", "persona.json");
|
|
17704
17655
|
}
|
|
17705
17656
|
claudeMdPath(personaId) {
|
|
17706
|
-
return
|
|
17657
|
+
return path6.join(this.personaDir(personaId), "CLAUDE.md");
|
|
17707
17658
|
}
|
|
17708
17659
|
/**
|
|
17709
17660
|
* Sandbox settings 落盘路径 —— 故意放在 `.clawd/` 而不是 `.claude/`,让 CC 的
|
|
@@ -17713,11 +17664,11 @@ var PersonaStore = class {
|
|
|
17713
17664
|
* 加载 persona 人格,只有 listener 多一层 OS sandbox。
|
|
17714
17665
|
*/
|
|
17715
17666
|
sandboxSettingsPath(personaId) {
|
|
17716
|
-
return
|
|
17667
|
+
return path6.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
|
|
17717
17668
|
}
|
|
17718
17669
|
write(persona, personality) {
|
|
17719
17670
|
const dir = this.personaDir(persona.personaId);
|
|
17720
|
-
fs6.mkdirSync(
|
|
17671
|
+
fs6.mkdirSync(path6.join(dir, ".clawd"), { recursive: true });
|
|
17721
17672
|
this.atomicWrite(this.claudeMdPath(persona.personaId), personality);
|
|
17722
17673
|
this.atomicWrite(
|
|
17723
17674
|
this.sandboxSettingsPath(persona.personaId),
|
|
@@ -17748,7 +17699,7 @@ var PersonaStore = class {
|
|
|
17748
17699
|
list() {
|
|
17749
17700
|
if (!fs6.existsSync(this.root)) return [];
|
|
17750
17701
|
return fs6.readdirSync(this.root).filter((name) => {
|
|
17751
|
-
return fs6.existsSync(
|
|
17702
|
+
return fs6.existsSync(path6.join(this.root, name, ".clawd", "persona.json"));
|
|
17752
17703
|
});
|
|
17753
17704
|
}
|
|
17754
17705
|
remove(personaId) {
|
|
@@ -17910,20 +17861,27 @@ var PersonaManager = class {
|
|
|
17910
17861
|
const persona = this.deps.registry.get(personaId);
|
|
17911
17862
|
if (!persona) throw new Error(`persona not found: ${personaId}`);
|
|
17912
17863
|
const subSessionId = this.deriveSubSessionId(personaId, token);
|
|
17913
|
-
const
|
|
17914
|
-
const existing = this.deps.sessionManager.readForScope(subSessionId, scope);
|
|
17864
|
+
const existing = this.deps.sessionManager.readForAgent(subSessionId, personaId);
|
|
17915
17865
|
if (existing) {
|
|
17916
17866
|
return { sessionFile: existing, isNew: false };
|
|
17917
17867
|
}
|
|
17918
17868
|
const tokenEntry = persona.tokenMap[token];
|
|
17919
17869
|
const subLabel = tokenEntry?.label ?? "unknown";
|
|
17920
|
-
const sessionFile = this.deps.sessionManager.
|
|
17870
|
+
const sessionFile = this.deps.sessionManager.createForAgent({
|
|
17921
17871
|
sessionId: subSessionId,
|
|
17922
|
-
|
|
17872
|
+
agentId: personaId,
|
|
17923
17873
|
cwd: this.deps.store.personaDirPath(personaId),
|
|
17924
17874
|
tool: "claude",
|
|
17925
17875
|
label: subLabel,
|
|
17926
|
-
model: persona.model
|
|
17876
|
+
model: persona.model,
|
|
17877
|
+
// listener 走 OS sandbox:sandbox JSON 不在 project 自动发现路径上(PersonaStore 把它
|
|
17878
|
+
// 落在 .clawd/sandbox-settings.json),靠 extraSettings 透传到 spawn 的 `--settings <file>`
|
|
17879
|
+
// 显式拉回。owner 路径不传 extraSettings,天然无 sandbox。
|
|
17880
|
+
subSessionMeta: {
|
|
17881
|
+
idleKillEnabled: true,
|
|
17882
|
+
personaMode: "listener",
|
|
17883
|
+
extraSettings: this.deps.store.sandboxSettingsPath(personaId)
|
|
17884
|
+
}
|
|
17927
17885
|
});
|
|
17928
17886
|
return { sessionFile, isNew: true };
|
|
17929
17887
|
}
|
|
@@ -17934,7 +17892,7 @@ var PersonaManager = class {
|
|
|
17934
17892
|
appendOwnerMessage(personaId, subSessionId, text) {
|
|
17935
17893
|
this.deps.sessionManager.injectOwnerMessage({
|
|
17936
17894
|
sessionId: subSessionId,
|
|
17937
|
-
|
|
17895
|
+
agentId: personaId,
|
|
17938
17896
|
text
|
|
17939
17897
|
});
|
|
17940
17898
|
}
|
|
@@ -17963,7 +17921,7 @@ var PersonaManager = class {
|
|
|
17963
17921
|
|
|
17964
17922
|
// src/persona/seed.ts
|
|
17965
17923
|
var fs7 = __toESM(require("fs"), 1);
|
|
17966
|
-
var
|
|
17924
|
+
var path7 = __toESM(require("path"), 1);
|
|
17967
17925
|
var import_node_url = require("url");
|
|
17968
17926
|
var import_meta = {};
|
|
17969
17927
|
var DEFAULT_PERSONAS = [
|
|
@@ -17980,19 +17938,26 @@ var DEFAULT_PERSONAS = [
|
|
|
17980
17938
|
model: "opus",
|
|
17981
17939
|
iconKey: "reading",
|
|
17982
17940
|
public: false
|
|
17941
|
+
},
|
|
17942
|
+
{
|
|
17943
|
+
personaId: "persona-clawd-helper",
|
|
17944
|
+
label: "clawd\u4F7F\u7528\u52A9\u624B",
|
|
17945
|
+
model: "opus",
|
|
17946
|
+
iconKey: "assist",
|
|
17947
|
+
public: false
|
|
17983
17948
|
}
|
|
17984
17949
|
];
|
|
17985
17950
|
function findDefaultsRoot() {
|
|
17986
17951
|
const candidates = [];
|
|
17987
17952
|
try {
|
|
17988
|
-
const here =
|
|
17989
|
-
candidates.push(
|
|
17990
|
-
candidates.push(
|
|
17953
|
+
const here = path7.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
17954
|
+
candidates.push(path7.resolve(here, "defaults"));
|
|
17955
|
+
candidates.push(path7.resolve(here, "persona-defaults"));
|
|
17991
17956
|
} catch {
|
|
17992
17957
|
}
|
|
17993
17958
|
if (process.argv[1]) {
|
|
17994
|
-
const argvDir =
|
|
17995
|
-
candidates.push(
|
|
17959
|
+
const argvDir = path7.dirname(process.argv[1]);
|
|
17960
|
+
candidates.push(path7.resolve(argvDir, "persona-defaults"));
|
|
17996
17961
|
}
|
|
17997
17962
|
for (const c of candidates) {
|
|
17998
17963
|
try {
|
|
@@ -18009,7 +17974,7 @@ function seedDefaultPersonas(args) {
|
|
|
18009
17974
|
args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
|
|
18010
17975
|
continue;
|
|
18011
17976
|
}
|
|
18012
|
-
const bundleDir =
|
|
17977
|
+
const bundleDir = path7.join(args.defaultsRoot, entry.personaId);
|
|
18013
17978
|
if (!fs7.existsSync(bundleDir)) {
|
|
18014
17979
|
args.logger.warn("persona.seed.skip", {
|
|
18015
17980
|
personaId: entry.personaId,
|
|
@@ -18018,7 +17983,7 @@ function seedDefaultPersonas(args) {
|
|
|
18018
17983
|
});
|
|
18019
17984
|
continue;
|
|
18020
17985
|
}
|
|
18021
|
-
const claudeMdPath =
|
|
17986
|
+
const claudeMdPath = path7.join(bundleDir, "CLAUDE.md");
|
|
18022
17987
|
if (!fs7.existsSync(claudeMdPath)) {
|
|
18023
17988
|
args.logger.warn("persona.seed.skip", {
|
|
18024
17989
|
personaId: entry.personaId,
|
|
@@ -18047,8 +18012,8 @@ function seedDefaultPersonas(args) {
|
|
|
18047
18012
|
function copyBundleExtras(srcDir, dstDir) {
|
|
18048
18013
|
for (const entry of fs7.readdirSync(srcDir, { withFileTypes: true })) {
|
|
18049
18014
|
if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
|
|
18050
|
-
const srcPath =
|
|
18051
|
-
const dstPath =
|
|
18015
|
+
const srcPath = path7.join(srcDir, entry.name);
|
|
18016
|
+
const dstPath = path7.join(dstDir, entry.name);
|
|
18052
18017
|
if (entry.isDirectory()) {
|
|
18053
18018
|
fs7.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
|
|
18054
18019
|
} else if (entry.isFile()) {
|
|
@@ -18064,14 +18029,14 @@ init_claude_history();
|
|
|
18064
18029
|
// src/workspace/browser.ts
|
|
18065
18030
|
var import_node_fs8 = __toESM(require("fs"), 1);
|
|
18066
18031
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
18067
|
-
var
|
|
18032
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
18068
18033
|
init_protocol();
|
|
18069
18034
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
18070
18035
|
function resolveInsideCwd(cwd, subpath) {
|
|
18071
|
-
const absCwd =
|
|
18072
|
-
const joined =
|
|
18073
|
-
const rel =
|
|
18074
|
-
if (rel.startsWith("..") ||
|
|
18036
|
+
const absCwd = import_node_path8.default.resolve(cwd);
|
|
18037
|
+
const joined = import_node_path8.default.resolve(absCwd, subpath ?? ".");
|
|
18038
|
+
const rel = import_node_path8.default.relative(absCwd, joined);
|
|
18039
|
+
if (rel.startsWith("..") || import_node_path8.default.isAbsolute(rel)) {
|
|
18075
18040
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
18076
18041
|
}
|
|
18077
18042
|
return joined;
|
|
@@ -18102,7 +18067,7 @@ var WorkspaceBrowser = class {
|
|
|
18102
18067
|
mtime: ""
|
|
18103
18068
|
};
|
|
18104
18069
|
try {
|
|
18105
|
-
const st = import_node_fs8.default.statSync(
|
|
18070
|
+
const st = import_node_fs8.default.statSync(import_node_path8.default.join(full, d.name));
|
|
18106
18071
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
18107
18072
|
if (d.isFile()) entry.size = st.size;
|
|
18108
18073
|
} catch {
|
|
@@ -18149,7 +18114,7 @@ var WorkspaceBrowser = class {
|
|
|
18149
18114
|
// src/skills/scanner.ts
|
|
18150
18115
|
var import_node_fs9 = __toESM(require("fs"), 1);
|
|
18151
18116
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
18152
|
-
var
|
|
18117
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
18153
18118
|
|
|
18154
18119
|
// src/skills/frontmatter.ts
|
|
18155
18120
|
var STRIP_QUOTES = /^["']|["']$/g;
|
|
@@ -18271,14 +18236,14 @@ function scanSkillDir(dir, source, seen, out, pluginName) {
|
|
|
18271
18236
|
return;
|
|
18272
18237
|
}
|
|
18273
18238
|
for (const ent of entries) {
|
|
18274
|
-
const entryPath =
|
|
18239
|
+
const entryPath = import_node_path9.default.join(dir, ent.name);
|
|
18275
18240
|
if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
|
|
18276
18241
|
let content;
|
|
18277
18242
|
try {
|
|
18278
|
-
content = import_node_fs9.default.readFileSync(
|
|
18243
|
+
content = import_node_fs9.default.readFileSync(import_node_path9.default.join(entryPath, "SKILL.md"), "utf8");
|
|
18279
18244
|
} catch {
|
|
18280
18245
|
try {
|
|
18281
|
-
content = import_node_fs9.default.readFileSync(
|
|
18246
|
+
content = import_node_fs9.default.readFileSync(import_node_path9.default.join(entryPath, "skill.md"), "utf8");
|
|
18282
18247
|
} catch {
|
|
18283
18248
|
continue;
|
|
18284
18249
|
}
|
|
@@ -18301,7 +18266,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
18301
18266
|
return;
|
|
18302
18267
|
}
|
|
18303
18268
|
for (const ent of entries) {
|
|
18304
|
-
const entryPath =
|
|
18269
|
+
const entryPath = import_node_path9.default.join(dir, ent.name);
|
|
18305
18270
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
|
|
18306
18271
|
const ns = ent.name;
|
|
18307
18272
|
let subEntries;
|
|
@@ -18312,7 +18277,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
18312
18277
|
}
|
|
18313
18278
|
for (const se of subEntries) {
|
|
18314
18279
|
if (!se.name.endsWith(".md")) continue;
|
|
18315
|
-
const sePath =
|
|
18280
|
+
const sePath = import_node_path9.default.join(entryPath, se.name);
|
|
18316
18281
|
let content;
|
|
18317
18282
|
try {
|
|
18318
18283
|
content = import_node_fs9.default.readFileSync(sePath, "utf8");
|
|
@@ -18348,7 +18313,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
18348
18313
|
}
|
|
18349
18314
|
}
|
|
18350
18315
|
function readInstalledPlugins(home) {
|
|
18351
|
-
const file =
|
|
18316
|
+
const file = import_node_path9.default.join(home, ".claude", "plugins", "installed_plugins.json");
|
|
18352
18317
|
let raw;
|
|
18353
18318
|
try {
|
|
18354
18319
|
raw = import_node_fs9.default.readFileSync(file, "utf8");
|
|
@@ -18399,14 +18364,14 @@ var SkillsScanner = class {
|
|
|
18399
18364
|
});
|
|
18400
18365
|
}
|
|
18401
18366
|
const fsBlock = [];
|
|
18402
|
-
scanSkillDir(
|
|
18403
|
-
scanCommandDir(
|
|
18404
|
-
scanSkillDir(
|
|
18405
|
-
scanCommandDir(
|
|
18367
|
+
scanSkillDir(import_node_path9.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
|
|
18368
|
+
scanCommandDir(import_node_path9.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
|
|
18369
|
+
scanSkillDir(import_node_path9.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
|
|
18370
|
+
scanCommandDir(import_node_path9.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
|
|
18406
18371
|
const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
|
|
18407
18372
|
for (const { name, root } of plugins) {
|
|
18408
|
-
scanSkillDir(
|
|
18409
|
-
scanCommandDir(
|
|
18373
|
+
scanSkillDir(import_node_path9.default.join(root, "skills"), "plugin", seen, fsBlock, name);
|
|
18374
|
+
scanCommandDir(import_node_path9.default.join(root, "commands"), "plugin", seen, fsBlock, name);
|
|
18410
18375
|
}
|
|
18411
18376
|
fsBlock.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
18412
18377
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -18416,7 +18381,7 @@ var SkillsScanner = class {
|
|
|
18416
18381
|
// src/skills/agents-scanner.ts
|
|
18417
18382
|
var import_node_fs10 = __toESM(require("fs"), 1);
|
|
18418
18383
|
var import_node_os6 = __toESM(require("os"), 1);
|
|
18419
|
-
var
|
|
18384
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
18420
18385
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
18421
18386
|
function isDirLikeSync2(p) {
|
|
18422
18387
|
try {
|
|
@@ -18454,10 +18419,10 @@ function scanAgentsDir(dir, source, seen, out) {
|
|
|
18454
18419
|
}
|
|
18455
18420
|
for (const ent of entries) {
|
|
18456
18421
|
if (!ent.name.endsWith(".md")) continue;
|
|
18457
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
18422
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path10.default.join(dir, ent.name)))) {
|
|
18458
18423
|
continue;
|
|
18459
18424
|
}
|
|
18460
|
-
const filePath =
|
|
18425
|
+
const filePath = import_node_path10.default.join(dir, ent.name);
|
|
18461
18426
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
18462
18427
|
if (seen.has(baseName)) continue;
|
|
18463
18428
|
seen.add(baseName);
|
|
@@ -18480,7 +18445,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
18480
18445
|
return;
|
|
18481
18446
|
}
|
|
18482
18447
|
for (const ent of entries) {
|
|
18483
|
-
const childPath =
|
|
18448
|
+
const childPath = import_node_path10.default.join(dir, ent.name);
|
|
18484
18449
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
18485
18450
|
walk(childPath, [...namespaces, ent.name]);
|
|
18486
18451
|
continue;
|
|
@@ -18505,9 +18470,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
18505
18470
|
walk(root, []);
|
|
18506
18471
|
}
|
|
18507
18472
|
function readInstalledPlugins2(home) {
|
|
18508
|
-
const pluginsDir =
|
|
18509
|
-
const v2 =
|
|
18510
|
-
const v1 =
|
|
18473
|
+
const pluginsDir = import_node_path10.default.join(home, ".claude", "plugins");
|
|
18474
|
+
const v2 = import_node_path10.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
18475
|
+
const v1 = import_node_path10.default.join(pluginsDir, "installed_plugins.json");
|
|
18511
18476
|
let raw = null;
|
|
18512
18477
|
for (const candidate of [v2, v1]) {
|
|
18513
18478
|
try {
|
|
@@ -18536,19 +18501,19 @@ function readInstalledPlugins2(home) {
|
|
|
18536
18501
|
return out;
|
|
18537
18502
|
}
|
|
18538
18503
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
18539
|
-
let cur =
|
|
18540
|
-
const fsRoot =
|
|
18504
|
+
let cur = import_node_path10.default.resolve(startCwd);
|
|
18505
|
+
const fsRoot = import_node_path10.default.parse(cur).root;
|
|
18541
18506
|
while (true) {
|
|
18542
|
-
scanAgentsDir(
|
|
18507
|
+
scanAgentsDir(import_node_path10.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
18543
18508
|
let hasGit = false;
|
|
18544
18509
|
try {
|
|
18545
|
-
hasGit = import_node_fs10.default.existsSync(
|
|
18510
|
+
hasGit = import_node_fs10.default.existsSync(import_node_path10.default.join(cur, ".git"));
|
|
18546
18511
|
} catch {
|
|
18547
18512
|
}
|
|
18548
18513
|
if (hasGit) return;
|
|
18549
18514
|
if (cur === home) return;
|
|
18550
18515
|
if (cur === fsRoot) return;
|
|
18551
|
-
const parent =
|
|
18516
|
+
const parent = import_node_path10.default.dirname(cur);
|
|
18552
18517
|
if (parent === cur) return;
|
|
18553
18518
|
cur = parent;
|
|
18554
18519
|
}
|
|
@@ -18583,7 +18548,7 @@ var AgentsScanner = class {
|
|
|
18583
18548
|
}
|
|
18584
18549
|
const fsBlock = [];
|
|
18585
18550
|
scanAgentsDir(
|
|
18586
|
-
|
|
18551
|
+
import_node_path10.default.join(this.home, ".claude", "agents"),
|
|
18587
18552
|
"global",
|
|
18588
18553
|
seen,
|
|
18589
18554
|
fsBlock
|
|
@@ -18597,7 +18562,7 @@ var AgentsScanner = class {
|
|
|
18597
18562
|
...this.extraPluginRoots
|
|
18598
18563
|
];
|
|
18599
18564
|
for (const { name, root } of plugins) {
|
|
18600
|
-
const agentsRoot =
|
|
18565
|
+
const agentsRoot = import_node_path10.default.join(root, "agents");
|
|
18601
18566
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
18602
18567
|
}
|
|
18603
18568
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -18607,7 +18572,7 @@ var AgentsScanner = class {
|
|
|
18607
18572
|
// src/observer/session-observer.ts
|
|
18608
18573
|
var import_node_fs11 = __toESM(require("fs"), 1);
|
|
18609
18574
|
var import_node_os7 = __toESM(require("os"), 1);
|
|
18610
|
-
var
|
|
18575
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
18611
18576
|
init_claude_history();
|
|
18612
18577
|
var SessionObserver = class {
|
|
18613
18578
|
constructor(opts) {
|
|
@@ -18619,7 +18584,7 @@ var SessionObserver = class {
|
|
|
18619
18584
|
watches = /* @__PURE__ */ new Map();
|
|
18620
18585
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
18621
18586
|
if (override) return override;
|
|
18622
|
-
return
|
|
18587
|
+
return import_node_path11.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
18623
18588
|
}
|
|
18624
18589
|
start(args) {
|
|
18625
18590
|
this.stop(args.sessionId);
|
|
@@ -18639,10 +18604,10 @@ var SessionObserver = class {
|
|
|
18639
18604
|
adapter: args.adapter
|
|
18640
18605
|
};
|
|
18641
18606
|
try {
|
|
18642
|
-
import_node_fs11.default.mkdirSync(
|
|
18607
|
+
import_node_fs11.default.mkdirSync(import_node_path11.default.dirname(filePath), { recursive: true });
|
|
18643
18608
|
} catch {
|
|
18644
18609
|
}
|
|
18645
|
-
w.watcher = import_node_fs11.default.watch(
|
|
18610
|
+
w.watcher = import_node_fs11.default.watch(import_node_path11.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
18646
18611
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
18647
18612
|
this.poll(w);
|
|
18648
18613
|
});
|
|
@@ -19158,18 +19123,13 @@ var PersonaBoundHandler = class {
|
|
|
19158
19123
|
}
|
|
19159
19124
|
return true;
|
|
19160
19125
|
};
|
|
19161
|
-
const listenerScope = () => ({
|
|
19162
|
-
kind: "persona",
|
|
19163
|
-
personaId: scope.personaId,
|
|
19164
|
-
mode: "listener"
|
|
19165
|
-
});
|
|
19166
19126
|
switch (type) {
|
|
19167
19127
|
case "session:subscribe": {
|
|
19168
19128
|
if (!requireScopedSession()) return;
|
|
19169
19129
|
if (unsubscribe) unsubscribe();
|
|
19170
19130
|
unsubscribe = this.deps.sessionManager.subscribe(
|
|
19171
19131
|
scope.subSessionId,
|
|
19172
|
-
|
|
19132
|
+
scope.personaId,
|
|
19173
19133
|
(eventFrame) => send(eventFrame)
|
|
19174
19134
|
);
|
|
19175
19135
|
if (requestId)
|
|
@@ -19199,9 +19159,9 @@ var PersonaBoundHandler = class {
|
|
|
19199
19159
|
return;
|
|
19200
19160
|
}
|
|
19201
19161
|
try {
|
|
19202
|
-
this.deps.sessionManager.
|
|
19162
|
+
this.deps.sessionManager.sendForAgent({
|
|
19203
19163
|
sessionId: scope.subSessionId,
|
|
19204
|
-
|
|
19164
|
+
agentId: scope.personaId,
|
|
19205
19165
|
text
|
|
19206
19166
|
});
|
|
19207
19167
|
if (requestId) send({ type: "session:send", ok: true, requestId });
|
|
@@ -19214,9 +19174,9 @@ var PersonaBoundHandler = class {
|
|
|
19214
19174
|
case "session:new": {
|
|
19215
19175
|
if (!requireScopedSession()) return;
|
|
19216
19176
|
try {
|
|
19217
|
-
this.deps.sessionManager.
|
|
19177
|
+
this.deps.sessionManager.resetForAgent({
|
|
19218
19178
|
sessionId: scope.subSessionId,
|
|
19219
|
-
|
|
19179
|
+
agentId: scope.personaId
|
|
19220
19180
|
});
|
|
19221
19181
|
if (requestId) send({ type: "session:info", sessionId: scope.subSessionId, requestId });
|
|
19222
19182
|
} catch (err) {
|
|
@@ -19230,9 +19190,9 @@ var PersonaBoundHandler = class {
|
|
|
19230
19190
|
const limit = typeof frame.limit === "number" && frame.limit > 0 ? frame.limit : 50;
|
|
19231
19191
|
const offset = typeof frame.offset === "number" && frame.offset >= 0 ? frame.offset : 0;
|
|
19232
19192
|
try {
|
|
19233
|
-
const page = this.deps.sessionManager.
|
|
19193
|
+
const page = this.deps.sessionManager.readHistoryPage(
|
|
19234
19194
|
scope.subSessionId,
|
|
19235
|
-
|
|
19195
|
+
scope.personaId,
|
|
19236
19196
|
limit,
|
|
19237
19197
|
offset
|
|
19238
19198
|
);
|
|
@@ -19363,9 +19323,9 @@ function isLocalhost(addr) {
|
|
|
19363
19323
|
|
|
19364
19324
|
// src/discovery/state-file.ts
|
|
19365
19325
|
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
19366
|
-
var
|
|
19326
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
19367
19327
|
function defaultStateFilePath(dataDir) {
|
|
19368
|
-
return
|
|
19328
|
+
return import_node_path12.default.join(dataDir, "state.json");
|
|
19369
19329
|
}
|
|
19370
19330
|
function isPidAlive(pid) {
|
|
19371
19331
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -19401,7 +19361,7 @@ var StateFileManager = class {
|
|
|
19401
19361
|
return { status: "stale", existing };
|
|
19402
19362
|
}
|
|
19403
19363
|
write(state) {
|
|
19404
|
-
import_node_fs12.default.mkdirSync(
|
|
19364
|
+
import_node_fs12.default.mkdirSync(import_node_path12.default.dirname(this.file), { recursive: true });
|
|
19405
19365
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
19406
19366
|
import_node_fs12.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
19407
19367
|
import_node_fs12.default.renameSync(tmp, this.file);
|
|
@@ -19422,13 +19382,13 @@ var StateFileManager = class {
|
|
|
19422
19382
|
|
|
19423
19383
|
// src/tunnel/tunnel-manager.ts
|
|
19424
19384
|
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
19425
|
-
var
|
|
19385
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
19426
19386
|
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
19427
19387
|
var import_node_child_process4 = require("child_process");
|
|
19428
19388
|
|
|
19429
19389
|
// src/tunnel/tunnel-store.ts
|
|
19430
19390
|
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
19431
|
-
var
|
|
19391
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
19432
19392
|
var TunnelStore = class {
|
|
19433
19393
|
constructor(filePath) {
|
|
19434
19394
|
this.filePath = filePath;
|
|
@@ -19447,7 +19407,7 @@ var TunnelStore = class {
|
|
|
19447
19407
|
}
|
|
19448
19408
|
}
|
|
19449
19409
|
async set(v) {
|
|
19450
|
-
const dir =
|
|
19410
|
+
const dir = import_node_path13.default.dirname(this.filePath);
|
|
19451
19411
|
await import_node_fs13.default.promises.mkdir(dir, { recursive: true });
|
|
19452
19412
|
const data = JSON.stringify(v, null, 2);
|
|
19453
19413
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
@@ -19559,7 +19519,7 @@ function escape(v) {
|
|
|
19559
19519
|
// src/tunnel/frpc-binary.ts
|
|
19560
19520
|
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
19561
19521
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
19562
|
-
var
|
|
19522
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
19563
19523
|
var import_node_child_process3 = require("child_process");
|
|
19564
19524
|
var import_node_stream = require("stream");
|
|
19565
19525
|
var import_promises = require("stream/promises");
|
|
@@ -19598,13 +19558,13 @@ async function ensureFrpcBinary(opts) {
|
|
|
19598
19558
|
}
|
|
19599
19559
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
19600
19560
|
const platform = opts.platform ?? detectPlatform();
|
|
19601
|
-
const binDir =
|
|
19561
|
+
const binDir = import_node_path14.default.join(opts.dataDir, "bin");
|
|
19602
19562
|
import_node_fs14.default.mkdirSync(binDir, { recursive: true });
|
|
19603
19563
|
cleanupStaleArtifacts(binDir);
|
|
19604
|
-
const stableBin =
|
|
19564
|
+
const stableBin = import_node_path14.default.join(binDir, "frpc");
|
|
19605
19565
|
if (import_node_fs14.default.existsSync(stableBin)) return stableBin;
|
|
19606
19566
|
const partialBin = `${stableBin}.partial`;
|
|
19607
|
-
const tarballPath =
|
|
19567
|
+
const tarballPath = import_node_path14.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
19608
19568
|
try {
|
|
19609
19569
|
const url = frpcDownloadUrl(version2, platform);
|
|
19610
19570
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -19630,7 +19590,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
19630
19590
|
}
|
|
19631
19591
|
for (const name of entries) {
|
|
19632
19592
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
19633
|
-
const full =
|
|
19593
|
+
const full = import_node_path14.default.join(binDir, name);
|
|
19634
19594
|
try {
|
|
19635
19595
|
import_node_fs14.default.rmSync(full, { recursive: true, force: true });
|
|
19636
19596
|
} catch {
|
|
@@ -19656,7 +19616,7 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
19656
19616
|
await (0, import_promises.pipeline)(nodeStream, out);
|
|
19657
19617
|
}
|
|
19658
19618
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
19659
|
-
const work =
|
|
19619
|
+
const work = import_node_path14.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
19660
19620
|
import_node_fs14.default.mkdirSync(work, { recursive: true });
|
|
19661
19621
|
try {
|
|
19662
19622
|
await new Promise((resolve2, reject) => {
|
|
@@ -19665,7 +19625,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
19665
19625
|
proc.on("exit", (code) => code === 0 ? resolve2() : reject(new Error(`tar exited ${code}`)));
|
|
19666
19626
|
});
|
|
19667
19627
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
19668
|
-
const src =
|
|
19628
|
+
const src = import_node_path14.default.join(work, dirName, "frpc");
|
|
19669
19629
|
if (!import_node_fs14.default.existsSync(src)) {
|
|
19670
19630
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
19671
19631
|
}
|
|
@@ -19680,7 +19640,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
19680
19640
|
var TunnelManager = class {
|
|
19681
19641
|
constructor(deps) {
|
|
19682
19642
|
this.deps = deps;
|
|
19683
|
-
this.store = deps.store ?? new TunnelStore(
|
|
19643
|
+
this.store = deps.store ?? new TunnelStore(import_node_path15.default.join(deps.dataDir, "tunnel.json"));
|
|
19684
19644
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
19685
19645
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
19686
19646
|
}
|
|
@@ -19797,7 +19757,7 @@ var TunnelManager = class {
|
|
|
19797
19757
|
dataDir: this.deps.dataDir,
|
|
19798
19758
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
19799
19759
|
});
|
|
19800
|
-
const tomlPath =
|
|
19760
|
+
const tomlPath = import_node_path15.default.join(this.deps.dataDir, "frpc.toml");
|
|
19801
19761
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto4.default.randomBytes(3).toString("hex")}`;
|
|
19802
19762
|
const toml = buildFrpcToml({
|
|
19803
19763
|
serverAddr: t.frpsHost,
|
|
@@ -19812,7 +19772,7 @@ var TunnelManager = class {
|
|
|
19812
19772
|
const proc = (this.deps.spawnImpl ?? import_node_child_process4.spawn)(frpcBin, ["-c", tomlPath], {
|
|
19813
19773
|
stdio: ["ignore", "pipe", "pipe"]
|
|
19814
19774
|
});
|
|
19815
|
-
const logFilePath =
|
|
19775
|
+
const logFilePath = import_node_path15.default.join(this.deps.dataDir, "frpc.log");
|
|
19816
19776
|
const logStream = import_node_fs15.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
19817
19777
|
logStream.on("error", () => {
|
|
19818
19778
|
});
|
|
@@ -19906,11 +19866,11 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
19906
19866
|
|
|
19907
19867
|
// src/auth-store.ts
|
|
19908
19868
|
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
19909
|
-
var
|
|
19869
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
19910
19870
|
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
19911
19871
|
var AUTH_FILE_NAME = "auth.json";
|
|
19912
19872
|
function authFilePath(dataDir) {
|
|
19913
|
-
return
|
|
19873
|
+
return import_node_path16.default.join(dataDir, AUTH_FILE_NAME);
|
|
19914
19874
|
}
|
|
19915
19875
|
function loadOrCreateAuthToken(opts) {
|
|
19916
19876
|
const file = authFilePath(opts.dataDir);
|
|
@@ -19942,7 +19902,7 @@ function readAuthFile(file) {
|
|
|
19942
19902
|
}
|
|
19943
19903
|
}
|
|
19944
19904
|
function writeAuthFile(file, content) {
|
|
19945
|
-
import_node_fs16.default.mkdirSync(
|
|
19905
|
+
import_node_fs16.default.mkdirSync(import_node_path16.default.dirname(file), { recursive: true });
|
|
19946
19906
|
import_node_fs16.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
19947
19907
|
try {
|
|
19948
19908
|
import_node_fs16.default.chmodSync(file, 384);
|
|
@@ -19953,11 +19913,11 @@ function writeAuthFile(file, content) {
|
|
|
19953
19913
|
// src/owner-profile.ts
|
|
19954
19914
|
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
19955
19915
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
19956
|
-
var
|
|
19916
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
19957
19917
|
var PROFILE_FILENAME = "profile.json";
|
|
19958
19918
|
function loadOwnerDisplayName(dataDir) {
|
|
19959
19919
|
const fallback = import_node_os10.default.userInfo().username;
|
|
19960
|
-
const profilePath =
|
|
19920
|
+
const profilePath = import_node_path17.default.join(dataDir, PROFILE_FILENAME);
|
|
19961
19921
|
let raw;
|
|
19962
19922
|
try {
|
|
19963
19923
|
raw = import_node_fs17.default.readFileSync(profilePath, "utf8");
|
|
@@ -19991,7 +19951,7 @@ init_protocol();
|
|
|
19991
19951
|
// src/session/fork.ts
|
|
19992
19952
|
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
19993
19953
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
19994
|
-
var
|
|
19954
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
19995
19955
|
init_claude_history();
|
|
19996
19956
|
function readJsonlEntries(file) {
|
|
19997
19957
|
const raw = import_node_fs18.default.readFileSync(file, "utf8");
|
|
@@ -20007,9 +19967,9 @@ function readJsonlEntries(file) {
|
|
|
20007
19967
|
return out;
|
|
20008
19968
|
}
|
|
20009
19969
|
function forkSession(input) {
|
|
20010
|
-
const baseDir = input.baseDir ??
|
|
20011
|
-
const projectDir =
|
|
20012
|
-
const sourceFile =
|
|
19970
|
+
const baseDir = input.baseDir ?? import_node_path18.default.join(import_node_os11.default.homedir(), ".claude");
|
|
19971
|
+
const projectDir = import_node_path18.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
19972
|
+
const sourceFile = import_node_path18.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
20013
19973
|
if (!import_node_fs18.default.existsSync(sourceFile)) {
|
|
20014
19974
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
20015
19975
|
}
|
|
@@ -20040,7 +20000,7 @@ function forkSession(input) {
|
|
|
20040
20000
|
}
|
|
20041
20001
|
forkedLines.push(JSON.stringify(forked));
|
|
20042
20002
|
}
|
|
20043
|
-
const forkedFilePath =
|
|
20003
|
+
const forkedFilePath = import_node_path18.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
20044
20004
|
import_node_fs18.default.mkdirSync(projectDir, { recursive: true });
|
|
20045
20005
|
import_node_fs18.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
20046
20006
|
return { forkedToolSessionId, forkedFilePath };
|
|
@@ -20332,7 +20292,7 @@ init_protocol();
|
|
|
20332
20292
|
var import_node_child_process5 = require("child_process");
|
|
20333
20293
|
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
20334
20294
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
20335
|
-
var
|
|
20295
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
20336
20296
|
var import_node_util = require("util");
|
|
20337
20297
|
var pexec = (0, import_node_util.promisify)(import_node_child_process5.execFile);
|
|
20338
20298
|
function formatChildProcessError(err) {
|
|
@@ -20347,7 +20307,7 @@ function formatChildProcessError(err) {
|
|
|
20347
20307
|
return e.message ?? "unknown error";
|
|
20348
20308
|
}
|
|
20349
20309
|
function normalizePath(p) {
|
|
20350
|
-
const resolved =
|
|
20310
|
+
const resolved = import_node_path19.default.resolve(p);
|
|
20351
20311
|
try {
|
|
20352
20312
|
return import_node_fs19.default.realpathSync(resolved);
|
|
20353
20313
|
} catch {
|
|
@@ -20450,13 +20410,13 @@ function flattenToDirName(branch) {
|
|
|
20450
20410
|
}
|
|
20451
20411
|
function encodeClaudeProjectDir(absPath) {
|
|
20452
20412
|
if (!absPath || typeof absPath !== "string") return "";
|
|
20453
|
-
let canonical =
|
|
20413
|
+
let canonical = import_node_path19.default.resolve(absPath);
|
|
20454
20414
|
try {
|
|
20455
20415
|
canonical = import_node_fs19.default.realpathSync(canonical);
|
|
20456
20416
|
} catch {
|
|
20457
20417
|
try {
|
|
20458
|
-
const parent = import_node_fs19.default.realpathSync(
|
|
20459
|
-
canonical =
|
|
20418
|
+
const parent = import_node_fs19.default.realpathSync(import_node_path19.default.dirname(canonical));
|
|
20419
|
+
canonical = import_node_path19.default.join(parent, import_node_path19.default.basename(canonical));
|
|
20460
20420
|
} catch {
|
|
20461
20421
|
}
|
|
20462
20422
|
}
|
|
@@ -20480,11 +20440,11 @@ async function createWorktree(input) {
|
|
|
20480
20440
|
if (!isGitRoot) {
|
|
20481
20441
|
throw new Error(`\u76EE\u5F55 ${cwd} \u4E0D\u662F git repo \u6839`);
|
|
20482
20442
|
}
|
|
20483
|
-
const parent =
|
|
20484
|
-
if (parent === "/" || parent ===
|
|
20443
|
+
const parent = import_node_path19.default.dirname(import_node_path19.default.resolve(cwd));
|
|
20444
|
+
if (parent === "/" || parent === import_node_path19.default.resolve(cwd)) {
|
|
20485
20445
|
throw new Error("repo \u5728\u78C1\u76D8\u6839\u76EE\u5F55\uFF0C\u65E0\u6CD5\u5728\u540C\u7EA7\u521B\u5EFA worktree");
|
|
20486
20446
|
}
|
|
20487
|
-
const worktreeRoot =
|
|
20447
|
+
const worktreeRoot = import_node_path19.default.join(parent, dirName);
|
|
20488
20448
|
try {
|
|
20489
20449
|
await pexec("git", ["-C", cwd, "fetch", "origin", baseBranch, "--no-tags"], {
|
|
20490
20450
|
timeout: 3e4
|
|
@@ -20531,8 +20491,8 @@ async function removeWorktree(input) {
|
|
|
20531
20491
|
);
|
|
20532
20492
|
const gitCommonDir = stdout.trim();
|
|
20533
20493
|
if (!gitCommonDir) throw new Error("empty git-common-dir");
|
|
20534
|
-
const absGitCommon =
|
|
20535
|
-
repoRoot =
|
|
20494
|
+
const absGitCommon = import_node_path19.default.isAbsolute(gitCommonDir) ? gitCommonDir : import_node_path19.default.resolve(worktreeRoot, gitCommonDir);
|
|
20495
|
+
repoRoot = import_node_path19.default.dirname(absGitCommon);
|
|
20536
20496
|
} catch {
|
|
20537
20497
|
repoRoot = null;
|
|
20538
20498
|
}
|
|
@@ -20563,9 +20523,9 @@ async function removeWorktree(input) {
|
|
|
20563
20523
|
try {
|
|
20564
20524
|
const encoded = encodeClaudeProjectDir(worktreeRoot);
|
|
20565
20525
|
if (encoded) {
|
|
20566
|
-
const projectsRoot =
|
|
20567
|
-
const target =
|
|
20568
|
-
if (target.startsWith(projectsRoot +
|
|
20526
|
+
const projectsRoot = import_node_path19.default.join(import_node_os12.default.homedir(), ".claude", "projects");
|
|
20527
|
+
const target = import_node_path19.default.resolve(projectsRoot, encoded);
|
|
20528
|
+
if (target.startsWith(projectsRoot + import_node_path19.default.sep) && target !== projectsRoot) {
|
|
20569
20529
|
import_node_fs19.default.rmSync(target, { recursive: true, force: true });
|
|
20570
20530
|
}
|
|
20571
20531
|
}
|
|
@@ -20734,7 +20694,7 @@ function buildPersonaHandlers(deps) {
|
|
|
20734
20694
|
};
|
|
20735
20695
|
const listSubSessions = async (frame) => {
|
|
20736
20696
|
const args = PersonaIdArgsSchema.parse(frame);
|
|
20737
|
-
const sessions = sessionManager.
|
|
20697
|
+
const sessions = sessionManager.listForAgent(args.personaId);
|
|
20738
20698
|
return {
|
|
20739
20699
|
response: { type: "persona:subSessions", sessions }
|
|
20740
20700
|
};
|
|
@@ -20781,7 +20741,7 @@ function buildMethodHandlers(deps) {
|
|
|
20781
20741
|
async function startDaemon(config) {
|
|
20782
20742
|
const logger = createLogger({
|
|
20783
20743
|
level: config.logLevel,
|
|
20784
|
-
file:
|
|
20744
|
+
file: import_node_path20.default.join(config.dataDir, "clawd.log")
|
|
20785
20745
|
});
|
|
20786
20746
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
20787
20747
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -20817,7 +20777,7 @@ async function startDaemon(config) {
|
|
|
20817
20777
|
const agents = new AgentsScanner();
|
|
20818
20778
|
const history = new ClaudeHistoryReader();
|
|
20819
20779
|
let transport = null;
|
|
20820
|
-
const personaStore = new PersonaStore(
|
|
20780
|
+
const personaStore = new PersonaStore(import_node_path20.default.join(config.dataDir, "personas"));
|
|
20821
20781
|
const defaultsRoot = findDefaultsRoot();
|
|
20822
20782
|
if (defaultsRoot) {
|
|
20823
20783
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -20831,7 +20791,7 @@ async function startDaemon(config) {
|
|
|
20831
20791
|
getAdapter,
|
|
20832
20792
|
historyReader: history,
|
|
20833
20793
|
dataDir: config.dataDir,
|
|
20834
|
-
personaRoot:
|
|
20794
|
+
personaRoot: import_node_path20.default.join(config.dataDir, "personas"),
|
|
20835
20795
|
personaStore,
|
|
20836
20796
|
ownerDisplayName,
|
|
20837
20797
|
broadcastFrame: (frame, target) => {
|
|
@@ -21005,8 +20965,8 @@ async function startDaemon(config) {
|
|
|
21005
20965
|
const lines = [
|
|
21006
20966
|
`Tunnel: ${r.url}`,
|
|
21007
20967
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
21008
|
-
`Frpc config: ${
|
|
21009
|
-
`Frpc log: ${
|
|
20968
|
+
`Frpc config: ${import_node_path20.default.join(config.dataDir, "frpc.toml")}`,
|
|
20969
|
+
`Frpc log: ${import_node_path20.default.join(config.dataDir, "frpc.log")}`
|
|
21010
20970
|
];
|
|
21011
20971
|
const width = Math.max(...lines.map((l) => l.length));
|
|
21012
20972
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -21019,7 +20979,7 @@ ${bar}
|
|
|
21019
20979
|
|
|
21020
20980
|
`);
|
|
21021
20981
|
try {
|
|
21022
|
-
const connectPath =
|
|
20982
|
+
const connectPath = import_node_path20.default.join(config.dataDir, "connect.txt");
|
|
21023
20983
|
import_node_fs20.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
21024
20984
|
} catch {
|
|
21025
20985
|
}
|