@clawos-dev/clawd 0.2.53-beta.84.b617e1e → 0.2.53
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 +654 -436
- package/dist/persona-defaults/persona-clawd-helper/CLAUDE.md +129 -0
- package/dist/persona-defaults/persona-feishu-assistant/CLAUDE.md +177 -0
- package/dist/persona-defaults/persona-knowledge-base/CLAUDE.md +124 -0
- package/dist/persona-defaults/persona-researcher/CLAUDE.md +49 -0
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -597,8 +597,8 @@ var init_parseUtil = __esm({
|
|
|
597
597
|
init_errors2();
|
|
598
598
|
init_en();
|
|
599
599
|
makeIssue = (params) => {
|
|
600
|
-
const { data, path:
|
|
601
|
-
const fullPath = [...
|
|
600
|
+
const { data, path: path27, errorMaps, issueData } = params;
|
|
601
|
+
const fullPath = [...path27, ...issueData.path || []];
|
|
602
602
|
const fullIssue = {
|
|
603
603
|
...issueData,
|
|
604
604
|
path: fullPath
|
|
@@ -909,11 +909,11 @@ var init_types = __esm({
|
|
|
909
909
|
init_parseUtil();
|
|
910
910
|
init_util();
|
|
911
911
|
ParseInputLazyPath = class {
|
|
912
|
-
constructor(parent, value,
|
|
912
|
+
constructor(parent, value, path27, key) {
|
|
913
913
|
this._cachedPath = [];
|
|
914
914
|
this.parent = parent;
|
|
915
915
|
this.data = value;
|
|
916
|
-
this._path =
|
|
916
|
+
this._path = path27;
|
|
917
917
|
this._key = key;
|
|
918
918
|
}
|
|
919
919
|
get path() {
|
|
@@ -5223,8 +5223,8 @@ var require_req = __commonJS({
|
|
|
5223
5223
|
if (req.originalUrl) {
|
|
5224
5224
|
_req.url = req.originalUrl;
|
|
5225
5225
|
} else {
|
|
5226
|
-
const
|
|
5227
|
-
_req.url = typeof
|
|
5226
|
+
const path27 = req.path;
|
|
5227
|
+
_req.url = typeof path27 === "string" ? path27 : req.url ? req.url.path || req.url : void 0;
|
|
5228
5228
|
}
|
|
5229
5229
|
if (req.query) {
|
|
5230
5230
|
_req.query = req.query;
|
|
@@ -5389,14 +5389,14 @@ var require_redact = __commonJS({
|
|
|
5389
5389
|
}
|
|
5390
5390
|
return obj;
|
|
5391
5391
|
}
|
|
5392
|
-
function parsePath(
|
|
5392
|
+
function parsePath(path27) {
|
|
5393
5393
|
const parts = [];
|
|
5394
5394
|
let current = "";
|
|
5395
5395
|
let inBrackets = false;
|
|
5396
5396
|
let inQuotes = false;
|
|
5397
5397
|
let quoteChar = "";
|
|
5398
|
-
for (let i = 0; i <
|
|
5399
|
-
const char =
|
|
5398
|
+
for (let i = 0; i < path27.length; i++) {
|
|
5399
|
+
const char = path27[i];
|
|
5400
5400
|
if (!inBrackets && char === ".") {
|
|
5401
5401
|
if (current) {
|
|
5402
5402
|
parts.push(current);
|
|
@@ -5527,10 +5527,10 @@ var require_redact = __commonJS({
|
|
|
5527
5527
|
return current;
|
|
5528
5528
|
}
|
|
5529
5529
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
5530
|
-
for (const
|
|
5531
|
-
const parts = parsePath(
|
|
5530
|
+
for (const path27 of paths) {
|
|
5531
|
+
const parts = parsePath(path27);
|
|
5532
5532
|
if (parts.includes("*")) {
|
|
5533
|
-
redactWildcardPath(obj, parts, censor,
|
|
5533
|
+
redactWildcardPath(obj, parts, censor, path27, remove);
|
|
5534
5534
|
} else {
|
|
5535
5535
|
if (remove) {
|
|
5536
5536
|
removeKey(obj, parts);
|
|
@@ -5615,8 +5615,8 @@ var require_redact = __commonJS({
|
|
|
5615
5615
|
}
|
|
5616
5616
|
} else {
|
|
5617
5617
|
if (afterWildcard.includes("*")) {
|
|
5618
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
5619
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
5618
|
+
const wrappedCensor = typeof censor === "function" ? (value, path27) => {
|
|
5619
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path27];
|
|
5620
5620
|
return censor(value, fullPath);
|
|
5621
5621
|
} : censor;
|
|
5622
5622
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -5651,8 +5651,8 @@ var require_redact = __commonJS({
|
|
|
5651
5651
|
return null;
|
|
5652
5652
|
}
|
|
5653
5653
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
5654
|
-
for (const
|
|
5655
|
-
const parts = parsePath(
|
|
5654
|
+
for (const path27 of pathsToClone) {
|
|
5655
|
+
const parts = parsePath(path27);
|
|
5656
5656
|
let current = pathStructure;
|
|
5657
5657
|
for (let i = 0; i < parts.length; i++) {
|
|
5658
5658
|
const part = parts[i];
|
|
@@ -5704,24 +5704,24 @@ var require_redact = __commonJS({
|
|
|
5704
5704
|
}
|
|
5705
5705
|
return cloneSelectively(obj, pathStructure);
|
|
5706
5706
|
}
|
|
5707
|
-
function validatePath(
|
|
5708
|
-
if (typeof
|
|
5707
|
+
function validatePath(path27) {
|
|
5708
|
+
if (typeof path27 !== "string") {
|
|
5709
5709
|
throw new Error("Paths must be (non-empty) strings");
|
|
5710
5710
|
}
|
|
5711
|
-
if (
|
|
5711
|
+
if (path27 === "") {
|
|
5712
5712
|
throw new Error("Invalid redaction path ()");
|
|
5713
5713
|
}
|
|
5714
|
-
if (
|
|
5715
|
-
throw new Error(`Invalid redaction path (${
|
|
5714
|
+
if (path27.includes("..")) {
|
|
5715
|
+
throw new Error(`Invalid redaction path (${path27})`);
|
|
5716
5716
|
}
|
|
5717
|
-
if (
|
|
5718
|
-
throw new Error(`Invalid redaction path (${
|
|
5717
|
+
if (path27.includes(",")) {
|
|
5718
|
+
throw new Error(`Invalid redaction path (${path27})`);
|
|
5719
5719
|
}
|
|
5720
5720
|
let bracketCount = 0;
|
|
5721
5721
|
let inQuotes = false;
|
|
5722
5722
|
let quoteChar = "";
|
|
5723
|
-
for (let i = 0; i <
|
|
5724
|
-
const char =
|
|
5723
|
+
for (let i = 0; i < path27.length; i++) {
|
|
5724
|
+
const char = path27[i];
|
|
5725
5725
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
5726
5726
|
if (!inQuotes) {
|
|
5727
5727
|
inQuotes = true;
|
|
@@ -5735,20 +5735,20 @@ var require_redact = __commonJS({
|
|
|
5735
5735
|
} else if (char === "]" && !inQuotes) {
|
|
5736
5736
|
bracketCount--;
|
|
5737
5737
|
if (bracketCount < 0) {
|
|
5738
|
-
throw new Error(`Invalid redaction path (${
|
|
5738
|
+
throw new Error(`Invalid redaction path (${path27})`);
|
|
5739
5739
|
}
|
|
5740
5740
|
}
|
|
5741
5741
|
}
|
|
5742
5742
|
if (bracketCount !== 0) {
|
|
5743
|
-
throw new Error(`Invalid redaction path (${
|
|
5743
|
+
throw new Error(`Invalid redaction path (${path27})`);
|
|
5744
5744
|
}
|
|
5745
5745
|
}
|
|
5746
5746
|
function validatePaths(paths) {
|
|
5747
5747
|
if (!Array.isArray(paths)) {
|
|
5748
5748
|
throw new TypeError("paths must be an array");
|
|
5749
5749
|
}
|
|
5750
|
-
for (const
|
|
5751
|
-
validatePath(
|
|
5750
|
+
for (const path27 of paths) {
|
|
5751
|
+
validatePath(path27);
|
|
5752
5752
|
}
|
|
5753
5753
|
}
|
|
5754
5754
|
function slowRedact(options = {}) {
|
|
@@ -5916,8 +5916,8 @@ var require_redaction = __commonJS({
|
|
|
5916
5916
|
if (shape[k] === null) {
|
|
5917
5917
|
o[k] = (value) => topCensor(value, [k]);
|
|
5918
5918
|
} else {
|
|
5919
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
5920
|
-
return censor(value, [k, ...
|
|
5919
|
+
const wrappedCensor = typeof censor === "function" ? (value, path27) => {
|
|
5920
|
+
return censor(value, [k, ...path27]);
|
|
5921
5921
|
} : censor;
|
|
5922
5922
|
o[k] = Redact({
|
|
5923
5923
|
paths: shape[k],
|
|
@@ -6135,10 +6135,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
6135
6135
|
var require_sonic_boom = __commonJS({
|
|
6136
6136
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
6137
6137
|
"use strict";
|
|
6138
|
-
var
|
|
6138
|
+
var fs25 = require("fs");
|
|
6139
6139
|
var EventEmitter2 = require("events");
|
|
6140
6140
|
var inherits = require("util").inherits;
|
|
6141
|
-
var
|
|
6141
|
+
var path27 = require("path");
|
|
6142
6142
|
var sleep = require_atomic_sleep();
|
|
6143
6143
|
var assert = require("assert");
|
|
6144
6144
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -6192,20 +6192,20 @@ var require_sonic_boom = __commonJS({
|
|
|
6192
6192
|
const mode = sonic.mode;
|
|
6193
6193
|
if (sonic.sync) {
|
|
6194
6194
|
try {
|
|
6195
|
-
if (sonic.mkdir)
|
|
6196
|
-
const fd =
|
|
6195
|
+
if (sonic.mkdir) fs25.mkdirSync(path27.dirname(file), { recursive: true });
|
|
6196
|
+
const fd = fs25.openSync(file, flags, mode);
|
|
6197
6197
|
fileOpened(null, fd);
|
|
6198
6198
|
} catch (err) {
|
|
6199
6199
|
fileOpened(err);
|
|
6200
6200
|
throw err;
|
|
6201
6201
|
}
|
|
6202
6202
|
} else if (sonic.mkdir) {
|
|
6203
|
-
|
|
6203
|
+
fs25.mkdir(path27.dirname(file), { recursive: true }, (err) => {
|
|
6204
6204
|
if (err) return fileOpened(err);
|
|
6205
|
-
|
|
6205
|
+
fs25.open(file, flags, mode, fileOpened);
|
|
6206
6206
|
});
|
|
6207
6207
|
} else {
|
|
6208
|
-
|
|
6208
|
+
fs25.open(file, flags, mode, fileOpened);
|
|
6209
6209
|
}
|
|
6210
6210
|
}
|
|
6211
6211
|
function SonicBoom(opts) {
|
|
@@ -6246,8 +6246,8 @@ var require_sonic_boom = __commonJS({
|
|
|
6246
6246
|
this.flush = flushBuffer;
|
|
6247
6247
|
this.flushSync = flushBufferSync;
|
|
6248
6248
|
this._actualWrite = actualWriteBuffer;
|
|
6249
|
-
fsWriteSync = () =>
|
|
6250
|
-
fsWrite = () =>
|
|
6249
|
+
fsWriteSync = () => fs25.writeSync(this.fd, this._writingBuf);
|
|
6250
|
+
fsWrite = () => fs25.write(this.fd, this._writingBuf, this.release);
|
|
6251
6251
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
6252
6252
|
this._writingBuf = "";
|
|
6253
6253
|
this.write = write;
|
|
@@ -6256,15 +6256,15 @@ var require_sonic_boom = __commonJS({
|
|
|
6256
6256
|
this._actualWrite = actualWrite;
|
|
6257
6257
|
fsWriteSync = () => {
|
|
6258
6258
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6259
|
-
return
|
|
6259
|
+
return fs25.writeSync(this.fd, this._writingBuf);
|
|
6260
6260
|
}
|
|
6261
|
-
return
|
|
6261
|
+
return fs25.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6262
6262
|
};
|
|
6263
6263
|
fsWrite = () => {
|
|
6264
6264
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
6265
|
-
return
|
|
6265
|
+
return fs25.write(this.fd, this._writingBuf, this.release);
|
|
6266
6266
|
}
|
|
6267
|
-
return
|
|
6267
|
+
return fs25.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
6268
6268
|
};
|
|
6269
6269
|
} else {
|
|
6270
6270
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -6321,7 +6321,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6321
6321
|
}
|
|
6322
6322
|
}
|
|
6323
6323
|
if (this._fsync) {
|
|
6324
|
-
|
|
6324
|
+
fs25.fsyncSync(this.fd);
|
|
6325
6325
|
}
|
|
6326
6326
|
const len = this._len;
|
|
6327
6327
|
if (this._reopening) {
|
|
@@ -6435,7 +6435,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6435
6435
|
const onDrain = () => {
|
|
6436
6436
|
if (!this._fsync) {
|
|
6437
6437
|
try {
|
|
6438
|
-
|
|
6438
|
+
fs25.fsync(this.fd, (err) => {
|
|
6439
6439
|
this._flushPending = false;
|
|
6440
6440
|
cb(err);
|
|
6441
6441
|
});
|
|
@@ -6537,7 +6537,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6537
6537
|
const fd = this.fd;
|
|
6538
6538
|
this.once("ready", () => {
|
|
6539
6539
|
if (fd !== this.fd) {
|
|
6540
|
-
|
|
6540
|
+
fs25.close(fd, (err) => {
|
|
6541
6541
|
if (err) {
|
|
6542
6542
|
return this.emit("error", err);
|
|
6543
6543
|
}
|
|
@@ -6586,7 +6586,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6586
6586
|
buf = this._bufs[0];
|
|
6587
6587
|
}
|
|
6588
6588
|
try {
|
|
6589
|
-
const n = Buffer.isBuffer(buf) ?
|
|
6589
|
+
const n = Buffer.isBuffer(buf) ? fs25.writeSync(this.fd, buf) : fs25.writeSync(this.fd, buf, "utf8");
|
|
6590
6590
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
6591
6591
|
buf = releasedBufObj.writingBuf;
|
|
6592
6592
|
this._len = releasedBufObj.len;
|
|
@@ -6602,7 +6602,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6602
6602
|
}
|
|
6603
6603
|
}
|
|
6604
6604
|
try {
|
|
6605
|
-
|
|
6605
|
+
fs25.fsyncSync(this.fd);
|
|
6606
6606
|
} catch {
|
|
6607
6607
|
}
|
|
6608
6608
|
}
|
|
@@ -6623,7 +6623,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6623
6623
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
6624
6624
|
}
|
|
6625
6625
|
try {
|
|
6626
|
-
const n =
|
|
6626
|
+
const n = fs25.writeSync(this.fd, buf);
|
|
6627
6627
|
buf = buf.subarray(n);
|
|
6628
6628
|
this._len = Math.max(this._len - n, 0);
|
|
6629
6629
|
if (buf.length <= 0) {
|
|
@@ -6651,13 +6651,13 @@ var require_sonic_boom = __commonJS({
|
|
|
6651
6651
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
6652
6652
|
if (this.sync) {
|
|
6653
6653
|
try {
|
|
6654
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
6654
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs25.writeSync(this.fd, this._writingBuf) : fs25.writeSync(this.fd, this._writingBuf, "utf8");
|
|
6655
6655
|
release(null, written);
|
|
6656
6656
|
} catch (err) {
|
|
6657
6657
|
release(err);
|
|
6658
6658
|
}
|
|
6659
6659
|
} else {
|
|
6660
|
-
|
|
6660
|
+
fs25.write(this.fd, this._writingBuf, release);
|
|
6661
6661
|
}
|
|
6662
6662
|
}
|
|
6663
6663
|
function actualWriteBuffer() {
|
|
@@ -6666,7 +6666,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6666
6666
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
6667
6667
|
if (this.sync) {
|
|
6668
6668
|
try {
|
|
6669
|
-
const written =
|
|
6669
|
+
const written = fs25.writeSync(this.fd, this._writingBuf);
|
|
6670
6670
|
release(null, written);
|
|
6671
6671
|
} catch (err) {
|
|
6672
6672
|
release(err);
|
|
@@ -6675,7 +6675,7 @@ var require_sonic_boom = __commonJS({
|
|
|
6675
6675
|
if (kCopyBuffer) {
|
|
6676
6676
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
6677
6677
|
}
|
|
6678
|
-
|
|
6678
|
+
fs25.write(this.fd, this._writingBuf, release);
|
|
6679
6679
|
}
|
|
6680
6680
|
}
|
|
6681
6681
|
function actualClose(sonic) {
|
|
@@ -6691,12 +6691,12 @@ var require_sonic_boom = __commonJS({
|
|
|
6691
6691
|
sonic._lens = [];
|
|
6692
6692
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
6693
6693
|
try {
|
|
6694
|
-
|
|
6694
|
+
fs25.fsync(sonic.fd, closeWrapped);
|
|
6695
6695
|
} catch {
|
|
6696
6696
|
}
|
|
6697
6697
|
function closeWrapped() {
|
|
6698
6698
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
6699
|
-
|
|
6699
|
+
fs25.close(sonic.fd, done);
|
|
6700
6700
|
} else {
|
|
6701
6701
|
done();
|
|
6702
6702
|
}
|
|
@@ -6953,7 +6953,7 @@ var require_thread_stream = __commonJS({
|
|
|
6953
6953
|
var { version: version2 } = require_package();
|
|
6954
6954
|
var { EventEmitter: EventEmitter2 } = require("events");
|
|
6955
6955
|
var { Worker } = require("worker_threads");
|
|
6956
|
-
var { join:
|
|
6956
|
+
var { join: join4 } = require("path");
|
|
6957
6957
|
var { pathToFileURL } = require("url");
|
|
6958
6958
|
var { wait } = require_wait();
|
|
6959
6959
|
var {
|
|
@@ -6989,7 +6989,7 @@ var require_thread_stream = __commonJS({
|
|
|
6989
6989
|
function createWorker(stream, opts) {
|
|
6990
6990
|
const { filename, workerData } = opts;
|
|
6991
6991
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
6992
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
6992
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join4(__dirname, "lib", "worker.js");
|
|
6993
6993
|
const worker = new Worker(toExecute, {
|
|
6994
6994
|
...opts.workerOpts,
|
|
6995
6995
|
trackUnmanagedFds: false,
|
|
@@ -7375,7 +7375,7 @@ var require_transport = __commonJS({
|
|
|
7375
7375
|
"use strict";
|
|
7376
7376
|
var { createRequire } = require("module");
|
|
7377
7377
|
var getCallers = require_caller();
|
|
7378
|
-
var { join:
|
|
7378
|
+
var { join: join4, isAbsolute, sep } = require("path");
|
|
7379
7379
|
var sleep = require_atomic_sleep();
|
|
7380
7380
|
var onExit = require_on_exit_leak_free();
|
|
7381
7381
|
var ThreadStream = require_thread_stream();
|
|
@@ -7438,7 +7438,7 @@ var require_transport = __commonJS({
|
|
|
7438
7438
|
throw new Error("only one of target or targets can be specified");
|
|
7439
7439
|
}
|
|
7440
7440
|
if (targets) {
|
|
7441
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
7441
|
+
target = bundlerOverrides["pino-worker"] || join4(__dirname, "worker.js");
|
|
7442
7442
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
7443
7443
|
return {
|
|
7444
7444
|
...dest,
|
|
@@ -7456,7 +7456,7 @@ var require_transport = __commonJS({
|
|
|
7456
7456
|
});
|
|
7457
7457
|
});
|
|
7458
7458
|
} else if (pipeline2) {
|
|
7459
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
7459
|
+
target = bundlerOverrides["pino-worker"] || join4(__dirname, "worker.js");
|
|
7460
7460
|
options.pipelines = [pipeline2.map((dest) => {
|
|
7461
7461
|
return {
|
|
7462
7462
|
...dest,
|
|
@@ -7478,7 +7478,7 @@ var require_transport = __commonJS({
|
|
|
7478
7478
|
return origin;
|
|
7479
7479
|
}
|
|
7480
7480
|
if (origin === "pino/file") {
|
|
7481
|
-
return
|
|
7481
|
+
return join4(__dirname, "..", "file.js");
|
|
7482
7482
|
}
|
|
7483
7483
|
let fixTarget2;
|
|
7484
7484
|
for (const filePath of callers) {
|
|
@@ -8468,7 +8468,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
8468
8468
|
return circularValue;
|
|
8469
8469
|
}
|
|
8470
8470
|
let res = "";
|
|
8471
|
-
let
|
|
8471
|
+
let join4 = ",";
|
|
8472
8472
|
const originalIndentation = indentation;
|
|
8473
8473
|
if (Array.isArray(value)) {
|
|
8474
8474
|
if (value.length === 0) {
|
|
@@ -8482,7 +8482,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
8482
8482
|
indentation += spacer;
|
|
8483
8483
|
res += `
|
|
8484
8484
|
${indentation}`;
|
|
8485
|
-
|
|
8485
|
+
join4 = `,
|
|
8486
8486
|
${indentation}`;
|
|
8487
8487
|
}
|
|
8488
8488
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -8490,13 +8490,13 @@ ${indentation}`;
|
|
|
8490
8490
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
8491
8491
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
8492
8492
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
8493
|
-
res +=
|
|
8493
|
+
res += join4;
|
|
8494
8494
|
}
|
|
8495
8495
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
8496
8496
|
res += tmp !== void 0 ? tmp : "null";
|
|
8497
8497
|
if (value.length - 1 > maximumBreadth) {
|
|
8498
8498
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
8499
|
-
res += `${
|
|
8499
|
+
res += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
8500
8500
|
}
|
|
8501
8501
|
if (spacer !== "") {
|
|
8502
8502
|
res += `
|
|
@@ -8517,7 +8517,7 @@ ${originalIndentation}`;
|
|
|
8517
8517
|
let separator = "";
|
|
8518
8518
|
if (spacer !== "") {
|
|
8519
8519
|
indentation += spacer;
|
|
8520
|
-
|
|
8520
|
+
join4 = `,
|
|
8521
8521
|
${indentation}`;
|
|
8522
8522
|
whitespace = " ";
|
|
8523
8523
|
}
|
|
@@ -8531,13 +8531,13 @@ ${indentation}`;
|
|
|
8531
8531
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
8532
8532
|
if (tmp !== void 0) {
|
|
8533
8533
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
8534
|
-
separator =
|
|
8534
|
+
separator = join4;
|
|
8535
8535
|
}
|
|
8536
8536
|
}
|
|
8537
8537
|
if (keyLength > maximumBreadth) {
|
|
8538
8538
|
const removedKeys = keyLength - maximumBreadth;
|
|
8539
8539
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
8540
|
-
separator =
|
|
8540
|
+
separator = join4;
|
|
8541
8541
|
}
|
|
8542
8542
|
if (spacer !== "" && separator.length > 1) {
|
|
8543
8543
|
res = `
|
|
@@ -8578,7 +8578,7 @@ ${originalIndentation}`;
|
|
|
8578
8578
|
}
|
|
8579
8579
|
const originalIndentation = indentation;
|
|
8580
8580
|
let res = "";
|
|
8581
|
-
let
|
|
8581
|
+
let join4 = ",";
|
|
8582
8582
|
if (Array.isArray(value)) {
|
|
8583
8583
|
if (value.length === 0) {
|
|
8584
8584
|
return "[]";
|
|
@@ -8591,7 +8591,7 @@ ${originalIndentation}`;
|
|
|
8591
8591
|
indentation += spacer;
|
|
8592
8592
|
res += `
|
|
8593
8593
|
${indentation}`;
|
|
8594
|
-
|
|
8594
|
+
join4 = `,
|
|
8595
8595
|
${indentation}`;
|
|
8596
8596
|
}
|
|
8597
8597
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -8599,13 +8599,13 @@ ${indentation}`;
|
|
|
8599
8599
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
8600
8600
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
8601
8601
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
8602
|
-
res +=
|
|
8602
|
+
res += join4;
|
|
8603
8603
|
}
|
|
8604
8604
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
8605
8605
|
res += tmp !== void 0 ? tmp : "null";
|
|
8606
8606
|
if (value.length - 1 > maximumBreadth) {
|
|
8607
8607
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
8608
|
-
res += `${
|
|
8608
|
+
res += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
8609
8609
|
}
|
|
8610
8610
|
if (spacer !== "") {
|
|
8611
8611
|
res += `
|
|
@@ -8618,7 +8618,7 @@ ${originalIndentation}`;
|
|
|
8618
8618
|
let whitespace = "";
|
|
8619
8619
|
if (spacer !== "") {
|
|
8620
8620
|
indentation += spacer;
|
|
8621
|
-
|
|
8621
|
+
join4 = `,
|
|
8622
8622
|
${indentation}`;
|
|
8623
8623
|
whitespace = " ";
|
|
8624
8624
|
}
|
|
@@ -8627,7 +8627,7 @@ ${indentation}`;
|
|
|
8627
8627
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
8628
8628
|
if (tmp !== void 0) {
|
|
8629
8629
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
8630
|
-
separator =
|
|
8630
|
+
separator = join4;
|
|
8631
8631
|
}
|
|
8632
8632
|
}
|
|
8633
8633
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -8685,20 +8685,20 @@ ${originalIndentation}`;
|
|
|
8685
8685
|
indentation += spacer;
|
|
8686
8686
|
let res2 = `
|
|
8687
8687
|
${indentation}`;
|
|
8688
|
-
const
|
|
8688
|
+
const join5 = `,
|
|
8689
8689
|
${indentation}`;
|
|
8690
8690
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
8691
8691
|
let i = 0;
|
|
8692
8692
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
8693
8693
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
8694
8694
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
8695
|
-
res2 +=
|
|
8695
|
+
res2 += join5;
|
|
8696
8696
|
}
|
|
8697
8697
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
8698
8698
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
8699
8699
|
if (value.length - 1 > maximumBreadth) {
|
|
8700
8700
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
8701
|
-
res2 += `${
|
|
8701
|
+
res2 += `${join5}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
8702
8702
|
}
|
|
8703
8703
|
res2 += `
|
|
8704
8704
|
${originalIndentation}`;
|
|
@@ -8714,16 +8714,16 @@ ${originalIndentation}`;
|
|
|
8714
8714
|
return '"[Object]"';
|
|
8715
8715
|
}
|
|
8716
8716
|
indentation += spacer;
|
|
8717
|
-
const
|
|
8717
|
+
const join4 = `,
|
|
8718
8718
|
${indentation}`;
|
|
8719
8719
|
let res = "";
|
|
8720
8720
|
let separator = "";
|
|
8721
8721
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
8722
8722
|
if (isTypedArrayWithEntries(value)) {
|
|
8723
|
-
res += stringifyTypedArray(value,
|
|
8723
|
+
res += stringifyTypedArray(value, join4, maximumBreadth);
|
|
8724
8724
|
keys = keys.slice(value.length);
|
|
8725
8725
|
maximumPropertiesToStringify -= value.length;
|
|
8726
|
-
separator =
|
|
8726
|
+
separator = join4;
|
|
8727
8727
|
}
|
|
8728
8728
|
if (deterministic) {
|
|
8729
8729
|
keys = sort(keys, comparator);
|
|
@@ -8734,13 +8734,13 @@ ${indentation}`;
|
|
|
8734
8734
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
8735
8735
|
if (tmp !== void 0) {
|
|
8736
8736
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
8737
|
-
separator =
|
|
8737
|
+
separator = join4;
|
|
8738
8738
|
}
|
|
8739
8739
|
}
|
|
8740
8740
|
if (keyLength > maximumBreadth) {
|
|
8741
8741
|
const removedKeys = keyLength - maximumBreadth;
|
|
8742
8742
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
8743
|
-
separator =
|
|
8743
|
+
separator = join4;
|
|
8744
8744
|
}
|
|
8745
8745
|
if (separator !== "") {
|
|
8746
8746
|
res = `
|
|
@@ -9060,7 +9060,7 @@ var require_multistream = __commonJS({
|
|
|
9060
9060
|
var require_pino = __commonJS({
|
|
9061
9061
|
"../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
|
|
9062
9062
|
"use strict";
|
|
9063
|
-
var
|
|
9063
|
+
var os16 = require("os");
|
|
9064
9064
|
var stdSerializers = require_pino_std_serializers();
|
|
9065
9065
|
var caller = require_caller();
|
|
9066
9066
|
var redaction = require_redaction();
|
|
@@ -9107,7 +9107,7 @@ var require_pino = __commonJS({
|
|
|
9107
9107
|
} = symbols;
|
|
9108
9108
|
var { epochTime, nullTime } = time;
|
|
9109
9109
|
var { pid } = process;
|
|
9110
|
-
var hostname =
|
|
9110
|
+
var hostname = os16.hostname();
|
|
9111
9111
|
var defaultErrorSerializer = stdSerializers.err;
|
|
9112
9112
|
var defaultOptions = {
|
|
9113
9113
|
level: "info",
|
|
@@ -9831,11 +9831,11 @@ var init_lib = __esm({
|
|
|
9831
9831
|
}
|
|
9832
9832
|
}
|
|
9833
9833
|
},
|
|
9834
|
-
addToPath: function addToPath(
|
|
9835
|
-
var last =
|
|
9834
|
+
addToPath: function addToPath(path27, added, removed, oldPosInc, options) {
|
|
9835
|
+
var last = path27.lastComponent;
|
|
9836
9836
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
9837
9837
|
return {
|
|
9838
|
-
oldPos:
|
|
9838
|
+
oldPos: path27.oldPos + oldPosInc,
|
|
9839
9839
|
lastComponent: {
|
|
9840
9840
|
count: last.count + 1,
|
|
9841
9841
|
added,
|
|
@@ -9845,7 +9845,7 @@ var init_lib = __esm({
|
|
|
9845
9845
|
};
|
|
9846
9846
|
} else {
|
|
9847
9847
|
return {
|
|
9848
|
-
oldPos:
|
|
9848
|
+
oldPos: path27.oldPos + oldPosInc,
|
|
9849
9849
|
lastComponent: {
|
|
9850
9850
|
count: 1,
|
|
9851
9851
|
added,
|
|
@@ -9903,7 +9903,7 @@ var init_lib = __esm({
|
|
|
9903
9903
|
tokenize: function tokenize(value) {
|
|
9904
9904
|
return Array.from(value);
|
|
9905
9905
|
},
|
|
9906
|
-
join: function
|
|
9906
|
+
join: function join3(chars) {
|
|
9907
9907
|
return chars.join("");
|
|
9908
9908
|
},
|
|
9909
9909
|
postProcess: function postProcess(changeObjects) {
|
|
@@ -10276,10 +10276,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
10276
10276
|
const memories = raw.map((m) => {
|
|
10277
10277
|
if (!m || typeof m !== "object") return null;
|
|
10278
10278
|
const rec = m;
|
|
10279
|
-
const
|
|
10279
|
+
const path27 = typeof rec.path === "string" ? rec.path : null;
|
|
10280
10280
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
10281
|
-
if (!
|
|
10282
|
-
const entry = { path:
|
|
10281
|
+
if (!path27 || content == null) return null;
|
|
10282
|
+
const entry = { path: path27, content };
|
|
10283
10283
|
if (typeof rec.mtimeMs === "number") entry.mtimeMs = rec.mtimeMs;
|
|
10284
10284
|
return entry;
|
|
10285
10285
|
}).filter((m) => m !== null);
|
|
@@ -10316,7 +10316,7 @@ function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
|
|
|
10316
10316
|
if (backupFileName === null) return null;
|
|
10317
10317
|
try {
|
|
10318
10318
|
return import_node_fs6.default.readFileSync(
|
|
10319
|
-
|
|
10319
|
+
import_node_path7.default.join(fileHistoryRoot, toolSessionId, backupFileName),
|
|
10320
10320
|
"utf8"
|
|
10321
10321
|
);
|
|
10322
10322
|
} catch {
|
|
@@ -10331,13 +10331,13 @@ function readCurrentContent(filePath) {
|
|
|
10331
10331
|
return null;
|
|
10332
10332
|
}
|
|
10333
10333
|
}
|
|
10334
|
-
var import_node_fs6, import_node_os2,
|
|
10334
|
+
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;
|
|
10335
10335
|
var init_claude_history = __esm({
|
|
10336
10336
|
"src/tools/claude-history.ts"() {
|
|
10337
10337
|
"use strict";
|
|
10338
10338
|
import_node_fs6 = __toESM(require("fs"), 1);
|
|
10339
10339
|
import_node_os2 = __toESM(require("os"), 1);
|
|
10340
|
-
|
|
10340
|
+
import_node_path7 = __toESM(require("path"), 1);
|
|
10341
10341
|
init_lib();
|
|
10342
10342
|
init_tool_result_extra();
|
|
10343
10343
|
TASK_NOTIFICATION_RE = /<task-notification\b[\s\S]*?<\/task-notification>/i;
|
|
@@ -10361,9 +10361,9 @@ var init_claude_history = __esm({
|
|
|
10361
10361
|
// 每次 user 提交前 trackEdit 拷一份,作为 rewind 回退目标
|
|
10362
10362
|
fileHistoryRoot;
|
|
10363
10363
|
constructor(opts = {}) {
|
|
10364
|
-
const base = opts.baseDir ??
|
|
10365
|
-
this.projectsRoot =
|
|
10366
|
-
this.fileHistoryRoot =
|
|
10364
|
+
const base = opts.baseDir ?? import_node_path7.default.join(import_node_os2.default.homedir(), ".claude");
|
|
10365
|
+
this.projectsRoot = import_node_path7.default.join(base, "projects");
|
|
10366
|
+
this.fileHistoryRoot = import_node_path7.default.join(base, "file-history");
|
|
10367
10367
|
}
|
|
10368
10368
|
async listProjects() {
|
|
10369
10369
|
let entries;
|
|
@@ -10376,9 +10376,9 @@ var init_claude_history = __esm({
|
|
|
10376
10376
|
const out = [];
|
|
10377
10377
|
for (const ent of entries) {
|
|
10378
10378
|
if (!ent.isDirectory()) continue;
|
|
10379
|
-
const dir =
|
|
10379
|
+
const dir = import_node_path7.default.join(this.projectsRoot, ent.name);
|
|
10380
10380
|
const files = import_node_fs6.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
10381
|
-
const updatedAtMs = files.reduce((m, f) => Math.max(m, safeStatMtime(
|
|
10381
|
+
const updatedAtMs = files.reduce((m, f) => Math.max(m, safeStatMtime(import_node_path7.default.join(dir, f))), 0);
|
|
10382
10382
|
out.push({
|
|
10383
10383
|
projectPath: hashDirToCwd(ent.name),
|
|
10384
10384
|
hashDir: ent.name,
|
|
@@ -10390,7 +10390,7 @@ var init_claude_history = __esm({
|
|
|
10390
10390
|
return out;
|
|
10391
10391
|
}
|
|
10392
10392
|
async listSessions(args) {
|
|
10393
|
-
const dir =
|
|
10393
|
+
const dir = import_node_path7.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
|
|
10394
10394
|
let files;
|
|
10395
10395
|
try {
|
|
10396
10396
|
files = import_node_fs6.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
@@ -10400,7 +10400,7 @@ var init_claude_history = __esm({
|
|
|
10400
10400
|
}
|
|
10401
10401
|
const out = [];
|
|
10402
10402
|
for (const f of files) {
|
|
10403
|
-
const full =
|
|
10403
|
+
const full = import_node_path7.default.join(dir, f);
|
|
10404
10404
|
const toolSessionId = f.slice(0, -".jsonl".length);
|
|
10405
10405
|
const lines = readJsonlLines(full);
|
|
10406
10406
|
let summary = "";
|
|
@@ -10455,7 +10455,7 @@ var init_claude_history = __esm({
|
|
|
10455
10455
|
return out;
|
|
10456
10456
|
}
|
|
10457
10457
|
async read(args) {
|
|
10458
|
-
const file =
|
|
10458
|
+
const file = import_node_path7.default.join(
|
|
10459
10459
|
this.projectsRoot,
|
|
10460
10460
|
cwdToHashDir(args.cwd),
|
|
10461
10461
|
`${args.toolSessionId}.jsonl`
|
|
@@ -10488,7 +10488,7 @@ var init_claude_history = __esm({
|
|
|
10488
10488
|
// 独立目录路径:<projectsRoot>/<cwdHash>/<toolSessionId>/subagents/*.jsonl
|
|
10489
10489
|
// 返回 null 表示目录不存在(调用方回退旧实现);返回空数组表示目录存在但无 jsonl
|
|
10490
10490
|
listSubagentsFromDirectory(cwd, toolSessionId) {
|
|
10491
|
-
const dir =
|
|
10491
|
+
const dir = import_node_path7.default.join(
|
|
10492
10492
|
this.projectsRoot,
|
|
10493
10493
|
cwdToHashDir(cwd),
|
|
10494
10494
|
toolSessionId,
|
|
@@ -10506,7 +10506,7 @@ var init_claude_history = __esm({
|
|
|
10506
10506
|
if (!e.isFile()) continue;
|
|
10507
10507
|
if (!e.name.startsWith("agent-") || !e.name.endsWith(".jsonl")) continue;
|
|
10508
10508
|
const subagentId = e.name.slice("agent-".length, -".jsonl".length);
|
|
10509
|
-
const filePath =
|
|
10509
|
+
const filePath = import_node_path7.default.join(dir, e.name);
|
|
10510
10510
|
const lines = readJsonlLines(filePath);
|
|
10511
10511
|
let firstText = "";
|
|
10512
10512
|
let messageCount = 0;
|
|
@@ -10523,7 +10523,7 @@ var init_claude_history = __esm({
|
|
|
10523
10523
|
return out;
|
|
10524
10524
|
}
|
|
10525
10525
|
listSubagentsFromMainJsonl(cwd, toolSessionId) {
|
|
10526
|
-
const file =
|
|
10526
|
+
const file = import_node_path7.default.join(
|
|
10527
10527
|
this.projectsRoot,
|
|
10528
10528
|
cwdToHashDir(cwd),
|
|
10529
10529
|
`${toolSessionId}.jsonl`
|
|
@@ -10558,7 +10558,7 @@ var init_claude_history = __esm({
|
|
|
10558
10558
|
}
|
|
10559
10559
|
// 独立文件路径:agent-<subagentId>.jsonl;文件不存在返回 null 让调用方回退旧实现
|
|
10560
10560
|
readSubagentFromFile(cwd, toolSessionId, subagentId) {
|
|
10561
|
-
const file =
|
|
10561
|
+
const file = import_node_path7.default.join(
|
|
10562
10562
|
this.projectsRoot,
|
|
10563
10563
|
cwdToHashDir(cwd),
|
|
10564
10564
|
toolSessionId,
|
|
@@ -10586,7 +10586,7 @@ var init_claude_history = __esm({
|
|
|
10586
10586
|
* "那一刻每个 tracked 文件对应的 backup 文件名"
|
|
10587
10587
|
*/
|
|
10588
10588
|
readFileHistorySnapshots(args) {
|
|
10589
|
-
const file =
|
|
10589
|
+
const file = import_node_path7.default.join(
|
|
10590
10590
|
this.projectsRoot,
|
|
10591
10591
|
cwdToHashDir(args.cwd),
|
|
10592
10592
|
`${args.toolSessionId}.jsonl`
|
|
@@ -10631,7 +10631,7 @@ var init_claude_history = __esm({
|
|
|
10631
10631
|
for (const [anchorId, target] of snapshots) {
|
|
10632
10632
|
let hasAny = false;
|
|
10633
10633
|
for (const [rawPath, backup] of Object.entries(target)) {
|
|
10634
|
-
const absPath =
|
|
10634
|
+
const absPath = import_node_path7.default.isAbsolute(rawPath) ? rawPath : import_node_path7.default.join(args.cwd, rawPath);
|
|
10635
10635
|
const backupContent = readBackupContent(
|
|
10636
10636
|
this.fileHistoryRoot,
|
|
10637
10637
|
args.toolSessionId,
|
|
@@ -10671,7 +10671,7 @@ var init_claude_history = __esm({
|
|
|
10671
10671
|
let totalInsertions = 0;
|
|
10672
10672
|
let totalDeletions = 0;
|
|
10673
10673
|
for (const [rawPath, backup] of Object.entries(target)) {
|
|
10674
|
-
const absPath =
|
|
10674
|
+
const absPath = import_node_path7.default.isAbsolute(rawPath) ? rawPath : import_node_path7.default.join(args.cwd, rawPath);
|
|
10675
10675
|
const backupContent = readBackupContent(
|
|
10676
10676
|
this.fileHistoryRoot,
|
|
10677
10677
|
args.toolSessionId,
|
|
@@ -10718,7 +10718,7 @@ var init_claude_history = __esm({
|
|
|
10718
10718
|
};
|
|
10719
10719
|
}
|
|
10720
10720
|
readSubagentFromMainJsonl(cwd, toolSessionId, subagentId) {
|
|
10721
|
-
const file =
|
|
10721
|
+
const file = import_node_path7.default.join(
|
|
10722
10722
|
this.projectsRoot,
|
|
10723
10723
|
cwdToHashDir(cwd),
|
|
10724
10724
|
`${toolSessionId}.jsonl`
|
|
@@ -10742,7 +10742,7 @@ var init_claude_history = __esm({
|
|
|
10742
10742
|
// src/tools/claude.ts
|
|
10743
10743
|
function macOSDesktopCandidates(home) {
|
|
10744
10744
|
return [
|
|
10745
|
-
|
|
10745
|
+
import_node_path8.default.join(home, "Applications", "Claude.app", "Contents", "Resources", "app.asar.unpacked", "node_modules", "@anthropic-ai", "claude-code", "cli.js"),
|
|
10746
10746
|
"/Applications/Claude.app/Contents/Resources/app.asar.unpacked/node_modules/@anthropic-ai/claude-code/cli.js"
|
|
10747
10747
|
];
|
|
10748
10748
|
}
|
|
@@ -10804,6 +10804,7 @@ function buildSpawnArgs(ctx) {
|
|
|
10804
10804
|
}
|
|
10805
10805
|
}
|
|
10806
10806
|
if (ctx.extraSettings) args.push("--settings", ctx.extraSettings);
|
|
10807
|
+
if (ctx.extraSystemPrompt) args.push("--append-system-prompt", ctx.extraSystemPrompt);
|
|
10807
10808
|
if (ctx.effort) args.push("--effort", ctx.effort);
|
|
10808
10809
|
if (ctx.toolSessionId) args.push("--resume", ctx.toolSessionId);
|
|
10809
10810
|
return args;
|
|
@@ -11082,10 +11083,10 @@ function parseAttachment(obj) {
|
|
|
11082
11083
|
const memories = raw.map((m) => {
|
|
11083
11084
|
if (!m || typeof m !== "object") return null;
|
|
11084
11085
|
const rec = m;
|
|
11085
|
-
const
|
|
11086
|
+
const path27 = typeof rec.path === "string" ? rec.path : null;
|
|
11086
11087
|
const content = typeof rec.content === "string" ? rec.content : null;
|
|
11087
|
-
if (!
|
|
11088
|
-
const out = { path:
|
|
11088
|
+
if (!path27 || content == null) return null;
|
|
11089
|
+
const out = { path: path27, content };
|
|
11089
11090
|
if (typeof rec.mtimeMs === "number") out.mtimeMs = rec.mtimeMs;
|
|
11090
11091
|
return out;
|
|
11091
11092
|
}).filter((m) => m !== null);
|
|
@@ -11189,7 +11190,7 @@ function encodeClaudeStdin(text) {
|
|
|
11189
11190
|
};
|
|
11190
11191
|
return JSON.stringify(frame) + "\n";
|
|
11191
11192
|
}
|
|
11192
|
-
var import_node_child_process, import_node_child_process2, import_node_fs7, import_node_os3,
|
|
11193
|
+
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;
|
|
11193
11194
|
var init_claude = __esm({
|
|
11194
11195
|
"src/tools/claude.ts"() {
|
|
11195
11196
|
"use strict";
|
|
@@ -11197,7 +11198,7 @@ var init_claude = __esm({
|
|
|
11197
11198
|
import_node_child_process2 = require("child_process");
|
|
11198
11199
|
import_node_fs7 = __toESM(require("fs"), 1);
|
|
11199
11200
|
import_node_os3 = __toESM(require("os"), 1);
|
|
11200
|
-
|
|
11201
|
+
import_node_path8 = __toESM(require("path"), 1);
|
|
11201
11202
|
init_protocol();
|
|
11202
11203
|
init_claude_history();
|
|
11203
11204
|
init_tool_result_extra();
|
|
@@ -20456,22 +20457,22 @@ var require_websocket_server = __commonJS({
|
|
|
20456
20457
|
// src/run-case/recorder.ts
|
|
20457
20458
|
function startRunCaseRecorder(opts) {
|
|
20458
20459
|
const now = opts.now ?? Date.now;
|
|
20459
|
-
const dir =
|
|
20460
|
+
const dir = import_node_path23.default.dirname(opts.recordPath);
|
|
20460
20461
|
let stream = null;
|
|
20461
20462
|
let closing = false;
|
|
20462
20463
|
let closedSettled = false;
|
|
20463
20464
|
let closedResolve;
|
|
20464
|
-
const closed = new Promise((
|
|
20465
|
+
const closed = new Promise((resolve2) => {
|
|
20465
20466
|
closedResolve = () => {
|
|
20466
20467
|
if (closedSettled) return;
|
|
20467
20468
|
closedSettled = true;
|
|
20468
|
-
|
|
20469
|
+
resolve2();
|
|
20469
20470
|
};
|
|
20470
20471
|
});
|
|
20471
20472
|
const ensureStream = () => {
|
|
20472
20473
|
if (stream) return stream;
|
|
20473
|
-
|
|
20474
|
-
stream =
|
|
20474
|
+
import_node_fs22.default.mkdirSync(dir, { recursive: true });
|
|
20475
|
+
stream = import_node_fs22.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
20475
20476
|
stream.on("close", () => closedResolve());
|
|
20476
20477
|
return stream;
|
|
20477
20478
|
};
|
|
@@ -20496,12 +20497,12 @@ function startRunCaseRecorder(opts) {
|
|
|
20496
20497
|
};
|
|
20497
20498
|
return { tap, close, closed };
|
|
20498
20499
|
}
|
|
20499
|
-
var
|
|
20500
|
+
var import_node_fs22, import_node_path23;
|
|
20500
20501
|
var init_recorder = __esm({
|
|
20501
20502
|
"src/run-case/recorder.ts"() {
|
|
20502
20503
|
"use strict";
|
|
20503
|
-
|
|
20504
|
-
|
|
20504
|
+
import_node_fs22 = __toESM(require("fs"), 1);
|
|
20505
|
+
import_node_path23 = __toESM(require("path"), 1);
|
|
20505
20506
|
}
|
|
20506
20507
|
});
|
|
20507
20508
|
|
|
@@ -20544,7 +20545,7 @@ var init_wire = __esm({
|
|
|
20544
20545
|
// src/run-case/controller.ts
|
|
20545
20546
|
async function runController(opts) {
|
|
20546
20547
|
const now = opts.now ?? Date.now;
|
|
20547
|
-
const cwd = opts.cwd ?? (0,
|
|
20548
|
+
const cwd = opts.cwd ?? (0, import_node_fs23.mkdtempSync)(import_node_path24.default.join(import_node_os15.default.tmpdir(), "clawd-runcase-"));
|
|
20548
20549
|
const ownsCwd = opts.cwd === void 0;
|
|
20549
20550
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
20550
20551
|
const spawnCtx = { cwd };
|
|
@@ -20557,8 +20558,8 @@ async function runController(opts) {
|
|
|
20557
20558
|
let exitCode = null;
|
|
20558
20559
|
let procExited = false;
|
|
20559
20560
|
let resolveProcExit;
|
|
20560
|
-
const procExitPromise = new Promise((
|
|
20561
|
-
resolveProcExit =
|
|
20561
|
+
const procExitPromise = new Promise((resolve2) => {
|
|
20562
|
+
resolveProcExit = resolve2;
|
|
20562
20563
|
});
|
|
20563
20564
|
const writeEvent = (event) => {
|
|
20564
20565
|
try {
|
|
@@ -20705,19 +20706,19 @@ async function runController(opts) {
|
|
|
20705
20706
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
20706
20707
|
if (ownsCwd) {
|
|
20707
20708
|
try {
|
|
20708
|
-
(0,
|
|
20709
|
+
(0, import_node_fs23.rmSync)(cwd, { recursive: true, force: true });
|
|
20709
20710
|
} catch {
|
|
20710
20711
|
}
|
|
20711
20712
|
}
|
|
20712
20713
|
return exitCode ?? 0;
|
|
20713
20714
|
}
|
|
20714
|
-
var
|
|
20715
|
+
var import_node_fs23, import_node_os15, import_node_path24;
|
|
20715
20716
|
var init_controller = __esm({
|
|
20716
20717
|
"src/run-case/controller.ts"() {
|
|
20717
20718
|
"use strict";
|
|
20718
|
-
|
|
20719
|
-
|
|
20720
|
-
|
|
20719
|
+
import_node_fs23 = require("fs");
|
|
20720
|
+
import_node_os15 = __toESM(require("os"), 1);
|
|
20721
|
+
import_node_path24 = __toESM(require("path"), 1);
|
|
20721
20722
|
init_claude();
|
|
20722
20723
|
init_stdout_splitter();
|
|
20723
20724
|
init_permission_stdio();
|
|
@@ -20949,8 +20950,8 @@ Env (advanced):
|
|
|
20949
20950
|
`;
|
|
20950
20951
|
|
|
20951
20952
|
// src/index.ts
|
|
20952
|
-
var
|
|
20953
|
-
var
|
|
20953
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
20954
|
+
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
20954
20955
|
|
|
20955
20956
|
// src/logger.ts
|
|
20956
20957
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
@@ -20989,9 +20990,30 @@ function createLogger(opts = {}) {
|
|
|
20989
20990
|
|
|
20990
20991
|
// src/session/store.ts
|
|
20991
20992
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
20992
|
-
var
|
|
20993
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
20993
20994
|
init_protocol();
|
|
20994
|
-
|
|
20995
|
+
|
|
20996
|
+
// src/session/scope.ts
|
|
20997
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
20998
|
+
function scopeKey(scope) {
|
|
20999
|
+
return scope.kind === "default" ? "default" : `persona:${scope.personaId}:${scope.mode}`;
|
|
21000
|
+
}
|
|
21001
|
+
function scopeSubPath(scope) {
|
|
21002
|
+
return scope.kind === "default" ? ["default"] : [scope.personaId, scope.mode];
|
|
21003
|
+
}
|
|
21004
|
+
function metaFromScope(scope, personaRoot) {
|
|
21005
|
+
if (scope.kind === "default") return void 0;
|
|
21006
|
+
if (scope.mode === "owner") {
|
|
21007
|
+
return { idleKillEnabled: false, personaMode: "owner" };
|
|
21008
|
+
}
|
|
21009
|
+
return {
|
|
21010
|
+
idleKillEnabled: true,
|
|
21011
|
+
personaMode: "listener",
|
|
21012
|
+
extraSettings: import_node_path3.default.join(personaRoot, scope.personaId, ".clawd", "sandbox-settings.json")
|
|
21013
|
+
};
|
|
21014
|
+
}
|
|
21015
|
+
|
|
21016
|
+
// src/session/store.ts
|
|
20995
21017
|
function safeFileName(sessionId) {
|
|
20996
21018
|
const base = sessionId.replace(/[^a-zA-Z0-9_\-.]/g, "_");
|
|
20997
21019
|
const cleaned = base.replace(/^\.+/, (dots) => "_".repeat(dots.length));
|
|
@@ -21003,20 +21025,15 @@ function safeFileName(sessionId) {
|
|
|
21003
21025
|
var SessionStore = class {
|
|
21004
21026
|
root;
|
|
21005
21027
|
constructor(opts) {
|
|
21006
|
-
const
|
|
21007
|
-
|
|
21008
|
-
|
|
21009
|
-
|
|
21010
|
-
|
|
21011
|
-
|
|
21012
|
-
}
|
|
21013
|
-
this.root = import_node_path3.default.join(opts.personaRoot, safeFileName(agentId), ".clawd", "sub-sessions");
|
|
21014
|
-
} else {
|
|
21015
|
-
this.root = import_node_path3.default.join(opts.dataDir, "sessions", agentId);
|
|
21016
|
-
}
|
|
21028
|
+
const scope = opts.scope ?? { kind: "default" };
|
|
21029
|
+
this.root = import_node_path4.default.join(
|
|
21030
|
+
opts.dataDir,
|
|
21031
|
+
"sessions",
|
|
21032
|
+
...scopeSubPath(scope).map(safeFileName)
|
|
21033
|
+
);
|
|
21017
21034
|
}
|
|
21018
21035
|
filePath(sessionId) {
|
|
21019
|
-
return
|
|
21036
|
+
return import_node_path4.default.join(this.root, `${safeFileName(sessionId)}.json`);
|
|
21020
21037
|
}
|
|
21021
21038
|
ensureDir() {
|
|
21022
21039
|
import_node_fs3.default.mkdirSync(this.root, { recursive: true });
|
|
@@ -21064,7 +21081,7 @@ var SessionStore = class {
|
|
|
21064
21081
|
for (const name of entries) {
|
|
21065
21082
|
if (!name.endsWith(".json")) continue;
|
|
21066
21083
|
if (name.includes(".tmp-")) continue;
|
|
21067
|
-
const full =
|
|
21084
|
+
const full = import_node_path4.default.join(this.root, name);
|
|
21068
21085
|
try {
|
|
21069
21086
|
const raw = import_node_fs3.default.readFileSync(full, "utf8");
|
|
21070
21087
|
const parsed = JSON.parse(raw);
|
|
@@ -21080,7 +21097,7 @@ var SessionStore = class {
|
|
|
21080
21097
|
|
|
21081
21098
|
// src/session/manager.ts
|
|
21082
21099
|
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
21083
|
-
var
|
|
21100
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
21084
21101
|
|
|
21085
21102
|
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
21086
21103
|
var byteToHex = [];
|
|
@@ -21167,6 +21184,20 @@ function buildRule(tool, input) {
|
|
|
21167
21184
|
|
|
21168
21185
|
// src/session/reducer.ts
|
|
21169
21186
|
init_permission_stdio();
|
|
21187
|
+
|
|
21188
|
+
// src/persona/connection-prompt.ts
|
|
21189
|
+
var OWNER_TEMPLATE = `# \u8FDE\u63A5\u4E0A\u4E0B\u6587
|
|
21190
|
+
\u4F60\u73B0\u5728\u4EE5 Owner \u8EAB\u4EFD\u88AB\u8FDE\u63A5\uFF0C\u5BF9\u65B9\u5C31\u662F owner \u672C\u4EBA\uFF08{ownerLabel}\uFF09\u3002
|
|
21191
|
+
\u81EA\u6211\u4ECB\u7ECD\u65F6\u4F7F\u7528\u7B2C\u4E00/\u7B2C\u4E8C\u4EBA\u79F0\uFF0C\u4F8B\u5982\u300C\u6211\u662F\u60A8\u7684 xxx \u52A9\u624B\u300D\u3002`;
|
|
21192
|
+
var LISTENER_TEMPLATE = `# \u8FDE\u63A5\u4E0A\u4E0B\u6587
|
|
21193
|
+
\u4F60\u73B0\u5728\u4EE5 Listener \u8EAB\u4EFD\u88AB\u8FDE\u63A5\uFF0C\u672C persona \u7684 owner \u662F\u300C{ownerLabel}\u300D\uFF0C\u4F46\u5F53\u524D\u5BF9\u8BDD\u7684\u5BF9\u65B9\u4E0D\u662F owner \u672C\u4EBA\u3002
|
|
21194
|
+
\u81EA\u6211\u4ECB\u7ECD\u65F6\u4F7F\u7528\u7B2C\u4E09\u4EBA\u79F0\u6307\u4EE3 owner\uFF0C\u4F8B\u5982\u300C\u6211\u662F {ownerLabel} \u7684 xxx \u52A9\u624B\uFF0C\u4F60\u53EF\u4EE5\u901A\u8FC7\u6211\u770B\u5230\u4ED6\u7684 xxx\u300D\u3002\u4E0D\u8981\u628A\u5BF9\u65B9\u5F53\u6210 owner\uFF0C\u4E0D\u8981\u66FF owner \u505A\u51FA\u627F\u8BFA\u3002`;
|
|
21195
|
+
function buildConnectionPrompt(args) {
|
|
21196
|
+
const template = args.mode === "owner" ? OWNER_TEMPLATE : LISTENER_TEMPLATE;
|
|
21197
|
+
return template.replace(/\{ownerLabel\}/g, args.ownerLabel);
|
|
21198
|
+
}
|
|
21199
|
+
|
|
21200
|
+
// src/session/reducer.ts
|
|
21170
21201
|
function cloneState(s) {
|
|
21171
21202
|
return {
|
|
21172
21203
|
file: s.file,
|
|
@@ -21216,7 +21247,7 @@ function emitSessionEvent(sessionId, event, target) {
|
|
|
21216
21247
|
};
|
|
21217
21248
|
return target ? { kind: "emit-frame", frame, target } : { kind: "emit-frame", frame };
|
|
21218
21249
|
}
|
|
21219
|
-
function buildSpawnContext(state) {
|
|
21250
|
+
function buildSpawnContext(state, deps) {
|
|
21220
21251
|
const file = state.file;
|
|
21221
21252
|
const ctx = {
|
|
21222
21253
|
cwd: file.cwd,
|
|
@@ -21228,6 +21259,10 @@ function buildSpawnContext(state) {
|
|
|
21228
21259
|
const meta = state.subSessionMeta;
|
|
21229
21260
|
if (meta?.personaMode) {
|
|
21230
21261
|
ctx.personaMode = meta.personaMode;
|
|
21262
|
+
ctx.extraSystemPrompt = buildConnectionPrompt({
|
|
21263
|
+
mode: meta.personaMode,
|
|
21264
|
+
ownerLabel: deps.ownerDisplayName
|
|
21265
|
+
});
|
|
21231
21266
|
}
|
|
21232
21267
|
if (meta?.extraSettings) {
|
|
21233
21268
|
ctx.extraSettings = meta.extraSettings;
|
|
@@ -21416,7 +21451,7 @@ function applyCommand(state, command, deps) {
|
|
|
21416
21451
|
next.nextSeq = 0;
|
|
21417
21452
|
next.turnOpen = false;
|
|
21418
21453
|
next.status = "running";
|
|
21419
|
-
effects.push({ kind: "spawn", ctx: buildSpawnContext(next) });
|
|
21454
|
+
effects.push({ kind: "spawn", ctx: buildSpawnContext(next, deps) });
|
|
21420
21455
|
effects.push({
|
|
21421
21456
|
kind: "emit-frame",
|
|
21422
21457
|
frame: {
|
|
@@ -21468,7 +21503,7 @@ function applyCommand(state, command, deps) {
|
|
|
21468
21503
|
next.nextSeq = 0;
|
|
21469
21504
|
next.turnOpen = false;
|
|
21470
21505
|
next.status = "running";
|
|
21471
|
-
effects.push({ kind: "spawn", ctx: buildSpawnContext(next) });
|
|
21506
|
+
effects.push({ kind: "spawn", ctx: buildSpawnContext(next, deps) });
|
|
21472
21507
|
effects.push({
|
|
21473
21508
|
kind: "emit-frame",
|
|
21474
21509
|
frame: { type: "session:status", sessionId, status: "running" }
|
|
@@ -21790,7 +21825,7 @@ init_stdout_splitter();
|
|
|
21790
21825
|
|
|
21791
21826
|
// src/ipc-recorder.ts
|
|
21792
21827
|
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
21793
|
-
var
|
|
21828
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
21794
21829
|
function tsForFilename(ms) {
|
|
21795
21830
|
return new Date(ms).toISOString().replace(/[:.]/g, "-");
|
|
21796
21831
|
}
|
|
@@ -21801,12 +21836,12 @@ function startRecorder(opts) {
|
|
|
21801
21836
|
return null;
|
|
21802
21837
|
}
|
|
21803
21838
|
const now = opts.now ?? Date.now;
|
|
21804
|
-
const dir =
|
|
21805
|
-
const filePath =
|
|
21839
|
+
const dir = import_node_path5.default.join(opts.dataDir, "ipc-recordings", opts.sessionId);
|
|
21840
|
+
const filePath = import_node_path5.default.join(dir, `${tsForFilename(now())}.jsonl`);
|
|
21806
21841
|
let stream = null;
|
|
21807
21842
|
let closedResolve;
|
|
21808
|
-
const closed = new Promise((
|
|
21809
|
-
closedResolve =
|
|
21843
|
+
const closed = new Promise((resolve2) => {
|
|
21844
|
+
closedResolve = resolve2;
|
|
21810
21845
|
});
|
|
21811
21846
|
let exited = false;
|
|
21812
21847
|
const ensureStream = () => {
|
|
@@ -21930,7 +21965,8 @@ var SessionRunner = class {
|
|
|
21930
21965
|
bufferCap: this.hooks.bufferCap ?? 500,
|
|
21931
21966
|
now: this.hooks.now ?? Date.now,
|
|
21932
21967
|
resolveContextWindow: this.hooks.resolveContextWindow,
|
|
21933
|
-
genUuid: this.hooks.genUuid ?? v4_default
|
|
21968
|
+
genUuid: this.hooks.genUuid ?? v4_default,
|
|
21969
|
+
ownerDisplayName: this.hooks.ownerDisplayName
|
|
21934
21970
|
};
|
|
21935
21971
|
const { state, effects } = reduceSession(this.state, inputMsg, deps);
|
|
21936
21972
|
this.state = state;
|
|
@@ -21946,13 +21982,13 @@ var SessionRunner = class {
|
|
|
21946
21982
|
// 已经停止则立即 resolve;超时(默认 3000ms)抛错由上层透传成 RPC error
|
|
21947
21983
|
async waitUntilStopped(timeoutMs = DEFAULT_WAIT_STOP_TIMEOUT_MS) {
|
|
21948
21984
|
if (!this.state.procAlive) return;
|
|
21949
|
-
return new Promise((
|
|
21985
|
+
return new Promise((resolve2, reject) => {
|
|
21950
21986
|
let settled = false;
|
|
21951
21987
|
const onStop = () => {
|
|
21952
21988
|
if (settled) return;
|
|
21953
21989
|
settled = true;
|
|
21954
21990
|
clearTimeout(timer);
|
|
21955
|
-
|
|
21991
|
+
resolve2();
|
|
21956
21992
|
};
|
|
21957
21993
|
const timer = setTimeout(() => {
|
|
21958
21994
|
if (settled) return;
|
|
@@ -21997,7 +22033,7 @@ var SessionRunner = class {
|
|
|
21997
22033
|
};
|
|
21998
22034
|
const payload = JSON.stringify(frame) + "\n";
|
|
21999
22035
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_CONTROL_REQUEST_TIMEOUT_MS;
|
|
22000
|
-
return new Promise((
|
|
22036
|
+
return new Promise((resolve2, reject) => {
|
|
22001
22037
|
const timer = setTimeout(() => {
|
|
22002
22038
|
const pending = this.pendingControlRequests.get(requestId);
|
|
22003
22039
|
if (!pending) return;
|
|
@@ -22005,7 +22041,7 @@ var SessionRunner = class {
|
|
|
22005
22041
|
reject(new Error(`control_request timeout: ${subtype}`));
|
|
22006
22042
|
}, timeoutMs);
|
|
22007
22043
|
timer.unref?.();
|
|
22008
|
-
this.pendingControlRequests.set(requestId, { resolve, reject, timer });
|
|
22044
|
+
this.pendingControlRequests.set(requestId, { resolve: resolve2, reject, timer });
|
|
22009
22045
|
try {
|
|
22010
22046
|
proc.stdin?.write(payload);
|
|
22011
22047
|
this.recorder?.tapStdinWrite(payload);
|
|
@@ -22243,7 +22279,6 @@ function makeInitialState(file, subSessionMeta) {
|
|
|
22243
22279
|
var SessionManager = class {
|
|
22244
22280
|
constructor(deps) {
|
|
22245
22281
|
this.deps = deps;
|
|
22246
|
-
this.storesByAgent.set(DEFAULT_AGENT_ID, deps.store);
|
|
22247
22282
|
}
|
|
22248
22283
|
deps;
|
|
22249
22284
|
// sessionId → SessionRunner;在 send / ensureSession 时按需创建
|
|
@@ -22259,12 +22294,11 @@ var SessionManager = class {
|
|
|
22259
22294
|
// 由 observer 监听 jsonl user 行后调 recordRealUserUuid 建立映射;rewind 系列 RPC 在
|
|
22260
22295
|
// 入参 / 出参做转译,保证 UI 看到的 uuid 始终是 events 流里的 synth uuid
|
|
22261
22296
|
realUuidBySynth = /* @__PURE__ */ new Map();
|
|
22262
|
-
//
|
|
22263
|
-
//
|
|
22264
|
-
storesByAgent
|
|
22265
|
-
//
|
|
22266
|
-
|
|
22267
|
-
subSessionMetaBySid = /* @__PURE__ */ new Map();
|
|
22297
|
+
// SessionStore 按 scope 派生(root = <dataDir>/sessions/<scopeSubPath>/)。
|
|
22298
|
+
// default scope 直接复用 deps.store;persona scope(owner / listener)第一次访问时按需创建并缓存。
|
|
22299
|
+
// 取代旧的 storesByAgent —— agentId 概念由 SessionScope 取代,路径即身份,
|
|
22300
|
+
// SubSessionMeta 由 scope 派生(metaFromScope),不再需要运行时 cache 或 ownerPersonaId 兜底。
|
|
22301
|
+
storesByScope = /* @__PURE__ */ new Map();
|
|
22268
22302
|
// persona-bound transport 订阅器:sessionId → Set<listener>。
|
|
22269
22303
|
// 透传 owner 路径白名单 EventFrame(routeFromRunner 决定哪些 type 进入),listener 端按
|
|
22270
22304
|
// `frame.type` narrow 出 'session:event'(ParsedEvent)/ 'session:status'(procAlive 同步)等。
|
|
@@ -22289,22 +22323,18 @@ var SessionManager = class {
|
|
|
22289
22323
|
attachObserver(observer) {
|
|
22290
22324
|
this.attachedObserver = observer;
|
|
22291
22325
|
}
|
|
22292
|
-
// 按
|
|
22293
|
-
//
|
|
22294
|
-
|
|
22295
|
-
|
|
22296
|
-
const
|
|
22326
|
+
// 按 scope 拿对应的 SessionStore。default scope 复用 deps.store(保证与
|
|
22327
|
+
// bootstrap 注入的 store 一致);persona scope 第一次访问时按需创建并缓存。
|
|
22328
|
+
storeFor(scope) {
|
|
22329
|
+
if (scope.kind === "default") return this.deps.store;
|
|
22330
|
+
const key = scopeKey(scope);
|
|
22331
|
+
const cached = this.storesByScope.get(key);
|
|
22297
22332
|
if (cached) return cached;
|
|
22298
22333
|
if (!this.deps.dataDir) {
|
|
22299
|
-
throw new Error(`SessionManager: dataDir required to
|
|
22334
|
+
throw new Error(`SessionManager: dataDir required to construct SessionStore for scope=${key}`);
|
|
22300
22335
|
}
|
|
22301
|
-
|
|
22302
|
-
|
|
22303
|
-
`SessionManager: personaRoot is required to route agentId='${agentId}'. Bootstrap must wire personaRoot when constructing SessionManager for persona sub-sessions.`
|
|
22304
|
-
);
|
|
22305
|
-
}
|
|
22306
|
-
const st = new SessionStore({ dataDir: this.deps.dataDir, agentId, personaRoot: this.deps.personaRoot });
|
|
22307
|
-
this.storesByAgent.set(agentId, st);
|
|
22336
|
+
const st = new SessionStore({ dataDir: this.deps.dataDir, scope });
|
|
22337
|
+
this.storesByScope.set(key, st);
|
|
22308
22338
|
return st;
|
|
22309
22339
|
}
|
|
22310
22340
|
async getCapabilities(tool) {
|
|
@@ -22315,26 +22345,80 @@ var SessionManager = class {
|
|
|
22315
22345
|
this.capabilitiesCache.set(tool, caps);
|
|
22316
22346
|
return caps;
|
|
22317
22347
|
}
|
|
22318
|
-
//
|
|
22319
|
-
//
|
|
22320
|
-
//
|
|
22321
|
-
|
|
22322
|
-
|
|
22323
|
-
|
|
22324
|
-
|
|
22325
|
-
|
|
22348
|
+
// 由 SessionFile.ownerPersonaId schema 字段推回写入 scope。
|
|
22349
|
+
// ownerPersonaId 由 create({ownerPersonaId}) 在 schema 落盘时记入,永远只反映
|
|
22350
|
+
// session 出身(不可变);此函数只用于 SessionStore 的写入路由,不参与运行时行为
|
|
22351
|
+
// 决策(personaMode='owner' 等由路径 → scope → metaFromScope 派生)。
|
|
22352
|
+
// 仅覆盖 owner + default 两类——listener sub-session 不会从 default RPC 路径进来。
|
|
22353
|
+
scopeForFile(file) {
|
|
22354
|
+
return file.ownerPersonaId ? { kind: "persona", personaId: file.ownerPersonaId, mode: "owner" } : { kind: "default" };
|
|
22355
|
+
}
|
|
22356
|
+
// 扫 <dataDir>/sessions/ 列出所有 persona 命名空间(不含 'default')。
|
|
22357
|
+
// 用于 findOwnedSession / listAllOwned 跨 scope 查询。
|
|
22358
|
+
listPersonaIdsOnDisk() {
|
|
22359
|
+
if (!this.deps.dataDir) return [];
|
|
22360
|
+
const root = import_node_path6.default.join(this.deps.dataDir, "sessions");
|
|
22361
|
+
let entries;
|
|
22362
|
+
try {
|
|
22363
|
+
entries = import_node_fs5.default.readdirSync(root, { withFileTypes: true });
|
|
22364
|
+
} catch (err) {
|
|
22365
|
+
const code = err?.code;
|
|
22366
|
+
if (code === "ENOENT") return [];
|
|
22367
|
+
throw err;
|
|
22326
22368
|
}
|
|
22327
|
-
return
|
|
22369
|
+
return entries.filter((e) => e.isDirectory() && e.name !== "default").map((e) => e.name);
|
|
22370
|
+
}
|
|
22371
|
+
// owner / default 两个分类下按 sessionId 找文件——前端只传 sessionId 不带 scope,
|
|
22372
|
+
// SessionManager 在这里扫盘定位(default 直接试,未命中再轮询所有 persona owner 目录)。
|
|
22373
|
+
// listener sub-session 不走这条——transport 始终明确传 (personaId, sessionId)。
|
|
22374
|
+
findOwnedSession(sessionId) {
|
|
22375
|
+
const dflt = this.deps.store.read(sessionId);
|
|
22376
|
+
if (dflt) return dflt;
|
|
22377
|
+
for (const personaId of this.listPersonaIdsOnDisk()) {
|
|
22378
|
+
const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
|
|
22379
|
+
const file = ownerStore.read(sessionId);
|
|
22380
|
+
if (file) return file;
|
|
22381
|
+
}
|
|
22382
|
+
return null;
|
|
22383
|
+
}
|
|
22384
|
+
// 合并 default + 所有 persona owner 的 SessionFile —— 桌面 App 主 session 列表入口。
|
|
22385
|
+
// 同样不含 listener sub-session(listener 走 persona:listSubSessions RPC 单独入口)。
|
|
22386
|
+
listAllOwned() {
|
|
22387
|
+
const out = [];
|
|
22388
|
+
out.push(...this.deps.store.list());
|
|
22389
|
+
for (const personaId of this.listPersonaIdsOnDisk()) {
|
|
22390
|
+
const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
|
|
22391
|
+
out.push(...ownerStore.list());
|
|
22392
|
+
}
|
|
22393
|
+
return out.sort(
|
|
22394
|
+
(a, b) => a.updatedAt > b.updatedAt ? -1 : a.updatedAt < b.updatedAt ? 1 : 0
|
|
22395
|
+
);
|
|
22396
|
+
}
|
|
22397
|
+
// 写回 SessionFile,自动根据 ownerPersonaId 派生写入 scope。
|
|
22398
|
+
// 调用方原先都是 `deps.store.write(updated)`,全部走这里收口路由。
|
|
22399
|
+
writeOwned(file) {
|
|
22400
|
+
return this.storeFor(this.scopeForFile(file)).write(file);
|
|
22401
|
+
}
|
|
22402
|
+
// 删除 owned SessionFile(default 或 persona/owner),与 findOwnedSession 对称扫盘。
|
|
22403
|
+
deleteOwned(sessionId) {
|
|
22404
|
+
if (this.deps.store.delete(sessionId)) return true;
|
|
22405
|
+
for (const personaId of this.listPersonaIdsOnDisk()) {
|
|
22406
|
+
const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
|
|
22407
|
+
if (ownerStore.delete(sessionId)) return true;
|
|
22408
|
+
}
|
|
22409
|
+
return false;
|
|
22328
22410
|
}
|
|
22329
22411
|
// 创建 runner 时包一层 broadcast hook:所有外出 frame 统一走 routeFromRunner,
|
|
22330
|
-
// 经过 compressFrameForWire 后决定是 push collector 还是走 deps.broadcastFrame
|
|
22331
|
-
//
|
|
22332
|
-
//
|
|
22333
|
-
// owner
|
|
22334
|
-
|
|
22412
|
+
// 经过 compressFrameForWire 后决定是 push collector 还是走 deps.broadcastFrame。
|
|
22413
|
+
// scope 决定两件事:SessionStore 路由 + SubSessionMeta 派生(metaFromScope)。
|
|
22414
|
+
// - default → 复用 deps.store,无 subSessionMeta(普通 session)
|
|
22415
|
+
// - persona/owner → <dataDir>/sessions/<personaId>/owner/,meta={idleKillEnabled:false, personaMode:'owner'}
|
|
22416
|
+
// - persona/listener → <dataDir>/sessions/<personaId>/listener/,meta={idleKillEnabled:true, personaMode:'listener', extraSettings:<sandbox>}
|
|
22417
|
+
newRunner(file, scope) {
|
|
22335
22418
|
const adapter = this.deps.getAdapter(file.tool ?? "claude");
|
|
22336
|
-
const store =
|
|
22337
|
-
const
|
|
22419
|
+
const store = this.storeFor(scope);
|
|
22420
|
+
const subSessionMeta = metaFromScope(scope, this.deps.personaRoot ?? "");
|
|
22421
|
+
const runner = new SessionRunner(makeInitialState(file, subSessionMeta), {
|
|
22338
22422
|
broadcastFrame: (frame, target) => this.routeFromRunner(frame, target),
|
|
22339
22423
|
store,
|
|
22340
22424
|
adapter,
|
|
@@ -22345,7 +22429,8 @@ var SessionManager = class {
|
|
|
22345
22429
|
// adapter 自己持有模型表 + 兜底逻辑(contains / opus-1M / [1m] 等),manager 不再 cache 转发
|
|
22346
22430
|
resolveContextWindow: (tool, modelId) => this.deps.getAdapter(tool).resolveContextWindow(modelId),
|
|
22347
22431
|
dataDir: this.deps.dataDir,
|
|
22348
|
-
personaStore: this.deps.personaStore
|
|
22432
|
+
personaStore: this.deps.personaStore,
|
|
22433
|
+
ownerDisplayName: this.deps.ownerDisplayName
|
|
22349
22434
|
});
|
|
22350
22435
|
if (this.deps.mode === "tui" && !file.toolSessionId) {
|
|
22351
22436
|
const newTsid = v4_default();
|
|
@@ -22438,7 +22523,7 @@ var SessionManager = class {
|
|
|
22438
22523
|
if (!this.deps.personaRoot) {
|
|
22439
22524
|
throw new Error("personaRoot required to derive cwd from ownerPersonaId");
|
|
22440
22525
|
}
|
|
22441
|
-
cwd =
|
|
22526
|
+
cwd = import_node_path6.default.join(this.deps.personaRoot, safeFileName(args.ownerPersonaId));
|
|
22442
22527
|
}
|
|
22443
22528
|
if (!cwd) {
|
|
22444
22529
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, "cwd required when ownerPersonaId is absent");
|
|
@@ -22470,13 +22555,8 @@ var SessionManager = class {
|
|
|
22470
22555
|
createdAt: iso,
|
|
22471
22556
|
updatedAt: iso
|
|
22472
22557
|
};
|
|
22473
|
-
const
|
|
22474
|
-
|
|
22475
|
-
this.subSessionMetaBySid.set(written.sessionId, {
|
|
22476
|
-
idleKillEnabled: false,
|
|
22477
|
-
personaMode: "owner"
|
|
22478
|
-
});
|
|
22479
|
-
}
|
|
22558
|
+
const scope = args.ownerPersonaId ? { kind: "persona", personaId: args.ownerPersonaId, mode: "owner" } : { kind: "default" };
|
|
22559
|
+
const written = this.storeFor(scope).write(file);
|
|
22480
22560
|
return { response: written, broadcast: [] };
|
|
22481
22561
|
}
|
|
22482
22562
|
pin(args) {
|
|
@@ -22491,13 +22571,13 @@ var SessionManager = class {
|
|
|
22491
22571
|
return { response: value, broadcast };
|
|
22492
22572
|
}
|
|
22493
22573
|
const updated = { ...existing, pinnedAt };
|
|
22494
|
-
this.
|
|
22574
|
+
this.writeOwned(updated);
|
|
22495
22575
|
return { response: updated, broadcast: [] };
|
|
22496
22576
|
}
|
|
22497
22577
|
// sidebar 拖拽完成 → 整体重写 pinned root 的 pinSortOrder(按 orderedIds 下标 0,1,2...)
|
|
22498
22578
|
// orderedIds 必须正好覆盖所有当前 pinned root(既不能漏,也不能含 unpinned id)
|
|
22499
22579
|
reorderPins(args) {
|
|
22500
|
-
const all = this.
|
|
22580
|
+
const all = this.listAllOwned();
|
|
22501
22581
|
const currentPinnedIds = new Set(
|
|
22502
22582
|
all.filter((f) => typeof f.pinnedAt === "number").map((f) => f.sessionId)
|
|
22503
22583
|
);
|
|
@@ -22527,14 +22607,14 @@ var SessionManager = class {
|
|
|
22527
22607
|
} else {
|
|
22528
22608
|
const existing = this.getFile(sessionId);
|
|
22529
22609
|
const updated = { ...existing, pinSortOrder: index };
|
|
22530
|
-
this.
|
|
22610
|
+
this.writeOwned(updated);
|
|
22531
22611
|
updatedFiles.push(updated);
|
|
22532
22612
|
}
|
|
22533
22613
|
});
|
|
22534
22614
|
return { response: { sessions: updatedFiles }, broadcast };
|
|
22535
22615
|
}
|
|
22536
22616
|
list() {
|
|
22537
|
-
return { response: { sessions: this.
|
|
22617
|
+
return { response: { sessions: this.listAllOwned() }, broadcast: [] };
|
|
22538
22618
|
}
|
|
22539
22619
|
get(args) {
|
|
22540
22620
|
const file = this.getFile(args.sessionId);
|
|
@@ -22587,10 +22667,11 @@ var SessionManager = class {
|
|
|
22587
22667
|
for (const [synth, real] of map) reverse.set(real, synth);
|
|
22588
22668
|
return realUuids.map((r) => reverse.get(r) ?? r);
|
|
22589
22669
|
}
|
|
22590
|
-
// 内部帮手:不走 ManagerResult 的 get,直接拿 SessionFile
|
|
22670
|
+
// 内部帮手:不走 ManagerResult 的 get,直接拿 SessionFile。
|
|
22671
|
+
// 优先 runner cache(hot path);冷态走 findOwnedSession 跨 default + 所有 persona owner 扫盘。
|
|
22591
22672
|
getFile(sessionId) {
|
|
22592
22673
|
const runner = this.runners.get(sessionId);
|
|
22593
|
-
const existing = runner?.getState().file ?? this.
|
|
22674
|
+
const existing = runner?.getState().file ?? this.findOwnedSession(sessionId);
|
|
22594
22675
|
if (!existing) throw new ClawdError(ERROR_CODES.SESSION_NOT_FOUND, sessionId);
|
|
22595
22676
|
return existing;
|
|
22596
22677
|
}
|
|
@@ -22605,11 +22686,11 @@ var SessionManager = class {
|
|
|
22605
22686
|
return { response: value, broadcast };
|
|
22606
22687
|
}
|
|
22607
22688
|
const updated = { ...existing, ...args.patch, updatedAt: nowIso2(this.deps) };
|
|
22608
|
-
this.
|
|
22689
|
+
this.writeOwned(updated);
|
|
22609
22690
|
return { response: updated, broadcast: [] };
|
|
22610
22691
|
}
|
|
22611
22692
|
delete(args) {
|
|
22612
|
-
const existing = this.
|
|
22693
|
+
const existing = this.findOwnedSession(args.sessionId);
|
|
22613
22694
|
if (!existing) throw new ClawdError(ERROR_CODES.SESSION_NOT_FOUND, args.sessionId);
|
|
22614
22695
|
const runner = this.runners.get(args.sessionId);
|
|
22615
22696
|
if (runner) {
|
|
@@ -22620,7 +22701,7 @@ var SessionManager = class {
|
|
|
22620
22701
|
this.realUuidBySynth.delete(args.sessionId);
|
|
22621
22702
|
return { response: { sessionId: args.sessionId }, broadcast };
|
|
22622
22703
|
}
|
|
22623
|
-
this.
|
|
22704
|
+
this.deleteOwned(args.sessionId);
|
|
22624
22705
|
return {
|
|
22625
22706
|
response: { sessionId: args.sessionId },
|
|
22626
22707
|
broadcast: [
|
|
@@ -22632,8 +22713,7 @@ var SessionManager = class {
|
|
|
22632
22713
|
const existing = this.getFile(args.sessionId);
|
|
22633
22714
|
let runner = this.runners.get(args.sessionId);
|
|
22634
22715
|
if (!runner) {
|
|
22635
|
-
|
|
22636
|
-
runner = this.newRunner(existing, { subSessionMeta });
|
|
22716
|
+
runner = this.newRunner(existing, this.scopeForFile(existing));
|
|
22637
22717
|
this.runners.set(args.sessionId, runner);
|
|
22638
22718
|
}
|
|
22639
22719
|
const { broadcast } = this.withCollector(() => {
|
|
@@ -22727,8 +22807,7 @@ var SessionManager = class {
|
|
|
22727
22807
|
const file = this.getFile(args.sessionId);
|
|
22728
22808
|
let runner = this.runners.get(args.sessionId);
|
|
22729
22809
|
if (!runner) {
|
|
22730
|
-
|
|
22731
|
-
runner = this.newRunner(file, { subSessionMeta });
|
|
22810
|
+
runner = this.newRunner(file, this.scopeForFile(file));
|
|
22732
22811
|
this.runners.set(args.sessionId, runner);
|
|
22733
22812
|
}
|
|
22734
22813
|
if (!runner.getState().procAlive) {
|
|
@@ -22779,7 +22858,7 @@ var SessionManager = class {
|
|
|
22779
22858
|
});
|
|
22780
22859
|
return { response: value, broadcast };
|
|
22781
22860
|
}
|
|
22782
|
-
const existing = this.
|
|
22861
|
+
const existing = this.findOwnedSession(args.sessionId);
|
|
22783
22862
|
const {
|
|
22784
22863
|
toolSessionId: _drop,
|
|
22785
22864
|
contextUsage: _ctx,
|
|
@@ -22794,7 +22873,7 @@ var SessionManager = class {
|
|
|
22794
22873
|
void _branch;
|
|
22795
22874
|
void _model;
|
|
22796
22875
|
const updated = { ...rest, updatedAt: nowIso2(this.deps) };
|
|
22797
|
-
return { response: this.
|
|
22876
|
+
return { response: this.writeOwned(updated), broadcast: [] };
|
|
22798
22877
|
}
|
|
22799
22878
|
resume(args) {
|
|
22800
22879
|
this.getFile(args.sessionId);
|
|
@@ -22809,13 +22888,13 @@ var SessionManager = class {
|
|
|
22809
22888
|
});
|
|
22810
22889
|
return { response: value, broadcast };
|
|
22811
22890
|
}
|
|
22812
|
-
const existing = this.
|
|
22891
|
+
const existing = this.findOwnedSession(args.sessionId);
|
|
22813
22892
|
const updated = {
|
|
22814
22893
|
...existing,
|
|
22815
22894
|
toolSessionId: args.toolSessionId,
|
|
22816
22895
|
updatedAt: nowIso2(this.deps)
|
|
22817
22896
|
};
|
|
22818
|
-
return { response: this.
|
|
22897
|
+
return { response: this.writeOwned(updated), broadcast: [] };
|
|
22819
22898
|
}
|
|
22820
22899
|
getEvents(args) {
|
|
22821
22900
|
const runner = this.runners.get(args.sessionId);
|
|
@@ -22883,39 +22962,44 @@ var SessionManager = class {
|
|
|
22883
22962
|
if (!runner) return "idle";
|
|
22884
22963
|
return compressStatus(runner.getState().status);
|
|
22885
22964
|
}
|
|
22886
|
-
// 给 observer 用:保证有 runner 但不 spawn(仅创建 state
|
|
22965
|
+
// 给 observer 用:保证有 runner 但不 spawn(仅创建 state 容器)。
|
|
22966
|
+
// observer 喂事件路径只走 default + owner(普通 + owner persona session)
|
|
22967
|
+
// ——listener sub-session 的 observer 路径走 ensureRunnerForScope。
|
|
22887
22968
|
ensureSession(file) {
|
|
22888
22969
|
let r = this.runners.get(file.sessionId);
|
|
22889
22970
|
if (r) return r;
|
|
22890
|
-
|
|
22891
|
-
r = this.newRunner(file, { subSessionMeta });
|
|
22971
|
+
r = this.newRunner(file, this.scopeForFile(file));
|
|
22892
22972
|
this.runners.set(file.sessionId, r);
|
|
22893
22973
|
return r;
|
|
22894
22974
|
}
|
|
22895
|
-
// ---------------- persona / sub-session 专用 API ----------------
|
|
22975
|
+
// ---------------- persona / listener sub-session 专用 API ----------------
|
|
22896
22976
|
//
|
|
22897
|
-
// PersonaManager 是 SessionManager 之上的薄编排层,sub-session
|
|
22898
|
-
//
|
|
22899
|
-
// - SessionFile 落到 <
|
|
22977
|
+
// PersonaManager 是 SessionManager 之上的薄编排层,listener sub-session 的持久化
|
|
22978
|
+
// (SessionFile)仍由 SessionManager 持有。区别于普通 / owner session:
|
|
22979
|
+
// - SessionFile 落到 <dataDir>/sessions/<personaId>/listener/(拓扑分类)
|
|
22900
22980
|
// - reducer state.subSessionMeta.idleKillEnabled = true(turn_end 自动 idle-kill)
|
|
22901
22981
|
// - sessionId 由 PersonaManager 派生(personaId-<tokenHash>),不走自动 newSessionId
|
|
22902
|
-
|
|
22903
|
-
|
|
22904
|
-
|
|
22982
|
+
//
|
|
22983
|
+
// 这些 API 接 SessionScope 参数(不再是单参 agentId)—— transport 始终明确传
|
|
22984
|
+
// {kind:'persona', personaId, mode:'listener'},与 owner / default 分类隔离。
|
|
22985
|
+
/** 按 scope 读取 SessionFile;不存在返回 null */
|
|
22986
|
+
readForScope(sessionId, scope) {
|
|
22987
|
+
return this.storeFor(scope).read(sessionId);
|
|
22905
22988
|
}
|
|
22906
22989
|
/**
|
|
22907
|
-
*
|
|
22908
|
-
*
|
|
22990
|
+
* 列出指定 persona 在指定 mode 下的所有 SessionFile。
|
|
22991
|
+
* persona:listSubSessions RPC 入口(mode='listener');
|
|
22992
|
+
* 路径下还未写过任何 session 时 list() 返回空数组(SessionStore.list 内部 ENOENT 处理)
|
|
22909
22993
|
*/
|
|
22910
|
-
|
|
22911
|
-
return this.storeFor(
|
|
22994
|
+
listPersonaSessions(personaId, mode) {
|
|
22995
|
+
return this.storeFor({ kind: "persona", personaId, mode }).list();
|
|
22912
22996
|
}
|
|
22913
22997
|
/**
|
|
22914
22998
|
* 创建 sub-session 的 SessionFile + 准备 runner(不 spawn)。
|
|
22915
|
-
*
|
|
22916
|
-
* 同一 sessionId 重复调用:抛错(PersonaManager 应先调
|
|
22999
|
+
* SubSessionMeta 不进 SessionFile schema,运行时由 scope → metaFromScope 派生。
|
|
23000
|
+
* 同一 sessionId 重复调用:抛错(PersonaManager 应先调 readForScope 命中复用)
|
|
22917
23001
|
*/
|
|
22918
|
-
|
|
23002
|
+
createForScope(args) {
|
|
22919
23003
|
try {
|
|
22920
23004
|
const stat = import_node_fs5.default.statSync(args.cwd);
|
|
22921
23005
|
if (!stat.isDirectory()) throw new Error("not dir");
|
|
@@ -22924,9 +23008,11 @@ var SessionManager = class {
|
|
|
22924
23008
|
}
|
|
22925
23009
|
const tool = args.tool ?? "claude";
|
|
22926
23010
|
this.deps.getAdapter(tool);
|
|
22927
|
-
const store = this.storeFor(args.
|
|
23011
|
+
const store = this.storeFor(args.scope);
|
|
22928
23012
|
if (store.read(args.sessionId)) {
|
|
22929
|
-
throw new Error(
|
|
23013
|
+
throw new Error(
|
|
23014
|
+
`session already exists for scope ${scopeKey(args.scope)}: ${args.sessionId}`
|
|
23015
|
+
);
|
|
22930
23016
|
}
|
|
22931
23017
|
const iso = nowIso2(this.deps);
|
|
22932
23018
|
const file = {
|
|
@@ -22939,11 +23025,7 @@ var SessionManager = class {
|
|
|
22939
23025
|
createdAt: iso,
|
|
22940
23026
|
updatedAt: iso
|
|
22941
23027
|
};
|
|
22942
|
-
|
|
22943
|
-
if (args.subSessionMeta) {
|
|
22944
|
-
this.subSessionMetaBySid.set(args.sessionId, args.subSessionMeta);
|
|
22945
|
-
}
|
|
22946
|
-
return written;
|
|
23028
|
+
return store.write(file);
|
|
22947
23029
|
}
|
|
22948
23030
|
/**
|
|
22949
23031
|
* persona-bound transport 用:读取 sub-session 的历史 ParsedEvent[]。
|
|
@@ -22954,22 +23036,21 @@ var SessionManager = class {
|
|
|
22954
23036
|
* 不读 jsonl:
|
|
22955
23037
|
* 1. observer 路径在 spawn 后会自动接管 jsonl 回灌,进 reducer buffer。
|
|
22956
23038
|
* 2. 第一次握手时 sub-session 还没 spawn → toolSessionId 为空 → jsonl 不存在。
|
|
22957
|
-
* sessionFile 不存在抛 SESSION_NOT_FOUND;上层应先调
|
|
23039
|
+
* sessionFile 不存在抛 SESSION_NOT_FOUND;上层应先调 createForScope。
|
|
22958
23040
|
*/
|
|
22959
|
-
|
|
22960
|
-
const
|
|
22961
|
-
const file = store.read(sessionId);
|
|
23041
|
+
readHistoryEventsForScope(sessionId, scope) {
|
|
23042
|
+
const file = this.storeFor(scope).read(sessionId);
|
|
22962
23043
|
if (!file) {
|
|
22963
23044
|
throw new ClawdError(
|
|
22964
23045
|
ERROR_CODES.SESSION_NOT_FOUND,
|
|
22965
|
-
`sub-session not found: ${
|
|
23046
|
+
`sub-session not found: ${scopeKey(scope)}/${sessionId}`
|
|
22966
23047
|
);
|
|
22967
23048
|
}
|
|
22968
|
-
const runner = this.
|
|
23049
|
+
const runner = this.ensureRunnerForScope(file, scope);
|
|
22969
23050
|
return runner.getState().buffer.map((e) => e.event);
|
|
22970
23051
|
}
|
|
22971
23052
|
/**
|
|
22972
|
-
* persona-bound transport 用:基于
|
|
23053
|
+
* persona-bound transport 用:基于 readHistoryEventsForScope 的 buffer 切片视图,支持分页。
|
|
22973
23054
|
*
|
|
22974
23055
|
* Why a new method instead of reusing `history:read` RPC handler:
|
|
22975
23056
|
* - `history:read` 走 HandlerDeps.history.read(),读 CC 写盘的 jsonl 文件
|
|
@@ -22977,18 +23058,15 @@ var SessionManager = class {
|
|
|
22977
23058
|
* 两条路径数据形态、时序、字段不同,不能共享 helper。persona-bound 客户端必须
|
|
22978
23059
|
* 走 buffer 路径,才能保证首屏回放和实时帧无 gap、无重复。
|
|
22979
23060
|
*
|
|
22980
|
-
* Why not 改 readHistoryEvents 加 limit/offset:现有 readHistoryEvents 的语义是
|
|
22981
|
-
* "返回 buffer 全部",被其它路径(rewind uuid 转译等)依赖;保留它不动,新加分页方法。
|
|
22982
|
-
*
|
|
22983
23061
|
* 切片语义:clip 安全边界,response.offset 保留请求值便于客户端识别越界请求。
|
|
22984
23062
|
* - offset >= total → events: [], offset: 请求值, total: 当前 buffer 长度
|
|
22985
23063
|
* - offset + limit > total → 返回 tail [offset, total),长度 = total - offset
|
|
22986
23064
|
* - 正常 → 返回 [offset, offset + limit)
|
|
22987
23065
|
*
|
|
22988
|
-
* SESSION_NOT_FOUND 行为继承
|
|
23066
|
+
* SESSION_NOT_FOUND 行为继承 readHistoryEventsForScope(store.read 返回 null 即抛)。
|
|
22989
23067
|
*/
|
|
22990
|
-
|
|
22991
|
-
const all = this.
|
|
23068
|
+
readHistoryPageForScope(sessionId, scope, limit, offset) {
|
|
23069
|
+
const all = this.readHistoryEventsForScope(sessionId, scope);
|
|
22992
23070
|
const total = all.length;
|
|
22993
23071
|
const start = Math.min(offset, total);
|
|
22994
23072
|
const end = Math.min(start + limit, total);
|
|
@@ -23001,36 +23079,34 @@ var SessionManager = class {
|
|
|
23001
23079
|
* 返回 unsubscribe;不破坏现有 wire 广播路径——routeFromRunner 同时 fan-out 到
|
|
23002
23080
|
* eventSubscribers 和 deps.broadcastFrame
|
|
23003
23081
|
*/
|
|
23004
|
-
subscribe(
|
|
23005
|
-
|
|
23006
|
-
let subs = this.eventSubscribers.get(sid);
|
|
23082
|
+
subscribe(sessionId, _scope, listener) {
|
|
23083
|
+
let subs = this.eventSubscribers.get(sessionId);
|
|
23007
23084
|
if (!subs) {
|
|
23008
23085
|
subs = /* @__PURE__ */ new Set();
|
|
23009
|
-
this.eventSubscribers.set(
|
|
23086
|
+
this.eventSubscribers.set(sessionId, subs);
|
|
23010
23087
|
}
|
|
23011
23088
|
subs.add(listener);
|
|
23012
23089
|
return () => {
|
|
23013
|
-
const cur = this.eventSubscribers.get(
|
|
23090
|
+
const cur = this.eventSubscribers.get(sessionId);
|
|
23014
23091
|
if (!cur) return;
|
|
23015
23092
|
cur.delete(listener);
|
|
23016
|
-
if (cur.size === 0) this.eventSubscribers.delete(
|
|
23093
|
+
if (cur.size === 0) this.eventSubscribers.delete(sessionId);
|
|
23017
23094
|
};
|
|
23018
23095
|
}
|
|
23019
23096
|
/**
|
|
23020
|
-
* persona-bound transport 用:sub-session 路径的 send(按
|
|
23021
|
-
*
|
|
23022
|
-
*
|
|
23097
|
+
* persona-bound transport 用:sub-session 路径的 send(按 scope 路由 SessionStore)。
|
|
23098
|
+
* 区别于 default scope 走 SessionManager.send:transport hello 已知 personaId 和 mode,
|
|
23099
|
+
* 显式传 scope 避免跨命名空间 sessionId 撞车。
|
|
23023
23100
|
*/
|
|
23024
|
-
|
|
23025
|
-
const
|
|
23026
|
-
const file = store.read(args.sessionId);
|
|
23101
|
+
sendForScope(args) {
|
|
23102
|
+
const file = this.storeFor(args.scope).read(args.sessionId);
|
|
23027
23103
|
if (!file) {
|
|
23028
23104
|
throw new ClawdError(
|
|
23029
23105
|
ERROR_CODES.SESSION_NOT_FOUND,
|
|
23030
|
-
`sub-session not found: ${args.
|
|
23106
|
+
`sub-session not found: ${scopeKey(args.scope)}/${args.sessionId}`
|
|
23031
23107
|
);
|
|
23032
23108
|
}
|
|
23033
|
-
const runner = this.
|
|
23109
|
+
const runner = this.ensureRunnerForScope(file, args.scope);
|
|
23034
23110
|
const { broadcast } = this.withCollector(() => {
|
|
23035
23111
|
runner.input({ kind: "command", command: { kind: "send", text: args.text } });
|
|
23036
23112
|
});
|
|
@@ -23040,53 +23116,47 @@ var SessionManager = class {
|
|
|
23040
23116
|
* persona-bound transport 用:sub-session reset。
|
|
23041
23117
|
* 复用 reducer 'new' 命令:清 toolSessionId / buffer / nextSeq / pending* + kill proc + emit
|
|
23042
23118
|
* session:cleared。语义上等价 alice 端"清空当前会话上下文"。
|
|
23043
|
-
* 归档已写盘的 jsonl 不在本路径处理(CC 后续 spawn 会写新的 toolSessionId.jsonl
|
|
23044
|
-
* 物理归档可在后续单独 task 加(spec § 6 待 plan 决定项)。
|
|
23119
|
+
* 归档已写盘的 jsonl 不在本路径处理(CC 后续 spawn 会写新的 toolSessionId.jsonl,旧的留盘)。
|
|
23045
23120
|
*/
|
|
23046
|
-
|
|
23047
|
-
const
|
|
23048
|
-
const file = store.read(args.sessionId);
|
|
23121
|
+
resetForScope(args) {
|
|
23122
|
+
const file = this.storeFor(args.scope).read(args.sessionId);
|
|
23049
23123
|
if (!file) {
|
|
23050
23124
|
throw new ClawdError(
|
|
23051
23125
|
ERROR_CODES.SESSION_NOT_FOUND,
|
|
23052
|
-
`sub-session not found: ${args.
|
|
23126
|
+
`sub-session not found: ${scopeKey(args.scope)}/${args.sessionId}`
|
|
23053
23127
|
);
|
|
23054
23128
|
}
|
|
23055
|
-
const runner = this.
|
|
23129
|
+
const runner = this.ensureRunnerForScope(file, args.scope);
|
|
23056
23130
|
const { broadcast } = this.withCollector(() => {
|
|
23057
23131
|
runner.input({ kind: "command", command: { kind: "new" } });
|
|
23058
23132
|
});
|
|
23059
23133
|
return { response: { ok: true }, broadcast };
|
|
23060
23134
|
}
|
|
23061
|
-
/** ensureSession 的
|
|
23062
|
-
|
|
23135
|
+
/** ensureSession 的 scope-aware 版本:复用现有 runner 或按 scope 创建(含 metaFromScope 派生 meta) */
|
|
23136
|
+
ensureRunnerForScope(file, scope) {
|
|
23063
23137
|
const existing = this.runners.get(file.sessionId);
|
|
23064
23138
|
if (existing) return existing;
|
|
23065
|
-
const
|
|
23066
|
-
const subSessionMeta = this.resolveSubSessionMeta(file);
|
|
23067
|
-
const runner = this.newRunner(file, { store, subSessionMeta });
|
|
23139
|
+
const runner = this.newRunner(file, scope);
|
|
23068
23140
|
this.runners.set(file.sessionId, runner);
|
|
23069
23141
|
return runner;
|
|
23070
23142
|
}
|
|
23071
23143
|
/**
|
|
23072
23144
|
* 老板插话:把 'inject-owner-text' input 喂给对应 runner,
|
|
23073
|
-
* runner 不存在时按
|
|
23145
|
+
* runner 不存在时按 scope 懒创建。
|
|
23074
23146
|
* frames 走异步路径(broadcastFrame):调用方一般在 PersonaManager.appendOwnerMessage
|
|
23075
23147
|
* 内部走 RPC 处理流,没有同步 collector 上下文
|
|
23076
23148
|
*/
|
|
23077
23149
|
injectOwnerMessage(args) {
|
|
23078
|
-
const
|
|
23079
|
-
const file = store.read(args.sessionId);
|
|
23150
|
+
const file = this.storeFor(args.scope).read(args.sessionId);
|
|
23080
23151
|
if (!file) {
|
|
23081
23152
|
throw new ClawdError(
|
|
23082
23153
|
ERROR_CODES.SESSION_NOT_FOUND,
|
|
23083
|
-
`sub-session not found: ${args.
|
|
23154
|
+
`sub-session not found: ${scopeKey(args.scope)}/${args.sessionId}`
|
|
23084
23155
|
);
|
|
23085
23156
|
}
|
|
23086
23157
|
let runner = this.runners.get(args.sessionId);
|
|
23087
23158
|
if (!runner) {
|
|
23088
|
-
|
|
23089
|
-
runner = this.newRunner(file, { store, subSessionMeta });
|
|
23159
|
+
runner = this.newRunner(file, args.scope);
|
|
23090
23160
|
this.runners.set(args.sessionId, runner);
|
|
23091
23161
|
}
|
|
23092
23162
|
runner.input({ kind: "inject-owner-text", text: args.text });
|
|
@@ -23305,7 +23375,7 @@ var SessionManager = class {
|
|
|
23305
23375
|
|
|
23306
23376
|
// src/persona/store.ts
|
|
23307
23377
|
var fs6 = __toESM(require("fs"), 1);
|
|
23308
|
-
var
|
|
23378
|
+
var path7 = __toESM(require("path"), 1);
|
|
23309
23379
|
init_protocol();
|
|
23310
23380
|
var DEFAULT_SETTINGS = {
|
|
23311
23381
|
permissions: {
|
|
@@ -23334,13 +23404,13 @@ var PersonaStore = class {
|
|
|
23334
23404
|
}
|
|
23335
23405
|
root;
|
|
23336
23406
|
personaDir(personaId) {
|
|
23337
|
-
return
|
|
23407
|
+
return path7.join(this.root, safeFileName(personaId));
|
|
23338
23408
|
}
|
|
23339
23409
|
metaPath(personaId) {
|
|
23340
|
-
return
|
|
23410
|
+
return path7.join(this.personaDir(personaId), ".clawd", "persona.json");
|
|
23341
23411
|
}
|
|
23342
23412
|
claudeMdPath(personaId) {
|
|
23343
|
-
return
|
|
23413
|
+
return path7.join(this.personaDir(personaId), "CLAUDE.md");
|
|
23344
23414
|
}
|
|
23345
23415
|
/**
|
|
23346
23416
|
* Sandbox settings 落盘路径 —— 故意放在 `.clawd/` 而不是 `.claude/`,让 CC 的
|
|
@@ -23350,11 +23420,11 @@ var PersonaStore = class {
|
|
|
23350
23420
|
* 加载 persona 人格,只有 listener 多一层 OS sandbox。
|
|
23351
23421
|
*/
|
|
23352
23422
|
sandboxSettingsPath(personaId) {
|
|
23353
|
-
return
|
|
23423
|
+
return path7.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
|
|
23354
23424
|
}
|
|
23355
23425
|
write(persona, personality) {
|
|
23356
23426
|
const dir = this.personaDir(persona.personaId);
|
|
23357
|
-
fs6.mkdirSync(
|
|
23427
|
+
fs6.mkdirSync(path7.join(dir, ".clawd"), { recursive: true });
|
|
23358
23428
|
this.atomicWrite(this.claudeMdPath(persona.personaId), personality);
|
|
23359
23429
|
this.atomicWrite(
|
|
23360
23430
|
this.sandboxSettingsPath(persona.personaId),
|
|
@@ -23385,7 +23455,7 @@ var PersonaStore = class {
|
|
|
23385
23455
|
list() {
|
|
23386
23456
|
if (!fs6.existsSync(this.root)) return [];
|
|
23387
23457
|
return fs6.readdirSync(this.root).filter((name) => {
|
|
23388
|
-
return fs6.existsSync(
|
|
23458
|
+
return fs6.existsSync(path7.join(this.root, name, ".clawd", "persona.json"));
|
|
23389
23459
|
});
|
|
23390
23460
|
}
|
|
23391
23461
|
remove(personaId) {
|
|
@@ -23547,27 +23617,20 @@ var PersonaManager = class {
|
|
|
23547
23617
|
const persona = this.deps.registry.get(personaId);
|
|
23548
23618
|
if (!persona) throw new Error(`persona not found: ${personaId}`);
|
|
23549
23619
|
const subSessionId = this.deriveSubSessionId(personaId, token);
|
|
23550
|
-
const
|
|
23620
|
+
const scope = { kind: "persona", personaId, mode: "listener" };
|
|
23621
|
+
const existing = this.deps.sessionManager.readForScope(subSessionId, scope);
|
|
23551
23622
|
if (existing) {
|
|
23552
23623
|
return { sessionFile: existing, isNew: false };
|
|
23553
23624
|
}
|
|
23554
23625
|
const tokenEntry = persona.tokenMap[token];
|
|
23555
23626
|
const subLabel = tokenEntry?.label ?? "unknown";
|
|
23556
|
-
const sessionFile = this.deps.sessionManager.
|
|
23627
|
+
const sessionFile = this.deps.sessionManager.createForScope({
|
|
23557
23628
|
sessionId: subSessionId,
|
|
23558
|
-
|
|
23629
|
+
scope,
|
|
23559
23630
|
cwd: this.deps.store.personaDirPath(personaId),
|
|
23560
23631
|
tool: "claude",
|
|
23561
23632
|
label: subLabel,
|
|
23562
|
-
model: persona.model
|
|
23563
|
-
// listener 走 OS sandbox:sandbox JSON 不在 project 自动发现路径上(PersonaStore 把它
|
|
23564
|
-
// 落在 .clawd/sandbox-settings.json),靠 extraSettings 透传到 spawn 的 `--settings <file>`
|
|
23565
|
-
// 显式拉回。owner 路径不传 extraSettings,天然无 sandbox。
|
|
23566
|
-
subSessionMeta: {
|
|
23567
|
-
idleKillEnabled: true,
|
|
23568
|
-
personaMode: "listener",
|
|
23569
|
-
extraSettings: this.deps.store.sandboxSettingsPath(personaId)
|
|
23570
|
-
}
|
|
23633
|
+
model: persona.model
|
|
23571
23634
|
});
|
|
23572
23635
|
return { sessionFile, isNew: true };
|
|
23573
23636
|
}
|
|
@@ -23578,7 +23641,7 @@ var PersonaManager = class {
|
|
|
23578
23641
|
appendOwnerMessage(personaId, subSessionId, text) {
|
|
23579
23642
|
this.deps.sessionManager.injectOwnerMessage({
|
|
23580
23643
|
sessionId: subSessionId,
|
|
23581
|
-
|
|
23644
|
+
scope: { kind: "persona", personaId, mode: "listener" },
|
|
23582
23645
|
text
|
|
23583
23646
|
});
|
|
23584
23647
|
}
|
|
@@ -23605,13 +23668,123 @@ var PersonaManager = class {
|
|
|
23605
23668
|
}
|
|
23606
23669
|
};
|
|
23607
23670
|
|
|
23671
|
+
// src/persona/seed.ts
|
|
23672
|
+
var fs7 = __toESM(require("fs"), 1);
|
|
23673
|
+
var path8 = __toESM(require("path"), 1);
|
|
23674
|
+
var import_node_url = require("url");
|
|
23675
|
+
var import_meta = {};
|
|
23676
|
+
var DEFAULT_PERSONAS = [
|
|
23677
|
+
{
|
|
23678
|
+
personaId: "persona-researcher",
|
|
23679
|
+
label: "\u8C03\u7814\u5458",
|
|
23680
|
+
model: "opus",
|
|
23681
|
+
iconKey: "research",
|
|
23682
|
+
public: false
|
|
23683
|
+
},
|
|
23684
|
+
{
|
|
23685
|
+
personaId: "persona-knowledge-base",
|
|
23686
|
+
label: "\u77E5\u8BC6\u5E93\u7BA1\u7406\u5458",
|
|
23687
|
+
model: "opus",
|
|
23688
|
+
iconKey: "reading",
|
|
23689
|
+
public: false
|
|
23690
|
+
},
|
|
23691
|
+
{
|
|
23692
|
+
personaId: "persona-clawd-helper",
|
|
23693
|
+
label: "clawd\u4F7F\u7528\u52A9\u624B",
|
|
23694
|
+
model: "opus",
|
|
23695
|
+
iconKey: "assist",
|
|
23696
|
+
public: false
|
|
23697
|
+
},
|
|
23698
|
+
{
|
|
23699
|
+
personaId: "persona-feishu-assistant",
|
|
23700
|
+
label: "\u98DE\u4E66\u52A9\u7406",
|
|
23701
|
+
model: "opus",
|
|
23702
|
+
iconKey: "assist",
|
|
23703
|
+
public: false
|
|
23704
|
+
}
|
|
23705
|
+
];
|
|
23706
|
+
function findDefaultsRoot() {
|
|
23707
|
+
const candidates = [];
|
|
23708
|
+
try {
|
|
23709
|
+
const here = path8.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
23710
|
+
candidates.push(path8.resolve(here, "defaults"));
|
|
23711
|
+
candidates.push(path8.resolve(here, "persona-defaults"));
|
|
23712
|
+
} catch {
|
|
23713
|
+
}
|
|
23714
|
+
if (process.argv[1]) {
|
|
23715
|
+
const argvDir = path8.dirname(process.argv[1]);
|
|
23716
|
+
candidates.push(path8.resolve(argvDir, "persona-defaults"));
|
|
23717
|
+
}
|
|
23718
|
+
for (const c of candidates) {
|
|
23719
|
+
try {
|
|
23720
|
+
if (fs7.statSync(c).isDirectory()) return c;
|
|
23721
|
+
} catch {
|
|
23722
|
+
}
|
|
23723
|
+
}
|
|
23724
|
+
return null;
|
|
23725
|
+
}
|
|
23726
|
+
function seedDefaultPersonas(args) {
|
|
23727
|
+
const entries = args.entries ?? DEFAULT_PERSONAS;
|
|
23728
|
+
for (const entry of entries) {
|
|
23729
|
+
if (args.store.has(entry.personaId)) {
|
|
23730
|
+
args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
|
|
23731
|
+
continue;
|
|
23732
|
+
}
|
|
23733
|
+
const bundleDir = path8.join(args.defaultsRoot, entry.personaId);
|
|
23734
|
+
if (!fs7.existsSync(bundleDir)) {
|
|
23735
|
+
args.logger.warn("persona.seed.skip", {
|
|
23736
|
+
personaId: entry.personaId,
|
|
23737
|
+
reason: "bundle-missing",
|
|
23738
|
+
bundleDir
|
|
23739
|
+
});
|
|
23740
|
+
continue;
|
|
23741
|
+
}
|
|
23742
|
+
const claudeMdPath = path8.join(bundleDir, "CLAUDE.md");
|
|
23743
|
+
if (!fs7.existsSync(claudeMdPath)) {
|
|
23744
|
+
args.logger.warn("persona.seed.skip", {
|
|
23745
|
+
personaId: entry.personaId,
|
|
23746
|
+
reason: "no-CLAUDE.md",
|
|
23747
|
+
bundleDir
|
|
23748
|
+
});
|
|
23749
|
+
continue;
|
|
23750
|
+
}
|
|
23751
|
+
const personality = fs7.readFileSync(claudeMdPath, "utf8");
|
|
23752
|
+
const now = Date.now();
|
|
23753
|
+
const persona = {
|
|
23754
|
+
personaId: entry.personaId,
|
|
23755
|
+
label: entry.label,
|
|
23756
|
+
model: entry.model,
|
|
23757
|
+
public: entry.public,
|
|
23758
|
+
iconKey: entry.iconKey,
|
|
23759
|
+
tokenMap: {},
|
|
23760
|
+
createdAt: now,
|
|
23761
|
+
updatedAt: now
|
|
23762
|
+
};
|
|
23763
|
+
args.store.write(persona, personality);
|
|
23764
|
+
copyBundleExtras(bundleDir, args.store.personaDirPath(entry.personaId));
|
|
23765
|
+
args.logger.info("persona.seed.created", { personaId: entry.personaId });
|
|
23766
|
+
}
|
|
23767
|
+
}
|
|
23768
|
+
function copyBundleExtras(srcDir, dstDir) {
|
|
23769
|
+
for (const entry of fs7.readdirSync(srcDir, { withFileTypes: true })) {
|
|
23770
|
+
if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
|
|
23771
|
+
const srcPath = path8.join(srcDir, entry.name);
|
|
23772
|
+
const dstPath = path8.join(dstDir, entry.name);
|
|
23773
|
+
if (entry.isDirectory()) {
|
|
23774
|
+
fs7.cpSync(srcPath, dstPath, { recursive: true, dereference: true });
|
|
23775
|
+
} else if (entry.isFile()) {
|
|
23776
|
+
fs7.copyFileSync(srcPath, dstPath);
|
|
23777
|
+
}
|
|
23778
|
+
}
|
|
23779
|
+
}
|
|
23780
|
+
|
|
23608
23781
|
// src/index.ts
|
|
23609
23782
|
init_claude();
|
|
23610
23783
|
|
|
23611
23784
|
// src/tools/claude-tui.ts
|
|
23612
23785
|
var import_node_fs8 = __toESM(require("fs"), 1);
|
|
23613
23786
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
23614
|
-
var
|
|
23787
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
23615
23788
|
var headlessNs = __toESM(require_xterm_headless(), 1);
|
|
23616
23789
|
var serializeNs = __toESM(require_addon_serialize(), 1);
|
|
23617
23790
|
init_claude();
|
|
@@ -23845,10 +24018,10 @@ function createPopupDetector(opts) {
|
|
|
23845
24018
|
return visible;
|
|
23846
24019
|
},
|
|
23847
24020
|
writeBytes(data) {
|
|
23848
|
-
return new Promise((
|
|
24021
|
+
return new Promise((resolve2) => {
|
|
23849
24022
|
term.write(data, () => {
|
|
23850
24023
|
tick();
|
|
23851
|
-
|
|
24024
|
+
resolve2();
|
|
23852
24025
|
});
|
|
23853
24026
|
});
|
|
23854
24027
|
},
|
|
@@ -24065,7 +24238,7 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
|
|
|
24065
24238
|
function jsonlExistsForCtx(ctx) {
|
|
24066
24239
|
if (!ctx.toolSessionId) return false;
|
|
24067
24240
|
const home = import_node_os4.default.homedir();
|
|
24068
|
-
const file =
|
|
24241
|
+
const file = import_node_path9.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
|
|
24069
24242
|
try {
|
|
24070
24243
|
return import_node_fs8.default.statSync(file).isFile();
|
|
24071
24244
|
} catch {
|
|
@@ -24079,14 +24252,14 @@ init_claude_history();
|
|
|
24079
24252
|
// src/workspace/browser.ts
|
|
24080
24253
|
var import_node_fs9 = __toESM(require("fs"), 1);
|
|
24081
24254
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
24082
|
-
var
|
|
24255
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
24083
24256
|
init_protocol();
|
|
24084
24257
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
24085
24258
|
function resolveInsideCwd(cwd, subpath) {
|
|
24086
|
-
const absCwd =
|
|
24087
|
-
const joined =
|
|
24088
|
-
const rel =
|
|
24089
|
-
if (rel.startsWith("..") ||
|
|
24259
|
+
const absCwd = import_node_path10.default.resolve(cwd);
|
|
24260
|
+
const joined = import_node_path10.default.resolve(absCwd, subpath ?? ".");
|
|
24261
|
+
const rel = import_node_path10.default.relative(absCwd, joined);
|
|
24262
|
+
if (rel.startsWith("..") || import_node_path10.default.isAbsolute(rel)) {
|
|
24090
24263
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
24091
24264
|
}
|
|
24092
24265
|
return joined;
|
|
@@ -24117,7 +24290,7 @@ var WorkspaceBrowser = class {
|
|
|
24117
24290
|
mtime: ""
|
|
24118
24291
|
};
|
|
24119
24292
|
try {
|
|
24120
|
-
const st = import_node_fs9.default.statSync(
|
|
24293
|
+
const st = import_node_fs9.default.statSync(import_node_path10.default.join(full, d.name));
|
|
24121
24294
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
24122
24295
|
if (d.isFile()) entry.size = st.size;
|
|
24123
24296
|
} catch {
|
|
@@ -24164,7 +24337,7 @@ var WorkspaceBrowser = class {
|
|
|
24164
24337
|
// src/skills/scanner.ts
|
|
24165
24338
|
var import_node_fs10 = __toESM(require("fs"), 1);
|
|
24166
24339
|
var import_node_os6 = __toESM(require("os"), 1);
|
|
24167
|
-
var
|
|
24340
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
24168
24341
|
|
|
24169
24342
|
// src/skills/frontmatter.ts
|
|
24170
24343
|
var STRIP_QUOTES = /^["']|["']$/g;
|
|
@@ -24286,14 +24459,14 @@ function scanSkillDir(dir, source, seen, out, pluginName) {
|
|
|
24286
24459
|
return;
|
|
24287
24460
|
}
|
|
24288
24461
|
for (const ent of entries) {
|
|
24289
|
-
const entryPath =
|
|
24462
|
+
const entryPath = import_node_path11.default.join(dir, ent.name);
|
|
24290
24463
|
if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
|
|
24291
24464
|
let content;
|
|
24292
24465
|
try {
|
|
24293
|
-
content = import_node_fs10.default.readFileSync(
|
|
24466
|
+
content = import_node_fs10.default.readFileSync(import_node_path11.default.join(entryPath, "SKILL.md"), "utf8");
|
|
24294
24467
|
} catch {
|
|
24295
24468
|
try {
|
|
24296
|
-
content = import_node_fs10.default.readFileSync(
|
|
24469
|
+
content = import_node_fs10.default.readFileSync(import_node_path11.default.join(entryPath, "skill.md"), "utf8");
|
|
24297
24470
|
} catch {
|
|
24298
24471
|
continue;
|
|
24299
24472
|
}
|
|
@@ -24316,7 +24489,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
24316
24489
|
return;
|
|
24317
24490
|
}
|
|
24318
24491
|
for (const ent of entries) {
|
|
24319
|
-
const entryPath =
|
|
24492
|
+
const entryPath = import_node_path11.default.join(dir, ent.name);
|
|
24320
24493
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
|
|
24321
24494
|
const ns = ent.name;
|
|
24322
24495
|
let subEntries;
|
|
@@ -24327,7 +24500,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
24327
24500
|
}
|
|
24328
24501
|
for (const se of subEntries) {
|
|
24329
24502
|
if (!se.name.endsWith(".md")) continue;
|
|
24330
|
-
const sePath =
|
|
24503
|
+
const sePath = import_node_path11.default.join(entryPath, se.name);
|
|
24331
24504
|
let content;
|
|
24332
24505
|
try {
|
|
24333
24506
|
content = import_node_fs10.default.readFileSync(sePath, "utf8");
|
|
@@ -24363,7 +24536,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
24363
24536
|
}
|
|
24364
24537
|
}
|
|
24365
24538
|
function readInstalledPlugins(home) {
|
|
24366
|
-
const file =
|
|
24539
|
+
const file = import_node_path11.default.join(home, ".claude", "plugins", "installed_plugins.json");
|
|
24367
24540
|
let raw;
|
|
24368
24541
|
try {
|
|
24369
24542
|
raw = import_node_fs10.default.readFileSync(file, "utf8");
|
|
@@ -24414,14 +24587,14 @@ var SkillsScanner = class {
|
|
|
24414
24587
|
});
|
|
24415
24588
|
}
|
|
24416
24589
|
const fsBlock = [];
|
|
24417
|
-
scanSkillDir(
|
|
24418
|
-
scanCommandDir(
|
|
24419
|
-
scanSkillDir(
|
|
24420
|
-
scanCommandDir(
|
|
24590
|
+
scanSkillDir(import_node_path11.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
|
|
24591
|
+
scanCommandDir(import_node_path11.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
|
|
24592
|
+
scanSkillDir(import_node_path11.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
|
|
24593
|
+
scanCommandDir(import_node_path11.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
|
|
24421
24594
|
const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
|
|
24422
24595
|
for (const { name, root } of plugins) {
|
|
24423
|
-
scanSkillDir(
|
|
24424
|
-
scanCommandDir(
|
|
24596
|
+
scanSkillDir(import_node_path11.default.join(root, "skills"), "plugin", seen, fsBlock, name);
|
|
24597
|
+
scanCommandDir(import_node_path11.default.join(root, "commands"), "plugin", seen, fsBlock, name);
|
|
24425
24598
|
}
|
|
24426
24599
|
fsBlock.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
24427
24600
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -24431,7 +24604,7 @@ var SkillsScanner = class {
|
|
|
24431
24604
|
// src/skills/agents-scanner.ts
|
|
24432
24605
|
var import_node_fs11 = __toESM(require("fs"), 1);
|
|
24433
24606
|
var import_node_os7 = __toESM(require("os"), 1);
|
|
24434
|
-
var
|
|
24607
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
24435
24608
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
24436
24609
|
function isDirLikeSync2(p) {
|
|
24437
24610
|
try {
|
|
@@ -24469,10 +24642,10 @@ function scanAgentsDir(dir, source, seen, out) {
|
|
|
24469
24642
|
}
|
|
24470
24643
|
for (const ent of entries) {
|
|
24471
24644
|
if (!ent.name.endsWith(".md")) continue;
|
|
24472
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
24645
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path12.default.join(dir, ent.name)))) {
|
|
24473
24646
|
continue;
|
|
24474
24647
|
}
|
|
24475
|
-
const filePath =
|
|
24648
|
+
const filePath = import_node_path12.default.join(dir, ent.name);
|
|
24476
24649
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
24477
24650
|
if (seen.has(baseName)) continue;
|
|
24478
24651
|
seen.add(baseName);
|
|
@@ -24495,7 +24668,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
24495
24668
|
return;
|
|
24496
24669
|
}
|
|
24497
24670
|
for (const ent of entries) {
|
|
24498
|
-
const childPath =
|
|
24671
|
+
const childPath = import_node_path12.default.join(dir, ent.name);
|
|
24499
24672
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
24500
24673
|
walk(childPath, [...namespaces, ent.name]);
|
|
24501
24674
|
continue;
|
|
@@ -24520,9 +24693,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
24520
24693
|
walk(root, []);
|
|
24521
24694
|
}
|
|
24522
24695
|
function readInstalledPlugins2(home) {
|
|
24523
|
-
const pluginsDir =
|
|
24524
|
-
const v2 =
|
|
24525
|
-
const v1 =
|
|
24696
|
+
const pluginsDir = import_node_path12.default.join(home, ".claude", "plugins");
|
|
24697
|
+
const v2 = import_node_path12.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
24698
|
+
const v1 = import_node_path12.default.join(pluginsDir, "installed_plugins.json");
|
|
24526
24699
|
let raw = null;
|
|
24527
24700
|
for (const candidate of [v2, v1]) {
|
|
24528
24701
|
try {
|
|
@@ -24551,19 +24724,19 @@ function readInstalledPlugins2(home) {
|
|
|
24551
24724
|
return out;
|
|
24552
24725
|
}
|
|
24553
24726
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
24554
|
-
let cur =
|
|
24555
|
-
const fsRoot =
|
|
24727
|
+
let cur = import_node_path12.default.resolve(startCwd);
|
|
24728
|
+
const fsRoot = import_node_path12.default.parse(cur).root;
|
|
24556
24729
|
while (true) {
|
|
24557
|
-
scanAgentsDir(
|
|
24730
|
+
scanAgentsDir(import_node_path12.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
24558
24731
|
let hasGit = false;
|
|
24559
24732
|
try {
|
|
24560
|
-
hasGit = import_node_fs11.default.existsSync(
|
|
24733
|
+
hasGit = import_node_fs11.default.existsSync(import_node_path12.default.join(cur, ".git"));
|
|
24561
24734
|
} catch {
|
|
24562
24735
|
}
|
|
24563
24736
|
if (hasGit) return;
|
|
24564
24737
|
if (cur === home) return;
|
|
24565
24738
|
if (cur === fsRoot) return;
|
|
24566
|
-
const parent =
|
|
24739
|
+
const parent = import_node_path12.default.dirname(cur);
|
|
24567
24740
|
if (parent === cur) return;
|
|
24568
24741
|
cur = parent;
|
|
24569
24742
|
}
|
|
@@ -24598,7 +24771,7 @@ var AgentsScanner = class {
|
|
|
24598
24771
|
}
|
|
24599
24772
|
const fsBlock = [];
|
|
24600
24773
|
scanAgentsDir(
|
|
24601
|
-
|
|
24774
|
+
import_node_path12.default.join(this.home, ".claude", "agents"),
|
|
24602
24775
|
"global",
|
|
24603
24776
|
seen,
|
|
24604
24777
|
fsBlock
|
|
@@ -24612,7 +24785,7 @@ var AgentsScanner = class {
|
|
|
24612
24785
|
...this.extraPluginRoots
|
|
24613
24786
|
];
|
|
24614
24787
|
for (const { name, root } of plugins) {
|
|
24615
|
-
const agentsRoot =
|
|
24788
|
+
const agentsRoot = import_node_path12.default.join(root, "agents");
|
|
24616
24789
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
24617
24790
|
}
|
|
24618
24791
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -24622,7 +24795,7 @@ var AgentsScanner = class {
|
|
|
24622
24795
|
// src/observer/session-observer.ts
|
|
24623
24796
|
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
24624
24797
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
24625
|
-
var
|
|
24798
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
24626
24799
|
init_claude_history();
|
|
24627
24800
|
var SessionObserver = class {
|
|
24628
24801
|
constructor(opts) {
|
|
@@ -24634,7 +24807,7 @@ var SessionObserver = class {
|
|
|
24634
24807
|
watches = /* @__PURE__ */ new Map();
|
|
24635
24808
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
24636
24809
|
if (override) return override;
|
|
24637
|
-
return
|
|
24810
|
+
return import_node_path13.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
24638
24811
|
}
|
|
24639
24812
|
start(args) {
|
|
24640
24813
|
this.stop(args.sessionId);
|
|
@@ -24654,10 +24827,10 @@ var SessionObserver = class {
|
|
|
24654
24827
|
adapter: args.adapter
|
|
24655
24828
|
};
|
|
24656
24829
|
try {
|
|
24657
|
-
import_node_fs12.default.mkdirSync(
|
|
24830
|
+
import_node_fs12.default.mkdirSync(import_node_path13.default.dirname(filePath), { recursive: true });
|
|
24658
24831
|
} catch {
|
|
24659
24832
|
}
|
|
24660
|
-
w.watcher = import_node_fs12.default.watch(
|
|
24833
|
+
w.watcher = import_node_fs12.default.watch(import_node_path13.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
24661
24834
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
24662
24835
|
this.poll(w);
|
|
24663
24836
|
});
|
|
@@ -24839,7 +25012,7 @@ var LocalWsServer = class {
|
|
|
24839
25012
|
pingIntervalMs;
|
|
24840
25013
|
async start() {
|
|
24841
25014
|
const host = this.opts.host ?? "127.0.0.1";
|
|
24842
|
-
await new Promise((
|
|
25015
|
+
await new Promise((resolve2, reject) => {
|
|
24843
25016
|
const wss = new import_websocket_server.default({
|
|
24844
25017
|
host,
|
|
24845
25018
|
port: this.opts.port,
|
|
@@ -24847,7 +25020,7 @@ var LocalWsServer = class {
|
|
|
24847
25020
|
});
|
|
24848
25021
|
wss.on("listening", () => {
|
|
24849
25022
|
this.logger?.info("ws listening", { host, port: this.opts.port });
|
|
24850
|
-
|
|
25023
|
+
resolve2();
|
|
24851
25024
|
});
|
|
24852
25025
|
wss.on("error", (err) => {
|
|
24853
25026
|
this.logger?.error("ws server error", { err: err.message });
|
|
@@ -24867,8 +25040,8 @@ var LocalWsServer = class {
|
|
|
24867
25040
|
if (c.pingTimer) clearInterval(c.pingTimer);
|
|
24868
25041
|
}
|
|
24869
25042
|
this.clients.clear();
|
|
24870
|
-
await new Promise((
|
|
24871
|
-
this.wss?.close(() =>
|
|
25043
|
+
await new Promise((resolve2) => {
|
|
25044
|
+
this.wss?.close(() => resolve2());
|
|
24872
25045
|
});
|
|
24873
25046
|
this.wss = null;
|
|
24874
25047
|
}
|
|
@@ -25179,13 +25352,18 @@ var PersonaBoundHandler = class {
|
|
|
25179
25352
|
}
|
|
25180
25353
|
return true;
|
|
25181
25354
|
};
|
|
25355
|
+
const listenerScope = () => ({
|
|
25356
|
+
kind: "persona",
|
|
25357
|
+
personaId: scope.personaId,
|
|
25358
|
+
mode: "listener"
|
|
25359
|
+
});
|
|
25182
25360
|
switch (type) {
|
|
25183
25361
|
case "session:subscribe": {
|
|
25184
25362
|
if (!requireScopedSession()) return;
|
|
25185
25363
|
if (unsubscribe) unsubscribe();
|
|
25186
25364
|
unsubscribe = this.deps.sessionManager.subscribe(
|
|
25187
25365
|
scope.subSessionId,
|
|
25188
|
-
|
|
25366
|
+
listenerScope(),
|
|
25189
25367
|
(eventFrame) => send(eventFrame)
|
|
25190
25368
|
);
|
|
25191
25369
|
if (requestId)
|
|
@@ -25215,9 +25393,9 @@ var PersonaBoundHandler = class {
|
|
|
25215
25393
|
return;
|
|
25216
25394
|
}
|
|
25217
25395
|
try {
|
|
25218
|
-
this.deps.sessionManager.
|
|
25396
|
+
this.deps.sessionManager.sendForScope({
|
|
25219
25397
|
sessionId: scope.subSessionId,
|
|
25220
|
-
|
|
25398
|
+
scope: listenerScope(),
|
|
25221
25399
|
text
|
|
25222
25400
|
});
|
|
25223
25401
|
if (requestId) send({ type: "session:send", ok: true, requestId });
|
|
@@ -25230,9 +25408,9 @@ var PersonaBoundHandler = class {
|
|
|
25230
25408
|
case "session:new": {
|
|
25231
25409
|
if (!requireScopedSession()) return;
|
|
25232
25410
|
try {
|
|
25233
|
-
this.deps.sessionManager.
|
|
25411
|
+
this.deps.sessionManager.resetForScope({
|
|
25234
25412
|
sessionId: scope.subSessionId,
|
|
25235
|
-
|
|
25413
|
+
scope: listenerScope()
|
|
25236
25414
|
});
|
|
25237
25415
|
if (requestId) send({ type: "session:info", sessionId: scope.subSessionId, requestId });
|
|
25238
25416
|
} catch (err) {
|
|
@@ -25246,9 +25424,9 @@ var PersonaBoundHandler = class {
|
|
|
25246
25424
|
const limit = typeof frame.limit === "number" && frame.limit > 0 ? frame.limit : 50;
|
|
25247
25425
|
const offset = typeof frame.offset === "number" && frame.offset >= 0 ? frame.offset : 0;
|
|
25248
25426
|
try {
|
|
25249
|
-
const page = this.deps.sessionManager.
|
|
25427
|
+
const page = this.deps.sessionManager.readHistoryPageForScope(
|
|
25250
25428
|
scope.subSessionId,
|
|
25251
|
-
|
|
25429
|
+
listenerScope(),
|
|
25252
25430
|
limit,
|
|
25253
25431
|
offset
|
|
25254
25432
|
);
|
|
@@ -25379,9 +25557,9 @@ function isLocalhost(addr) {
|
|
|
25379
25557
|
|
|
25380
25558
|
// src/discovery/state-file.ts
|
|
25381
25559
|
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
25382
|
-
var
|
|
25560
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
25383
25561
|
function defaultStateFilePath(dataDir) {
|
|
25384
|
-
return
|
|
25562
|
+
return import_node_path14.default.join(dataDir, "state.json");
|
|
25385
25563
|
}
|
|
25386
25564
|
function isPidAlive(pid) {
|
|
25387
25565
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -25417,7 +25595,7 @@ var StateFileManager = class {
|
|
|
25417
25595
|
return { status: "stale", existing };
|
|
25418
25596
|
}
|
|
25419
25597
|
write(state) {
|
|
25420
|
-
import_node_fs13.default.mkdirSync(
|
|
25598
|
+
import_node_fs13.default.mkdirSync(import_node_path14.default.dirname(this.file), { recursive: true });
|
|
25421
25599
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
25422
25600
|
import_node_fs13.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
25423
25601
|
import_node_fs13.default.renameSync(tmp, this.file);
|
|
@@ -25438,13 +25616,13 @@ var StateFileManager = class {
|
|
|
25438
25616
|
|
|
25439
25617
|
// src/tunnel/tunnel-manager.ts
|
|
25440
25618
|
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
25441
|
-
var
|
|
25619
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
25442
25620
|
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
25443
25621
|
var import_node_child_process4 = require("child_process");
|
|
25444
25622
|
|
|
25445
25623
|
// src/tunnel/tunnel-store.ts
|
|
25446
25624
|
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
25447
|
-
var
|
|
25625
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
25448
25626
|
var TunnelStore = class {
|
|
25449
25627
|
constructor(filePath) {
|
|
25450
25628
|
this.filePath = filePath;
|
|
@@ -25463,7 +25641,7 @@ var TunnelStore = class {
|
|
|
25463
25641
|
}
|
|
25464
25642
|
}
|
|
25465
25643
|
async set(v) {
|
|
25466
|
-
const dir =
|
|
25644
|
+
const dir = import_node_path15.default.dirname(this.filePath);
|
|
25467
25645
|
await import_node_fs14.default.promises.mkdir(dir, { recursive: true });
|
|
25468
25646
|
const data = JSON.stringify(v, null, 2);
|
|
25469
25647
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
@@ -25575,7 +25753,7 @@ function escape(v) {
|
|
|
25575
25753
|
// src/tunnel/frpc-binary.ts
|
|
25576
25754
|
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
25577
25755
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
25578
|
-
var
|
|
25756
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
25579
25757
|
var import_node_child_process3 = require("child_process");
|
|
25580
25758
|
var import_node_stream2 = require("stream");
|
|
25581
25759
|
var import_promises = require("stream/promises");
|
|
@@ -25614,13 +25792,13 @@ async function ensureFrpcBinary(opts) {
|
|
|
25614
25792
|
}
|
|
25615
25793
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
25616
25794
|
const platform = opts.platform ?? detectPlatform();
|
|
25617
|
-
const binDir =
|
|
25795
|
+
const binDir = import_node_path16.default.join(opts.dataDir, "bin");
|
|
25618
25796
|
import_node_fs15.default.mkdirSync(binDir, { recursive: true });
|
|
25619
25797
|
cleanupStaleArtifacts(binDir);
|
|
25620
|
-
const stableBin =
|
|
25798
|
+
const stableBin = import_node_path16.default.join(binDir, "frpc");
|
|
25621
25799
|
if (import_node_fs15.default.existsSync(stableBin)) return stableBin;
|
|
25622
25800
|
const partialBin = `${stableBin}.partial`;
|
|
25623
|
-
const tarballPath =
|
|
25801
|
+
const tarballPath = import_node_path16.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
25624
25802
|
try {
|
|
25625
25803
|
const url = frpcDownloadUrl(version2, platform);
|
|
25626
25804
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -25646,7 +25824,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
25646
25824
|
}
|
|
25647
25825
|
for (const name of entries) {
|
|
25648
25826
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
25649
|
-
const full =
|
|
25827
|
+
const full = import_node_path16.default.join(binDir, name);
|
|
25650
25828
|
try {
|
|
25651
25829
|
import_node_fs15.default.rmSync(full, { recursive: true, force: true });
|
|
25652
25830
|
} catch {
|
|
@@ -25672,16 +25850,16 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
25672
25850
|
await (0, import_promises.pipeline)(nodeStream, out);
|
|
25673
25851
|
}
|
|
25674
25852
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
25675
|
-
const work =
|
|
25853
|
+
const work = import_node_path16.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
25676
25854
|
import_node_fs15.default.mkdirSync(work, { recursive: true });
|
|
25677
25855
|
try {
|
|
25678
|
-
await new Promise((
|
|
25856
|
+
await new Promise((resolve2, reject) => {
|
|
25679
25857
|
const proc = (0, import_node_child_process3.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
25680
25858
|
proc.on("error", reject);
|
|
25681
|
-
proc.on("exit", (code) => code === 0 ?
|
|
25859
|
+
proc.on("exit", (code) => code === 0 ? resolve2() : reject(new Error(`tar exited ${code}`)));
|
|
25682
25860
|
});
|
|
25683
25861
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
25684
|
-
const src =
|
|
25862
|
+
const src = import_node_path16.default.join(work, dirName, "frpc");
|
|
25685
25863
|
if (!import_node_fs15.default.existsSync(src)) {
|
|
25686
25864
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
25687
25865
|
}
|
|
@@ -25696,7 +25874,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
25696
25874
|
var TunnelManager = class {
|
|
25697
25875
|
constructor(deps) {
|
|
25698
25876
|
this.deps = deps;
|
|
25699
|
-
this.store = deps.store ?? new TunnelStore(
|
|
25877
|
+
this.store = deps.store ?? new TunnelStore(import_node_path17.default.join(deps.dataDir, "tunnel.json"));
|
|
25700
25878
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
25701
25879
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
25702
25880
|
}
|
|
@@ -25756,17 +25934,17 @@ var TunnelManager = class {
|
|
|
25756
25934
|
this.proc = null;
|
|
25757
25935
|
if (!proc) return;
|
|
25758
25936
|
proc.kill("SIGTERM");
|
|
25759
|
-
await new Promise((
|
|
25937
|
+
await new Promise((resolve2) => {
|
|
25760
25938
|
const t = setTimeout(() => {
|
|
25761
25939
|
try {
|
|
25762
25940
|
proc.kill("SIGKILL");
|
|
25763
25941
|
} catch {
|
|
25764
25942
|
}
|
|
25765
|
-
|
|
25943
|
+
resolve2();
|
|
25766
25944
|
}, 5e3);
|
|
25767
25945
|
proc.once("exit", () => {
|
|
25768
25946
|
clearTimeout(t);
|
|
25769
|
-
|
|
25947
|
+
resolve2();
|
|
25770
25948
|
});
|
|
25771
25949
|
});
|
|
25772
25950
|
}
|
|
@@ -25813,7 +25991,7 @@ var TunnelManager = class {
|
|
|
25813
25991
|
dataDir: this.deps.dataDir,
|
|
25814
25992
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
25815
25993
|
});
|
|
25816
|
-
const tomlPath =
|
|
25994
|
+
const tomlPath = import_node_path17.default.join(this.deps.dataDir, "frpc.toml");
|
|
25817
25995
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto4.default.randomBytes(3).toString("hex")}`;
|
|
25818
25996
|
const toml = buildFrpcToml({
|
|
25819
25997
|
serverAddr: t.frpsHost,
|
|
@@ -25828,7 +26006,7 @@ var TunnelManager = class {
|
|
|
25828
26006
|
const proc = (this.deps.spawnImpl ?? import_node_child_process4.spawn)(frpcBin, ["-c", tomlPath], {
|
|
25829
26007
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25830
26008
|
});
|
|
25831
|
-
const logFilePath =
|
|
26009
|
+
const logFilePath = import_node_path17.default.join(this.deps.dataDir, "frpc.log");
|
|
25832
26010
|
const logStream = import_node_fs16.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
25833
26011
|
logStream.on("error", () => {
|
|
25834
26012
|
});
|
|
@@ -25867,14 +26045,14 @@ function formatFrpcTail(raw, maxLines = 12) {
|
|
|
25867
26045
|
return ["\u2500\u2500\u2500 frpc output (last lines) \u2500\u2500\u2500", tail, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"].join("\n");
|
|
25868
26046
|
}
|
|
25869
26047
|
async function waitForFrpcReady(proc, timeoutMs) {
|
|
25870
|
-
return new Promise((
|
|
26048
|
+
return new Promise((resolve2) => {
|
|
25871
26049
|
let settled = false;
|
|
25872
26050
|
let buf = "";
|
|
25873
26051
|
const finish = (r) => {
|
|
25874
26052
|
if (settled) return;
|
|
25875
26053
|
settled = true;
|
|
25876
26054
|
cleanup();
|
|
25877
|
-
|
|
26055
|
+
resolve2(r);
|
|
25878
26056
|
};
|
|
25879
26057
|
const onData = (chunk) => {
|
|
25880
26058
|
buf += String(chunk);
|
|
@@ -25922,11 +26100,11 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
25922
26100
|
|
|
25923
26101
|
// src/auth-store.ts
|
|
25924
26102
|
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
25925
|
-
var
|
|
26103
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
25926
26104
|
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
25927
26105
|
var AUTH_FILE_NAME = "auth.json";
|
|
25928
26106
|
function authFilePath(dataDir) {
|
|
25929
|
-
return
|
|
26107
|
+
return import_node_path18.default.join(dataDir, AUTH_FILE_NAME);
|
|
25930
26108
|
}
|
|
25931
26109
|
function loadOrCreateAuthToken(opts) {
|
|
25932
26110
|
const file = authFilePath(opts.dataDir);
|
|
@@ -25958,7 +26136,7 @@ function readAuthFile(file) {
|
|
|
25958
26136
|
}
|
|
25959
26137
|
}
|
|
25960
26138
|
function writeAuthFile(file, content) {
|
|
25961
|
-
import_node_fs17.default.mkdirSync(
|
|
26139
|
+
import_node_fs17.default.mkdirSync(import_node_path18.default.dirname(file), { recursive: true });
|
|
25962
26140
|
import_node_fs17.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
25963
26141
|
try {
|
|
25964
26142
|
import_node_fs17.default.chmodSync(file, 384);
|
|
@@ -25966,6 +26144,38 @@ function writeAuthFile(file, content) {
|
|
|
25966
26144
|
}
|
|
25967
26145
|
}
|
|
25968
26146
|
|
|
26147
|
+
// src/owner-profile.ts
|
|
26148
|
+
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
26149
|
+
var import_node_os11 = __toESM(require("os"), 1);
|
|
26150
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
26151
|
+
var PROFILE_FILENAME = "profile.json";
|
|
26152
|
+
function loadOwnerDisplayName(dataDir) {
|
|
26153
|
+
const fallback = import_node_os11.default.userInfo().username;
|
|
26154
|
+
const profilePath = import_node_path19.default.join(dataDir, PROFILE_FILENAME);
|
|
26155
|
+
let raw;
|
|
26156
|
+
try {
|
|
26157
|
+
raw = import_node_fs18.default.readFileSync(profilePath, "utf8");
|
|
26158
|
+
} catch {
|
|
26159
|
+
return fallback;
|
|
26160
|
+
}
|
|
26161
|
+
let parsed;
|
|
26162
|
+
try {
|
|
26163
|
+
parsed = JSON.parse(raw);
|
|
26164
|
+
} catch (err) {
|
|
26165
|
+
console.warn(`[owner-profile] ${PROFILE_FILENAME} parse failed, falling back to OS username:`, err);
|
|
26166
|
+
return fallback;
|
|
26167
|
+
}
|
|
26168
|
+
if (!parsed || typeof parsed !== "object") return fallback;
|
|
26169
|
+
const displayName = parsed.displayName;
|
|
26170
|
+
if (typeof displayName !== "string" || displayName.length === 0) {
|
|
26171
|
+
if (displayName !== void 0) {
|
|
26172
|
+
console.warn(`[owner-profile] displayName must be non-empty string, falling back to OS username`);
|
|
26173
|
+
}
|
|
26174
|
+
return fallback;
|
|
26175
|
+
}
|
|
26176
|
+
return displayName;
|
|
26177
|
+
}
|
|
26178
|
+
|
|
25969
26179
|
// src/index.ts
|
|
25970
26180
|
init_protocol();
|
|
25971
26181
|
|
|
@@ -25973,12 +26183,12 @@ init_protocol();
|
|
|
25973
26183
|
init_protocol();
|
|
25974
26184
|
|
|
25975
26185
|
// src/session/fork.ts
|
|
25976
|
-
var
|
|
25977
|
-
var
|
|
25978
|
-
var
|
|
26186
|
+
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
26187
|
+
var import_node_os12 = __toESM(require("os"), 1);
|
|
26188
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
25979
26189
|
init_claude_history();
|
|
25980
26190
|
function readJsonlEntries(file) {
|
|
25981
|
-
const raw =
|
|
26191
|
+
const raw = import_node_fs19.default.readFileSync(file, "utf8");
|
|
25982
26192
|
const out = [];
|
|
25983
26193
|
for (const line of raw.split("\n")) {
|
|
25984
26194
|
const t = line.trim();
|
|
@@ -25991,10 +26201,10 @@ function readJsonlEntries(file) {
|
|
|
25991
26201
|
return out;
|
|
25992
26202
|
}
|
|
25993
26203
|
function forkSession(input) {
|
|
25994
|
-
const baseDir = input.baseDir ??
|
|
25995
|
-
const projectDir =
|
|
25996
|
-
const sourceFile =
|
|
25997
|
-
if (!
|
|
26204
|
+
const baseDir = input.baseDir ?? import_node_path20.default.join(import_node_os12.default.homedir(), ".claude");
|
|
26205
|
+
const projectDir = import_node_path20.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
26206
|
+
const sourceFile = import_node_path20.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
26207
|
+
if (!import_node_fs19.default.existsSync(sourceFile)) {
|
|
25998
26208
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
25999
26209
|
}
|
|
26000
26210
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -26024,9 +26234,9 @@ function forkSession(input) {
|
|
|
26024
26234
|
}
|
|
26025
26235
|
forkedLines.push(JSON.stringify(forked));
|
|
26026
26236
|
}
|
|
26027
|
-
const forkedFilePath =
|
|
26028
|
-
|
|
26029
|
-
|
|
26237
|
+
const forkedFilePath = import_node_path20.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
26238
|
+
import_node_fs19.default.mkdirSync(projectDir, { recursive: true });
|
|
26239
|
+
import_node_fs19.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
26030
26240
|
return { forkedToolSessionId, forkedFilePath };
|
|
26031
26241
|
}
|
|
26032
26242
|
|
|
@@ -26347,9 +26557,9 @@ init_protocol();
|
|
|
26347
26557
|
|
|
26348
26558
|
// src/workspace/git.ts
|
|
26349
26559
|
var import_node_child_process5 = require("child_process");
|
|
26350
|
-
var
|
|
26351
|
-
var
|
|
26352
|
-
var
|
|
26560
|
+
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
26561
|
+
var import_node_os13 = __toESM(require("os"), 1);
|
|
26562
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
26353
26563
|
var import_node_util = require("util");
|
|
26354
26564
|
var pexec = (0, import_node_util.promisify)(import_node_child_process5.execFile);
|
|
26355
26565
|
function formatChildProcessError(err) {
|
|
@@ -26364,9 +26574,9 @@ function formatChildProcessError(err) {
|
|
|
26364
26574
|
return e.message ?? "unknown error";
|
|
26365
26575
|
}
|
|
26366
26576
|
function normalizePath(p) {
|
|
26367
|
-
const resolved =
|
|
26577
|
+
const resolved = import_node_path21.default.resolve(p);
|
|
26368
26578
|
try {
|
|
26369
|
-
return
|
|
26579
|
+
return import_node_fs20.default.realpathSync(resolved);
|
|
26370
26580
|
} catch {
|
|
26371
26581
|
return resolved;
|
|
26372
26582
|
}
|
|
@@ -26453,7 +26663,7 @@ function sanitizeLabel(raw) {
|
|
|
26453
26663
|
function computePrefix() {
|
|
26454
26664
|
let username;
|
|
26455
26665
|
try {
|
|
26456
|
-
username =
|
|
26666
|
+
username = import_node_os13.default.userInfo().username;
|
|
26457
26667
|
} catch {
|
|
26458
26668
|
username = void 0;
|
|
26459
26669
|
}
|
|
@@ -26467,13 +26677,13 @@ function flattenToDirName(branch) {
|
|
|
26467
26677
|
}
|
|
26468
26678
|
function encodeClaudeProjectDir(absPath) {
|
|
26469
26679
|
if (!absPath || typeof absPath !== "string") return "";
|
|
26470
|
-
let canonical =
|
|
26680
|
+
let canonical = import_node_path21.default.resolve(absPath);
|
|
26471
26681
|
try {
|
|
26472
|
-
canonical =
|
|
26682
|
+
canonical = import_node_fs20.default.realpathSync(canonical);
|
|
26473
26683
|
} catch {
|
|
26474
26684
|
try {
|
|
26475
|
-
const parent =
|
|
26476
|
-
canonical =
|
|
26685
|
+
const parent = import_node_fs20.default.realpathSync(import_node_path21.default.dirname(canonical));
|
|
26686
|
+
canonical = import_node_path21.default.join(parent, import_node_path21.default.basename(canonical));
|
|
26477
26687
|
} catch {
|
|
26478
26688
|
}
|
|
26479
26689
|
}
|
|
@@ -26497,11 +26707,11 @@ async function createWorktree(input) {
|
|
|
26497
26707
|
if (!isGitRoot) {
|
|
26498
26708
|
throw new Error(`\u76EE\u5F55 ${cwd} \u4E0D\u662F git repo \u6839`);
|
|
26499
26709
|
}
|
|
26500
|
-
const parent =
|
|
26501
|
-
if (parent === "/" || parent ===
|
|
26710
|
+
const parent = import_node_path21.default.dirname(import_node_path21.default.resolve(cwd));
|
|
26711
|
+
if (parent === "/" || parent === import_node_path21.default.resolve(cwd)) {
|
|
26502
26712
|
throw new Error("repo \u5728\u78C1\u76D8\u6839\u76EE\u5F55\uFF0C\u65E0\u6CD5\u5728\u540C\u7EA7\u521B\u5EFA worktree");
|
|
26503
26713
|
}
|
|
26504
|
-
const worktreeRoot =
|
|
26714
|
+
const worktreeRoot = import_node_path21.default.join(parent, dirName);
|
|
26505
26715
|
try {
|
|
26506
26716
|
await pexec("git", ["-C", cwd, "fetch", "origin", baseBranch, "--no-tags"], {
|
|
26507
26717
|
timeout: 3e4
|
|
@@ -26520,7 +26730,7 @@ async function createWorktree(input) {
|
|
|
26520
26730
|
const msg = err.message;
|
|
26521
26731
|
if (msg.startsWith("\u5206\u652F ")) throw err;
|
|
26522
26732
|
}
|
|
26523
|
-
if (
|
|
26733
|
+
if (import_node_fs20.default.existsSync(worktreeRoot)) {
|
|
26524
26734
|
throw new Error(`\u76EE\u5F55 ${worktreeRoot} \u5DF2\u5B58\u5728\uFF0C\u8BF7\u6362\u4E00\u4E2A label \u6216\u6E05\u7406\u540E\u91CD\u8BD5`);
|
|
26525
26735
|
}
|
|
26526
26736
|
try {
|
|
@@ -26548,8 +26758,8 @@ async function removeWorktree(input) {
|
|
|
26548
26758
|
);
|
|
26549
26759
|
const gitCommonDir = stdout.trim();
|
|
26550
26760
|
if (!gitCommonDir) throw new Error("empty git-common-dir");
|
|
26551
|
-
const absGitCommon =
|
|
26552
|
-
repoRoot =
|
|
26761
|
+
const absGitCommon = import_node_path21.default.isAbsolute(gitCommonDir) ? gitCommonDir : import_node_path21.default.resolve(worktreeRoot, gitCommonDir);
|
|
26762
|
+
repoRoot = import_node_path21.default.dirname(absGitCommon);
|
|
26553
26763
|
} catch {
|
|
26554
26764
|
repoRoot = null;
|
|
26555
26765
|
}
|
|
@@ -26561,7 +26771,7 @@ async function removeWorktree(input) {
|
|
|
26561
26771
|
} catch (err) {
|
|
26562
26772
|
const stderr = err.stderr ?? "";
|
|
26563
26773
|
const lower = stderr.toLowerCase();
|
|
26564
|
-
const vanished = lower.includes("not a working tree") || lower.includes("is not a working tree") || !
|
|
26774
|
+
const vanished = lower.includes("not a working tree") || lower.includes("is not a working tree") || !import_node_fs20.default.existsSync(worktreeRoot);
|
|
26565
26775
|
if (!vanished) {
|
|
26566
26776
|
throw new Error(`\u6E05\u7406 worktree \u5931\u8D25\uFF1A${formatChildProcessError(err)}`);
|
|
26567
26777
|
}
|
|
@@ -26580,10 +26790,10 @@ async function removeWorktree(input) {
|
|
|
26580
26790
|
try {
|
|
26581
26791
|
const encoded = encodeClaudeProjectDir(worktreeRoot);
|
|
26582
26792
|
if (encoded) {
|
|
26583
|
-
const projectsRoot =
|
|
26584
|
-
const target =
|
|
26585
|
-
if (target.startsWith(projectsRoot +
|
|
26586
|
-
|
|
26793
|
+
const projectsRoot = import_node_path21.default.join(import_node_os13.default.homedir(), ".claude", "projects");
|
|
26794
|
+
const target = import_node_path21.default.resolve(projectsRoot, encoded);
|
|
26795
|
+
if (target.startsWith(projectsRoot + import_node_path21.default.sep) && target !== projectsRoot) {
|
|
26796
|
+
import_node_fs20.default.rmSync(target, { recursive: true, force: true });
|
|
26587
26797
|
}
|
|
26588
26798
|
}
|
|
26589
26799
|
} catch {
|
|
@@ -26655,7 +26865,7 @@ function buildCapabilitiesHandlers(deps) {
|
|
|
26655
26865
|
}
|
|
26656
26866
|
|
|
26657
26867
|
// src/handlers/meta.ts
|
|
26658
|
-
var
|
|
26868
|
+
var import_node_os14 = __toESM(require("os"), 1);
|
|
26659
26869
|
init_protocol();
|
|
26660
26870
|
|
|
26661
26871
|
// src/version.ts
|
|
@@ -26677,7 +26887,7 @@ function buildReadyFrame(deps) {
|
|
|
26677
26887
|
return {
|
|
26678
26888
|
version,
|
|
26679
26889
|
protocolVersion: PROTOCOL_VERSION,
|
|
26680
|
-
hostname:
|
|
26890
|
+
hostname: import_node_os14.default.hostname(),
|
|
26681
26891
|
os: process.platform,
|
|
26682
26892
|
tools,
|
|
26683
26893
|
runningSessions: info.runningSessions,
|
|
@@ -26752,7 +26962,7 @@ function buildPersonaHandlers(deps) {
|
|
|
26752
26962
|
};
|
|
26753
26963
|
const listSubSessions = async (frame) => {
|
|
26754
26964
|
const args = PersonaIdArgsSchema.parse(frame);
|
|
26755
|
-
const sessions = sessionManager.
|
|
26965
|
+
const sessions = sessionManager.listPersonaSessions(args.personaId, "listener");
|
|
26756
26966
|
return {
|
|
26757
26967
|
response: { type: "persona:subSessions", sessions }
|
|
26758
26968
|
};
|
|
@@ -26799,7 +27009,7 @@ function buildMethodHandlers(deps) {
|
|
|
26799
27009
|
async function startDaemon(config) {
|
|
26800
27010
|
const logger = createLogger({
|
|
26801
27011
|
level: config.logLevel,
|
|
26802
|
-
file:
|
|
27012
|
+
file: import_node_path22.default.join(config.dataDir, "clawd.log")
|
|
26803
27013
|
});
|
|
26804
27014
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
26805
27015
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -26831,15 +27041,23 @@ async function startDaemon(config) {
|
|
|
26831
27041
|
const agents = new AgentsScanner();
|
|
26832
27042
|
const history = new ClaudeHistoryReader();
|
|
26833
27043
|
let transport = null;
|
|
26834
|
-
const personaStore = new PersonaStore(
|
|
27044
|
+
const personaStore = new PersonaStore(import_node_path22.default.join(config.dataDir, "personas"));
|
|
27045
|
+
const defaultsRoot = findDefaultsRoot();
|
|
27046
|
+
if (defaultsRoot) {
|
|
27047
|
+
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
27048
|
+
} else {
|
|
27049
|
+
logger.warn("persona.seed.skip", { reason: "defaults-root-not-found" });
|
|
27050
|
+
}
|
|
27051
|
+
const ownerDisplayName = loadOwnerDisplayName(config.dataDir);
|
|
26835
27052
|
const manager = new SessionManager({
|
|
26836
27053
|
store,
|
|
26837
27054
|
logger,
|
|
26838
27055
|
getAdapter,
|
|
26839
27056
|
historyReader: history,
|
|
26840
27057
|
dataDir: config.dataDir,
|
|
26841
|
-
personaRoot:
|
|
27058
|
+
personaRoot: import_node_path22.default.join(config.dataDir, "personas"),
|
|
26842
27059
|
personaStore,
|
|
27060
|
+
ownerDisplayName,
|
|
26843
27061
|
mode: config.mode,
|
|
26844
27062
|
broadcastFrame: (frame, target) => {
|
|
26845
27063
|
if (target === "all") {
|
|
@@ -27050,8 +27268,8 @@ async function startDaemon(config) {
|
|
|
27050
27268
|
const lines = [
|
|
27051
27269
|
`Tunnel: ${r.url}`,
|
|
27052
27270
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
27053
|
-
`Frpc config: ${
|
|
27054
|
-
`Frpc log: ${
|
|
27271
|
+
`Frpc config: ${import_node_path22.default.join(config.dataDir, "frpc.toml")}`,
|
|
27272
|
+
`Frpc log: ${import_node_path22.default.join(config.dataDir, "frpc.log")}`
|
|
27055
27273
|
];
|
|
27056
27274
|
const width = Math.max(...lines.map((l) => l.length));
|
|
27057
27275
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -27064,8 +27282,8 @@ ${bar}
|
|
|
27064
27282
|
|
|
27065
27283
|
`);
|
|
27066
27284
|
try {
|
|
27067
|
-
const connectPath =
|
|
27068
|
-
|
|
27285
|
+
const connectPath = import_node_path22.default.join(config.dataDir, "connect.txt");
|
|
27286
|
+
import_node_fs21.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
27069
27287
|
} catch {
|
|
27070
27288
|
}
|
|
27071
27289
|
} catch (err) {
|