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