@clawos-dev/clawd 0.2.48-beta.76.f411c83 → 0.2.49
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 -342
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -296,8 +296,8 @@ var require_req = __commonJS({
|
|
|
296
296
|
if (req.originalUrl) {
|
|
297
297
|
_req.url = req.originalUrl;
|
|
298
298
|
} else {
|
|
299
|
-
const
|
|
300
|
-
_req.url = typeof
|
|
299
|
+
const 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;
|
|
16808
16843
|
}
|
|
16809
|
-
return
|
|
16844
|
+
return null;
|
|
16845
|
+
}
|
|
16846
|
+
// 合并 default + 所有 persona owner 的 SessionFile —— 桌面 App 主 session 列表入口。
|
|
16847
|
+
// 同样不含 listener sub-session(listener 走 persona:listSubSessions RPC 单独入口)。
|
|
16848
|
+
listAllOwned() {
|
|
16849
|
+
const out = [];
|
|
16850
|
+
out.push(...this.deps.store.list());
|
|
16851
|
+
for (const personaId of this.listPersonaIdsOnDisk()) {
|
|
16852
|
+
const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
|
|
16853
|
+
out.push(...ownerStore.list());
|
|
16854
|
+
}
|
|
16855
|
+
return out.sort(
|
|
16856
|
+
(a, b) => a.updatedAt > b.updatedAt ? -1 : a.updatedAt < b.updatedAt ? 1 : 0
|
|
16857
|
+
);
|
|
16858
|
+
}
|
|
16859
|
+
// 写回 SessionFile,自动根据 ownerPersonaId 派生写入 scope。
|
|
16860
|
+
// 调用方原先都是 `deps.store.write(updated)`,全部走这里收口路由。
|
|
16861
|
+
writeOwned(file) {
|
|
16862
|
+
return this.storeFor(this.scopeForFile(file)).write(file);
|
|
16863
|
+
}
|
|
16864
|
+
// 删除 owned SessionFile(default 或 persona/owner),与 findOwnedSession 对称扫盘。
|
|
16865
|
+
deleteOwned(sessionId) {
|
|
16866
|
+
if (this.deps.store.delete(sessionId)) return true;
|
|
16867
|
+
for (const personaId of this.listPersonaIdsOnDisk()) {
|
|
16868
|
+
const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
|
|
16869
|
+
if (ownerStore.delete(sessionId)) return true;
|
|
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 = [
|
|
@@ -17950,14 +17992,14 @@ var DEFAULT_PERSONAS = [
|
|
|
17950
17992
|
function findDefaultsRoot() {
|
|
17951
17993
|
const candidates = [];
|
|
17952
17994
|
try {
|
|
17953
|
-
const here =
|
|
17954
|
-
candidates.push(
|
|
17955
|
-
candidates.push(
|
|
17995
|
+
const here = path8.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
17996
|
+
candidates.push(path8.resolve(here, "defaults"));
|
|
17997
|
+
candidates.push(path8.resolve(here, "persona-defaults"));
|
|
17956
17998
|
} catch {
|
|
17957
17999
|
}
|
|
17958
18000
|
if (process.argv[1]) {
|
|
17959
|
-
const argvDir =
|
|
17960
|
-
candidates.push(
|
|
18001
|
+
const argvDir = path8.dirname(process.argv[1]);
|
|
18002
|
+
candidates.push(path8.resolve(argvDir, "persona-defaults"));
|
|
17961
18003
|
}
|
|
17962
18004
|
for (const c of candidates) {
|
|
17963
18005
|
try {
|
|
@@ -17974,7 +18016,7 @@ function seedDefaultPersonas(args) {
|
|
|
17974
18016
|
args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
|
|
17975
18017
|
continue;
|
|
17976
18018
|
}
|
|
17977
|
-
const bundleDir =
|
|
18019
|
+
const bundleDir = path8.join(args.defaultsRoot, entry.personaId);
|
|
17978
18020
|
if (!fs7.existsSync(bundleDir)) {
|
|
17979
18021
|
args.logger.warn("persona.seed.skip", {
|
|
17980
18022
|
personaId: entry.personaId,
|
|
@@ -17983,7 +18025,7 @@ function seedDefaultPersonas(args) {
|
|
|
17983
18025
|
});
|
|
17984
18026
|
continue;
|
|
17985
18027
|
}
|
|
17986
|
-
const claudeMdPath =
|
|
18028
|
+
const claudeMdPath = path8.join(bundleDir, "CLAUDE.md");
|
|
17987
18029
|
if (!fs7.existsSync(claudeMdPath)) {
|
|
17988
18030
|
args.logger.warn("persona.seed.skip", {
|
|
17989
18031
|
personaId: entry.personaId,
|
|
@@ -18012,8 +18054,8 @@ function seedDefaultPersonas(args) {
|
|
|
18012
18054
|
function copyBundleExtras(srcDir, dstDir) {
|
|
18013
18055
|
for (const entry of fs7.readdirSync(srcDir, { withFileTypes: true })) {
|
|
18014
18056
|
if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
|
|
18015
|
-
const srcPath =
|
|
18016
|
-
const dstPath =
|
|
18057
|
+
const srcPath = path8.join(srcDir, entry.name);
|
|
18058
|
+
const dstPath = path8.join(dstDir, entry.name);
|
|
18017
18059
|
if (entry.isDirectory()) {
|
|
18018
18060
|
fs7.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
|
|
18019
18061
|
} else if (entry.isFile()) {
|
|
@@ -18029,14 +18071,14 @@ init_claude_history();
|
|
|
18029
18071
|
// src/workspace/browser.ts
|
|
18030
18072
|
var import_node_fs8 = __toESM(require("fs"), 1);
|
|
18031
18073
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
18032
|
-
var
|
|
18074
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
18033
18075
|
init_protocol();
|
|
18034
18076
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
18035
18077
|
function resolveInsideCwd(cwd, subpath) {
|
|
18036
|
-
const absCwd =
|
|
18037
|
-
const joined =
|
|
18038
|
-
const rel =
|
|
18039
|
-
if (rel.startsWith("..") ||
|
|
18078
|
+
const absCwd = import_node_path9.default.resolve(cwd);
|
|
18079
|
+
const joined = import_node_path9.default.resolve(absCwd, subpath ?? ".");
|
|
18080
|
+
const rel = import_node_path9.default.relative(absCwd, joined);
|
|
18081
|
+
if (rel.startsWith("..") || import_node_path9.default.isAbsolute(rel)) {
|
|
18040
18082
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
18041
18083
|
}
|
|
18042
18084
|
return joined;
|
|
@@ -18067,7 +18109,7 @@ var WorkspaceBrowser = class {
|
|
|
18067
18109
|
mtime: ""
|
|
18068
18110
|
};
|
|
18069
18111
|
try {
|
|
18070
|
-
const st = import_node_fs8.default.statSync(
|
|
18112
|
+
const st = import_node_fs8.default.statSync(import_node_path9.default.join(full, d.name));
|
|
18071
18113
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
18072
18114
|
if (d.isFile()) entry.size = st.size;
|
|
18073
18115
|
} catch {
|
|
@@ -18114,7 +18156,7 @@ var WorkspaceBrowser = class {
|
|
|
18114
18156
|
// src/skills/scanner.ts
|
|
18115
18157
|
var import_node_fs9 = __toESM(require("fs"), 1);
|
|
18116
18158
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
18117
|
-
var
|
|
18159
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
18118
18160
|
|
|
18119
18161
|
// src/skills/frontmatter.ts
|
|
18120
18162
|
var STRIP_QUOTES = /^["']|["']$/g;
|
|
@@ -18236,14 +18278,14 @@ function scanSkillDir(dir, source, seen, out, pluginName) {
|
|
|
18236
18278
|
return;
|
|
18237
18279
|
}
|
|
18238
18280
|
for (const ent of entries) {
|
|
18239
|
-
const entryPath =
|
|
18281
|
+
const entryPath = import_node_path10.default.join(dir, ent.name);
|
|
18240
18282
|
if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
|
|
18241
18283
|
let content;
|
|
18242
18284
|
try {
|
|
18243
|
-
content = import_node_fs9.default.readFileSync(
|
|
18285
|
+
content = import_node_fs9.default.readFileSync(import_node_path10.default.join(entryPath, "SKILL.md"), "utf8");
|
|
18244
18286
|
} catch {
|
|
18245
18287
|
try {
|
|
18246
|
-
content = import_node_fs9.default.readFileSync(
|
|
18288
|
+
content = import_node_fs9.default.readFileSync(import_node_path10.default.join(entryPath, "skill.md"), "utf8");
|
|
18247
18289
|
} catch {
|
|
18248
18290
|
continue;
|
|
18249
18291
|
}
|
|
@@ -18266,7 +18308,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
18266
18308
|
return;
|
|
18267
18309
|
}
|
|
18268
18310
|
for (const ent of entries) {
|
|
18269
|
-
const entryPath =
|
|
18311
|
+
const entryPath = import_node_path10.default.join(dir, ent.name);
|
|
18270
18312
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
|
|
18271
18313
|
const ns = ent.name;
|
|
18272
18314
|
let subEntries;
|
|
@@ -18277,7 +18319,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
18277
18319
|
}
|
|
18278
18320
|
for (const se of subEntries) {
|
|
18279
18321
|
if (!se.name.endsWith(".md")) continue;
|
|
18280
|
-
const sePath =
|
|
18322
|
+
const sePath = import_node_path10.default.join(entryPath, se.name);
|
|
18281
18323
|
let content;
|
|
18282
18324
|
try {
|
|
18283
18325
|
content = import_node_fs9.default.readFileSync(sePath, "utf8");
|
|
@@ -18313,7 +18355,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
18313
18355
|
}
|
|
18314
18356
|
}
|
|
18315
18357
|
function readInstalledPlugins(home) {
|
|
18316
|
-
const file =
|
|
18358
|
+
const file = import_node_path10.default.join(home, ".claude", "plugins", "installed_plugins.json");
|
|
18317
18359
|
let raw;
|
|
18318
18360
|
try {
|
|
18319
18361
|
raw = import_node_fs9.default.readFileSync(file, "utf8");
|
|
@@ -18364,14 +18406,14 @@ var SkillsScanner = class {
|
|
|
18364
18406
|
});
|
|
18365
18407
|
}
|
|
18366
18408
|
const fsBlock = [];
|
|
18367
|
-
scanSkillDir(
|
|
18368
|
-
scanCommandDir(
|
|
18369
|
-
scanSkillDir(
|
|
18370
|
-
scanCommandDir(
|
|
18409
|
+
scanSkillDir(import_node_path10.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
|
|
18410
|
+
scanCommandDir(import_node_path10.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
|
|
18411
|
+
scanSkillDir(import_node_path10.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
|
|
18412
|
+
scanCommandDir(import_node_path10.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
|
|
18371
18413
|
const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
|
|
18372
18414
|
for (const { name, root } of plugins) {
|
|
18373
|
-
scanSkillDir(
|
|
18374
|
-
scanCommandDir(
|
|
18415
|
+
scanSkillDir(import_node_path10.default.join(root, "skills"), "plugin", seen, fsBlock, name);
|
|
18416
|
+
scanCommandDir(import_node_path10.default.join(root, "commands"), "plugin", seen, fsBlock, name);
|
|
18375
18417
|
}
|
|
18376
18418
|
fsBlock.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
18377
18419
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -18381,7 +18423,7 @@ var SkillsScanner = class {
|
|
|
18381
18423
|
// src/skills/agents-scanner.ts
|
|
18382
18424
|
var import_node_fs10 = __toESM(require("fs"), 1);
|
|
18383
18425
|
var import_node_os6 = __toESM(require("os"), 1);
|
|
18384
|
-
var
|
|
18426
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
18385
18427
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
18386
18428
|
function isDirLikeSync2(p) {
|
|
18387
18429
|
try {
|
|
@@ -18419,10 +18461,10 @@ function scanAgentsDir(dir, source, seen, out) {
|
|
|
18419
18461
|
}
|
|
18420
18462
|
for (const ent of entries) {
|
|
18421
18463
|
if (!ent.name.endsWith(".md")) continue;
|
|
18422
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
18464
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path11.default.join(dir, ent.name)))) {
|
|
18423
18465
|
continue;
|
|
18424
18466
|
}
|
|
18425
|
-
const filePath =
|
|
18467
|
+
const filePath = import_node_path11.default.join(dir, ent.name);
|
|
18426
18468
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
18427
18469
|
if (seen.has(baseName)) continue;
|
|
18428
18470
|
seen.add(baseName);
|
|
@@ -18445,7 +18487,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
18445
18487
|
return;
|
|
18446
18488
|
}
|
|
18447
18489
|
for (const ent of entries) {
|
|
18448
|
-
const childPath =
|
|
18490
|
+
const childPath = import_node_path11.default.join(dir, ent.name);
|
|
18449
18491
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
18450
18492
|
walk(childPath, [...namespaces, ent.name]);
|
|
18451
18493
|
continue;
|
|
@@ -18470,9 +18512,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
18470
18512
|
walk(root, []);
|
|
18471
18513
|
}
|
|
18472
18514
|
function readInstalledPlugins2(home) {
|
|
18473
|
-
const pluginsDir =
|
|
18474
|
-
const v2 =
|
|
18475
|
-
const v1 =
|
|
18515
|
+
const pluginsDir = import_node_path11.default.join(home, ".claude", "plugins");
|
|
18516
|
+
const v2 = import_node_path11.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
18517
|
+
const v1 = import_node_path11.default.join(pluginsDir, "installed_plugins.json");
|
|
18476
18518
|
let raw = null;
|
|
18477
18519
|
for (const candidate of [v2, v1]) {
|
|
18478
18520
|
try {
|
|
@@ -18501,19 +18543,19 @@ function readInstalledPlugins2(home) {
|
|
|
18501
18543
|
return out;
|
|
18502
18544
|
}
|
|
18503
18545
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
18504
|
-
let cur =
|
|
18505
|
-
const fsRoot =
|
|
18546
|
+
let cur = import_node_path11.default.resolve(startCwd);
|
|
18547
|
+
const fsRoot = import_node_path11.default.parse(cur).root;
|
|
18506
18548
|
while (true) {
|
|
18507
|
-
scanAgentsDir(
|
|
18549
|
+
scanAgentsDir(import_node_path11.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
18508
18550
|
let hasGit = false;
|
|
18509
18551
|
try {
|
|
18510
|
-
hasGit = import_node_fs10.default.existsSync(
|
|
18552
|
+
hasGit = import_node_fs10.default.existsSync(import_node_path11.default.join(cur, ".git"));
|
|
18511
18553
|
} catch {
|
|
18512
18554
|
}
|
|
18513
18555
|
if (hasGit) return;
|
|
18514
18556
|
if (cur === home) return;
|
|
18515
18557
|
if (cur === fsRoot) return;
|
|
18516
|
-
const parent =
|
|
18558
|
+
const parent = import_node_path11.default.dirname(cur);
|
|
18517
18559
|
if (parent === cur) return;
|
|
18518
18560
|
cur = parent;
|
|
18519
18561
|
}
|
|
@@ -18548,7 +18590,7 @@ var AgentsScanner = class {
|
|
|
18548
18590
|
}
|
|
18549
18591
|
const fsBlock = [];
|
|
18550
18592
|
scanAgentsDir(
|
|
18551
|
-
|
|
18593
|
+
import_node_path11.default.join(this.home, ".claude", "agents"),
|
|
18552
18594
|
"global",
|
|
18553
18595
|
seen,
|
|
18554
18596
|
fsBlock
|
|
@@ -18562,7 +18604,7 @@ var AgentsScanner = class {
|
|
|
18562
18604
|
...this.extraPluginRoots
|
|
18563
18605
|
];
|
|
18564
18606
|
for (const { name, root } of plugins) {
|
|
18565
|
-
const agentsRoot =
|
|
18607
|
+
const agentsRoot = import_node_path11.default.join(root, "agents");
|
|
18566
18608
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
18567
18609
|
}
|
|
18568
18610
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -18572,7 +18614,7 @@ var AgentsScanner = class {
|
|
|
18572
18614
|
// src/observer/session-observer.ts
|
|
18573
18615
|
var import_node_fs11 = __toESM(require("fs"), 1);
|
|
18574
18616
|
var import_node_os7 = __toESM(require("os"), 1);
|
|
18575
|
-
var
|
|
18617
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
18576
18618
|
init_claude_history();
|
|
18577
18619
|
var SessionObserver = class {
|
|
18578
18620
|
constructor(opts) {
|
|
@@ -18584,7 +18626,7 @@ var SessionObserver = class {
|
|
|
18584
18626
|
watches = /* @__PURE__ */ new Map();
|
|
18585
18627
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
18586
18628
|
if (override) return override;
|
|
18587
|
-
return
|
|
18629
|
+
return import_node_path12.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
18588
18630
|
}
|
|
18589
18631
|
start(args) {
|
|
18590
18632
|
this.stop(args.sessionId);
|
|
@@ -18604,10 +18646,10 @@ var SessionObserver = class {
|
|
|
18604
18646
|
adapter: args.adapter
|
|
18605
18647
|
};
|
|
18606
18648
|
try {
|
|
18607
|
-
import_node_fs11.default.mkdirSync(
|
|
18649
|
+
import_node_fs11.default.mkdirSync(import_node_path12.default.dirname(filePath), { recursive: true });
|
|
18608
18650
|
} catch {
|
|
18609
18651
|
}
|
|
18610
|
-
w.watcher = import_node_fs11.default.watch(
|
|
18652
|
+
w.watcher = import_node_fs11.default.watch(import_node_path12.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
18611
18653
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
18612
18654
|
this.poll(w);
|
|
18613
18655
|
});
|
|
@@ -19123,13 +19165,18 @@ var PersonaBoundHandler = class {
|
|
|
19123
19165
|
}
|
|
19124
19166
|
return true;
|
|
19125
19167
|
};
|
|
19168
|
+
const listenerScope = () => ({
|
|
19169
|
+
kind: "persona",
|
|
19170
|
+
personaId: scope.personaId,
|
|
19171
|
+
mode: "listener"
|
|
19172
|
+
});
|
|
19126
19173
|
switch (type) {
|
|
19127
19174
|
case "session:subscribe": {
|
|
19128
19175
|
if (!requireScopedSession()) return;
|
|
19129
19176
|
if (unsubscribe) unsubscribe();
|
|
19130
19177
|
unsubscribe = this.deps.sessionManager.subscribe(
|
|
19131
19178
|
scope.subSessionId,
|
|
19132
|
-
|
|
19179
|
+
listenerScope(),
|
|
19133
19180
|
(eventFrame) => send(eventFrame)
|
|
19134
19181
|
);
|
|
19135
19182
|
if (requestId)
|
|
@@ -19159,9 +19206,9 @@ var PersonaBoundHandler = class {
|
|
|
19159
19206
|
return;
|
|
19160
19207
|
}
|
|
19161
19208
|
try {
|
|
19162
|
-
this.deps.sessionManager.
|
|
19209
|
+
this.deps.sessionManager.sendForScope({
|
|
19163
19210
|
sessionId: scope.subSessionId,
|
|
19164
|
-
|
|
19211
|
+
scope: listenerScope(),
|
|
19165
19212
|
text
|
|
19166
19213
|
});
|
|
19167
19214
|
if (requestId) send({ type: "session:send", ok: true, requestId });
|
|
@@ -19174,9 +19221,9 @@ var PersonaBoundHandler = class {
|
|
|
19174
19221
|
case "session:new": {
|
|
19175
19222
|
if (!requireScopedSession()) return;
|
|
19176
19223
|
try {
|
|
19177
|
-
this.deps.sessionManager.
|
|
19224
|
+
this.deps.sessionManager.resetForScope({
|
|
19178
19225
|
sessionId: scope.subSessionId,
|
|
19179
|
-
|
|
19226
|
+
scope: listenerScope()
|
|
19180
19227
|
});
|
|
19181
19228
|
if (requestId) send({ type: "session:info", sessionId: scope.subSessionId, requestId });
|
|
19182
19229
|
} catch (err) {
|
|
@@ -19190,9 +19237,9 @@ var PersonaBoundHandler = class {
|
|
|
19190
19237
|
const limit = typeof frame.limit === "number" && frame.limit > 0 ? frame.limit : 50;
|
|
19191
19238
|
const offset = typeof frame.offset === "number" && frame.offset >= 0 ? frame.offset : 0;
|
|
19192
19239
|
try {
|
|
19193
|
-
const page = this.deps.sessionManager.
|
|
19240
|
+
const page = this.deps.sessionManager.readHistoryPageForScope(
|
|
19194
19241
|
scope.subSessionId,
|
|
19195
|
-
|
|
19242
|
+
listenerScope(),
|
|
19196
19243
|
limit,
|
|
19197
19244
|
offset
|
|
19198
19245
|
);
|
|
@@ -19323,9 +19370,9 @@ function isLocalhost(addr) {
|
|
|
19323
19370
|
|
|
19324
19371
|
// src/discovery/state-file.ts
|
|
19325
19372
|
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
19326
|
-
var
|
|
19373
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
19327
19374
|
function defaultStateFilePath(dataDir) {
|
|
19328
|
-
return
|
|
19375
|
+
return import_node_path13.default.join(dataDir, "state.json");
|
|
19329
19376
|
}
|
|
19330
19377
|
function isPidAlive(pid) {
|
|
19331
19378
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -19361,7 +19408,7 @@ var StateFileManager = class {
|
|
|
19361
19408
|
return { status: "stale", existing };
|
|
19362
19409
|
}
|
|
19363
19410
|
write(state) {
|
|
19364
|
-
import_node_fs12.default.mkdirSync(
|
|
19411
|
+
import_node_fs12.default.mkdirSync(import_node_path13.default.dirname(this.file), { recursive: true });
|
|
19365
19412
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
19366
19413
|
import_node_fs12.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
19367
19414
|
import_node_fs12.default.renameSync(tmp, this.file);
|
|
@@ -19382,13 +19429,13 @@ var StateFileManager = class {
|
|
|
19382
19429
|
|
|
19383
19430
|
// src/tunnel/tunnel-manager.ts
|
|
19384
19431
|
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
19385
|
-
var
|
|
19432
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
19386
19433
|
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
19387
19434
|
var import_node_child_process4 = require("child_process");
|
|
19388
19435
|
|
|
19389
19436
|
// src/tunnel/tunnel-store.ts
|
|
19390
19437
|
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
19391
|
-
var
|
|
19438
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
19392
19439
|
var TunnelStore = class {
|
|
19393
19440
|
constructor(filePath) {
|
|
19394
19441
|
this.filePath = filePath;
|
|
@@ -19407,7 +19454,7 @@ var TunnelStore = class {
|
|
|
19407
19454
|
}
|
|
19408
19455
|
}
|
|
19409
19456
|
async set(v) {
|
|
19410
|
-
const dir =
|
|
19457
|
+
const dir = import_node_path14.default.dirname(this.filePath);
|
|
19411
19458
|
await import_node_fs13.default.promises.mkdir(dir, { recursive: true });
|
|
19412
19459
|
const data = JSON.stringify(v, null, 2);
|
|
19413
19460
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
@@ -19519,7 +19566,7 @@ function escape(v) {
|
|
|
19519
19566
|
// src/tunnel/frpc-binary.ts
|
|
19520
19567
|
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
19521
19568
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
19522
|
-
var
|
|
19569
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
19523
19570
|
var import_node_child_process3 = require("child_process");
|
|
19524
19571
|
var import_node_stream = require("stream");
|
|
19525
19572
|
var import_promises = require("stream/promises");
|
|
@@ -19558,13 +19605,13 @@ async function ensureFrpcBinary(opts) {
|
|
|
19558
19605
|
}
|
|
19559
19606
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
19560
19607
|
const platform = opts.platform ?? detectPlatform();
|
|
19561
|
-
const binDir =
|
|
19608
|
+
const binDir = import_node_path15.default.join(opts.dataDir, "bin");
|
|
19562
19609
|
import_node_fs14.default.mkdirSync(binDir, { recursive: true });
|
|
19563
19610
|
cleanupStaleArtifacts(binDir);
|
|
19564
|
-
const stableBin =
|
|
19611
|
+
const stableBin = import_node_path15.default.join(binDir, "frpc");
|
|
19565
19612
|
if (import_node_fs14.default.existsSync(stableBin)) return stableBin;
|
|
19566
19613
|
const partialBin = `${stableBin}.partial`;
|
|
19567
|
-
const tarballPath =
|
|
19614
|
+
const tarballPath = import_node_path15.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
19568
19615
|
try {
|
|
19569
19616
|
const url = frpcDownloadUrl(version2, platform);
|
|
19570
19617
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -19590,7 +19637,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
19590
19637
|
}
|
|
19591
19638
|
for (const name of entries) {
|
|
19592
19639
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
19593
|
-
const full =
|
|
19640
|
+
const full = import_node_path15.default.join(binDir, name);
|
|
19594
19641
|
try {
|
|
19595
19642
|
import_node_fs14.default.rmSync(full, { recursive: true, force: true });
|
|
19596
19643
|
} catch {
|
|
@@ -19616,7 +19663,7 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
19616
19663
|
await (0, import_promises.pipeline)(nodeStream, out);
|
|
19617
19664
|
}
|
|
19618
19665
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
19619
|
-
const work =
|
|
19666
|
+
const work = import_node_path15.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
19620
19667
|
import_node_fs14.default.mkdirSync(work, { recursive: true });
|
|
19621
19668
|
try {
|
|
19622
19669
|
await new Promise((resolve2, reject) => {
|
|
@@ -19625,7 +19672,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
19625
19672
|
proc.on("exit", (code) => code === 0 ? resolve2() : reject(new Error(`tar exited ${code}`)));
|
|
19626
19673
|
});
|
|
19627
19674
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
19628
|
-
const src =
|
|
19675
|
+
const src = import_node_path15.default.join(work, dirName, "frpc");
|
|
19629
19676
|
if (!import_node_fs14.default.existsSync(src)) {
|
|
19630
19677
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
19631
19678
|
}
|
|
@@ -19640,7 +19687,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
19640
19687
|
var TunnelManager = class {
|
|
19641
19688
|
constructor(deps) {
|
|
19642
19689
|
this.deps = deps;
|
|
19643
|
-
this.store = deps.store ?? new TunnelStore(
|
|
19690
|
+
this.store = deps.store ?? new TunnelStore(import_node_path16.default.join(deps.dataDir, "tunnel.json"));
|
|
19644
19691
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
19645
19692
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
19646
19693
|
}
|
|
@@ -19757,7 +19804,7 @@ var TunnelManager = class {
|
|
|
19757
19804
|
dataDir: this.deps.dataDir,
|
|
19758
19805
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
19759
19806
|
});
|
|
19760
|
-
const tomlPath =
|
|
19807
|
+
const tomlPath = import_node_path16.default.join(this.deps.dataDir, "frpc.toml");
|
|
19761
19808
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto4.default.randomBytes(3).toString("hex")}`;
|
|
19762
19809
|
const toml = buildFrpcToml({
|
|
19763
19810
|
serverAddr: t.frpsHost,
|
|
@@ -19772,7 +19819,7 @@ var TunnelManager = class {
|
|
|
19772
19819
|
const proc = (this.deps.spawnImpl ?? import_node_child_process4.spawn)(frpcBin, ["-c", tomlPath], {
|
|
19773
19820
|
stdio: ["ignore", "pipe", "pipe"]
|
|
19774
19821
|
});
|
|
19775
|
-
const logFilePath =
|
|
19822
|
+
const logFilePath = import_node_path16.default.join(this.deps.dataDir, "frpc.log");
|
|
19776
19823
|
const logStream = import_node_fs15.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
19777
19824
|
logStream.on("error", () => {
|
|
19778
19825
|
});
|
|
@@ -19866,11 +19913,11 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
19866
19913
|
|
|
19867
19914
|
// src/auth-store.ts
|
|
19868
19915
|
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
19869
|
-
var
|
|
19916
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
19870
19917
|
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
19871
19918
|
var AUTH_FILE_NAME = "auth.json";
|
|
19872
19919
|
function authFilePath(dataDir) {
|
|
19873
|
-
return
|
|
19920
|
+
return import_node_path17.default.join(dataDir, AUTH_FILE_NAME);
|
|
19874
19921
|
}
|
|
19875
19922
|
function loadOrCreateAuthToken(opts) {
|
|
19876
19923
|
const file = authFilePath(opts.dataDir);
|
|
@@ -19902,7 +19949,7 @@ function readAuthFile(file) {
|
|
|
19902
19949
|
}
|
|
19903
19950
|
}
|
|
19904
19951
|
function writeAuthFile(file, content) {
|
|
19905
|
-
import_node_fs16.default.mkdirSync(
|
|
19952
|
+
import_node_fs16.default.mkdirSync(import_node_path17.default.dirname(file), { recursive: true });
|
|
19906
19953
|
import_node_fs16.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
19907
19954
|
try {
|
|
19908
19955
|
import_node_fs16.default.chmodSync(file, 384);
|
|
@@ -19913,11 +19960,11 @@ function writeAuthFile(file, content) {
|
|
|
19913
19960
|
// src/owner-profile.ts
|
|
19914
19961
|
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
19915
19962
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
19916
|
-
var
|
|
19963
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
19917
19964
|
var PROFILE_FILENAME = "profile.json";
|
|
19918
19965
|
function loadOwnerDisplayName(dataDir) {
|
|
19919
19966
|
const fallback = import_node_os10.default.userInfo().username;
|
|
19920
|
-
const profilePath =
|
|
19967
|
+
const profilePath = import_node_path18.default.join(dataDir, PROFILE_FILENAME);
|
|
19921
19968
|
let raw;
|
|
19922
19969
|
try {
|
|
19923
19970
|
raw = import_node_fs17.default.readFileSync(profilePath, "utf8");
|
|
@@ -19951,7 +19998,7 @@ init_protocol();
|
|
|
19951
19998
|
// src/session/fork.ts
|
|
19952
19999
|
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
19953
20000
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
19954
|
-
var
|
|
20001
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
19955
20002
|
init_claude_history();
|
|
19956
20003
|
function readJsonlEntries(file) {
|
|
19957
20004
|
const raw = import_node_fs18.default.readFileSync(file, "utf8");
|
|
@@ -19967,9 +20014,9 @@ function readJsonlEntries(file) {
|
|
|
19967
20014
|
return out;
|
|
19968
20015
|
}
|
|
19969
20016
|
function forkSession(input) {
|
|
19970
|
-
const baseDir = input.baseDir ??
|
|
19971
|
-
const projectDir =
|
|
19972
|
-
const sourceFile =
|
|
20017
|
+
const baseDir = input.baseDir ?? import_node_path19.default.join(import_node_os11.default.homedir(), ".claude");
|
|
20018
|
+
const projectDir = import_node_path19.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
20019
|
+
const sourceFile = import_node_path19.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
19973
20020
|
if (!import_node_fs18.default.existsSync(sourceFile)) {
|
|
19974
20021
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
19975
20022
|
}
|
|
@@ -20000,7 +20047,7 @@ function forkSession(input) {
|
|
|
20000
20047
|
}
|
|
20001
20048
|
forkedLines.push(JSON.stringify(forked));
|
|
20002
20049
|
}
|
|
20003
|
-
const forkedFilePath =
|
|
20050
|
+
const forkedFilePath = import_node_path19.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
20004
20051
|
import_node_fs18.default.mkdirSync(projectDir, { recursive: true });
|
|
20005
20052
|
import_node_fs18.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
20006
20053
|
return { forkedToolSessionId, forkedFilePath };
|
|
@@ -20292,7 +20339,7 @@ init_protocol();
|
|
|
20292
20339
|
var import_node_child_process5 = require("child_process");
|
|
20293
20340
|
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
20294
20341
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
20295
|
-
var
|
|
20342
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
20296
20343
|
var import_node_util = require("util");
|
|
20297
20344
|
var pexec = (0, import_node_util.promisify)(import_node_child_process5.execFile);
|
|
20298
20345
|
function formatChildProcessError(err) {
|
|
@@ -20307,7 +20354,7 @@ function formatChildProcessError(err) {
|
|
|
20307
20354
|
return e.message ?? "unknown error";
|
|
20308
20355
|
}
|
|
20309
20356
|
function normalizePath(p) {
|
|
20310
|
-
const resolved =
|
|
20357
|
+
const resolved = import_node_path20.default.resolve(p);
|
|
20311
20358
|
try {
|
|
20312
20359
|
return import_node_fs19.default.realpathSync(resolved);
|
|
20313
20360
|
} catch {
|
|
@@ -20410,13 +20457,13 @@ function flattenToDirName(branch) {
|
|
|
20410
20457
|
}
|
|
20411
20458
|
function encodeClaudeProjectDir(absPath) {
|
|
20412
20459
|
if (!absPath || typeof absPath !== "string") return "";
|
|
20413
|
-
let canonical =
|
|
20460
|
+
let canonical = import_node_path20.default.resolve(absPath);
|
|
20414
20461
|
try {
|
|
20415
20462
|
canonical = import_node_fs19.default.realpathSync(canonical);
|
|
20416
20463
|
} catch {
|
|
20417
20464
|
try {
|
|
20418
|
-
const parent = import_node_fs19.default.realpathSync(
|
|
20419
|
-
canonical =
|
|
20465
|
+
const parent = import_node_fs19.default.realpathSync(import_node_path20.default.dirname(canonical));
|
|
20466
|
+
canonical = import_node_path20.default.join(parent, import_node_path20.default.basename(canonical));
|
|
20420
20467
|
} catch {
|
|
20421
20468
|
}
|
|
20422
20469
|
}
|
|
@@ -20440,11 +20487,11 @@ async function createWorktree(input) {
|
|
|
20440
20487
|
if (!isGitRoot) {
|
|
20441
20488
|
throw new Error(`\u76EE\u5F55 ${cwd} \u4E0D\u662F git repo \u6839`);
|
|
20442
20489
|
}
|
|
20443
|
-
const parent =
|
|
20444
|
-
if (parent === "/" || parent ===
|
|
20490
|
+
const parent = import_node_path20.default.dirname(import_node_path20.default.resolve(cwd));
|
|
20491
|
+
if (parent === "/" || parent === import_node_path20.default.resolve(cwd)) {
|
|
20445
20492
|
throw new Error("repo \u5728\u78C1\u76D8\u6839\u76EE\u5F55\uFF0C\u65E0\u6CD5\u5728\u540C\u7EA7\u521B\u5EFA worktree");
|
|
20446
20493
|
}
|
|
20447
|
-
const worktreeRoot =
|
|
20494
|
+
const worktreeRoot = import_node_path20.default.join(parent, dirName);
|
|
20448
20495
|
try {
|
|
20449
20496
|
await pexec("git", ["-C", cwd, "fetch", "origin", baseBranch, "--no-tags"], {
|
|
20450
20497
|
timeout: 3e4
|
|
@@ -20491,8 +20538,8 @@ async function removeWorktree(input) {
|
|
|
20491
20538
|
);
|
|
20492
20539
|
const gitCommonDir = stdout.trim();
|
|
20493
20540
|
if (!gitCommonDir) throw new Error("empty git-common-dir");
|
|
20494
|
-
const absGitCommon =
|
|
20495
|
-
repoRoot =
|
|
20541
|
+
const absGitCommon = import_node_path20.default.isAbsolute(gitCommonDir) ? gitCommonDir : import_node_path20.default.resolve(worktreeRoot, gitCommonDir);
|
|
20542
|
+
repoRoot = import_node_path20.default.dirname(absGitCommon);
|
|
20496
20543
|
} catch {
|
|
20497
20544
|
repoRoot = null;
|
|
20498
20545
|
}
|
|
@@ -20523,9 +20570,9 @@ async function removeWorktree(input) {
|
|
|
20523
20570
|
try {
|
|
20524
20571
|
const encoded = encodeClaudeProjectDir(worktreeRoot);
|
|
20525
20572
|
if (encoded) {
|
|
20526
|
-
const projectsRoot =
|
|
20527
|
-
const target =
|
|
20528
|
-
if (target.startsWith(projectsRoot +
|
|
20573
|
+
const projectsRoot = import_node_path20.default.join(import_node_os12.default.homedir(), ".claude", "projects");
|
|
20574
|
+
const target = import_node_path20.default.resolve(projectsRoot, encoded);
|
|
20575
|
+
if (target.startsWith(projectsRoot + import_node_path20.default.sep) && target !== projectsRoot) {
|
|
20529
20576
|
import_node_fs19.default.rmSync(target, { recursive: true, force: true });
|
|
20530
20577
|
}
|
|
20531
20578
|
}
|
|
@@ -20694,7 +20741,7 @@ function buildPersonaHandlers(deps) {
|
|
|
20694
20741
|
};
|
|
20695
20742
|
const listSubSessions = async (frame) => {
|
|
20696
20743
|
const args = PersonaIdArgsSchema.parse(frame);
|
|
20697
|
-
const sessions = sessionManager.
|
|
20744
|
+
const sessions = sessionManager.listPersonaSessions(args.personaId, "listener");
|
|
20698
20745
|
return {
|
|
20699
20746
|
response: { type: "persona:subSessions", sessions }
|
|
20700
20747
|
};
|
|
@@ -20741,7 +20788,7 @@ function buildMethodHandlers(deps) {
|
|
|
20741
20788
|
async function startDaemon(config) {
|
|
20742
20789
|
const logger = createLogger({
|
|
20743
20790
|
level: config.logLevel,
|
|
20744
|
-
file:
|
|
20791
|
+
file: import_node_path21.default.join(config.dataDir, "clawd.log")
|
|
20745
20792
|
});
|
|
20746
20793
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
20747
20794
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -20777,7 +20824,7 @@ async function startDaemon(config) {
|
|
|
20777
20824
|
const agents = new AgentsScanner();
|
|
20778
20825
|
const history = new ClaudeHistoryReader();
|
|
20779
20826
|
let transport = null;
|
|
20780
|
-
const personaStore = new PersonaStore(
|
|
20827
|
+
const personaStore = new PersonaStore(import_node_path21.default.join(config.dataDir, "personas"));
|
|
20781
20828
|
const defaultsRoot = findDefaultsRoot();
|
|
20782
20829
|
if (defaultsRoot) {
|
|
20783
20830
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -20791,7 +20838,7 @@ async function startDaemon(config) {
|
|
|
20791
20838
|
getAdapter,
|
|
20792
20839
|
historyReader: history,
|
|
20793
20840
|
dataDir: config.dataDir,
|
|
20794
|
-
personaRoot:
|
|
20841
|
+
personaRoot: import_node_path21.default.join(config.dataDir, "personas"),
|
|
20795
20842
|
personaStore,
|
|
20796
20843
|
ownerDisplayName,
|
|
20797
20844
|
broadcastFrame: (frame, target) => {
|
|
@@ -20965,8 +21012,8 @@ async function startDaemon(config) {
|
|
|
20965
21012
|
const lines = [
|
|
20966
21013
|
`Tunnel: ${r.url}`,
|
|
20967
21014
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
20968
|
-
`Frpc config: ${
|
|
20969
|
-
`Frpc log: ${
|
|
21015
|
+
`Frpc config: ${import_node_path21.default.join(config.dataDir, "frpc.toml")}`,
|
|
21016
|
+
`Frpc log: ${import_node_path21.default.join(config.dataDir, "frpc.log")}`
|
|
20970
21017
|
];
|
|
20971
21018
|
const width = Math.max(...lines.map((l) => l.length));
|
|
20972
21019
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -20979,7 +21026,7 @@ ${bar}
|
|
|
20979
21026
|
|
|
20980
21027
|
`);
|
|
20981
21028
|
try {
|
|
20982
|
-
const connectPath =
|
|
21029
|
+
const connectPath = import_node_path21.default.join(config.dataDir, "connect.txt");
|
|
20983
21030
|
import_node_fs20.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
20984
21031
|
} catch {
|
|
20985
21032
|
}
|