@clawos-dev/clawd 0.2.47 → 0.2.48-beta.74.b742e0f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +389 -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 = [
|
|
@@ -17943,14 +17985,14 @@ var DEFAULT_PERSONAS = [
|
|
|
17943
17985
|
function findDefaultsRoot() {
|
|
17944
17986
|
const candidates = [];
|
|
17945
17987
|
try {
|
|
17946
|
-
const here =
|
|
17947
|
-
candidates.push(
|
|
17948
|
-
candidates.push(
|
|
17988
|
+
const here = path8.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
17989
|
+
candidates.push(path8.resolve(here, "defaults"));
|
|
17990
|
+
candidates.push(path8.resolve(here, "persona-defaults"));
|
|
17949
17991
|
} catch {
|
|
17950
17992
|
}
|
|
17951
17993
|
if (process.argv[1]) {
|
|
17952
|
-
const argvDir =
|
|
17953
|
-
candidates.push(
|
|
17994
|
+
const argvDir = path8.dirname(process.argv[1]);
|
|
17995
|
+
candidates.push(path8.resolve(argvDir, "persona-defaults"));
|
|
17954
17996
|
}
|
|
17955
17997
|
for (const c of candidates) {
|
|
17956
17998
|
try {
|
|
@@ -17967,7 +18009,7 @@ function seedDefaultPersonas(args) {
|
|
|
17967
18009
|
args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
|
|
17968
18010
|
continue;
|
|
17969
18011
|
}
|
|
17970
|
-
const bundleDir =
|
|
18012
|
+
const bundleDir = path8.join(args.defaultsRoot, entry.personaId);
|
|
17971
18013
|
if (!fs7.existsSync(bundleDir)) {
|
|
17972
18014
|
args.logger.warn("persona.seed.skip", {
|
|
17973
18015
|
personaId: entry.personaId,
|
|
@@ -17976,7 +18018,7 @@ function seedDefaultPersonas(args) {
|
|
|
17976
18018
|
});
|
|
17977
18019
|
continue;
|
|
17978
18020
|
}
|
|
17979
|
-
const claudeMdPath =
|
|
18021
|
+
const claudeMdPath = path8.join(bundleDir, "CLAUDE.md");
|
|
17980
18022
|
if (!fs7.existsSync(claudeMdPath)) {
|
|
17981
18023
|
args.logger.warn("persona.seed.skip", {
|
|
17982
18024
|
personaId: entry.personaId,
|
|
@@ -18005,8 +18047,8 @@ function seedDefaultPersonas(args) {
|
|
|
18005
18047
|
function copyBundleExtras(srcDir, dstDir) {
|
|
18006
18048
|
for (const entry of fs7.readdirSync(srcDir, { withFileTypes: true })) {
|
|
18007
18049
|
if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
|
|
18008
|
-
const srcPath =
|
|
18009
|
-
const dstPath =
|
|
18050
|
+
const srcPath = path8.join(srcDir, entry.name);
|
|
18051
|
+
const dstPath = path8.join(dstDir, entry.name);
|
|
18010
18052
|
if (entry.isDirectory()) {
|
|
18011
18053
|
fs7.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
|
|
18012
18054
|
} else if (entry.isFile()) {
|
|
@@ -18022,14 +18064,14 @@ init_claude_history();
|
|
|
18022
18064
|
// src/workspace/browser.ts
|
|
18023
18065
|
var import_node_fs8 = __toESM(require("fs"), 1);
|
|
18024
18066
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
18025
|
-
var
|
|
18067
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
18026
18068
|
init_protocol();
|
|
18027
18069
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
18028
18070
|
function resolveInsideCwd(cwd, subpath) {
|
|
18029
|
-
const absCwd =
|
|
18030
|
-
const joined =
|
|
18031
|
-
const rel =
|
|
18032
|
-
if (rel.startsWith("..") ||
|
|
18071
|
+
const absCwd = import_node_path9.default.resolve(cwd);
|
|
18072
|
+
const joined = import_node_path9.default.resolve(absCwd, subpath ?? ".");
|
|
18073
|
+
const rel = import_node_path9.default.relative(absCwd, joined);
|
|
18074
|
+
if (rel.startsWith("..") || import_node_path9.default.isAbsolute(rel)) {
|
|
18033
18075
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
18034
18076
|
}
|
|
18035
18077
|
return joined;
|
|
@@ -18060,7 +18102,7 @@ var WorkspaceBrowser = class {
|
|
|
18060
18102
|
mtime: ""
|
|
18061
18103
|
};
|
|
18062
18104
|
try {
|
|
18063
|
-
const st = import_node_fs8.default.statSync(
|
|
18105
|
+
const st = import_node_fs8.default.statSync(import_node_path9.default.join(full, d.name));
|
|
18064
18106
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
18065
18107
|
if (d.isFile()) entry.size = st.size;
|
|
18066
18108
|
} catch {
|
|
@@ -18107,7 +18149,7 @@ var WorkspaceBrowser = class {
|
|
|
18107
18149
|
// src/skills/scanner.ts
|
|
18108
18150
|
var import_node_fs9 = __toESM(require("fs"), 1);
|
|
18109
18151
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
18110
|
-
var
|
|
18152
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
18111
18153
|
|
|
18112
18154
|
// src/skills/frontmatter.ts
|
|
18113
18155
|
var STRIP_QUOTES = /^["']|["']$/g;
|
|
@@ -18229,14 +18271,14 @@ function scanSkillDir(dir, source, seen, out, pluginName) {
|
|
|
18229
18271
|
return;
|
|
18230
18272
|
}
|
|
18231
18273
|
for (const ent of entries) {
|
|
18232
|
-
const entryPath =
|
|
18274
|
+
const entryPath = import_node_path10.default.join(dir, ent.name);
|
|
18233
18275
|
if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
|
|
18234
18276
|
let content;
|
|
18235
18277
|
try {
|
|
18236
|
-
content = import_node_fs9.default.readFileSync(
|
|
18278
|
+
content = import_node_fs9.default.readFileSync(import_node_path10.default.join(entryPath, "SKILL.md"), "utf8");
|
|
18237
18279
|
} catch {
|
|
18238
18280
|
try {
|
|
18239
|
-
content = import_node_fs9.default.readFileSync(
|
|
18281
|
+
content = import_node_fs9.default.readFileSync(import_node_path10.default.join(entryPath, "skill.md"), "utf8");
|
|
18240
18282
|
} catch {
|
|
18241
18283
|
continue;
|
|
18242
18284
|
}
|
|
@@ -18259,7 +18301,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
18259
18301
|
return;
|
|
18260
18302
|
}
|
|
18261
18303
|
for (const ent of entries) {
|
|
18262
|
-
const entryPath =
|
|
18304
|
+
const entryPath = import_node_path10.default.join(dir, ent.name);
|
|
18263
18305
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
|
|
18264
18306
|
const ns = ent.name;
|
|
18265
18307
|
let subEntries;
|
|
@@ -18270,7 +18312,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
18270
18312
|
}
|
|
18271
18313
|
for (const se of subEntries) {
|
|
18272
18314
|
if (!se.name.endsWith(".md")) continue;
|
|
18273
|
-
const sePath =
|
|
18315
|
+
const sePath = import_node_path10.default.join(entryPath, se.name);
|
|
18274
18316
|
let content;
|
|
18275
18317
|
try {
|
|
18276
18318
|
content = import_node_fs9.default.readFileSync(sePath, "utf8");
|
|
@@ -18306,7 +18348,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
18306
18348
|
}
|
|
18307
18349
|
}
|
|
18308
18350
|
function readInstalledPlugins(home) {
|
|
18309
|
-
const file =
|
|
18351
|
+
const file = import_node_path10.default.join(home, ".claude", "plugins", "installed_plugins.json");
|
|
18310
18352
|
let raw;
|
|
18311
18353
|
try {
|
|
18312
18354
|
raw = import_node_fs9.default.readFileSync(file, "utf8");
|
|
@@ -18357,14 +18399,14 @@ var SkillsScanner = class {
|
|
|
18357
18399
|
});
|
|
18358
18400
|
}
|
|
18359
18401
|
const fsBlock = [];
|
|
18360
|
-
scanSkillDir(
|
|
18361
|
-
scanCommandDir(
|
|
18362
|
-
scanSkillDir(
|
|
18363
|
-
scanCommandDir(
|
|
18402
|
+
scanSkillDir(import_node_path10.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
|
|
18403
|
+
scanCommandDir(import_node_path10.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
|
|
18404
|
+
scanSkillDir(import_node_path10.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
|
|
18405
|
+
scanCommandDir(import_node_path10.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
|
|
18364
18406
|
const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
|
|
18365
18407
|
for (const { name, root } of plugins) {
|
|
18366
|
-
scanSkillDir(
|
|
18367
|
-
scanCommandDir(
|
|
18408
|
+
scanSkillDir(import_node_path10.default.join(root, "skills"), "plugin", seen, fsBlock, name);
|
|
18409
|
+
scanCommandDir(import_node_path10.default.join(root, "commands"), "plugin", seen, fsBlock, name);
|
|
18368
18410
|
}
|
|
18369
18411
|
fsBlock.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
18370
18412
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -18374,7 +18416,7 @@ var SkillsScanner = class {
|
|
|
18374
18416
|
// src/skills/agents-scanner.ts
|
|
18375
18417
|
var import_node_fs10 = __toESM(require("fs"), 1);
|
|
18376
18418
|
var import_node_os6 = __toESM(require("os"), 1);
|
|
18377
|
-
var
|
|
18419
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
18378
18420
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
18379
18421
|
function isDirLikeSync2(p) {
|
|
18380
18422
|
try {
|
|
@@ -18412,10 +18454,10 @@ function scanAgentsDir(dir, source, seen, out) {
|
|
|
18412
18454
|
}
|
|
18413
18455
|
for (const ent of entries) {
|
|
18414
18456
|
if (!ent.name.endsWith(".md")) continue;
|
|
18415
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
18457
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path11.default.join(dir, ent.name)))) {
|
|
18416
18458
|
continue;
|
|
18417
18459
|
}
|
|
18418
|
-
const filePath =
|
|
18460
|
+
const filePath = import_node_path11.default.join(dir, ent.name);
|
|
18419
18461
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
18420
18462
|
if (seen.has(baseName)) continue;
|
|
18421
18463
|
seen.add(baseName);
|
|
@@ -18438,7 +18480,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
18438
18480
|
return;
|
|
18439
18481
|
}
|
|
18440
18482
|
for (const ent of entries) {
|
|
18441
|
-
const childPath =
|
|
18483
|
+
const childPath = import_node_path11.default.join(dir, ent.name);
|
|
18442
18484
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
18443
18485
|
walk(childPath, [...namespaces, ent.name]);
|
|
18444
18486
|
continue;
|
|
@@ -18463,9 +18505,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
18463
18505
|
walk(root, []);
|
|
18464
18506
|
}
|
|
18465
18507
|
function readInstalledPlugins2(home) {
|
|
18466
|
-
const pluginsDir =
|
|
18467
|
-
const v2 =
|
|
18468
|
-
const v1 =
|
|
18508
|
+
const pluginsDir = import_node_path11.default.join(home, ".claude", "plugins");
|
|
18509
|
+
const v2 = import_node_path11.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
18510
|
+
const v1 = import_node_path11.default.join(pluginsDir, "installed_plugins.json");
|
|
18469
18511
|
let raw = null;
|
|
18470
18512
|
for (const candidate of [v2, v1]) {
|
|
18471
18513
|
try {
|
|
@@ -18494,19 +18536,19 @@ function readInstalledPlugins2(home) {
|
|
|
18494
18536
|
return out;
|
|
18495
18537
|
}
|
|
18496
18538
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
18497
|
-
let cur =
|
|
18498
|
-
const fsRoot =
|
|
18539
|
+
let cur = import_node_path11.default.resolve(startCwd);
|
|
18540
|
+
const fsRoot = import_node_path11.default.parse(cur).root;
|
|
18499
18541
|
while (true) {
|
|
18500
|
-
scanAgentsDir(
|
|
18542
|
+
scanAgentsDir(import_node_path11.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
18501
18543
|
let hasGit = false;
|
|
18502
18544
|
try {
|
|
18503
|
-
hasGit = import_node_fs10.default.existsSync(
|
|
18545
|
+
hasGit = import_node_fs10.default.existsSync(import_node_path11.default.join(cur, ".git"));
|
|
18504
18546
|
} catch {
|
|
18505
18547
|
}
|
|
18506
18548
|
if (hasGit) return;
|
|
18507
18549
|
if (cur === home) return;
|
|
18508
18550
|
if (cur === fsRoot) return;
|
|
18509
|
-
const parent =
|
|
18551
|
+
const parent = import_node_path11.default.dirname(cur);
|
|
18510
18552
|
if (parent === cur) return;
|
|
18511
18553
|
cur = parent;
|
|
18512
18554
|
}
|
|
@@ -18541,7 +18583,7 @@ var AgentsScanner = class {
|
|
|
18541
18583
|
}
|
|
18542
18584
|
const fsBlock = [];
|
|
18543
18585
|
scanAgentsDir(
|
|
18544
|
-
|
|
18586
|
+
import_node_path11.default.join(this.home, ".claude", "agents"),
|
|
18545
18587
|
"global",
|
|
18546
18588
|
seen,
|
|
18547
18589
|
fsBlock
|
|
@@ -18555,7 +18597,7 @@ var AgentsScanner = class {
|
|
|
18555
18597
|
...this.extraPluginRoots
|
|
18556
18598
|
];
|
|
18557
18599
|
for (const { name, root } of plugins) {
|
|
18558
|
-
const agentsRoot =
|
|
18600
|
+
const agentsRoot = import_node_path11.default.join(root, "agents");
|
|
18559
18601
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
18560
18602
|
}
|
|
18561
18603
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -18565,7 +18607,7 @@ var AgentsScanner = class {
|
|
|
18565
18607
|
// src/observer/session-observer.ts
|
|
18566
18608
|
var import_node_fs11 = __toESM(require("fs"), 1);
|
|
18567
18609
|
var import_node_os7 = __toESM(require("os"), 1);
|
|
18568
|
-
var
|
|
18610
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
18569
18611
|
init_claude_history();
|
|
18570
18612
|
var SessionObserver = class {
|
|
18571
18613
|
constructor(opts) {
|
|
@@ -18577,7 +18619,7 @@ var SessionObserver = class {
|
|
|
18577
18619
|
watches = /* @__PURE__ */ new Map();
|
|
18578
18620
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
18579
18621
|
if (override) return override;
|
|
18580
|
-
return
|
|
18622
|
+
return import_node_path12.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
18581
18623
|
}
|
|
18582
18624
|
start(args) {
|
|
18583
18625
|
this.stop(args.sessionId);
|
|
@@ -18597,10 +18639,10 @@ var SessionObserver = class {
|
|
|
18597
18639
|
adapter: args.adapter
|
|
18598
18640
|
};
|
|
18599
18641
|
try {
|
|
18600
|
-
import_node_fs11.default.mkdirSync(
|
|
18642
|
+
import_node_fs11.default.mkdirSync(import_node_path12.default.dirname(filePath), { recursive: true });
|
|
18601
18643
|
} catch {
|
|
18602
18644
|
}
|
|
18603
|
-
w.watcher = import_node_fs11.default.watch(
|
|
18645
|
+
w.watcher = import_node_fs11.default.watch(import_node_path12.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
18604
18646
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
18605
18647
|
this.poll(w);
|
|
18606
18648
|
});
|
|
@@ -19116,13 +19158,18 @@ var PersonaBoundHandler = class {
|
|
|
19116
19158
|
}
|
|
19117
19159
|
return true;
|
|
19118
19160
|
};
|
|
19161
|
+
const listenerScope = () => ({
|
|
19162
|
+
kind: "persona",
|
|
19163
|
+
personaId: scope.personaId,
|
|
19164
|
+
mode: "listener"
|
|
19165
|
+
});
|
|
19119
19166
|
switch (type) {
|
|
19120
19167
|
case "session:subscribe": {
|
|
19121
19168
|
if (!requireScopedSession()) return;
|
|
19122
19169
|
if (unsubscribe) unsubscribe();
|
|
19123
19170
|
unsubscribe = this.deps.sessionManager.subscribe(
|
|
19124
19171
|
scope.subSessionId,
|
|
19125
|
-
|
|
19172
|
+
listenerScope(),
|
|
19126
19173
|
(eventFrame) => send(eventFrame)
|
|
19127
19174
|
);
|
|
19128
19175
|
if (requestId)
|
|
@@ -19152,9 +19199,9 @@ var PersonaBoundHandler = class {
|
|
|
19152
19199
|
return;
|
|
19153
19200
|
}
|
|
19154
19201
|
try {
|
|
19155
|
-
this.deps.sessionManager.
|
|
19202
|
+
this.deps.sessionManager.sendForScope({
|
|
19156
19203
|
sessionId: scope.subSessionId,
|
|
19157
|
-
|
|
19204
|
+
scope: listenerScope(),
|
|
19158
19205
|
text
|
|
19159
19206
|
});
|
|
19160
19207
|
if (requestId) send({ type: "session:send", ok: true, requestId });
|
|
@@ -19167,9 +19214,9 @@ var PersonaBoundHandler = class {
|
|
|
19167
19214
|
case "session:new": {
|
|
19168
19215
|
if (!requireScopedSession()) return;
|
|
19169
19216
|
try {
|
|
19170
|
-
this.deps.sessionManager.
|
|
19217
|
+
this.deps.sessionManager.resetForScope({
|
|
19171
19218
|
sessionId: scope.subSessionId,
|
|
19172
|
-
|
|
19219
|
+
scope: listenerScope()
|
|
19173
19220
|
});
|
|
19174
19221
|
if (requestId) send({ type: "session:info", sessionId: scope.subSessionId, requestId });
|
|
19175
19222
|
} catch (err) {
|
|
@@ -19183,9 +19230,9 @@ var PersonaBoundHandler = class {
|
|
|
19183
19230
|
const limit = typeof frame.limit === "number" && frame.limit > 0 ? frame.limit : 50;
|
|
19184
19231
|
const offset = typeof frame.offset === "number" && frame.offset >= 0 ? frame.offset : 0;
|
|
19185
19232
|
try {
|
|
19186
|
-
const page = this.deps.sessionManager.
|
|
19233
|
+
const page = this.deps.sessionManager.readHistoryPageForScope(
|
|
19187
19234
|
scope.subSessionId,
|
|
19188
|
-
|
|
19235
|
+
listenerScope(),
|
|
19189
19236
|
limit,
|
|
19190
19237
|
offset
|
|
19191
19238
|
);
|
|
@@ -19316,9 +19363,9 @@ function isLocalhost(addr) {
|
|
|
19316
19363
|
|
|
19317
19364
|
// src/discovery/state-file.ts
|
|
19318
19365
|
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
19319
|
-
var
|
|
19366
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
19320
19367
|
function defaultStateFilePath(dataDir) {
|
|
19321
|
-
return
|
|
19368
|
+
return import_node_path13.default.join(dataDir, "state.json");
|
|
19322
19369
|
}
|
|
19323
19370
|
function isPidAlive(pid) {
|
|
19324
19371
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -19354,7 +19401,7 @@ var StateFileManager = class {
|
|
|
19354
19401
|
return { status: "stale", existing };
|
|
19355
19402
|
}
|
|
19356
19403
|
write(state) {
|
|
19357
|
-
import_node_fs12.default.mkdirSync(
|
|
19404
|
+
import_node_fs12.default.mkdirSync(import_node_path13.default.dirname(this.file), { recursive: true });
|
|
19358
19405
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
19359
19406
|
import_node_fs12.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
19360
19407
|
import_node_fs12.default.renameSync(tmp, this.file);
|
|
@@ -19375,13 +19422,13 @@ var StateFileManager = class {
|
|
|
19375
19422
|
|
|
19376
19423
|
// src/tunnel/tunnel-manager.ts
|
|
19377
19424
|
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
19378
|
-
var
|
|
19425
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
19379
19426
|
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
19380
19427
|
var import_node_child_process4 = require("child_process");
|
|
19381
19428
|
|
|
19382
19429
|
// src/tunnel/tunnel-store.ts
|
|
19383
19430
|
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
19384
|
-
var
|
|
19431
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
19385
19432
|
var TunnelStore = class {
|
|
19386
19433
|
constructor(filePath) {
|
|
19387
19434
|
this.filePath = filePath;
|
|
@@ -19400,7 +19447,7 @@ var TunnelStore = class {
|
|
|
19400
19447
|
}
|
|
19401
19448
|
}
|
|
19402
19449
|
async set(v) {
|
|
19403
|
-
const dir =
|
|
19450
|
+
const dir = import_node_path14.default.dirname(this.filePath);
|
|
19404
19451
|
await import_node_fs13.default.promises.mkdir(dir, { recursive: true });
|
|
19405
19452
|
const data = JSON.stringify(v, null, 2);
|
|
19406
19453
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
@@ -19512,7 +19559,7 @@ function escape(v) {
|
|
|
19512
19559
|
// src/tunnel/frpc-binary.ts
|
|
19513
19560
|
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
19514
19561
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
19515
|
-
var
|
|
19562
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
19516
19563
|
var import_node_child_process3 = require("child_process");
|
|
19517
19564
|
var import_node_stream = require("stream");
|
|
19518
19565
|
var import_promises = require("stream/promises");
|
|
@@ -19551,13 +19598,13 @@ async function ensureFrpcBinary(opts) {
|
|
|
19551
19598
|
}
|
|
19552
19599
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
19553
19600
|
const platform = opts.platform ?? detectPlatform();
|
|
19554
|
-
const binDir =
|
|
19601
|
+
const binDir = import_node_path15.default.join(opts.dataDir, "bin");
|
|
19555
19602
|
import_node_fs14.default.mkdirSync(binDir, { recursive: true });
|
|
19556
19603
|
cleanupStaleArtifacts(binDir);
|
|
19557
|
-
const stableBin =
|
|
19604
|
+
const stableBin = import_node_path15.default.join(binDir, "frpc");
|
|
19558
19605
|
if (import_node_fs14.default.existsSync(stableBin)) return stableBin;
|
|
19559
19606
|
const partialBin = `${stableBin}.partial`;
|
|
19560
|
-
const tarballPath =
|
|
19607
|
+
const tarballPath = import_node_path15.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
19561
19608
|
try {
|
|
19562
19609
|
const url = frpcDownloadUrl(version2, platform);
|
|
19563
19610
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -19583,7 +19630,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
19583
19630
|
}
|
|
19584
19631
|
for (const name of entries) {
|
|
19585
19632
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
19586
|
-
const full =
|
|
19633
|
+
const full = import_node_path15.default.join(binDir, name);
|
|
19587
19634
|
try {
|
|
19588
19635
|
import_node_fs14.default.rmSync(full, { recursive: true, force: true });
|
|
19589
19636
|
} catch {
|
|
@@ -19609,7 +19656,7 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
19609
19656
|
await (0, import_promises.pipeline)(nodeStream, out);
|
|
19610
19657
|
}
|
|
19611
19658
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
19612
|
-
const work =
|
|
19659
|
+
const work = import_node_path15.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
19613
19660
|
import_node_fs14.default.mkdirSync(work, { recursive: true });
|
|
19614
19661
|
try {
|
|
19615
19662
|
await new Promise((resolve2, reject) => {
|
|
@@ -19618,7 +19665,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
19618
19665
|
proc.on("exit", (code) => code === 0 ? resolve2() : reject(new Error(`tar exited ${code}`)));
|
|
19619
19666
|
});
|
|
19620
19667
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
19621
|
-
const src =
|
|
19668
|
+
const src = import_node_path15.default.join(work, dirName, "frpc");
|
|
19622
19669
|
if (!import_node_fs14.default.existsSync(src)) {
|
|
19623
19670
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
19624
19671
|
}
|
|
@@ -19633,7 +19680,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
19633
19680
|
var TunnelManager = class {
|
|
19634
19681
|
constructor(deps) {
|
|
19635
19682
|
this.deps = deps;
|
|
19636
|
-
this.store = deps.store ?? new TunnelStore(
|
|
19683
|
+
this.store = deps.store ?? new TunnelStore(import_node_path16.default.join(deps.dataDir, "tunnel.json"));
|
|
19637
19684
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
19638
19685
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
19639
19686
|
}
|
|
@@ -19750,7 +19797,7 @@ var TunnelManager = class {
|
|
|
19750
19797
|
dataDir: this.deps.dataDir,
|
|
19751
19798
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
19752
19799
|
});
|
|
19753
|
-
const tomlPath =
|
|
19800
|
+
const tomlPath = import_node_path16.default.join(this.deps.dataDir, "frpc.toml");
|
|
19754
19801
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto4.default.randomBytes(3).toString("hex")}`;
|
|
19755
19802
|
const toml = buildFrpcToml({
|
|
19756
19803
|
serverAddr: t.frpsHost,
|
|
@@ -19765,7 +19812,7 @@ var TunnelManager = class {
|
|
|
19765
19812
|
const proc = (this.deps.spawnImpl ?? import_node_child_process4.spawn)(frpcBin, ["-c", tomlPath], {
|
|
19766
19813
|
stdio: ["ignore", "pipe", "pipe"]
|
|
19767
19814
|
});
|
|
19768
|
-
const logFilePath =
|
|
19815
|
+
const logFilePath = import_node_path16.default.join(this.deps.dataDir, "frpc.log");
|
|
19769
19816
|
const logStream = import_node_fs15.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
19770
19817
|
logStream.on("error", () => {
|
|
19771
19818
|
});
|
|
@@ -19859,11 +19906,11 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
19859
19906
|
|
|
19860
19907
|
// src/auth-store.ts
|
|
19861
19908
|
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
19862
|
-
var
|
|
19909
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
19863
19910
|
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
19864
19911
|
var AUTH_FILE_NAME = "auth.json";
|
|
19865
19912
|
function authFilePath(dataDir) {
|
|
19866
|
-
return
|
|
19913
|
+
return import_node_path17.default.join(dataDir, AUTH_FILE_NAME);
|
|
19867
19914
|
}
|
|
19868
19915
|
function loadOrCreateAuthToken(opts) {
|
|
19869
19916
|
const file = authFilePath(opts.dataDir);
|
|
@@ -19895,7 +19942,7 @@ function readAuthFile(file) {
|
|
|
19895
19942
|
}
|
|
19896
19943
|
}
|
|
19897
19944
|
function writeAuthFile(file, content) {
|
|
19898
|
-
import_node_fs16.default.mkdirSync(
|
|
19945
|
+
import_node_fs16.default.mkdirSync(import_node_path17.default.dirname(file), { recursive: true });
|
|
19899
19946
|
import_node_fs16.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
19900
19947
|
try {
|
|
19901
19948
|
import_node_fs16.default.chmodSync(file, 384);
|
|
@@ -19906,11 +19953,11 @@ function writeAuthFile(file, content) {
|
|
|
19906
19953
|
// src/owner-profile.ts
|
|
19907
19954
|
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
19908
19955
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
19909
|
-
var
|
|
19956
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
19910
19957
|
var PROFILE_FILENAME = "profile.json";
|
|
19911
19958
|
function loadOwnerDisplayName(dataDir) {
|
|
19912
19959
|
const fallback = import_node_os10.default.userInfo().username;
|
|
19913
|
-
const profilePath =
|
|
19960
|
+
const profilePath = import_node_path18.default.join(dataDir, PROFILE_FILENAME);
|
|
19914
19961
|
let raw;
|
|
19915
19962
|
try {
|
|
19916
19963
|
raw = import_node_fs17.default.readFileSync(profilePath, "utf8");
|
|
@@ -19944,7 +19991,7 @@ init_protocol();
|
|
|
19944
19991
|
// src/session/fork.ts
|
|
19945
19992
|
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
19946
19993
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
19947
|
-
var
|
|
19994
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
19948
19995
|
init_claude_history();
|
|
19949
19996
|
function readJsonlEntries(file) {
|
|
19950
19997
|
const raw = import_node_fs18.default.readFileSync(file, "utf8");
|
|
@@ -19960,9 +20007,9 @@ function readJsonlEntries(file) {
|
|
|
19960
20007
|
return out;
|
|
19961
20008
|
}
|
|
19962
20009
|
function forkSession(input) {
|
|
19963
|
-
const baseDir = input.baseDir ??
|
|
19964
|
-
const projectDir =
|
|
19965
|
-
const sourceFile =
|
|
20010
|
+
const baseDir = input.baseDir ?? import_node_path19.default.join(import_node_os11.default.homedir(), ".claude");
|
|
20011
|
+
const projectDir = import_node_path19.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
20012
|
+
const sourceFile = import_node_path19.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
19966
20013
|
if (!import_node_fs18.default.existsSync(sourceFile)) {
|
|
19967
20014
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
19968
20015
|
}
|
|
@@ -19993,7 +20040,7 @@ function forkSession(input) {
|
|
|
19993
20040
|
}
|
|
19994
20041
|
forkedLines.push(JSON.stringify(forked));
|
|
19995
20042
|
}
|
|
19996
|
-
const forkedFilePath =
|
|
20043
|
+
const forkedFilePath = import_node_path19.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
19997
20044
|
import_node_fs18.default.mkdirSync(projectDir, { recursive: true });
|
|
19998
20045
|
import_node_fs18.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
19999
20046
|
return { forkedToolSessionId, forkedFilePath };
|
|
@@ -20285,7 +20332,7 @@ init_protocol();
|
|
|
20285
20332
|
var import_node_child_process5 = require("child_process");
|
|
20286
20333
|
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
20287
20334
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
20288
|
-
var
|
|
20335
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
20289
20336
|
var import_node_util = require("util");
|
|
20290
20337
|
var pexec = (0, import_node_util.promisify)(import_node_child_process5.execFile);
|
|
20291
20338
|
function formatChildProcessError(err) {
|
|
@@ -20300,7 +20347,7 @@ function formatChildProcessError(err) {
|
|
|
20300
20347
|
return e.message ?? "unknown error";
|
|
20301
20348
|
}
|
|
20302
20349
|
function normalizePath(p) {
|
|
20303
|
-
const resolved =
|
|
20350
|
+
const resolved = import_node_path20.default.resolve(p);
|
|
20304
20351
|
try {
|
|
20305
20352
|
return import_node_fs19.default.realpathSync(resolved);
|
|
20306
20353
|
} catch {
|
|
@@ -20403,13 +20450,13 @@ function flattenToDirName(branch) {
|
|
|
20403
20450
|
}
|
|
20404
20451
|
function encodeClaudeProjectDir(absPath) {
|
|
20405
20452
|
if (!absPath || typeof absPath !== "string") return "";
|
|
20406
|
-
let canonical =
|
|
20453
|
+
let canonical = import_node_path20.default.resolve(absPath);
|
|
20407
20454
|
try {
|
|
20408
20455
|
canonical = import_node_fs19.default.realpathSync(canonical);
|
|
20409
20456
|
} catch {
|
|
20410
20457
|
try {
|
|
20411
|
-
const parent = import_node_fs19.default.realpathSync(
|
|
20412
|
-
canonical =
|
|
20458
|
+
const parent = import_node_fs19.default.realpathSync(import_node_path20.default.dirname(canonical));
|
|
20459
|
+
canonical = import_node_path20.default.join(parent, import_node_path20.default.basename(canonical));
|
|
20413
20460
|
} catch {
|
|
20414
20461
|
}
|
|
20415
20462
|
}
|
|
@@ -20433,11 +20480,11 @@ async function createWorktree(input) {
|
|
|
20433
20480
|
if (!isGitRoot) {
|
|
20434
20481
|
throw new Error(`\u76EE\u5F55 ${cwd} \u4E0D\u662F git repo \u6839`);
|
|
20435
20482
|
}
|
|
20436
|
-
const parent =
|
|
20437
|
-
if (parent === "/" || parent ===
|
|
20483
|
+
const parent = import_node_path20.default.dirname(import_node_path20.default.resolve(cwd));
|
|
20484
|
+
if (parent === "/" || parent === import_node_path20.default.resolve(cwd)) {
|
|
20438
20485
|
throw new Error("repo \u5728\u78C1\u76D8\u6839\u76EE\u5F55\uFF0C\u65E0\u6CD5\u5728\u540C\u7EA7\u521B\u5EFA worktree");
|
|
20439
20486
|
}
|
|
20440
|
-
const worktreeRoot =
|
|
20487
|
+
const worktreeRoot = import_node_path20.default.join(parent, dirName);
|
|
20441
20488
|
try {
|
|
20442
20489
|
await pexec("git", ["-C", cwd, "fetch", "origin", baseBranch, "--no-tags"], {
|
|
20443
20490
|
timeout: 3e4
|
|
@@ -20484,8 +20531,8 @@ async function removeWorktree(input) {
|
|
|
20484
20531
|
);
|
|
20485
20532
|
const gitCommonDir = stdout.trim();
|
|
20486
20533
|
if (!gitCommonDir) throw new Error("empty git-common-dir");
|
|
20487
|
-
const absGitCommon =
|
|
20488
|
-
repoRoot =
|
|
20534
|
+
const absGitCommon = import_node_path20.default.isAbsolute(gitCommonDir) ? gitCommonDir : import_node_path20.default.resolve(worktreeRoot, gitCommonDir);
|
|
20535
|
+
repoRoot = import_node_path20.default.dirname(absGitCommon);
|
|
20489
20536
|
} catch {
|
|
20490
20537
|
repoRoot = null;
|
|
20491
20538
|
}
|
|
@@ -20516,9 +20563,9 @@ async function removeWorktree(input) {
|
|
|
20516
20563
|
try {
|
|
20517
20564
|
const encoded = encodeClaudeProjectDir(worktreeRoot);
|
|
20518
20565
|
if (encoded) {
|
|
20519
|
-
const projectsRoot =
|
|
20520
|
-
const target =
|
|
20521
|
-
if (target.startsWith(projectsRoot +
|
|
20566
|
+
const projectsRoot = import_node_path20.default.join(import_node_os12.default.homedir(), ".claude", "projects");
|
|
20567
|
+
const target = import_node_path20.default.resolve(projectsRoot, encoded);
|
|
20568
|
+
if (target.startsWith(projectsRoot + import_node_path20.default.sep) && target !== projectsRoot) {
|
|
20522
20569
|
import_node_fs19.default.rmSync(target, { recursive: true, force: true });
|
|
20523
20570
|
}
|
|
20524
20571
|
}
|
|
@@ -20687,7 +20734,7 @@ function buildPersonaHandlers(deps) {
|
|
|
20687
20734
|
};
|
|
20688
20735
|
const listSubSessions = async (frame) => {
|
|
20689
20736
|
const args = PersonaIdArgsSchema.parse(frame);
|
|
20690
|
-
const sessions = sessionManager.
|
|
20737
|
+
const sessions = sessionManager.listPersonaSessions(args.personaId, "listener");
|
|
20691
20738
|
return {
|
|
20692
20739
|
response: { type: "persona:subSessions", sessions }
|
|
20693
20740
|
};
|
|
@@ -20734,7 +20781,7 @@ function buildMethodHandlers(deps) {
|
|
|
20734
20781
|
async function startDaemon(config) {
|
|
20735
20782
|
const logger = createLogger({
|
|
20736
20783
|
level: config.logLevel,
|
|
20737
|
-
file:
|
|
20784
|
+
file: import_node_path21.default.join(config.dataDir, "clawd.log")
|
|
20738
20785
|
});
|
|
20739
20786
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
20740
20787
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -20770,7 +20817,7 @@ async function startDaemon(config) {
|
|
|
20770
20817
|
const agents = new AgentsScanner();
|
|
20771
20818
|
const history = new ClaudeHistoryReader();
|
|
20772
20819
|
let transport = null;
|
|
20773
|
-
const personaStore = new PersonaStore(
|
|
20820
|
+
const personaStore = new PersonaStore(import_node_path21.default.join(config.dataDir, "personas"));
|
|
20774
20821
|
const defaultsRoot = findDefaultsRoot();
|
|
20775
20822
|
if (defaultsRoot) {
|
|
20776
20823
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -20784,7 +20831,7 @@ async function startDaemon(config) {
|
|
|
20784
20831
|
getAdapter,
|
|
20785
20832
|
historyReader: history,
|
|
20786
20833
|
dataDir: config.dataDir,
|
|
20787
|
-
personaRoot:
|
|
20834
|
+
personaRoot: import_node_path21.default.join(config.dataDir, "personas"),
|
|
20788
20835
|
personaStore,
|
|
20789
20836
|
ownerDisplayName,
|
|
20790
20837
|
broadcastFrame: (frame, target) => {
|
|
@@ -20958,8 +21005,8 @@ async function startDaemon(config) {
|
|
|
20958
21005
|
const lines = [
|
|
20959
21006
|
`Tunnel: ${r.url}`,
|
|
20960
21007
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
20961
|
-
`Frpc config: ${
|
|
20962
|
-
`Frpc log: ${
|
|
21008
|
+
`Frpc config: ${import_node_path21.default.join(config.dataDir, "frpc.toml")}`,
|
|
21009
|
+
`Frpc log: ${import_node_path21.default.join(config.dataDir, "frpc.log")}`
|
|
20963
21010
|
];
|
|
20964
21011
|
const width = Math.max(...lines.map((l) => l.length));
|
|
20965
21012
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -20972,7 +21019,7 @@ ${bar}
|
|
|
20972
21019
|
|
|
20973
21020
|
`);
|
|
20974
21021
|
try {
|
|
20975
|
-
const connectPath =
|
|
21022
|
+
const connectPath = import_node_path21.default.join(config.dataDir, "connect.txt");
|
|
20976
21023
|
import_node_fs20.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
20977
21024
|
} catch {
|
|
20978
21025
|
}
|