@clawos-dev/clawd 0.2.139 → 0.2.140-beta.290.4d01c03
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
CHANGED
|
@@ -720,8 +720,8 @@ var init_parseUtil = __esm({
|
|
|
720
720
|
init_errors2();
|
|
721
721
|
init_en();
|
|
722
722
|
makeIssue = (params) => {
|
|
723
|
-
const { data, path:
|
|
724
|
-
const fullPath = [...
|
|
723
|
+
const { data, path: path59, errorMaps, issueData } = params;
|
|
724
|
+
const fullPath = [...path59, ...issueData.path || []];
|
|
725
725
|
const fullIssue = {
|
|
726
726
|
...issueData,
|
|
727
727
|
path: fullPath
|
|
@@ -1032,11 +1032,11 @@ var init_types = __esm({
|
|
|
1032
1032
|
init_parseUtil();
|
|
1033
1033
|
init_util();
|
|
1034
1034
|
ParseInputLazyPath = class {
|
|
1035
|
-
constructor(parent, value,
|
|
1035
|
+
constructor(parent, value, path59, key) {
|
|
1036
1036
|
this._cachedPath = [];
|
|
1037
1037
|
this.parent = parent;
|
|
1038
1038
|
this.data = value;
|
|
1039
|
-
this._path =
|
|
1039
|
+
this._path = path59;
|
|
1040
1040
|
this._key = key;
|
|
1041
1041
|
}
|
|
1042
1042
|
get path() {
|
|
@@ -4752,6 +4752,13 @@ var init_schemas = __esm({
|
|
|
4752
4752
|
* - native `session:*` handler 完全不感知 mirror(UI 操作 mirror 不走 native 路径)
|
|
4753
4753
|
*/
|
|
4754
4754
|
originOwnerPrincipalId: external_exports.string().min(1).optional(),
|
|
4755
|
+
/**
|
|
4756
|
+
* Dispatch 派生的 session 在 create 时记录源 session 的 sessionId(稳定 key);
|
|
4757
|
+
* sidebar 据此把 dispatch 出来的 sub-session 折叠在源 session 下。非 dispatch session 缺省。
|
|
4758
|
+
* mirror SessionFile 上必须 strip(朋友 daemon 上的 sessionId 在本机无意义,会让本机
|
|
4759
|
+
* 反查路径走错;按 #750 一族防线处理,跟 ownerPersonaId 同地点 strip)。
|
|
4760
|
+
*/
|
|
4761
|
+
dispatchedFromSessionId: external_exports.string().min(1).optional(),
|
|
4755
4762
|
createdAt: external_exports.string().min(1),
|
|
4756
4763
|
updatedAt: external_exports.string().min(1)
|
|
4757
4764
|
});
|
|
@@ -5926,6 +5933,34 @@ var init_feishu_auth = __esm({
|
|
|
5926
5933
|
}
|
|
5927
5934
|
});
|
|
5928
5935
|
|
|
5936
|
+
// ../protocol/src/dispatch.ts
|
|
5937
|
+
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema;
|
|
5938
|
+
var init_dispatch = __esm({
|
|
5939
|
+
"../protocol/src/dispatch.ts"() {
|
|
5940
|
+
"use strict";
|
|
5941
|
+
init_zod();
|
|
5942
|
+
DispatchOutcomeSchema = external_exports.discriminatedUnion("kind", [
|
|
5943
|
+
external_exports.object({
|
|
5944
|
+
kind: external_exports.literal("success"),
|
|
5945
|
+
text: external_exports.string(),
|
|
5946
|
+
filePaths: external_exports.array(external_exports.string()).optional()
|
|
5947
|
+
}),
|
|
5948
|
+
external_exports.object({
|
|
5949
|
+
kind: external_exports.literal("failure"),
|
|
5950
|
+
reason: external_exports.string()
|
|
5951
|
+
})
|
|
5952
|
+
]);
|
|
5953
|
+
DispatchRunArgsSchema = external_exports.object({
|
|
5954
|
+
targetPersona: external_exports.string().min(1),
|
|
5955
|
+
prompt: external_exports.string()
|
|
5956
|
+
});
|
|
5957
|
+
DispatchCompleteArgsSchema = external_exports.object({
|
|
5958
|
+
dispatchId: external_exports.string().min(1),
|
|
5959
|
+
outcome: DispatchOutcomeSchema
|
|
5960
|
+
});
|
|
5961
|
+
}
|
|
5962
|
+
});
|
|
5963
|
+
|
|
5929
5964
|
// ../protocol/src/runtime.ts
|
|
5930
5965
|
var init_runtime = __esm({
|
|
5931
5966
|
"../protocol/src/runtime.ts"() {
|
|
@@ -5944,6 +5979,7 @@ var init_runtime = __esm({
|
|
|
5944
5979
|
init_contact();
|
|
5945
5980
|
init_extension();
|
|
5946
5981
|
init_feishu_auth();
|
|
5982
|
+
init_dispatch();
|
|
5947
5983
|
}
|
|
5948
5984
|
});
|
|
5949
5985
|
|
|
@@ -6218,8 +6254,8 @@ var require_req = __commonJS({
|
|
|
6218
6254
|
if (req.originalUrl) {
|
|
6219
6255
|
_req.url = req.originalUrl;
|
|
6220
6256
|
} else {
|
|
6221
|
-
const
|
|
6222
|
-
_req.url = typeof
|
|
6257
|
+
const path59 = req.path;
|
|
6258
|
+
_req.url = typeof path59 === "string" ? path59 : req.url ? req.url.path || req.url : void 0;
|
|
6223
6259
|
}
|
|
6224
6260
|
if (req.query) {
|
|
6225
6261
|
_req.query = req.query;
|
|
@@ -6384,14 +6420,14 @@ var require_redact = __commonJS({
|
|
|
6384
6420
|
}
|
|
6385
6421
|
return obj;
|
|
6386
6422
|
}
|
|
6387
|
-
function parsePath(
|
|
6423
|
+
function parsePath(path59) {
|
|
6388
6424
|
const parts = [];
|
|
6389
6425
|
let current = "";
|
|
6390
6426
|
let inBrackets = false;
|
|
6391
6427
|
let inQuotes = false;
|
|
6392
6428
|
let quoteChar = "";
|
|
6393
|
-
for (let i = 0; i <
|
|
6394
|
-
const char =
|
|
6429
|
+
for (let i = 0; i < path59.length; i++) {
|
|
6430
|
+
const char = path59[i];
|
|
6395
6431
|
if (!inBrackets && char === ".") {
|
|
6396
6432
|
if (current) {
|
|
6397
6433
|
parts.push(current);
|
|
@@ -6522,10 +6558,10 @@ var require_redact = __commonJS({
|
|
|
6522
6558
|
return current;
|
|
6523
6559
|
}
|
|
6524
6560
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
6525
|
-
for (const
|
|
6526
|
-
const parts = parsePath(
|
|
6561
|
+
for (const path59 of paths) {
|
|
6562
|
+
const parts = parsePath(path59);
|
|
6527
6563
|
if (parts.includes("*")) {
|
|
6528
|
-
redactWildcardPath(obj, parts, censor,
|
|
6564
|
+
redactWildcardPath(obj, parts, censor, path59, remove);
|
|
6529
6565
|
} else {
|
|
6530
6566
|
if (remove) {
|
|
6531
6567
|
removeKey(obj, parts);
|
|
@@ -6610,8 +6646,8 @@ var require_redact = __commonJS({
|
|
|
6610
6646
|
}
|
|
6611
6647
|
} else {
|
|
6612
6648
|
if (afterWildcard.includes("*")) {
|
|
6613
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6614
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
6649
|
+
const wrappedCensor = typeof censor === "function" ? (value, path59) => {
|
|
6650
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path59];
|
|
6615
6651
|
return censor(value, fullPath);
|
|
6616
6652
|
} : censor;
|
|
6617
6653
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6646,8 +6682,8 @@ var require_redact = __commonJS({
|
|
|
6646
6682
|
return null;
|
|
6647
6683
|
}
|
|
6648
6684
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6649
|
-
for (const
|
|
6650
|
-
const parts = parsePath(
|
|
6685
|
+
for (const path59 of pathsToClone) {
|
|
6686
|
+
const parts = parsePath(path59);
|
|
6651
6687
|
let current = pathStructure;
|
|
6652
6688
|
for (let i = 0; i < parts.length; i++) {
|
|
6653
6689
|
const part = parts[i];
|
|
@@ -6699,24 +6735,24 @@ var require_redact = __commonJS({
|
|
|
6699
6735
|
}
|
|
6700
6736
|
return cloneSelectively(obj, pathStructure);
|
|
6701
6737
|
}
|
|
6702
|
-
function validatePath(
|
|
6703
|
-
if (typeof
|
|
6738
|
+
function validatePath(path59) {
|
|
6739
|
+
if (typeof path59 !== "string") {
|
|
6704
6740
|
throw new Error("Paths must be (non-empty) strings");
|
|
6705
6741
|
}
|
|
6706
|
-
if (
|
|
6742
|
+
if (path59 === "") {
|
|
6707
6743
|
throw new Error("Invalid redaction path ()");
|
|
6708
6744
|
}
|
|
6709
|
-
if (
|
|
6710
|
-
throw new Error(`Invalid redaction path (${
|
|
6745
|
+
if (path59.includes("..")) {
|
|
6746
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6711
6747
|
}
|
|
6712
|
-
if (
|
|
6713
|
-
throw new Error(`Invalid redaction path (${
|
|
6748
|
+
if (path59.includes(",")) {
|
|
6749
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6714
6750
|
}
|
|
6715
6751
|
let bracketCount = 0;
|
|
6716
6752
|
let inQuotes = false;
|
|
6717
6753
|
let quoteChar = "";
|
|
6718
|
-
for (let i = 0; i <
|
|
6719
|
-
const char =
|
|
6754
|
+
for (let i = 0; i < path59.length; i++) {
|
|
6755
|
+
const char = path59[i];
|
|
6720
6756
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6721
6757
|
if (!inQuotes) {
|
|
6722
6758
|
inQuotes = true;
|
|
@@ -6730,20 +6766,20 @@ var require_redact = __commonJS({
|
|
|
6730
6766
|
} else if (char === "]" && !inQuotes) {
|
|
6731
6767
|
bracketCount--;
|
|
6732
6768
|
if (bracketCount < 0) {
|
|
6733
|
-
throw new Error(`Invalid redaction path (${
|
|
6769
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6734
6770
|
}
|
|
6735
6771
|
}
|
|
6736
6772
|
}
|
|
6737
6773
|
if (bracketCount !== 0) {
|
|
6738
|
-
throw new Error(`Invalid redaction path (${
|
|
6774
|
+
throw new Error(`Invalid redaction path (${path59})`);
|
|
6739
6775
|
}
|
|
6740
6776
|
}
|
|
6741
6777
|
function validatePaths(paths) {
|
|
6742
6778
|
if (!Array.isArray(paths)) {
|
|
6743
6779
|
throw new TypeError("paths must be an array");
|
|
6744
6780
|
}
|
|
6745
|
-
for (const
|
|
6746
|
-
validatePath(
|
|
6781
|
+
for (const path59 of paths) {
|
|
6782
|
+
validatePath(path59);
|
|
6747
6783
|
}
|
|
6748
6784
|
}
|
|
6749
6785
|
function slowRedact(options = {}) {
|
|
@@ -6911,8 +6947,8 @@ var require_redaction = __commonJS({
|
|
|
6911
6947
|
if (shape[k2] === null) {
|
|
6912
6948
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
6913
6949
|
} else {
|
|
6914
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6915
|
-
return censor(value, [k2, ...
|
|
6950
|
+
const wrappedCensor = typeof censor === "function" ? (value, path59) => {
|
|
6951
|
+
return censor(value, [k2, ...path59]);
|
|
6916
6952
|
} : censor;
|
|
6917
6953
|
o[k2] = Redact({
|
|
6918
6954
|
paths: shape[k2],
|
|
@@ -7130,10 +7166,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
7130
7166
|
var require_sonic_boom = __commonJS({
|
|
7131
7167
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
7132
7168
|
"use strict";
|
|
7133
|
-
var
|
|
7169
|
+
var fs52 = require("fs");
|
|
7134
7170
|
var EventEmitter3 = require("events");
|
|
7135
7171
|
var inherits = require("util").inherits;
|
|
7136
|
-
var
|
|
7172
|
+
var path59 = require("path");
|
|
7137
7173
|
var sleep = require_atomic_sleep();
|
|
7138
7174
|
var assert = require("assert");
|
|
7139
7175
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -7187,20 +7223,20 @@ var require_sonic_boom = __commonJS({
|
|
|
7187
7223
|
const mode = sonic.mode;
|
|
7188
7224
|
if (sonic.sync) {
|
|
7189
7225
|
try {
|
|
7190
|
-
if (sonic.mkdir)
|
|
7191
|
-
const fd =
|
|
7226
|
+
if (sonic.mkdir) fs52.mkdirSync(path59.dirname(file), { recursive: true });
|
|
7227
|
+
const fd = fs52.openSync(file, flags, mode);
|
|
7192
7228
|
fileOpened(null, fd);
|
|
7193
7229
|
} catch (err) {
|
|
7194
7230
|
fileOpened(err);
|
|
7195
7231
|
throw err;
|
|
7196
7232
|
}
|
|
7197
7233
|
} else if (sonic.mkdir) {
|
|
7198
|
-
|
|
7234
|
+
fs52.mkdir(path59.dirname(file), { recursive: true }, (err) => {
|
|
7199
7235
|
if (err) return fileOpened(err);
|
|
7200
|
-
|
|
7236
|
+
fs52.open(file, flags, mode, fileOpened);
|
|
7201
7237
|
});
|
|
7202
7238
|
} else {
|
|
7203
|
-
|
|
7239
|
+
fs52.open(file, flags, mode, fileOpened);
|
|
7204
7240
|
}
|
|
7205
7241
|
}
|
|
7206
7242
|
function SonicBoom(opts) {
|
|
@@ -7241,8 +7277,8 @@ var require_sonic_boom = __commonJS({
|
|
|
7241
7277
|
this.flush = flushBuffer;
|
|
7242
7278
|
this.flushSync = flushBufferSync;
|
|
7243
7279
|
this._actualWrite = actualWriteBuffer;
|
|
7244
|
-
fsWriteSync = () =>
|
|
7245
|
-
fsWrite = () =>
|
|
7280
|
+
fsWriteSync = () => fs52.writeSync(this.fd, this._writingBuf);
|
|
7281
|
+
fsWrite = () => fs52.write(this.fd, this._writingBuf, this.release);
|
|
7246
7282
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
7247
7283
|
this._writingBuf = "";
|
|
7248
7284
|
this.write = write;
|
|
@@ -7251,15 +7287,15 @@ var require_sonic_boom = __commonJS({
|
|
|
7251
7287
|
this._actualWrite = actualWrite;
|
|
7252
7288
|
fsWriteSync = () => {
|
|
7253
7289
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7254
|
-
return
|
|
7290
|
+
return fs52.writeSync(this.fd, this._writingBuf);
|
|
7255
7291
|
}
|
|
7256
|
-
return
|
|
7292
|
+
return fs52.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7257
7293
|
};
|
|
7258
7294
|
fsWrite = () => {
|
|
7259
7295
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7260
|
-
return
|
|
7296
|
+
return fs52.write(this.fd, this._writingBuf, this.release);
|
|
7261
7297
|
}
|
|
7262
|
-
return
|
|
7298
|
+
return fs52.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
7263
7299
|
};
|
|
7264
7300
|
} else {
|
|
7265
7301
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -7316,7 +7352,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7316
7352
|
}
|
|
7317
7353
|
}
|
|
7318
7354
|
if (this._fsync) {
|
|
7319
|
-
|
|
7355
|
+
fs52.fsyncSync(this.fd);
|
|
7320
7356
|
}
|
|
7321
7357
|
const len = this._len;
|
|
7322
7358
|
if (this._reopening) {
|
|
@@ -7430,7 +7466,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7430
7466
|
const onDrain = () => {
|
|
7431
7467
|
if (!this._fsync) {
|
|
7432
7468
|
try {
|
|
7433
|
-
|
|
7469
|
+
fs52.fsync(this.fd, (err) => {
|
|
7434
7470
|
this._flushPending = false;
|
|
7435
7471
|
cb(err);
|
|
7436
7472
|
});
|
|
@@ -7532,7 +7568,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7532
7568
|
const fd = this.fd;
|
|
7533
7569
|
this.once("ready", () => {
|
|
7534
7570
|
if (fd !== this.fd) {
|
|
7535
|
-
|
|
7571
|
+
fs52.close(fd, (err) => {
|
|
7536
7572
|
if (err) {
|
|
7537
7573
|
return this.emit("error", err);
|
|
7538
7574
|
}
|
|
@@ -7581,7 +7617,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7581
7617
|
buf = this._bufs[0];
|
|
7582
7618
|
}
|
|
7583
7619
|
try {
|
|
7584
|
-
const n = Buffer.isBuffer(buf) ?
|
|
7620
|
+
const n = Buffer.isBuffer(buf) ? fs52.writeSync(this.fd, buf) : fs52.writeSync(this.fd, buf, "utf8");
|
|
7585
7621
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
7586
7622
|
buf = releasedBufObj.writingBuf;
|
|
7587
7623
|
this._len = releasedBufObj.len;
|
|
@@ -7597,7 +7633,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7597
7633
|
}
|
|
7598
7634
|
}
|
|
7599
7635
|
try {
|
|
7600
|
-
|
|
7636
|
+
fs52.fsyncSync(this.fd);
|
|
7601
7637
|
} catch {
|
|
7602
7638
|
}
|
|
7603
7639
|
}
|
|
@@ -7618,7 +7654,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7618
7654
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
7619
7655
|
}
|
|
7620
7656
|
try {
|
|
7621
|
-
const n =
|
|
7657
|
+
const n = fs52.writeSync(this.fd, buf);
|
|
7622
7658
|
buf = buf.subarray(n);
|
|
7623
7659
|
this._len = Math.max(this._len - n, 0);
|
|
7624
7660
|
if (buf.length <= 0) {
|
|
@@ -7646,13 +7682,13 @@ var require_sonic_boom = __commonJS({
|
|
|
7646
7682
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
7647
7683
|
if (this.sync) {
|
|
7648
7684
|
try {
|
|
7649
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
7685
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs52.writeSync(this.fd, this._writingBuf) : fs52.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7650
7686
|
release(null, written);
|
|
7651
7687
|
} catch (err) {
|
|
7652
7688
|
release(err);
|
|
7653
7689
|
}
|
|
7654
7690
|
} else {
|
|
7655
|
-
|
|
7691
|
+
fs52.write(this.fd, this._writingBuf, release);
|
|
7656
7692
|
}
|
|
7657
7693
|
}
|
|
7658
7694
|
function actualWriteBuffer() {
|
|
@@ -7661,7 +7697,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7661
7697
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
7662
7698
|
if (this.sync) {
|
|
7663
7699
|
try {
|
|
7664
|
-
const written =
|
|
7700
|
+
const written = fs52.writeSync(this.fd, this._writingBuf);
|
|
7665
7701
|
release(null, written);
|
|
7666
7702
|
} catch (err) {
|
|
7667
7703
|
release(err);
|
|
@@ -7670,7 +7706,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7670
7706
|
if (kCopyBuffer) {
|
|
7671
7707
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
7672
7708
|
}
|
|
7673
|
-
|
|
7709
|
+
fs52.write(this.fd, this._writingBuf, release);
|
|
7674
7710
|
}
|
|
7675
7711
|
}
|
|
7676
7712
|
function actualClose(sonic) {
|
|
@@ -7686,12 +7722,12 @@ var require_sonic_boom = __commonJS({
|
|
|
7686
7722
|
sonic._lens = [];
|
|
7687
7723
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
7688
7724
|
try {
|
|
7689
|
-
|
|
7725
|
+
fs52.fsync(sonic.fd, closeWrapped);
|
|
7690
7726
|
} catch {
|
|
7691
7727
|
}
|
|
7692
7728
|
function closeWrapped() {
|
|
7693
7729
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
7694
|
-
|
|
7730
|
+
fs52.close(sonic.fd, done);
|
|
7695
7731
|
} else {
|
|
7696
7732
|
done();
|
|
7697
7733
|
}
|
|
@@ -10055,7 +10091,7 @@ var require_multistream = __commonJS({
|
|
|
10055
10091
|
var require_pino = __commonJS({
|
|
10056
10092
|
"../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
|
|
10057
10093
|
"use strict";
|
|
10058
|
-
var
|
|
10094
|
+
var os22 = require("os");
|
|
10059
10095
|
var stdSerializers = require_pino_std_serializers();
|
|
10060
10096
|
var caller = require_caller();
|
|
10061
10097
|
var redaction = require_redaction();
|
|
@@ -10102,7 +10138,7 @@ var require_pino = __commonJS({
|
|
|
10102
10138
|
} = symbols;
|
|
10103
10139
|
var { epochTime, nullTime } = time;
|
|
10104
10140
|
var { pid } = process;
|
|
10105
|
-
var hostname =
|
|
10141
|
+
var hostname = os22.hostname();
|
|
10106
10142
|
var defaultErrorSerializer = stdSerializers.err;
|
|
10107
10143
|
var defaultOptions = {
|
|
10108
10144
|
level: "info",
|
|
@@ -10826,11 +10862,11 @@ var init_lib = __esm({
|
|
|
10826
10862
|
}
|
|
10827
10863
|
}
|
|
10828
10864
|
},
|
|
10829
|
-
addToPath: function addToPath(
|
|
10830
|
-
var last =
|
|
10865
|
+
addToPath: function addToPath(path59, added, removed, oldPosInc, options) {
|
|
10866
|
+
var last = path59.lastComponent;
|
|
10831
10867
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10832
10868
|
return {
|
|
10833
|
-
oldPos:
|
|
10869
|
+
oldPos: path59.oldPos + oldPosInc,
|
|
10834
10870
|
lastComponent: {
|
|
10835
10871
|
count: last.count + 1,
|
|
10836
10872
|
added,
|
|
@@ -10840,7 +10876,7 @@ var init_lib = __esm({
|
|
|
10840
10876
|
};
|
|
10841
10877
|
} else {
|
|
10842
10878
|
return {
|
|
10843
|
-
oldPos:
|
|
10879
|
+
oldPos: path59.oldPos + oldPosInc,
|
|
10844
10880
|
lastComponent: {
|
|
10845
10881
|
count: 1,
|
|
10846
10882
|
added,
|
|
@@ -11286,10 +11322,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
11286
11322
|
const memories = raw.map((m2) => {
|
|
11287
11323
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11288
11324
|
const rec3 = m2;
|
|
11289
|
-
const
|
|
11325
|
+
const path59 = typeof rec3.path === "string" ? rec3.path : null;
|
|
11290
11326
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
11291
|
-
if (!
|
|
11292
|
-
const entry = { path:
|
|
11327
|
+
if (!path59 || content == null) return null;
|
|
11328
|
+
const entry = { path: path59, content };
|
|
11293
11329
|
if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
|
|
11294
11330
|
return entry;
|
|
11295
11331
|
}).filter((m2) => m2 !== null);
|
|
@@ -11809,6 +11845,9 @@ function buildSpawnArgs(ctx) {
|
|
|
11809
11845
|
if (ctx.addDirs) {
|
|
11810
11846
|
for (const dir of ctx.addDirs) args.push("--add-dir", dir);
|
|
11811
11847
|
}
|
|
11848
|
+
if (ctx.dispatchMcpConfigPath) {
|
|
11849
|
+
args.push("--mcp-config", ctx.dispatchMcpConfigPath);
|
|
11850
|
+
}
|
|
11812
11851
|
if (ctx.effort) args.push("--effort", ctx.effort);
|
|
11813
11852
|
if (ctx.toolSessionId) args.push("--resume", ctx.toolSessionId);
|
|
11814
11853
|
return args;
|
|
@@ -12088,10 +12127,10 @@ function parseAttachment(obj) {
|
|
|
12088
12127
|
const memories = raw.map((m2) => {
|
|
12089
12128
|
if (!m2 || typeof m2 !== "object") return null;
|
|
12090
12129
|
const rec3 = m2;
|
|
12091
|
-
const
|
|
12130
|
+
const path59 = typeof rec3.path === "string" ? rec3.path : null;
|
|
12092
12131
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
12093
|
-
if (!
|
|
12094
|
-
const out = { path:
|
|
12132
|
+
if (!path59 || content == null) return null;
|
|
12133
|
+
const out = { path: path59, content };
|
|
12095
12134
|
if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
|
|
12096
12135
|
return out;
|
|
12097
12136
|
}).filter((m2) => m2 !== null);
|
|
@@ -23878,8 +23917,8 @@ var require_utils = __commonJS({
|
|
|
23878
23917
|
var result = transform[inputType][outputType](input);
|
|
23879
23918
|
return result;
|
|
23880
23919
|
};
|
|
23881
|
-
exports2.resolve = function(
|
|
23882
|
-
var parts =
|
|
23920
|
+
exports2.resolve = function(path59) {
|
|
23921
|
+
var parts = path59.split("/");
|
|
23883
23922
|
var result = [];
|
|
23884
23923
|
for (var index = 0; index < parts.length; index++) {
|
|
23885
23924
|
var part = parts[index];
|
|
@@ -29732,18 +29771,18 @@ var require_object = __commonJS({
|
|
|
29732
29771
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
29733
29772
|
this.files[name] = object;
|
|
29734
29773
|
};
|
|
29735
|
-
var parentFolder = function(
|
|
29736
|
-
if (
|
|
29737
|
-
|
|
29774
|
+
var parentFolder = function(path59) {
|
|
29775
|
+
if (path59.slice(-1) === "/") {
|
|
29776
|
+
path59 = path59.substring(0, path59.length - 1);
|
|
29738
29777
|
}
|
|
29739
|
-
var lastSlash =
|
|
29740
|
-
return lastSlash > 0 ?
|
|
29778
|
+
var lastSlash = path59.lastIndexOf("/");
|
|
29779
|
+
return lastSlash > 0 ? path59.substring(0, lastSlash) : "";
|
|
29741
29780
|
};
|
|
29742
|
-
var forceTrailingSlash = function(
|
|
29743
|
-
if (
|
|
29744
|
-
|
|
29781
|
+
var forceTrailingSlash = function(path59) {
|
|
29782
|
+
if (path59.slice(-1) !== "/") {
|
|
29783
|
+
path59 += "/";
|
|
29745
29784
|
}
|
|
29746
|
-
return
|
|
29785
|
+
return path59;
|
|
29747
29786
|
};
|
|
29748
29787
|
var folderAdd = function(name, createFolders) {
|
|
29749
29788
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -30745,7 +30784,7 @@ var require_lib3 = __commonJS({
|
|
|
30745
30784
|
// src/run-case/recorder.ts
|
|
30746
30785
|
function startRunCaseRecorder(opts) {
|
|
30747
30786
|
const now = opts.now ?? Date.now;
|
|
30748
|
-
const dir =
|
|
30787
|
+
const dir = import_node_path47.default.dirname(opts.recordPath);
|
|
30749
30788
|
let stream = null;
|
|
30750
30789
|
let closing = false;
|
|
30751
30790
|
let closedSettled = false;
|
|
@@ -30759,8 +30798,8 @@ function startRunCaseRecorder(opts) {
|
|
|
30759
30798
|
});
|
|
30760
30799
|
const ensureStream = () => {
|
|
30761
30800
|
if (stream) return stream;
|
|
30762
|
-
|
|
30763
|
-
stream =
|
|
30801
|
+
import_node_fs35.default.mkdirSync(dir, { recursive: true });
|
|
30802
|
+
stream = import_node_fs35.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
30764
30803
|
stream.on("close", () => closedResolve());
|
|
30765
30804
|
return stream;
|
|
30766
30805
|
};
|
|
@@ -30785,12 +30824,12 @@ function startRunCaseRecorder(opts) {
|
|
|
30785
30824
|
};
|
|
30786
30825
|
return { tap, close, closed };
|
|
30787
30826
|
}
|
|
30788
|
-
var
|
|
30827
|
+
var import_node_fs35, import_node_path47;
|
|
30789
30828
|
var init_recorder = __esm({
|
|
30790
30829
|
"src/run-case/recorder.ts"() {
|
|
30791
30830
|
"use strict";
|
|
30792
|
-
|
|
30793
|
-
|
|
30831
|
+
import_node_fs35 = __toESM(require("fs"), 1);
|
|
30832
|
+
import_node_path47 = __toESM(require("path"), 1);
|
|
30794
30833
|
}
|
|
30795
30834
|
});
|
|
30796
30835
|
|
|
@@ -30833,7 +30872,7 @@ var init_wire = __esm({
|
|
|
30833
30872
|
// src/run-case/controller.ts
|
|
30834
30873
|
async function runController(opts) {
|
|
30835
30874
|
const now = opts.now ?? Date.now;
|
|
30836
|
-
const cwd = opts.cwd ?? (0,
|
|
30875
|
+
const cwd = opts.cwd ?? (0, import_node_fs36.mkdtempSync)(import_node_path48.default.join(import_node_os20.default.tmpdir(), "clawd-runcase-"));
|
|
30837
30876
|
const ownsCwd = opts.cwd === void 0;
|
|
30838
30877
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
30839
30878
|
const spawnCtx = { cwd };
|
|
@@ -30994,19 +31033,19 @@ async function runController(opts) {
|
|
|
30994
31033
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
30995
31034
|
if (ownsCwd) {
|
|
30996
31035
|
try {
|
|
30997
|
-
(0,
|
|
31036
|
+
(0, import_node_fs36.rmSync)(cwd, { recursive: true, force: true });
|
|
30998
31037
|
} catch {
|
|
30999
31038
|
}
|
|
31000
31039
|
}
|
|
31001
31040
|
return exitCode ?? 0;
|
|
31002
31041
|
}
|
|
31003
|
-
var
|
|
31042
|
+
var import_node_fs36, import_node_os20, import_node_path48;
|
|
31004
31043
|
var init_controller = __esm({
|
|
31005
31044
|
"src/run-case/controller.ts"() {
|
|
31006
31045
|
"use strict";
|
|
31007
|
-
|
|
31008
|
-
|
|
31009
|
-
|
|
31046
|
+
import_node_fs36 = require("fs");
|
|
31047
|
+
import_node_os20 = __toESM(require("os"), 1);
|
|
31048
|
+
import_node_path48 = __toESM(require("path"), 1);
|
|
31010
31049
|
init_claude();
|
|
31011
31050
|
init_stdout_splitter();
|
|
31012
31051
|
init_permission_stdio();
|
|
@@ -31241,8 +31280,59 @@ Env (advanced):
|
|
|
31241
31280
|
`;
|
|
31242
31281
|
|
|
31243
31282
|
// src/index.ts
|
|
31244
|
-
var
|
|
31245
|
-
var
|
|
31283
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
31284
|
+
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
31285
|
+
var import_node_os19 = __toESM(require("os"), 1);
|
|
31286
|
+
|
|
31287
|
+
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
31288
|
+
var byteToHex = [];
|
|
31289
|
+
for (let i = 0; i < 256; ++i) {
|
|
31290
|
+
byteToHex.push((i + 256).toString(16).slice(1));
|
|
31291
|
+
}
|
|
31292
|
+
function unsafeStringify(arr, offset = 0) {
|
|
31293
|
+
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
|
31294
|
+
}
|
|
31295
|
+
|
|
31296
|
+
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/rng.js
|
|
31297
|
+
var import_node_crypto = __toESM(require("crypto"));
|
|
31298
|
+
var rnds8Pool = new Uint8Array(256);
|
|
31299
|
+
var poolPtr = rnds8Pool.length;
|
|
31300
|
+
function rng() {
|
|
31301
|
+
if (poolPtr > rnds8Pool.length - 16) {
|
|
31302
|
+
import_node_crypto.default.randomFillSync(rnds8Pool);
|
|
31303
|
+
poolPtr = 0;
|
|
31304
|
+
}
|
|
31305
|
+
return rnds8Pool.slice(poolPtr, poolPtr += 16);
|
|
31306
|
+
}
|
|
31307
|
+
|
|
31308
|
+
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/native.js
|
|
31309
|
+
var import_node_crypto2 = __toESM(require("crypto"));
|
|
31310
|
+
var native_default = {
|
|
31311
|
+
randomUUID: import_node_crypto2.default.randomUUID
|
|
31312
|
+
};
|
|
31313
|
+
|
|
31314
|
+
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/v4.js
|
|
31315
|
+
function v4(options, buf, offset) {
|
|
31316
|
+
if (native_default.randomUUID && !buf && !options) {
|
|
31317
|
+
return native_default.randomUUID();
|
|
31318
|
+
}
|
|
31319
|
+
options = options || {};
|
|
31320
|
+
const rnds = options.random || (options.rng || rng)();
|
|
31321
|
+
rnds[6] = rnds[6] & 15 | 64;
|
|
31322
|
+
rnds[8] = rnds[8] & 63 | 128;
|
|
31323
|
+
if (buf) {
|
|
31324
|
+
offset = offset || 0;
|
|
31325
|
+
for (let i = 0; i < 16; ++i) {
|
|
31326
|
+
buf[offset + i] = rnds[i];
|
|
31327
|
+
}
|
|
31328
|
+
return buf;
|
|
31329
|
+
}
|
|
31330
|
+
return unsafeStringify(rnds);
|
|
31331
|
+
}
|
|
31332
|
+
var v4_default = v4;
|
|
31333
|
+
|
|
31334
|
+
// src/index.ts
|
|
31335
|
+
var import_node_url2 = require("url");
|
|
31246
31336
|
|
|
31247
31337
|
// src/logger.ts
|
|
31248
31338
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
@@ -31484,55 +31574,6 @@ var SessionStoreFactory = class {
|
|
|
31484
31574
|
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
31485
31575
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
31486
31576
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
31487
|
-
|
|
31488
|
-
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
31489
|
-
var byteToHex = [];
|
|
31490
|
-
for (let i = 0; i < 256; ++i) {
|
|
31491
|
-
byteToHex.push((i + 256).toString(16).slice(1));
|
|
31492
|
-
}
|
|
31493
|
-
function unsafeStringify(arr, offset = 0) {
|
|
31494
|
-
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
|
31495
|
-
}
|
|
31496
|
-
|
|
31497
|
-
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/rng.js
|
|
31498
|
-
var import_node_crypto = __toESM(require("crypto"));
|
|
31499
|
-
var rnds8Pool = new Uint8Array(256);
|
|
31500
|
-
var poolPtr = rnds8Pool.length;
|
|
31501
|
-
function rng() {
|
|
31502
|
-
if (poolPtr > rnds8Pool.length - 16) {
|
|
31503
|
-
import_node_crypto.default.randomFillSync(rnds8Pool);
|
|
31504
|
-
poolPtr = 0;
|
|
31505
|
-
}
|
|
31506
|
-
return rnds8Pool.slice(poolPtr, poolPtr += 16);
|
|
31507
|
-
}
|
|
31508
|
-
|
|
31509
|
-
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/native.js
|
|
31510
|
-
var import_node_crypto2 = __toESM(require("crypto"));
|
|
31511
|
-
var native_default = {
|
|
31512
|
-
randomUUID: import_node_crypto2.default.randomUUID
|
|
31513
|
-
};
|
|
31514
|
-
|
|
31515
|
-
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/v4.js
|
|
31516
|
-
function v4(options, buf, offset) {
|
|
31517
|
-
if (native_default.randomUUID && !buf && !options) {
|
|
31518
|
-
return native_default.randomUUID();
|
|
31519
|
-
}
|
|
31520
|
-
options = options || {};
|
|
31521
|
-
const rnds = options.random || (options.rng || rng)();
|
|
31522
|
-
rnds[6] = rnds[6] & 15 | 64;
|
|
31523
|
-
rnds[8] = rnds[8] & 63 | 128;
|
|
31524
|
-
if (buf) {
|
|
31525
|
-
offset = offset || 0;
|
|
31526
|
-
for (let i = 0; i < 16; ++i) {
|
|
31527
|
-
buf[offset + i] = rnds[i];
|
|
31528
|
-
}
|
|
31529
|
-
return buf;
|
|
31530
|
-
}
|
|
31531
|
-
return unsafeStringify(rnds);
|
|
31532
|
-
}
|
|
31533
|
-
var v4_default = v4;
|
|
31534
|
-
|
|
31535
|
-
// src/session/manager.ts
|
|
31536
31577
|
init_protocol();
|
|
31537
31578
|
|
|
31538
31579
|
// src/tools/guest-settings.ts
|
|
@@ -31657,6 +31698,32 @@ function buildConnectionPrompt(args) {
|
|
|
31657
31698
|
return result;
|
|
31658
31699
|
}
|
|
31659
31700
|
|
|
31701
|
+
// src/dispatch/system-prompt.ts
|
|
31702
|
+
var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A persona\uFF08dispatch\uFF09
|
|
31703
|
+
|
|
31704
|
+
\u5F53\u7528\u6237\u6D88\u606F\u91CC\u542B \`@persona/<id>\`\uFF08\u5982 \`@persona/persona-bug-fixer\`\uFF09\u65F6\uFF0C**\u4F60\u5FC5\u987B**\u7ACB\u5373\u8C03 MCP tool \`mcp__clawd-dispatch__personaDispatch\` \u59D4\u6D3E\uFF0C\u4E0D\u8981\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF1A
|
|
31705
|
+
|
|
31706
|
+
- \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
|
|
31707
|
+
- \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
|
|
31708
|
+
|
|
31709
|
+
tool \u4F1A\u963B\u585E\u6302\u8D77\u7B49\u5BF9\u65B9\u4EBA\u683C\u5E72\u5B8C\uFF0C\u628A outcome\uFF08\u542B text + \u53EF\u9009 filePaths\uFF09\u4F5C\u4E3A tool_result \u56DE\u7ED9\u4F60\uFF0C\u4F60\u518D\u7EFC\u5408\u56DE\u5E94\u7528\u6237\u3002
|
|
31710
|
+
|
|
31711
|
+
- **\u4E0D\u8981**\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF08\u4F60\u4E0D\u662F\u90A3\u4E2A persona\uFF09
|
|
31712
|
+
- **\u4E0D\u8981** in-place \u6A21\u4EFF\u5BF9\u65B9\u4EBA\u683C \u2014\u2014 dispatch \u662F\u771F\u5207\u5230\u53E6\u4E00\u4E2A\u72EC\u7ACB session
|
|
31713
|
+
- \u4E00\u53E5\u8BDD\u91CC\u591A\u4E2A \`@persona/<id>\` \u65F6\u9009\u7B2C\u4E00\u4E2A\uFF08tool \u4E00\u6B21\u53EA\u5904\u7406\u4E00\u4E2A target\uFF09
|
|
31714
|
+
- \u59D4\u6D3E\u5931\u8D25\uFF08tool_result.is_error=true\uFF09\u65F6\u5982\u5B9E\u544A\u8BC9\u7528\u6237\u539F\u56E0\uFF0C**\u4E0D\u8981\u91CD\u8BD5**
|
|
31715
|
+
|
|
31716
|
+
## \u88AB dispatch \u63A5\u5230\u4EFB\u52A1
|
|
31717
|
+
|
|
31718
|
+
\u5982\u679C\u4F60\u7684 session \u7B2C\u4E00\u6761 user message \u662F \`<system-reminder>You have been dispatched by owner from another persona session ...</system-reminder>\`\uFF0C\u4F60\u662F\u88AB\u53E6\u4E00\u4E2A persona \u59D4\u6D3E\u6765\u5E72\u6D3B\u7684\uFF1A
|
|
31719
|
+
|
|
31720
|
+
- \u4EFB\u52A1\u5728 \`Task:\` \u6BB5
|
|
31721
|
+
- \u539F\u4F1A\u8BDD\u7684\u5BF9\u8BDD\u5386\u53F2\u5728 \`Source conversation\` \u6BB5\u7ED9\u7684 jsonl \u8DEF\u5F84\u4E0B\uFF1B\u6309\u9700 Read \u5B83\u4E86\u89E3\u4E0A\u4E0B\u6587\uFF08\u4E0D\u5FC5\u8BFB\u5B8C\uFF09
|
|
31722
|
+
- \u5E72\u5B8C\u540E**\u5FC5\u987B**\u8C03 \`mcp__clawd-dispatch__personaDispatchComplete\` \u62A5\u544A\u7ED3\u679C\uFF1A
|
|
31723
|
+
- \u6210\u529F\uFF1A\`{ text: "\u603B\u7ED3/\u7ED3\u8BBA", filePaths?: ["\u4F60\u4EA7\u51FA/\u6539\u7684\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84"] }\`
|
|
31724
|
+
- \u5931\u8D25\uFF1A\`{ isFailure: true, reason: "..." }\`
|
|
31725
|
+
- \u62A5\u544A\u5B8C\u540E\u4F60\u7684 session \u5C31\u7ED3\u675F\u4E86\uFF0C\u4E0D\u8981\u7EE7\u7EED\u8F93\u51FA`;
|
|
31726
|
+
|
|
31660
31727
|
// src/session/reducer.ts
|
|
31661
31728
|
function cloneState(s) {
|
|
31662
31729
|
return {
|
|
@@ -31735,6 +31802,9 @@ function buildSpawnContext(state, deps) {
|
|
|
31735
31802
|
env.CLAWD_SESSION_ID = file.sessionId;
|
|
31736
31803
|
const daemonUrl = deps.getDaemonUrl?.() ?? null;
|
|
31737
31804
|
if (daemonUrl) env.CLAWD_DAEMON_URL = daemonUrl;
|
|
31805
|
+
const dispatchId = deps.lookupDispatchByBSessionId?.(file.sessionId);
|
|
31806
|
+
if (dispatchId) env.CLAWD_DISPATCH_ID = dispatchId;
|
|
31807
|
+
const dispatchMcpConfigPath2 = deps.getDispatchMcpConfigPath?.() ?? null;
|
|
31738
31808
|
const ctx = {
|
|
31739
31809
|
cwd: file.cwd,
|
|
31740
31810
|
toolSessionId: file.toolSessionId,
|
|
@@ -31744,7 +31814,10 @@ function buildSpawnContext(state, deps) {
|
|
|
31744
31814
|
env,
|
|
31745
31815
|
// Phase 2 capability platform (plan §3): personaRoot 透传给 buildSpawnArgs;
|
|
31746
31816
|
// 内部 shouldSandbox(cwd, personaRoot) 决定是否注入 --settings sandbox-settings.
|
|
31747
|
-
personaRoot: deps.personaRoot
|
|
31817
|
+
personaRoot: deps.personaRoot,
|
|
31818
|
+
// Persona dispatch:所有 session(A 和 B)都挂同一份 dispatch.mcp.json,让两边的 cc
|
|
31819
|
+
// 都能看到 personaDispatch / personaDispatchComplete tool;按 env 区分实际行为。
|
|
31820
|
+
dispatchMcpConfigPath: dispatchMcpConfigPath2 ?? void 0
|
|
31748
31821
|
};
|
|
31749
31822
|
const meta = state.subSessionMeta;
|
|
31750
31823
|
if (meta?.personaMode) {
|
|
@@ -31755,6 +31828,9 @@ function buildSpawnContext(state, deps) {
|
|
|
31755
31828
|
workDir: meta.userWorkDir
|
|
31756
31829
|
});
|
|
31757
31830
|
}
|
|
31831
|
+
if (dispatchMcpConfigPath2) {
|
|
31832
|
+
ctx.extraSystemPrompt = (ctx.extraSystemPrompt ? ctx.extraSystemPrompt + "\n\n" : "") + DISPATCH_SYSTEM_PROMPT_HINT;
|
|
31833
|
+
}
|
|
31758
31834
|
if (meta?.extraSettings) {
|
|
31759
31835
|
ctx.extraSettings = meta.extraSettings;
|
|
31760
31836
|
}
|
|
@@ -32420,35 +32496,6 @@ function startRecorder(opts) {
|
|
|
32420
32496
|
};
|
|
32421
32497
|
}
|
|
32422
32498
|
|
|
32423
|
-
// src/persona/mention-injection.ts
|
|
32424
|
-
var MENTION_RE = /@persona\/([A-Za-z0-9_-]+)(?=\s|$|[^A-Za-z0-9_-])/g;
|
|
32425
|
-
function injectPersonaMentions(rawText, store) {
|
|
32426
|
-
const resolved = [];
|
|
32427
|
-
const body = rawText.replace(MENTION_RE, (match, id) => {
|
|
32428
|
-
const meta = store.read(id);
|
|
32429
|
-
const personality = store.readPersonality(id);
|
|
32430
|
-
if (meta && personality !== null) {
|
|
32431
|
-
resolved.push({ label: meta.label, personality });
|
|
32432
|
-
return "";
|
|
32433
|
-
}
|
|
32434
|
-
return match;
|
|
32435
|
-
});
|
|
32436
|
-
if (resolved.length === 0) {
|
|
32437
|
-
return { systemReminder: null, userText: rawText };
|
|
32438
|
-
}
|
|
32439
|
-
const blocks = resolved.map((r) => {
|
|
32440
|
-
const safe = r.personality.replace(/<\/system-reminder>/gi, "</ system-reminder>");
|
|
32441
|
-
return `[Acting as persona "${r.label}" for this message]
|
|
32442
|
-
${safe}`;
|
|
32443
|
-
});
|
|
32444
|
-
return {
|
|
32445
|
-
systemReminder: `<system-reminder>
|
|
32446
|
-
${blocks.join("\n\n")}
|
|
32447
|
-
</system-reminder>`,
|
|
32448
|
-
userText: body.trim()
|
|
32449
|
-
};
|
|
32450
|
-
}
|
|
32451
|
-
|
|
32452
32499
|
// src/session/runner.ts
|
|
32453
32500
|
var DEFAULT_CONTROL_REQUEST_TIMEOUT_MS = 1e4;
|
|
32454
32501
|
function encodeAllowWithInputControlResponse(requestId, updatedInput) {
|
|
@@ -32497,7 +32544,6 @@ var SessionRunner = class {
|
|
|
32497
32544
|
}
|
|
32498
32545
|
// 外部推送 input 到 reducer,然后执行产出的 effects
|
|
32499
32546
|
input(inputMsg) {
|
|
32500
|
-
const personaStore = this.hooks.personaStore;
|
|
32501
32547
|
const adapter = this.hooks.adapter;
|
|
32502
32548
|
const deps = {
|
|
32503
32549
|
// file-sharing (spec §6 PR 3):在 stdout-line 解析时同步观察 file-edit 工具事件,
|
|
@@ -32507,20 +32553,10 @@ var SessionRunner = class {
|
|
|
32507
32553
|
if (this.hooks.onFileEdit) this.observeForFileEdit(events);
|
|
32508
32554
|
return events;
|
|
32509
32555
|
},
|
|
32510
|
-
//
|
|
32511
|
-
//
|
|
32512
|
-
//
|
|
32513
|
-
|
|
32514
|
-
// - 第二条正常用户气泡,刷新页面不再暴露 personality 文本。
|
|
32515
|
-
encodeStdin: (t, ctx) => {
|
|
32516
|
-
if (!personaStore) return adapter.encodeStdin(t, ctx) ?? "";
|
|
32517
|
-
const { systemReminder, userText } = injectPersonaMentions(t, personaStore);
|
|
32518
|
-
if (systemReminder === null) return adapter.encodeStdin(userText, ctx) ?? "";
|
|
32519
|
-
const metaFrame = adapter.encodeStdin(systemReminder, ctx) ?? "";
|
|
32520
|
-
if (userText === "") return metaFrame;
|
|
32521
|
-
const userFrame = adapter.encodeStdin(userText, ctx) ?? "";
|
|
32522
|
-
return metaFrame + userFrame;
|
|
32523
|
-
},
|
|
32556
|
+
// Persona dispatch (Task 9):原 in-place `@persona/<id>` 注入路径已删,cc 自己看到字面
|
|
32557
|
+
// token 会调 personaDispatch MCP tool 委派(dispatch.mcp.json 通过 cc --mcp-config 加载,
|
|
32558
|
+
// CLAUDE.md 教 cc 触发条件)。encodeStdin 现在是 adapter 的简单 passthrough。
|
|
32559
|
+
encodeStdin: (t, ctx) => adapter.encodeStdin(t, ctx) ?? "",
|
|
32524
32560
|
bufferCap: this.hooks.bufferCap ?? 500,
|
|
32525
32561
|
now: this.hooks.now ?? Date.now,
|
|
32526
32562
|
resolveContextWindow: this.hooks.resolveContextWindow,
|
|
@@ -32530,6 +32566,10 @@ var SessionRunner = class {
|
|
|
32530
32566
|
// 单栏 refactor (spec 2026-06-02 §5.1): cc 子进程 env 注入 CLAWD_DAEMON_URL,让 assistant
|
|
32531
32567
|
// curl daemon HTTP RPC adapter (/api/rpc/<method>) 触发管理操作。null = HTTP adapter 未启。
|
|
32532
32568
|
getDaemonUrl: this.hooks.getDaemonUrl,
|
|
32569
|
+
// Persona dispatch:透传 dispatch.mcp.json 路径闭包 + B→dispatchId 反查闭包。
|
|
32570
|
+
// 见 reducer.buildSpawnContext 注 CLAWD_DISPATCH_ID env / 派生 SpawnContext.dispatchMcpConfigPath
|
|
32571
|
+
getDispatchMcpConfigPath: this.hooks.getDispatchMcpConfigPath,
|
|
32572
|
+
lookupDispatchByBSessionId: this.hooks.lookupDispatchByBSessionId,
|
|
32533
32573
|
// ReadyGate v2:透传 mode 让 reducer send / ready-detected 分支决定走暂存队列还是直写
|
|
32534
32574
|
mode: this.hooks.mode,
|
|
32535
32575
|
// [RG-DBG] 注入 logger 让 reducer rgDbg 走 pino 进 clawd.log;定位完跟 rgDbg 一起删
|
|
@@ -32989,6 +33029,22 @@ function nowIso2(deps) {
|
|
|
32989
33029
|
function newSessionId() {
|
|
32990
33030
|
return v4_default().replace(/-/g, "").slice(0, 16);
|
|
32991
33031
|
}
|
|
33032
|
+
function buildDispatchTaskPack(args) {
|
|
33033
|
+
return `[Dispatched from owner \u2014 another persona session\u59D4\u6D3E\u7ED9\u4F60\u6267\u884C\u4EFB\u52A1]
|
|
33034
|
+
|
|
33035
|
+
Task:
|
|
33036
|
+
${args.prompt}
|
|
33037
|
+
|
|
33038
|
+
Source conversation (jsonl, CC stream-json format, one message per line):
|
|
33039
|
+
${args.sourceJsonlPath}
|
|
33040
|
+
You may read this file with your Read tool to understand context. You do not have to read it all.
|
|
33041
|
+
|
|
33042
|
+
When done, call the MCP tool \`mcp__clawd-dispatch__personaDispatchComplete\` with your result:
|
|
33043
|
+
- Success: { text: "...", filePaths?: ["abs/path", ...] }
|
|
33044
|
+
- Failure: { isFailure: true, reason: "..." }
|
|
33045
|
+
|
|
33046
|
+
dispatchId for this task: ${args.dispatchId}`;
|
|
33047
|
+
}
|
|
32992
33048
|
function derivePersonaSpawnCwd(file, personaRoot) {
|
|
32993
33049
|
const personaId = file.ownerPersonaId;
|
|
32994
33050
|
if (!personaId) return file.cwd;
|
|
@@ -33286,7 +33342,8 @@ var SessionManager = class {
|
|
|
33286
33342
|
// adapter 自己持有模型表 + 兜底逻辑(contains / opus-1M / [1m] 等),manager 不再 cache 转发
|
|
33287
33343
|
resolveContextWindow: (tool, modelId) => this.deps.getAdapter(tool).resolveContextWindow(modelId),
|
|
33288
33344
|
dataDir: this.deps.dataDir,
|
|
33289
|
-
personaStore
|
|
33345
|
+
// personaStore 不再透给 runner hooks(in-place mention 注入路径已删,runner 不用);
|
|
33346
|
+
// manager 自身的 sandbox 派生仍直接读 this.deps.personaStore。
|
|
33290
33347
|
ownerDisplayName: this.deps.ownerDisplayName,
|
|
33291
33348
|
// Phase 2 capability platform (plan §3): 透传 personaRoot, buildSpawnArgs 据
|
|
33292
33349
|
// cwd 是否在 personaRoot 下自动决定是否注入 --settings sandbox-settings.json.
|
|
@@ -33294,6 +33351,10 @@ var SessionManager = class {
|
|
|
33294
33351
|
// 单栏 refactor (spec 2026-06-02 §5.1): 透传 daemon HTTP RPC base URL 闭包,
|
|
33295
33352
|
// reducer 把它注入 cc 子进程 env CLAWD_DAEMON_URL.
|
|
33296
33353
|
getDaemonUrl: this.deps.getDaemonUrl,
|
|
33354
|
+
// Persona dispatch (Task 7): dispatch.mcp.json 路径 + B sessionId → dispatchId 反查
|
|
33355
|
+
// 闭包透传给 reducer,让 cc spawn 加 --mcp-config flag + B session 注 CLAWD_DISPATCH_ID env.
|
|
33356
|
+
getDispatchMcpConfigPath: this.deps.dispatchMcpConfigPath ? () => this.deps.dispatchMcpConfigPath ?? null : void 0,
|
|
33357
|
+
lookupDispatchByBSessionId: this.deps.personaDispatchManager ? (bSid) => this.deps.personaDispatchManager?.lookupDispatchByBSessionId(bSid) : void 0,
|
|
33297
33358
|
// file-sharing (spec §6 PR 3):闭包 scope + sessionId,runner 只暴露 tool/relPath/cwd
|
|
33298
33359
|
onFileEdit: attachmentGroup ? (input) => attachmentGroup.onFileEdit({
|
|
33299
33360
|
scope,
|
|
@@ -33509,15 +33570,20 @@ var SessionManager = class {
|
|
|
33509
33570
|
// 强制走 deps.store(即 default scope),不走 scopeForFile:mirror 物理落 default 即可。
|
|
33510
33571
|
// 远端 creator / origin 字段原值保留(不被本机 ctx 派生覆写)。
|
|
33511
33572
|
//
|
|
33512
|
-
// strip 远端 personaId:mirror SessionFile
|
|
33513
|
-
//
|
|
33514
|
-
//
|
|
33573
|
+
// strip 远端 personaId / dispatchedFromSessionId:mirror SessionFile 上这两个字段都指向
|
|
33574
|
+
// 朋友 daemon 上的本地 id,本机不持有对应 persona / 源 session。留着会让按这些字段反查的
|
|
33575
|
+
// 本机消费者(MyPersonasSection 按 ownerPersonaId 反查 persona、sidebar 按
|
|
33576
|
+
// dispatchedFromSessionId 折叠 sub-session)走错分支。写入前清掉。#750 一族防线。
|
|
33515
33577
|
//
|
|
33516
33578
|
// 与 manager.create / manager.update 区别:
|
|
33517
33579
|
// - 不走 newRunner / attachObserver / cwd 校验(mirror 是纯 metadata 层)
|
|
33518
33580
|
// - 不发 session:info 帧(manager.create / .update 通过 reducer/wireCollector 发 push)
|
|
33519
33581
|
mirrorUpsert(file) {
|
|
33520
|
-
const {
|
|
33582
|
+
const {
|
|
33583
|
+
ownerPersonaId: _strippedPid,
|
|
33584
|
+
dispatchedFromSessionId: _strippedDsp,
|
|
33585
|
+
...rest
|
|
33586
|
+
} = file;
|
|
33521
33587
|
return this.deps.store.write(rest);
|
|
33522
33588
|
}
|
|
33523
33589
|
// mirror peer sessions:删本机 mirror SessionFile。mirror 一律落 default(mirrorUpsert
|
|
@@ -34102,6 +34168,66 @@ var SessionManager = class {
|
|
|
34102
34168
|
this.runners.set(file.sessionId, runner);
|
|
34103
34169
|
return runner;
|
|
34104
34170
|
}
|
|
34171
|
+
/**
|
|
34172
|
+
* Persona dispatch: 启动 B session 并投递任务包当第一条 user message。
|
|
34173
|
+
*
|
|
34174
|
+
* - 复用 persona-owner 创建路径(cwd=personaDir、scope=persona-owner、不沙箱)
|
|
34175
|
+
* - SessionFile 上写 dispatchedFromSessionId 关联回 A(UI 折叠用;mirror 一侧 strip)
|
|
34176
|
+
* - 跟 PersonaDispatchManager 双向登记 dispatchId ↔ B sessionId,让后续 reducer
|
|
34177
|
+
* buildSpawnContext 能反查到 dispatchId 注 CLAWD_DISPATCH_ID env
|
|
34178
|
+
* - 投 inject-owner-text 任务包;包尾教 B 用 personaDispatchComplete tool 回传
|
|
34179
|
+
*
|
|
34180
|
+
* cwd 派生与 SessionManager.create 的 owner persona 路径一致(derivePersonaSpawnCwd)。
|
|
34181
|
+
*/
|
|
34182
|
+
createDispatchedSession(args) {
|
|
34183
|
+
if (!this.deps.personaRoot) {
|
|
34184
|
+
throw new Error("createDispatchedSession: personaRoot missing in ManagerDeps");
|
|
34185
|
+
}
|
|
34186
|
+
if (!this.deps.personaDispatchManager) {
|
|
34187
|
+
throw new Error("createDispatchedSession: personaDispatchManager missing in ManagerDeps");
|
|
34188
|
+
}
|
|
34189
|
+
const sessionId = newSessionId();
|
|
34190
|
+
const scope = {
|
|
34191
|
+
kind: "persona",
|
|
34192
|
+
personaId: args.targetPersona,
|
|
34193
|
+
mode: "owner"
|
|
34194
|
+
};
|
|
34195
|
+
const cwd = import_node_path6.default.join(this.deps.personaRoot, safeFileName(args.targetPersona));
|
|
34196
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
34197
|
+
const file = {
|
|
34198
|
+
sessionId,
|
|
34199
|
+
cwd,
|
|
34200
|
+
tool: "claude",
|
|
34201
|
+
ownerPersonaId: args.targetPersona,
|
|
34202
|
+
dispatchedFromSessionId: args.sourceSessionId,
|
|
34203
|
+
createdAt: now,
|
|
34204
|
+
updatedAt: now
|
|
34205
|
+
};
|
|
34206
|
+
this.storeFor(scope).write(file);
|
|
34207
|
+
this.deps.personaDispatchManager.registerBSession(args.dispatchId, sessionId);
|
|
34208
|
+
this.deps.logger?.info("dispatch.createDispatchedSession.file-written", {
|
|
34209
|
+
dispatchId: args.dispatchId,
|
|
34210
|
+
bSessionId: sessionId,
|
|
34211
|
+
targetPersona: args.targetPersona,
|
|
34212
|
+
cwd
|
|
34213
|
+
});
|
|
34214
|
+
const runner = this.ensureRunnerForScope(file, scope);
|
|
34215
|
+
this.deps.logger?.info("dispatch.createDispatchedSession.runner-ready", {
|
|
34216
|
+
dispatchId: args.dispatchId,
|
|
34217
|
+
bSessionId: sessionId
|
|
34218
|
+
});
|
|
34219
|
+
const taskPack = buildDispatchTaskPack({
|
|
34220
|
+
prompt: args.prompt,
|
|
34221
|
+
sourceJsonlPath: args.sourceJsonlPath,
|
|
34222
|
+
dispatchId: args.dispatchId
|
|
34223
|
+
});
|
|
34224
|
+
runner.input({ kind: "command", command: { kind: "send", text: taskPack } });
|
|
34225
|
+
this.deps.logger?.info("dispatch.createDispatchedSession.task-pack-sent", {
|
|
34226
|
+
dispatchId: args.dispatchId,
|
|
34227
|
+
bSessionId: sessionId
|
|
34228
|
+
});
|
|
34229
|
+
return { sessionId };
|
|
34230
|
+
}
|
|
34105
34231
|
/**
|
|
34106
34232
|
* 老板插话:把 'inject-owner-text' input 喂给对应 runner,
|
|
34107
34233
|
* runner 不存在时按 scope 懒创建。
|
|
@@ -35535,8 +35661,8 @@ function turnStartInput(text) {
|
|
|
35535
35661
|
const items = [];
|
|
35536
35662
|
let leftover = text;
|
|
35537
35663
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
35538
|
-
const [marker, name,
|
|
35539
|
-
items.push({ type: "skill", name, path:
|
|
35664
|
+
const [marker, name, path59] = m2;
|
|
35665
|
+
items.push({ type: "skill", name, path: path59 });
|
|
35540
35666
|
leftover = leftover.replace(marker, "");
|
|
35541
35667
|
}
|
|
35542
35668
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -36763,6 +36889,9 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
|
|
|
36763
36889
|
if (ctx.addDirs) {
|
|
36764
36890
|
for (const dir of ctx.addDirs) args.push("--add-dir", dir);
|
|
36765
36891
|
}
|
|
36892
|
+
if (ctx.dispatchMcpConfigPath) {
|
|
36893
|
+
args.push("--mcp-config", ctx.dispatchMcpConfigPath);
|
|
36894
|
+
}
|
|
36766
36895
|
if (ctx.effort) args.push("--effort", ctx.effort);
|
|
36767
36896
|
return args;
|
|
36768
36897
|
}
|
|
@@ -36780,6 +36909,155 @@ function jsonlExistsForCtx(ctx) {
|
|
|
36780
36909
|
// src/index.ts
|
|
36781
36910
|
init_claude_history();
|
|
36782
36911
|
|
|
36912
|
+
// src/dispatch/manager.ts
|
|
36913
|
+
function defer() {
|
|
36914
|
+
let resolve6;
|
|
36915
|
+
const promise = new Promise((r) => {
|
|
36916
|
+
resolve6 = r;
|
|
36917
|
+
});
|
|
36918
|
+
return { promise, resolve: resolve6 };
|
|
36919
|
+
}
|
|
36920
|
+
var PersonaDispatchManager = class {
|
|
36921
|
+
constructor(deps) {
|
|
36922
|
+
this.deps = deps;
|
|
36923
|
+
}
|
|
36924
|
+
deps;
|
|
36925
|
+
map = /* @__PURE__ */ new Map();
|
|
36926
|
+
start(args) {
|
|
36927
|
+
const dispatchId = this.deps.genId();
|
|
36928
|
+
this.map.set(dispatchId, {
|
|
36929
|
+
dispatchId,
|
|
36930
|
+
sourceSessionId: args.sourceSessionId,
|
|
36931
|
+
targetPersona: args.targetPersona,
|
|
36932
|
+
waiters: [],
|
|
36933
|
+
outcome: null
|
|
36934
|
+
});
|
|
36935
|
+
return { dispatchId };
|
|
36936
|
+
}
|
|
36937
|
+
get(dispatchId) {
|
|
36938
|
+
return this.map.get(dispatchId);
|
|
36939
|
+
}
|
|
36940
|
+
async wait(dispatchId) {
|
|
36941
|
+
const state = this.map.get(dispatchId);
|
|
36942
|
+
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
36943
|
+
if (state.outcome) return state.outcome;
|
|
36944
|
+
const d = defer();
|
|
36945
|
+
state.waiters.push(d);
|
|
36946
|
+
return d.promise;
|
|
36947
|
+
}
|
|
36948
|
+
complete(dispatchId, outcome) {
|
|
36949
|
+
const state = this.map.get(dispatchId);
|
|
36950
|
+
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
36951
|
+
state.outcome = outcome;
|
|
36952
|
+
const waiters = state.waiters;
|
|
36953
|
+
state.waiters = [];
|
|
36954
|
+
for (const w2 of waiters) w2.resolve(outcome);
|
|
36955
|
+
}
|
|
36956
|
+
/** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
|
|
36957
|
+
registerBSession(dispatchId, bSessionId) {
|
|
36958
|
+
const state = this.map.get(dispatchId);
|
|
36959
|
+
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
36960
|
+
state.bSessionId = bSessionId;
|
|
36961
|
+
}
|
|
36962
|
+
/** reducer buildSpawnContext 调,按 B 的 sessionId 反查 dispatchId(用于注 CLAWD_DISPATCH_ID env) */
|
|
36963
|
+
lookupDispatchByBSessionId(bSessionId) {
|
|
36964
|
+
for (const state of this.map.values()) {
|
|
36965
|
+
if (state.bSessionId === bSessionId) return state.dispatchId;
|
|
36966
|
+
}
|
|
36967
|
+
return void 0;
|
|
36968
|
+
}
|
|
36969
|
+
};
|
|
36970
|
+
|
|
36971
|
+
// src/dispatch/mcp-config.ts
|
|
36972
|
+
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
36973
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
36974
|
+
function dispatchMcpConfigPath(dataDir) {
|
|
36975
|
+
return import_node_path10.default.join(dataDir, "dispatch.mcp.json");
|
|
36976
|
+
}
|
|
36977
|
+
function writeDispatchMcpConfig(args) {
|
|
36978
|
+
const cfgPath = dispatchMcpConfigPath(args.dataDir);
|
|
36979
|
+
const content = {
|
|
36980
|
+
_comment: "daemon \u542F\u52A8\u65F6\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002dispatch-mcp-server.cjs \u662F daemon \u81EA\u5E26\u7684 stdio MCP server\u3002env.CLAWD_DISPATCH_LOG \u6307 server \u5199\u65E5\u5FD7\u7684 append \u6587\u4EF6\u8DEF\u5F84\uFF08dispatch \u6D41\u7A0B\u8282\u70B9 + fetch \u9519\u8BEF\u7EC6\u8282\uFF09\u3002",
|
|
36981
|
+
mcpServers: {
|
|
36982
|
+
"clawd-dispatch": {
|
|
36983
|
+
type: "stdio",
|
|
36984
|
+
command: "node",
|
|
36985
|
+
args: [args.serverScriptPath],
|
|
36986
|
+
...args.logPath ? { env: { CLAWD_DISPATCH_LOG: args.logPath } } : {}
|
|
36987
|
+
}
|
|
36988
|
+
}
|
|
36989
|
+
};
|
|
36990
|
+
import_node_fs12.default.mkdirSync(args.dataDir, { recursive: true });
|
|
36991
|
+
import_node_fs12.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
|
|
36992
|
+
return cfgPath;
|
|
36993
|
+
}
|
|
36994
|
+
|
|
36995
|
+
// src/handlers/persona-dispatch.ts
|
|
36996
|
+
init_protocol();
|
|
36997
|
+
function buildPersonaDispatchHandlers(deps) {
|
|
36998
|
+
const { personaDispatchManager: mgr, spawnB, logger } = deps;
|
|
36999
|
+
const run = async (frame) => {
|
|
37000
|
+
const { type: _t, requestId: _r, ...rest } = frame;
|
|
37001
|
+
const sourceSessionId = typeof rest.sessionId === "string" ? rest.sessionId : void 0;
|
|
37002
|
+
const args = DispatchRunArgsSchema.parse(rest);
|
|
37003
|
+
if (!sourceSessionId) {
|
|
37004
|
+
throw new Error(
|
|
37005
|
+
"personaDispatch:run requires sessionId (caller must pass x-clawd-session-id header)"
|
|
37006
|
+
);
|
|
37007
|
+
}
|
|
37008
|
+
const { dispatchId } = mgr.start({
|
|
37009
|
+
sourceSessionId,
|
|
37010
|
+
targetPersona: args.targetPersona
|
|
37011
|
+
});
|
|
37012
|
+
logger?.info("dispatch.run.received", {
|
|
37013
|
+
dispatchId,
|
|
37014
|
+
sourceSessionId,
|
|
37015
|
+
targetPersona: args.targetPersona,
|
|
37016
|
+
promptLen: args.prompt.length
|
|
37017
|
+
});
|
|
37018
|
+
void spawnB({
|
|
37019
|
+
dispatchId,
|
|
37020
|
+
sourceSessionId,
|
|
37021
|
+
targetPersona: args.targetPersona,
|
|
37022
|
+
prompt: args.prompt
|
|
37023
|
+
}).then(() => {
|
|
37024
|
+
logger?.info("dispatch.spawnB.ok", { dispatchId });
|
|
37025
|
+
}).catch((err) => {
|
|
37026
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
37027
|
+
logger?.warn("dispatch.spawnB.failed", { dispatchId, reason });
|
|
37028
|
+
mgr.complete(dispatchId, {
|
|
37029
|
+
kind: "failure",
|
|
37030
|
+
reason: `failed to spawn B: ${reason}`
|
|
37031
|
+
});
|
|
37032
|
+
});
|
|
37033
|
+
logger?.info("dispatch.run.waiting", { dispatchId });
|
|
37034
|
+
const outcome = await mgr.wait(dispatchId);
|
|
37035
|
+
logger?.info("dispatch.run.resolved", {
|
|
37036
|
+
dispatchId,
|
|
37037
|
+
outcomeKind: outcome.kind
|
|
37038
|
+
});
|
|
37039
|
+
return {
|
|
37040
|
+
response: { type: "personaDispatch:run:ok", outcome }
|
|
37041
|
+
};
|
|
37042
|
+
};
|
|
37043
|
+
const complete = async (frame) => {
|
|
37044
|
+
const { type: _t, requestId: _r, ...rest } = frame;
|
|
37045
|
+
const args = DispatchCompleteArgsSchema.parse(rest);
|
|
37046
|
+
logger?.info("dispatch.complete.received", {
|
|
37047
|
+
dispatchId: args.dispatchId,
|
|
37048
|
+
outcomeKind: args.outcome.kind
|
|
37049
|
+
});
|
|
37050
|
+
mgr.complete(args.dispatchId, args.outcome);
|
|
37051
|
+
return {
|
|
37052
|
+
response: { type: "personaDispatch:complete:ok" }
|
|
37053
|
+
};
|
|
37054
|
+
};
|
|
37055
|
+
return {
|
|
37056
|
+
"personaDispatch:run": run,
|
|
37057
|
+
"personaDispatch:complete": complete
|
|
37058
|
+
};
|
|
37059
|
+
}
|
|
37060
|
+
|
|
36783
37061
|
// src/tools/codex-history.ts
|
|
36784
37062
|
var import_node_child_process5 = require("child_process");
|
|
36785
37063
|
var DEFAULT_TIMEOUT_MS = 8e3;
|
|
@@ -36966,13 +37244,13 @@ function mapSkillsListResponse(res) {
|
|
|
36966
37244
|
const r = s ?? {};
|
|
36967
37245
|
const name = str3(r.name);
|
|
36968
37246
|
if (!name) continue;
|
|
36969
|
-
const
|
|
37247
|
+
const path59 = str3(r.path);
|
|
36970
37248
|
const description = str3(r.description);
|
|
36971
37249
|
const isPlugin = name.includes(":");
|
|
36972
37250
|
out.push({
|
|
36973
37251
|
name,
|
|
36974
37252
|
source: isPlugin ? "plugin" : "project",
|
|
36975
|
-
...
|
|
37253
|
+
...path59 ? { path: path59 } : {},
|
|
36976
37254
|
...description ? { description } : {},
|
|
36977
37255
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
36978
37256
|
});
|
|
@@ -37011,23 +37289,23 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
37011
37289
|
}
|
|
37012
37290
|
|
|
37013
37291
|
// src/workspace/browser.ts
|
|
37014
|
-
var
|
|
37292
|
+
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
37015
37293
|
var import_node_os6 = __toESM(require("os"), 1);
|
|
37016
|
-
var
|
|
37294
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
37017
37295
|
init_protocol();
|
|
37018
37296
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
37019
37297
|
function resolveInsideCwd(cwd, subpath) {
|
|
37020
|
-
const absCwd =
|
|
37021
|
-
const joined =
|
|
37022
|
-
const rel =
|
|
37023
|
-
if (rel.startsWith("..") ||
|
|
37298
|
+
const absCwd = import_node_path11.default.resolve(cwd);
|
|
37299
|
+
const joined = import_node_path11.default.resolve(absCwd, subpath ?? ".");
|
|
37300
|
+
const rel = import_node_path11.default.relative(absCwd, joined);
|
|
37301
|
+
if (rel.startsWith("..") || import_node_path11.default.isAbsolute(rel)) {
|
|
37024
37302
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
37025
37303
|
}
|
|
37026
37304
|
return joined;
|
|
37027
37305
|
}
|
|
37028
37306
|
function ensureCwd(cwd) {
|
|
37029
37307
|
try {
|
|
37030
|
-
const stat =
|
|
37308
|
+
const stat = import_node_fs13.default.statSync(cwd);
|
|
37031
37309
|
if (!stat.isDirectory()) {
|
|
37032
37310
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
|
|
37033
37311
|
}
|
|
@@ -37041,7 +37319,7 @@ var WorkspaceBrowser = class {
|
|
|
37041
37319
|
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os6.default.homedir();
|
|
37042
37320
|
ensureCwd(cwd);
|
|
37043
37321
|
const full = resolveInsideCwd(cwd, args.path);
|
|
37044
|
-
const dirents =
|
|
37322
|
+
const dirents = import_node_fs13.default.readdirSync(full, { withFileTypes: true });
|
|
37045
37323
|
const entries = [];
|
|
37046
37324
|
for (const d of dirents) {
|
|
37047
37325
|
if (!args.showHidden && d.name.startsWith(".")) continue;
|
|
@@ -37051,7 +37329,7 @@ var WorkspaceBrowser = class {
|
|
|
37051
37329
|
mtime: ""
|
|
37052
37330
|
};
|
|
37053
37331
|
try {
|
|
37054
|
-
const st =
|
|
37332
|
+
const st = import_node_fs13.default.statSync(import_node_path11.default.join(full, d.name));
|
|
37055
37333
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
37056
37334
|
if (d.isFile()) entry.size = st.size;
|
|
37057
37335
|
} catch {
|
|
@@ -37067,14 +37345,14 @@ var WorkspaceBrowser = class {
|
|
|
37067
37345
|
read(args) {
|
|
37068
37346
|
ensureCwd(args.cwd);
|
|
37069
37347
|
const full = resolveInsideCwd(args.cwd, args.path);
|
|
37070
|
-
const st =
|
|
37348
|
+
const st = import_node_fs13.default.statSync(full);
|
|
37071
37349
|
if (!st.isFile()) {
|
|
37072
37350
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
|
|
37073
37351
|
}
|
|
37074
37352
|
if (st.size > MAX_FILE_BYTES) {
|
|
37075
37353
|
throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
|
|
37076
37354
|
}
|
|
37077
|
-
const buf =
|
|
37355
|
+
const buf = import_node_fs13.default.readFileSync(full);
|
|
37078
37356
|
const isBinary = buf.includes(0);
|
|
37079
37357
|
if (isBinary) {
|
|
37080
37358
|
return {
|
|
@@ -37096,20 +37374,20 @@ var WorkspaceBrowser = class {
|
|
|
37096
37374
|
};
|
|
37097
37375
|
|
|
37098
37376
|
// src/skills/agents-scanner.ts
|
|
37099
|
-
var
|
|
37377
|
+
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
37100
37378
|
var import_node_os7 = __toESM(require("os"), 1);
|
|
37101
|
-
var
|
|
37379
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
37102
37380
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
37103
37381
|
function isDirLikeSync2(p2) {
|
|
37104
37382
|
try {
|
|
37105
|
-
return
|
|
37383
|
+
return import_node_fs14.default.statSync(p2).isDirectory();
|
|
37106
37384
|
} catch {
|
|
37107
37385
|
return false;
|
|
37108
37386
|
}
|
|
37109
37387
|
}
|
|
37110
37388
|
function fileExistsSync(p2) {
|
|
37111
37389
|
try {
|
|
37112
|
-
return
|
|
37390
|
+
return import_node_fs14.default.statSync(p2).isFile();
|
|
37113
37391
|
} catch {
|
|
37114
37392
|
return false;
|
|
37115
37393
|
}
|
|
@@ -37117,7 +37395,7 @@ function fileExistsSync(p2) {
|
|
|
37117
37395
|
function parseAgentFile(filePath) {
|
|
37118
37396
|
let content;
|
|
37119
37397
|
try {
|
|
37120
|
-
content =
|
|
37398
|
+
content = import_node_fs14.default.readFileSync(filePath, "utf8");
|
|
37121
37399
|
} catch {
|
|
37122
37400
|
return {};
|
|
37123
37401
|
}
|
|
@@ -37130,16 +37408,16 @@ function parseAgentFile(filePath) {
|
|
|
37130
37408
|
function scanAgentsDir(dir, source, seen, out) {
|
|
37131
37409
|
let entries;
|
|
37132
37410
|
try {
|
|
37133
|
-
entries =
|
|
37411
|
+
entries = import_node_fs14.default.readdirSync(dir, { withFileTypes: true });
|
|
37134
37412
|
} catch {
|
|
37135
37413
|
return;
|
|
37136
37414
|
}
|
|
37137
37415
|
for (const ent of entries) {
|
|
37138
37416
|
if (!ent.name.endsWith(".md")) continue;
|
|
37139
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
37417
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path12.default.join(dir, ent.name)))) {
|
|
37140
37418
|
continue;
|
|
37141
37419
|
}
|
|
37142
|
-
const filePath =
|
|
37420
|
+
const filePath = import_node_path12.default.join(dir, ent.name);
|
|
37143
37421
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
37144
37422
|
if (seen.has(baseName)) continue;
|
|
37145
37423
|
seen.add(baseName);
|
|
@@ -37157,12 +37435,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
37157
37435
|
function walk2(dir, namespaces) {
|
|
37158
37436
|
let entries;
|
|
37159
37437
|
try {
|
|
37160
|
-
entries =
|
|
37438
|
+
entries = import_node_fs14.default.readdirSync(dir, { withFileTypes: true });
|
|
37161
37439
|
} catch {
|
|
37162
37440
|
return;
|
|
37163
37441
|
}
|
|
37164
37442
|
for (const ent of entries) {
|
|
37165
|
-
const childPath =
|
|
37443
|
+
const childPath = import_node_path12.default.join(dir, ent.name);
|
|
37166
37444
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
37167
37445
|
walk2(childPath, [...namespaces, ent.name]);
|
|
37168
37446
|
continue;
|
|
@@ -37187,13 +37465,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
37187
37465
|
walk2(root, []);
|
|
37188
37466
|
}
|
|
37189
37467
|
function readInstalledPlugins2(home) {
|
|
37190
|
-
const pluginsDir =
|
|
37191
|
-
const v2 =
|
|
37192
|
-
const v1 =
|
|
37468
|
+
const pluginsDir = import_node_path12.default.join(home, ".claude", "plugins");
|
|
37469
|
+
const v2 = import_node_path12.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
37470
|
+
const v1 = import_node_path12.default.join(pluginsDir, "installed_plugins.json");
|
|
37193
37471
|
let raw = null;
|
|
37194
37472
|
for (const candidate of [v2, v1]) {
|
|
37195
37473
|
try {
|
|
37196
|
-
raw =
|
|
37474
|
+
raw = import_node_fs14.default.readFileSync(candidate, "utf8");
|
|
37197
37475
|
break;
|
|
37198
37476
|
} catch {
|
|
37199
37477
|
}
|
|
@@ -37218,19 +37496,19 @@ function readInstalledPlugins2(home) {
|
|
|
37218
37496
|
return out;
|
|
37219
37497
|
}
|
|
37220
37498
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
37221
|
-
let cur =
|
|
37222
|
-
const fsRoot =
|
|
37499
|
+
let cur = import_node_path12.default.resolve(startCwd);
|
|
37500
|
+
const fsRoot = import_node_path12.default.parse(cur).root;
|
|
37223
37501
|
while (true) {
|
|
37224
|
-
scanAgentsDir(
|
|
37502
|
+
scanAgentsDir(import_node_path12.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
37225
37503
|
let hasGit = false;
|
|
37226
37504
|
try {
|
|
37227
|
-
hasGit =
|
|
37505
|
+
hasGit = import_node_fs14.default.existsSync(import_node_path12.default.join(cur, ".git"));
|
|
37228
37506
|
} catch {
|
|
37229
37507
|
}
|
|
37230
37508
|
if (hasGit) return;
|
|
37231
37509
|
if (cur === home) return;
|
|
37232
37510
|
if (cur === fsRoot) return;
|
|
37233
|
-
const parent =
|
|
37511
|
+
const parent = import_node_path12.default.dirname(cur);
|
|
37234
37512
|
if (parent === cur) return;
|
|
37235
37513
|
cur = parent;
|
|
37236
37514
|
}
|
|
@@ -37265,7 +37543,7 @@ var AgentsScanner = class {
|
|
|
37265
37543
|
}
|
|
37266
37544
|
const fsBlock = [];
|
|
37267
37545
|
scanAgentsDir(
|
|
37268
|
-
|
|
37546
|
+
import_node_path12.default.join(this.home, ".claude", "agents"),
|
|
37269
37547
|
"global",
|
|
37270
37548
|
seen,
|
|
37271
37549
|
fsBlock
|
|
@@ -37279,7 +37557,7 @@ var AgentsScanner = class {
|
|
|
37279
37557
|
...this.extraPluginRoots
|
|
37280
37558
|
];
|
|
37281
37559
|
for (const { name, root } of plugins) {
|
|
37282
|
-
const agentsRoot =
|
|
37560
|
+
const agentsRoot = import_node_path12.default.join(root, "agents");
|
|
37283
37561
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
37284
37562
|
}
|
|
37285
37563
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -37287,15 +37565,15 @@ var AgentsScanner = class {
|
|
|
37287
37565
|
};
|
|
37288
37566
|
|
|
37289
37567
|
// src/observer/session-observer.ts
|
|
37290
|
-
var
|
|
37568
|
+
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
37291
37569
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
37292
|
-
var
|
|
37570
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
37293
37571
|
init_claude_history();
|
|
37294
37572
|
|
|
37295
37573
|
// src/observer/subagent-meta-observer.ts
|
|
37296
|
-
var
|
|
37574
|
+
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
37297
37575
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
37298
|
-
var
|
|
37576
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
37299
37577
|
init_claude_history();
|
|
37300
37578
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
37301
37579
|
var SubagentMetaObserver = class {
|
|
@@ -37308,7 +37586,7 @@ var SubagentMetaObserver = class {
|
|
|
37308
37586
|
watches = /* @__PURE__ */ new Map();
|
|
37309
37587
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
37310
37588
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
37311
|
-
return
|
|
37589
|
+
return import_node_path13.default.join(
|
|
37312
37590
|
this.home,
|
|
37313
37591
|
".claude",
|
|
37314
37592
|
"projects",
|
|
@@ -37338,7 +37616,7 @@ var SubagentMetaObserver = class {
|
|
|
37338
37616
|
attachWatcher(w2) {
|
|
37339
37617
|
if (w2.watcher) return;
|
|
37340
37618
|
try {
|
|
37341
|
-
w2.watcher =
|
|
37619
|
+
w2.watcher = import_node_fs15.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
|
|
37342
37620
|
if (!name) return;
|
|
37343
37621
|
const m2 = META_RE.exec(String(name));
|
|
37344
37622
|
if (!m2) return;
|
|
@@ -37350,7 +37628,7 @@ var SubagentMetaObserver = class {
|
|
|
37350
37628
|
scan(w2) {
|
|
37351
37629
|
let entries;
|
|
37352
37630
|
try {
|
|
37353
|
-
entries =
|
|
37631
|
+
entries = import_node_fs15.default.readdirSync(w2.dirPath);
|
|
37354
37632
|
} catch {
|
|
37355
37633
|
return;
|
|
37356
37634
|
}
|
|
@@ -37364,10 +37642,10 @@ var SubagentMetaObserver = class {
|
|
|
37364
37642
|
if (!m2) return;
|
|
37365
37643
|
const agentId = m2[1];
|
|
37366
37644
|
if (w2.emitted.has(agentId)) return;
|
|
37367
|
-
const file =
|
|
37645
|
+
const file = import_node_path13.default.join(w2.dirPath, name);
|
|
37368
37646
|
let raw;
|
|
37369
37647
|
try {
|
|
37370
|
-
raw =
|
|
37648
|
+
raw = import_node_fs15.default.readFileSync(file, "utf8");
|
|
37371
37649
|
} catch {
|
|
37372
37650
|
return;
|
|
37373
37651
|
}
|
|
@@ -37424,14 +37702,14 @@ var SessionObserver = class {
|
|
|
37424
37702
|
metaObserver;
|
|
37425
37703
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
37426
37704
|
if (override) return override;
|
|
37427
|
-
return
|
|
37705
|
+
return import_node_path14.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
37428
37706
|
}
|
|
37429
37707
|
start(args) {
|
|
37430
37708
|
this.stop(args.sessionId);
|
|
37431
37709
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
37432
37710
|
let size = 0;
|
|
37433
37711
|
try {
|
|
37434
|
-
size =
|
|
37712
|
+
size = import_node_fs16.default.statSync(filePath).size;
|
|
37435
37713
|
} catch {
|
|
37436
37714
|
}
|
|
37437
37715
|
const w2 = {
|
|
@@ -37445,10 +37723,10 @@ var SessionObserver = class {
|
|
|
37445
37723
|
prevIsRejectSentinel: false
|
|
37446
37724
|
};
|
|
37447
37725
|
try {
|
|
37448
|
-
|
|
37726
|
+
import_node_fs16.default.mkdirSync(import_node_path14.default.dirname(filePath), { recursive: true });
|
|
37449
37727
|
} catch {
|
|
37450
37728
|
}
|
|
37451
|
-
w2.watcher =
|
|
37729
|
+
w2.watcher = import_node_fs16.default.watch(import_node_path14.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
37452
37730
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
37453
37731
|
this.poll(w2);
|
|
37454
37732
|
});
|
|
@@ -37471,7 +37749,7 @@ var SessionObserver = class {
|
|
|
37471
37749
|
// 异常静默吞,不阻塞 watcher 启动
|
|
37472
37750
|
hydrateMetaTail(w2, maxLines = 200) {
|
|
37473
37751
|
try {
|
|
37474
|
-
const raw =
|
|
37752
|
+
const raw = import_node_fs16.default.readFileSync(w2.filePath, "utf8");
|
|
37475
37753
|
if (!raw) return;
|
|
37476
37754
|
const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
37477
37755
|
if (allLines.length === 0) return;
|
|
@@ -37495,7 +37773,7 @@ var SessionObserver = class {
|
|
|
37495
37773
|
poll(w2) {
|
|
37496
37774
|
let size = 0;
|
|
37497
37775
|
try {
|
|
37498
|
-
size =
|
|
37776
|
+
size = import_node_fs16.default.statSync(w2.filePath).size;
|
|
37499
37777
|
} catch {
|
|
37500
37778
|
return;
|
|
37501
37779
|
}
|
|
@@ -37504,11 +37782,11 @@ var SessionObserver = class {
|
|
|
37504
37782
|
w2.buf = "";
|
|
37505
37783
|
}
|
|
37506
37784
|
if (size === w2.lastSize) return;
|
|
37507
|
-
const fd =
|
|
37785
|
+
const fd = import_node_fs16.default.openSync(w2.filePath, "r");
|
|
37508
37786
|
try {
|
|
37509
37787
|
const len = size - w2.lastSize;
|
|
37510
37788
|
const buf = Buffer.alloc(len);
|
|
37511
|
-
|
|
37789
|
+
import_node_fs16.default.readSync(fd, buf, 0, len, w2.lastSize);
|
|
37512
37790
|
w2.lastSize = size;
|
|
37513
37791
|
w2.buf += buf.toString("utf8");
|
|
37514
37792
|
let newlineIndex;
|
|
@@ -37531,7 +37809,7 @@ var SessionObserver = class {
|
|
|
37531
37809
|
}
|
|
37532
37810
|
}
|
|
37533
37811
|
} finally {
|
|
37534
|
-
|
|
37812
|
+
import_node_fs16.default.closeSync(fd);
|
|
37535
37813
|
}
|
|
37536
37814
|
}
|
|
37537
37815
|
// 解析 JSONL 单行:仅当是主链 user 文本行(非 sidechain / 非 sub-agent / message.role='user'
|
|
@@ -38254,14 +38532,14 @@ async function authenticate(token, deps) {
|
|
|
38254
38532
|
}
|
|
38255
38533
|
|
|
38256
38534
|
// src/permission/capability-store.ts
|
|
38257
|
-
var
|
|
38258
|
-
var
|
|
38535
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
38536
|
+
var path19 = __toESM(require("path"), 1);
|
|
38259
38537
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
38260
38538
|
var FILE_VERSION = 1;
|
|
38261
38539
|
var CapabilityStore = class {
|
|
38262
38540
|
constructor(dataDir) {
|
|
38263
38541
|
this.dataDir = dataDir;
|
|
38264
|
-
|
|
38542
|
+
fs19.mkdirSync(dataDir, { recursive: true });
|
|
38265
38543
|
this.cache = this.readFromDisk();
|
|
38266
38544
|
}
|
|
38267
38545
|
dataDir;
|
|
@@ -38285,13 +38563,13 @@ var CapabilityStore = class {
|
|
|
38285
38563
|
this.flush();
|
|
38286
38564
|
}
|
|
38287
38565
|
filePath() {
|
|
38288
|
-
return
|
|
38566
|
+
return path19.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
38289
38567
|
}
|
|
38290
38568
|
readFromDisk() {
|
|
38291
38569
|
const file = this.filePath();
|
|
38292
38570
|
let raw;
|
|
38293
38571
|
try {
|
|
38294
|
-
raw =
|
|
38572
|
+
raw = fs19.readFileSync(file, "utf8");
|
|
38295
38573
|
} catch (err) {
|
|
38296
38574
|
if (err?.code === "ENOENT") return [];
|
|
38297
38575
|
return [];
|
|
@@ -38319,10 +38597,10 @@ var CapabilityStore = class {
|
|
|
38319
38597
|
}
|
|
38320
38598
|
atomicWrite(file, content) {
|
|
38321
38599
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
38322
|
-
|
|
38323
|
-
|
|
38600
|
+
fs19.writeFileSync(tmp, content, { mode: 384 });
|
|
38601
|
+
fs19.renameSync(tmp, file);
|
|
38324
38602
|
try {
|
|
38325
|
-
|
|
38603
|
+
fs19.chmodSync(file, 384);
|
|
38326
38604
|
} catch {
|
|
38327
38605
|
}
|
|
38328
38606
|
}
|
|
@@ -38415,14 +38693,14 @@ var CapabilityManager = class {
|
|
|
38415
38693
|
};
|
|
38416
38694
|
|
|
38417
38695
|
// src/permission/cleanup.ts
|
|
38418
|
-
var
|
|
38696
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
38419
38697
|
function cleanupGuestSessionsForCapability(cap, factory) {
|
|
38420
38698
|
const removed = [];
|
|
38421
38699
|
for (const g2 of cap.grants) {
|
|
38422
38700
|
if (g2.resource.type !== "persona") continue;
|
|
38423
38701
|
const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
|
|
38424
38702
|
try {
|
|
38425
|
-
|
|
38703
|
+
fs20.rmSync(dir, { recursive: true, force: true });
|
|
38426
38704
|
removed.push(dir);
|
|
38427
38705
|
} catch {
|
|
38428
38706
|
}
|
|
@@ -38431,13 +38709,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
38431
38709
|
}
|
|
38432
38710
|
|
|
38433
38711
|
// src/inbox/inbox-store.ts
|
|
38434
|
-
var
|
|
38435
|
-
var
|
|
38712
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
38713
|
+
var path20 = __toESM(require("path"), 1);
|
|
38436
38714
|
var INBOX_SUBDIR = "inbox";
|
|
38437
38715
|
var InboxStore = class {
|
|
38438
38716
|
constructor(dataDir) {
|
|
38439
38717
|
this.dataDir = dataDir;
|
|
38440
|
-
|
|
38718
|
+
fs21.mkdirSync(this.dirPath(), { recursive: true });
|
|
38441
38719
|
}
|
|
38442
38720
|
dataDir;
|
|
38443
38721
|
/**
|
|
@@ -38449,7 +38727,7 @@ var InboxStore = class {
|
|
|
38449
38727
|
const file = this.filePath(peerDeviceId);
|
|
38450
38728
|
let raw;
|
|
38451
38729
|
try {
|
|
38452
|
-
raw =
|
|
38730
|
+
raw = fs21.readFileSync(file, "utf8");
|
|
38453
38731
|
} catch (err) {
|
|
38454
38732
|
if (err?.code === "ENOENT") return [];
|
|
38455
38733
|
return [];
|
|
@@ -38465,7 +38743,7 @@ var InboxStore = class {
|
|
|
38465
38743
|
const dir = this.dirPath();
|
|
38466
38744
|
let entries;
|
|
38467
38745
|
try {
|
|
38468
|
-
entries =
|
|
38746
|
+
entries = fs21.readdirSync(dir);
|
|
38469
38747
|
} catch (err) {
|
|
38470
38748
|
if (err?.code === "ENOENT") return [];
|
|
38471
38749
|
return [];
|
|
@@ -38481,9 +38759,9 @@ var InboxStore = class {
|
|
|
38481
38759
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
38482
38760
|
const file = this.filePath(message.peerDeviceId);
|
|
38483
38761
|
const line = JSON.stringify(message) + "\n";
|
|
38484
|
-
|
|
38762
|
+
fs21.appendFileSync(file, line, { mode: 384 });
|
|
38485
38763
|
try {
|
|
38486
|
-
|
|
38764
|
+
fs21.chmodSync(file, 384);
|
|
38487
38765
|
} catch {
|
|
38488
38766
|
}
|
|
38489
38767
|
}
|
|
@@ -38513,7 +38791,7 @@ var InboxStore = class {
|
|
|
38513
38791
|
removeByPeerDeviceId(peerDeviceId) {
|
|
38514
38792
|
const file = this.filePath(peerDeviceId);
|
|
38515
38793
|
try {
|
|
38516
|
-
|
|
38794
|
+
fs21.unlinkSync(file);
|
|
38517
38795
|
} catch (err) {
|
|
38518
38796
|
if (err?.code === "ENOENT") return;
|
|
38519
38797
|
}
|
|
@@ -38522,18 +38800,18 @@ var InboxStore = class {
|
|
|
38522
38800
|
const file = this.filePath(peerDeviceId);
|
|
38523
38801
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
38524
38802
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
38525
|
-
|
|
38526
|
-
|
|
38803
|
+
fs21.writeFileSync(tmp, content, { mode: 384 });
|
|
38804
|
+
fs21.renameSync(tmp, file);
|
|
38527
38805
|
try {
|
|
38528
|
-
|
|
38806
|
+
fs21.chmodSync(file, 384);
|
|
38529
38807
|
} catch {
|
|
38530
38808
|
}
|
|
38531
38809
|
}
|
|
38532
38810
|
dirPath() {
|
|
38533
|
-
return
|
|
38811
|
+
return path20.join(this.dataDir, INBOX_SUBDIR);
|
|
38534
38812
|
}
|
|
38535
38813
|
filePath(peerDeviceId) {
|
|
38536
|
-
return
|
|
38814
|
+
return path20.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
38537
38815
|
}
|
|
38538
38816
|
};
|
|
38539
38817
|
function parseAllLines(raw) {
|
|
@@ -38620,8 +38898,8 @@ var InboxManager = class {
|
|
|
38620
38898
|
};
|
|
38621
38899
|
|
|
38622
38900
|
// src/state/contact-store.ts
|
|
38623
|
-
var
|
|
38624
|
-
var
|
|
38901
|
+
var fs22 = __toESM(require("fs"), 1);
|
|
38902
|
+
var path21 = __toESM(require("path"), 1);
|
|
38625
38903
|
var FILE_NAME = "contacts.json";
|
|
38626
38904
|
var ContactStore = class {
|
|
38627
38905
|
constructor(dataDir) {
|
|
@@ -38631,10 +38909,10 @@ var ContactStore = class {
|
|
|
38631
38909
|
contacts = /* @__PURE__ */ new Map();
|
|
38632
38910
|
load() {
|
|
38633
38911
|
this.contacts.clear();
|
|
38634
|
-
const file =
|
|
38912
|
+
const file = path21.join(this.dataDir, FILE_NAME);
|
|
38635
38913
|
let raw;
|
|
38636
38914
|
try {
|
|
38637
|
-
raw =
|
|
38915
|
+
raw = fs22.readFileSync(file, "utf8");
|
|
38638
38916
|
} catch (err) {
|
|
38639
38917
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
38640
38918
|
return;
|
|
@@ -38677,20 +38955,20 @@ var ContactStore = class {
|
|
|
38677
38955
|
return existed;
|
|
38678
38956
|
}
|
|
38679
38957
|
flush() {
|
|
38680
|
-
const file =
|
|
38958
|
+
const file = path21.join(this.dataDir, FILE_NAME);
|
|
38681
38959
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
38682
38960
|
const content = JSON.stringify(
|
|
38683
38961
|
{ contacts: Array.from(this.contacts.values()) },
|
|
38684
38962
|
null,
|
|
38685
38963
|
2
|
|
38686
38964
|
);
|
|
38687
|
-
|
|
38688
|
-
|
|
38689
|
-
|
|
38965
|
+
fs22.mkdirSync(this.dataDir, { recursive: true });
|
|
38966
|
+
fs22.writeFileSync(tmp, content, { mode: 384 });
|
|
38967
|
+
fs22.renameSync(tmp, file);
|
|
38690
38968
|
}
|
|
38691
38969
|
renameBak(file) {
|
|
38692
38970
|
try {
|
|
38693
|
-
|
|
38971
|
+
fs22.renameSync(file, `${file}.bak`);
|
|
38694
38972
|
} catch {
|
|
38695
38973
|
}
|
|
38696
38974
|
}
|
|
@@ -38840,61 +39118,61 @@ async function autoReverseContact(args) {
|
|
|
38840
39118
|
}
|
|
38841
39119
|
|
|
38842
39120
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
38843
|
-
var
|
|
38844
|
-
var
|
|
39121
|
+
var fs23 = __toESM(require("fs"), 1);
|
|
39122
|
+
var path22 = __toESM(require("path"), 1);
|
|
38845
39123
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
38846
39124
|
function migrateFlattenSessions(opts) {
|
|
38847
39125
|
const dataDir = opts.dataDir;
|
|
38848
39126
|
const now = opts.now ?? Date.now;
|
|
38849
|
-
const sessionsDir =
|
|
38850
|
-
const flagPath =
|
|
39127
|
+
const sessionsDir = path22.join(dataDir, "sessions");
|
|
39128
|
+
const flagPath = path22.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
38851
39129
|
if (existsSync3(flagPath)) {
|
|
38852
39130
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
38853
39131
|
}
|
|
38854
39132
|
let movedBare = 0;
|
|
38855
39133
|
let movedVmOwner = 0;
|
|
38856
39134
|
let archivedListener = 0;
|
|
38857
|
-
const defaultDir =
|
|
39135
|
+
const defaultDir = path22.join(sessionsDir, "default");
|
|
38858
39136
|
if (existsSync3(defaultDir)) {
|
|
38859
39137
|
for (const entry of readdirSafe(defaultDir)) {
|
|
38860
39138
|
if (!entry.endsWith(".json")) continue;
|
|
38861
|
-
const src =
|
|
38862
|
-
const dst =
|
|
38863
|
-
|
|
39139
|
+
const src = path22.join(defaultDir, entry);
|
|
39140
|
+
const dst = path22.join(sessionsDir, entry);
|
|
39141
|
+
fs23.renameSync(src, dst);
|
|
38864
39142
|
movedBare += 1;
|
|
38865
39143
|
}
|
|
38866
39144
|
rmdirIfEmpty(defaultDir);
|
|
38867
39145
|
}
|
|
38868
39146
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
38869
|
-
const personaDir =
|
|
39147
|
+
const personaDir = path22.join(sessionsDir, pid);
|
|
38870
39148
|
if (!isDir(personaDir)) continue;
|
|
38871
39149
|
if (pid === "default") continue;
|
|
38872
|
-
const ownerSrc =
|
|
39150
|
+
const ownerSrc = path22.join(personaDir, "owner");
|
|
38873
39151
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
38874
|
-
const ownerDst =
|
|
38875
|
-
|
|
39152
|
+
const ownerDst = path22.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
39153
|
+
fs23.mkdirSync(ownerDst, { recursive: true });
|
|
38876
39154
|
for (const file of readdirSafe(ownerSrc)) {
|
|
38877
39155
|
if (!file.endsWith(".json")) continue;
|
|
38878
|
-
|
|
39156
|
+
fs23.renameSync(path22.join(ownerSrc, file), path22.join(ownerDst, file));
|
|
38879
39157
|
movedVmOwner += 1;
|
|
38880
39158
|
}
|
|
38881
39159
|
rmdirIfEmpty(ownerSrc);
|
|
38882
39160
|
}
|
|
38883
|
-
const listenerSrc =
|
|
39161
|
+
const listenerSrc = path22.join(personaDir, "listener");
|
|
38884
39162
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
38885
|
-
const archiveDst =
|
|
38886
|
-
|
|
39163
|
+
const archiveDst = path22.join(dataDir, ".legacy", `listener-${pid}`);
|
|
39164
|
+
fs23.mkdirSync(archiveDst, { recursive: true });
|
|
38887
39165
|
for (const file of readdirSafe(listenerSrc)) {
|
|
38888
39166
|
if (!file.endsWith(".json")) continue;
|
|
38889
|
-
|
|
39167
|
+
fs23.renameSync(path22.join(listenerSrc, file), path22.join(archiveDst, file));
|
|
38890
39168
|
archivedListener += 1;
|
|
38891
39169
|
}
|
|
38892
39170
|
rmdirIfEmpty(listenerSrc);
|
|
38893
39171
|
}
|
|
38894
39172
|
rmdirIfEmpty(personaDir);
|
|
38895
39173
|
}
|
|
38896
|
-
|
|
38897
|
-
|
|
39174
|
+
fs23.mkdirSync(sessionsDir, { recursive: true });
|
|
39175
|
+
fs23.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
38898
39176
|
return {
|
|
38899
39177
|
skipped: false,
|
|
38900
39178
|
flagWritten: true,
|
|
@@ -38905,7 +39183,7 @@ function migrateFlattenSessions(opts) {
|
|
|
38905
39183
|
}
|
|
38906
39184
|
function existsSync3(p2) {
|
|
38907
39185
|
try {
|
|
38908
|
-
|
|
39186
|
+
fs23.statSync(p2);
|
|
38909
39187
|
return true;
|
|
38910
39188
|
} catch {
|
|
38911
39189
|
return false;
|
|
@@ -38913,31 +39191,31 @@ function existsSync3(p2) {
|
|
|
38913
39191
|
}
|
|
38914
39192
|
function isDir(p2) {
|
|
38915
39193
|
try {
|
|
38916
|
-
return
|
|
39194
|
+
return fs23.statSync(p2).isDirectory();
|
|
38917
39195
|
} catch {
|
|
38918
39196
|
return false;
|
|
38919
39197
|
}
|
|
38920
39198
|
}
|
|
38921
39199
|
function readdirSafe(p2) {
|
|
38922
39200
|
try {
|
|
38923
|
-
return
|
|
39201
|
+
return fs23.readdirSync(p2);
|
|
38924
39202
|
} catch {
|
|
38925
39203
|
return [];
|
|
38926
39204
|
}
|
|
38927
39205
|
}
|
|
38928
39206
|
function rmdirIfEmpty(p2) {
|
|
38929
39207
|
try {
|
|
38930
|
-
|
|
39208
|
+
fs23.rmdirSync(p2);
|
|
38931
39209
|
} catch {
|
|
38932
39210
|
}
|
|
38933
39211
|
}
|
|
38934
39212
|
|
|
38935
39213
|
// src/transport/http-router.ts
|
|
38936
|
-
var
|
|
38937
|
-
var
|
|
39214
|
+
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
39215
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
38938
39216
|
|
|
38939
39217
|
// src/attachment/mime.ts
|
|
38940
|
-
var
|
|
39218
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
38941
39219
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
38942
39220
|
var EXT_TO_NATIVE_MIME = {
|
|
38943
39221
|
// 图片
|
|
@@ -39044,7 +39322,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
39044
39322
|
".mk"
|
|
39045
39323
|
]);
|
|
39046
39324
|
function lookupMime(filePathOrName) {
|
|
39047
|
-
const ext =
|
|
39325
|
+
const ext = import_node_path15.default.extname(filePathOrName).toLowerCase();
|
|
39048
39326
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
39049
39327
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
39050
39328
|
return "application/octet-stream";
|
|
@@ -39113,8 +39391,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
39113
39391
|
}
|
|
39114
39392
|
|
|
39115
39393
|
// src/attachment/upload.ts
|
|
39116
|
-
var
|
|
39117
|
-
var
|
|
39394
|
+
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
39395
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
39118
39396
|
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
39119
39397
|
var import_promises = require("stream/promises");
|
|
39120
39398
|
var UploadError = class extends Error {
|
|
@@ -39126,22 +39404,22 @@ var UploadError = class extends Error {
|
|
|
39126
39404
|
code;
|
|
39127
39405
|
};
|
|
39128
39406
|
function assertValidFileName(fileName) {
|
|
39129
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
39407
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path16.default.basename(fileName)) {
|
|
39130
39408
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
39131
39409
|
}
|
|
39132
39410
|
}
|
|
39133
39411
|
var HASH_PREFIX_LEN = 16;
|
|
39134
39412
|
async function writeUploadedAttachment(args) {
|
|
39135
39413
|
assertValidFileName(args.fileName);
|
|
39136
|
-
const attachmentsRoot =
|
|
39414
|
+
const attachmentsRoot = import_node_path16.default.join(args.sessionDir, ".attachments");
|
|
39137
39415
|
try {
|
|
39138
|
-
|
|
39416
|
+
import_node_fs17.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
39139
39417
|
} catch (err) {
|
|
39140
39418
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
39141
39419
|
}
|
|
39142
39420
|
const hasher = import_node_crypto5.default.createHash("sha256");
|
|
39143
39421
|
let actualSize = 0;
|
|
39144
|
-
const tmpPath =
|
|
39422
|
+
const tmpPath = import_node_path16.default.join(
|
|
39145
39423
|
attachmentsRoot,
|
|
39146
39424
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto5.default.randomBytes(4).toString("hex")}`
|
|
39147
39425
|
);
|
|
@@ -39156,18 +39434,18 @@ async function writeUploadedAttachment(args) {
|
|
|
39156
39434
|
yield buf;
|
|
39157
39435
|
}
|
|
39158
39436
|
},
|
|
39159
|
-
|
|
39437
|
+
import_node_fs17.default.createWriteStream(tmpPath, { mode: 384 })
|
|
39160
39438
|
);
|
|
39161
39439
|
} catch (err) {
|
|
39162
39440
|
try {
|
|
39163
|
-
|
|
39441
|
+
import_node_fs17.default.unlinkSync(tmpPath);
|
|
39164
39442
|
} catch {
|
|
39165
39443
|
}
|
|
39166
39444
|
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
39167
39445
|
}
|
|
39168
39446
|
if (actualSize !== args.contentLength) {
|
|
39169
39447
|
try {
|
|
39170
|
-
|
|
39448
|
+
import_node_fs17.default.unlinkSync(tmpPath);
|
|
39171
39449
|
} catch {
|
|
39172
39450
|
}
|
|
39173
39451
|
throw new UploadError(
|
|
@@ -39176,35 +39454,35 @@ async function writeUploadedAttachment(args) {
|
|
|
39176
39454
|
);
|
|
39177
39455
|
}
|
|
39178
39456
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
39179
|
-
const hashDir =
|
|
39457
|
+
const hashDir = import_node_path16.default.join(attachmentsRoot, attachmentId);
|
|
39180
39458
|
let finalFileName;
|
|
39181
39459
|
let hashDirExists = false;
|
|
39182
39460
|
try {
|
|
39183
|
-
hashDirExists =
|
|
39461
|
+
hashDirExists = import_node_fs17.default.statSync(hashDir).isDirectory();
|
|
39184
39462
|
} catch {
|
|
39185
39463
|
}
|
|
39186
39464
|
if (hashDirExists) {
|
|
39187
|
-
const existing =
|
|
39465
|
+
const existing = import_node_fs17.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
|
|
39188
39466
|
finalFileName = existing[0] ?? args.fileName;
|
|
39189
39467
|
try {
|
|
39190
|
-
|
|
39468
|
+
import_node_fs17.default.unlinkSync(tmpPath);
|
|
39191
39469
|
} catch {
|
|
39192
39470
|
}
|
|
39193
39471
|
} else {
|
|
39194
39472
|
try {
|
|
39195
|
-
|
|
39473
|
+
import_node_fs17.default.mkdirSync(hashDir, { recursive: true });
|
|
39196
39474
|
finalFileName = args.fileName;
|
|
39197
|
-
|
|
39475
|
+
import_node_fs17.default.renameSync(tmpPath, import_node_path16.default.join(hashDir, finalFileName));
|
|
39198
39476
|
} catch (err) {
|
|
39199
39477
|
try {
|
|
39200
|
-
|
|
39478
|
+
import_node_fs17.default.unlinkSync(tmpPath);
|
|
39201
39479
|
} catch {
|
|
39202
39480
|
}
|
|
39203
39481
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
39204
39482
|
}
|
|
39205
39483
|
}
|
|
39206
|
-
const absPath =
|
|
39207
|
-
const relPath =
|
|
39484
|
+
const absPath = import_node_path16.default.join(hashDir, finalFileName);
|
|
39485
|
+
const relPath = import_node_path16.default.relative(args.sessionDir, absPath);
|
|
39208
39486
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
39209
39487
|
relPath: absPath,
|
|
39210
39488
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -39218,7 +39496,7 @@ async function writeUploadedAttachment(args) {
|
|
|
39218
39496
|
|
|
39219
39497
|
// src/extension/import.ts
|
|
39220
39498
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
39221
|
-
var
|
|
39499
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
39222
39500
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
39223
39501
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
39224
39502
|
var ImportError = class extends Error {
|
|
@@ -39236,7 +39514,7 @@ async function importZip(buf, root) {
|
|
|
39236
39514
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
39237
39515
|
}
|
|
39238
39516
|
for (const name of Object.keys(zip.files)) {
|
|
39239
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
39517
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path17.default.isAbsolute(name)) {
|
|
39240
39518
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
39241
39519
|
}
|
|
39242
39520
|
}
|
|
@@ -39269,7 +39547,7 @@ async function importZip(buf, root) {
|
|
|
39269
39547
|
);
|
|
39270
39548
|
}
|
|
39271
39549
|
}
|
|
39272
|
-
const destDir =
|
|
39550
|
+
const destDir = import_node_path17.default.join(root, manifest.id);
|
|
39273
39551
|
let destExists = false;
|
|
39274
39552
|
try {
|
|
39275
39553
|
await import_promises2.default.access(destDir);
|
|
@@ -39279,15 +39557,15 @@ async function importZip(buf, root) {
|
|
|
39279
39557
|
if (destExists) {
|
|
39280
39558
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
39281
39559
|
}
|
|
39282
|
-
const stage = await import_promises2.default.mkdtemp(
|
|
39560
|
+
const stage = await import_promises2.default.mkdtemp(import_node_path17.default.join(import_node_os10.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
39283
39561
|
try {
|
|
39284
39562
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
39285
|
-
const dest =
|
|
39563
|
+
const dest = import_node_path17.default.join(stage, name);
|
|
39286
39564
|
if (entry.dir) {
|
|
39287
39565
|
await import_promises2.default.mkdir(dest, { recursive: true });
|
|
39288
39566
|
continue;
|
|
39289
39567
|
}
|
|
39290
|
-
await import_promises2.default.mkdir(
|
|
39568
|
+
await import_promises2.default.mkdir(import_node_path17.default.dirname(dest), { recursive: true });
|
|
39291
39569
|
const content = await entry.async("nodebuffer");
|
|
39292
39570
|
await import_promises2.default.writeFile(dest, content);
|
|
39293
39571
|
}
|
|
@@ -39312,7 +39590,12 @@ var EXPOSED_RPC_METHODS = [
|
|
|
39312
39590
|
"appBuilder.startDevServer",
|
|
39313
39591
|
"appBuilder.reportStage",
|
|
39314
39592
|
// 单栏 §5.6.5 fix: UI 切 session 时调(assistant 不需要主动调,但暴露白名单避免误猜成 forbidden)
|
|
39315
|
-
"appBuilder.setActiveSession"
|
|
39593
|
+
"appBuilder.setActiveSession",
|
|
39594
|
+
// Persona dispatch (Task 4): A 端 dispatch MCP server 调 run(hold-and-wait 一次);
|
|
39595
|
+
// B 端 dispatch MCP server 调 complete(带 outcome 触发 run 端 resolve)。详见
|
|
39596
|
+
// protocol/src/dispatch.ts。
|
|
39597
|
+
"personaDispatch.run",
|
|
39598
|
+
"personaDispatch.complete"
|
|
39316
39599
|
];
|
|
39317
39600
|
async function handleRpcRequest(input) {
|
|
39318
39601
|
const { method, body, sessionId, dispatcher } = input;
|
|
@@ -39401,7 +39684,7 @@ function isValidUploadFileName(fileName) {
|
|
|
39401
39684
|
if (fileName === "." || fileName === "..") return false;
|
|
39402
39685
|
if (fileName.startsWith(".")) return false;
|
|
39403
39686
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
39404
|
-
return fileName ===
|
|
39687
|
+
return fileName === import_node_path18.default.basename(fileName);
|
|
39405
39688
|
}
|
|
39406
39689
|
function createHttpRouter(deps) {
|
|
39407
39690
|
return async (req, res) => {
|
|
@@ -39448,6 +39731,8 @@ function createHttpRouter(deps) {
|
|
|
39448
39731
|
sendJson(res, 403, { code: "NOT_LOOPBACK", message: "RPC adapter only accepts loopback connections" });
|
|
39449
39732
|
return true;
|
|
39450
39733
|
}
|
|
39734
|
+
req.socket.setTimeout(0);
|
|
39735
|
+
res.socket?.setTimeout(0);
|
|
39451
39736
|
const method = url.pathname.slice(RPC_ROUTE_PREFIX.length).split("?")[0] ?? "";
|
|
39452
39737
|
const sessionId = req.headers["x-clawd-session-id"] ?? void 0;
|
|
39453
39738
|
let body;
|
|
@@ -39630,7 +39915,7 @@ function createHttpRouter(deps) {
|
|
|
39630
39915
|
return true;
|
|
39631
39916
|
}
|
|
39632
39917
|
let absPath;
|
|
39633
|
-
if (
|
|
39918
|
+
if (import_node_path18.default.isAbsolute(pathParam)) {
|
|
39634
39919
|
absPath = pathParam;
|
|
39635
39920
|
} else if (deps.sessionStore) {
|
|
39636
39921
|
const file = deps.sessionStore.read(sid);
|
|
@@ -39638,7 +39923,7 @@ function createHttpRouter(deps) {
|
|
|
39638
39923
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
39639
39924
|
return true;
|
|
39640
39925
|
}
|
|
39641
|
-
absPath =
|
|
39926
|
+
absPath = import_node_path18.default.join(file.cwd, pathParam);
|
|
39642
39927
|
} else {
|
|
39643
39928
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
39644
39929
|
return true;
|
|
@@ -39721,7 +40006,7 @@ function withCtx(ctx, body) {
|
|
|
39721
40006
|
function streamFile(res, absPath, logger) {
|
|
39722
40007
|
let stat;
|
|
39723
40008
|
try {
|
|
39724
|
-
stat =
|
|
40009
|
+
stat = import_node_fs18.default.statSync(absPath);
|
|
39725
40010
|
} catch (err) {
|
|
39726
40011
|
const code = err?.code;
|
|
39727
40012
|
if (code === "ENOENT") {
|
|
@@ -39736,7 +40021,7 @@ function streamFile(res, absPath, logger) {
|
|
|
39736
40021
|
return;
|
|
39737
40022
|
}
|
|
39738
40023
|
const mime = lookupMime(absPath);
|
|
39739
|
-
const basename =
|
|
40024
|
+
const basename = import_node_path18.default.basename(absPath);
|
|
39740
40025
|
res.writeHead(200, {
|
|
39741
40026
|
"Content-Type": mime,
|
|
39742
40027
|
"Content-Length": String(stat.size),
|
|
@@ -39744,7 +40029,7 @@ function streamFile(res, absPath, logger) {
|
|
|
39744
40029
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
39745
40030
|
"X-Content-Type-Options": "nosniff"
|
|
39746
40031
|
});
|
|
39747
|
-
const stream =
|
|
40032
|
+
const stream = import_node_fs18.default.createReadStream(absPath);
|
|
39748
40033
|
stream.on("error", (err) => {
|
|
39749
40034
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
39750
40035
|
res.destroy();
|
|
@@ -39753,8 +40038,8 @@ function streamFile(res, absPath, logger) {
|
|
|
39753
40038
|
}
|
|
39754
40039
|
|
|
39755
40040
|
// src/attachment/gc.ts
|
|
39756
|
-
var
|
|
39757
|
-
var
|
|
40041
|
+
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
40042
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
39758
40043
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
39759
40044
|
function runAttachmentGc(args) {
|
|
39760
40045
|
const now = (args.now ?? Date.now)();
|
|
@@ -39763,38 +40048,38 @@ function runAttachmentGc(args) {
|
|
|
39763
40048
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
39764
40049
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
39765
40050
|
if (entry.stale) continue;
|
|
39766
|
-
if (
|
|
40051
|
+
if (import_node_path19.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
39767
40052
|
}
|
|
39768
40053
|
}
|
|
39769
40054
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
39770
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
40055
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path19.default.join(
|
|
39771
40056
|
args.dataDir,
|
|
39772
40057
|
"sessions",
|
|
39773
40058
|
...scopeSubPath(scope).map(safeFileName),
|
|
39774
40059
|
safeFileName(sessionId)
|
|
39775
40060
|
);
|
|
39776
|
-
const attRoot =
|
|
40061
|
+
const attRoot = import_node_path19.default.join(sessionDir, ".attachments");
|
|
39777
40062
|
let hashDirs;
|
|
39778
40063
|
try {
|
|
39779
|
-
hashDirs =
|
|
40064
|
+
hashDirs = import_node_fs19.default.readdirSync(attRoot);
|
|
39780
40065
|
} catch (err) {
|
|
39781
40066
|
if (err.code === "ENOENT") continue;
|
|
39782
40067
|
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
39783
40068
|
continue;
|
|
39784
40069
|
}
|
|
39785
40070
|
for (const hashDir of hashDirs) {
|
|
39786
|
-
const hashDirAbs =
|
|
40071
|
+
const hashDirAbs = import_node_path19.default.join(attRoot, hashDir);
|
|
39787
40072
|
let files;
|
|
39788
40073
|
try {
|
|
39789
|
-
files =
|
|
40074
|
+
files = import_node_fs19.default.readdirSync(hashDirAbs);
|
|
39790
40075
|
} catch {
|
|
39791
40076
|
continue;
|
|
39792
40077
|
}
|
|
39793
40078
|
for (const name of files) {
|
|
39794
|
-
const file =
|
|
40079
|
+
const file = import_node_path19.default.join(hashDirAbs, name);
|
|
39795
40080
|
let stat;
|
|
39796
40081
|
try {
|
|
39797
|
-
stat =
|
|
40082
|
+
stat = import_node_fs19.default.statSync(file);
|
|
39798
40083
|
} catch {
|
|
39799
40084
|
continue;
|
|
39800
40085
|
}
|
|
@@ -39803,26 +40088,26 @@ function runAttachmentGc(args) {
|
|
|
39803
40088
|
if (age < ttlMs) continue;
|
|
39804
40089
|
if (liveAbs.has(file)) continue;
|
|
39805
40090
|
try {
|
|
39806
|
-
|
|
40091
|
+
import_node_fs19.default.unlinkSync(file);
|
|
39807
40092
|
} catch (err) {
|
|
39808
40093
|
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
39809
40094
|
}
|
|
39810
40095
|
}
|
|
39811
40096
|
try {
|
|
39812
|
-
if (
|
|
40097
|
+
if (import_node_fs19.default.readdirSync(hashDirAbs).length === 0) import_node_fs19.default.rmdirSync(hashDirAbs);
|
|
39813
40098
|
} catch {
|
|
39814
40099
|
}
|
|
39815
40100
|
}
|
|
39816
40101
|
try {
|
|
39817
|
-
if (
|
|
40102
|
+
if (import_node_fs19.default.readdirSync(attRoot).length === 0) import_node_fs19.default.rmdirSync(attRoot);
|
|
39818
40103
|
} catch {
|
|
39819
40104
|
}
|
|
39820
40105
|
}
|
|
39821
40106
|
}
|
|
39822
40107
|
|
|
39823
40108
|
// src/attachment/group.ts
|
|
39824
|
-
var
|
|
39825
|
-
var
|
|
40109
|
+
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
40110
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
39826
40111
|
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
39827
40112
|
init_protocol();
|
|
39828
40113
|
var GroupFileStore = class {
|
|
@@ -39834,11 +40119,11 @@ var GroupFileStore = class {
|
|
|
39834
40119
|
this.logger = opts.logger;
|
|
39835
40120
|
}
|
|
39836
40121
|
rootForScope(scope) {
|
|
39837
|
-
return
|
|
40122
|
+
return import_node_path20.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
39838
40123
|
}
|
|
39839
40124
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
39840
40125
|
filePath(scope, sessionId) {
|
|
39841
|
-
return
|
|
40126
|
+
return import_node_path20.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
39842
40127
|
}
|
|
39843
40128
|
cacheKey(scope, sessionId) {
|
|
39844
40129
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -39847,7 +40132,7 @@ var GroupFileStore = class {
|
|
|
39847
40132
|
readFile(scope, sessionId) {
|
|
39848
40133
|
const file = this.filePath(scope, sessionId);
|
|
39849
40134
|
try {
|
|
39850
|
-
const raw =
|
|
40135
|
+
const raw = import_node_fs20.default.readFileSync(file, "utf8");
|
|
39851
40136
|
const parsed = JSON.parse(raw);
|
|
39852
40137
|
if (!Array.isArray(parsed)) {
|
|
39853
40138
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -39873,10 +40158,10 @@ var GroupFileStore = class {
|
|
|
39873
40158
|
}
|
|
39874
40159
|
writeFile(scope, sessionId, entries) {
|
|
39875
40160
|
const file = this.filePath(scope, sessionId);
|
|
39876
|
-
|
|
40161
|
+
import_node_fs20.default.mkdirSync(import_node_path20.default.dirname(file), { recursive: true });
|
|
39877
40162
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
39878
|
-
|
|
39879
|
-
|
|
40163
|
+
import_node_fs20.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
40164
|
+
import_node_fs20.default.renameSync(tmp, file);
|
|
39880
40165
|
}
|
|
39881
40166
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
39882
40167
|
list(scope, sessionId) {
|
|
@@ -39962,10 +40247,10 @@ var GroupFileStore = class {
|
|
|
39962
40247
|
};
|
|
39963
40248
|
|
|
39964
40249
|
// src/discovery/state-file.ts
|
|
39965
|
-
var
|
|
39966
|
-
var
|
|
40250
|
+
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
40251
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
39967
40252
|
function defaultStateFilePath(dataDir) {
|
|
39968
|
-
return
|
|
40253
|
+
return import_node_path21.default.join(dataDir, "state.json");
|
|
39969
40254
|
}
|
|
39970
40255
|
function isPidAlive(pid) {
|
|
39971
40256
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -39987,7 +40272,7 @@ var StateFileManager = class {
|
|
|
39987
40272
|
}
|
|
39988
40273
|
read() {
|
|
39989
40274
|
try {
|
|
39990
|
-
const raw =
|
|
40275
|
+
const raw = import_node_fs21.default.readFileSync(this.file, "utf8");
|
|
39991
40276
|
const parsed = JSON.parse(raw);
|
|
39992
40277
|
return parsed;
|
|
39993
40278
|
} catch {
|
|
@@ -40001,20 +40286,20 @@ var StateFileManager = class {
|
|
|
40001
40286
|
return { status: "stale", existing };
|
|
40002
40287
|
}
|
|
40003
40288
|
write(state) {
|
|
40004
|
-
|
|
40289
|
+
import_node_fs21.default.mkdirSync(import_node_path21.default.dirname(this.file), { recursive: true });
|
|
40005
40290
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
40006
|
-
|
|
40007
|
-
|
|
40291
|
+
import_node_fs21.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
40292
|
+
import_node_fs21.default.renameSync(tmp, this.file);
|
|
40008
40293
|
if (process.platform !== "win32") {
|
|
40009
40294
|
try {
|
|
40010
|
-
|
|
40295
|
+
import_node_fs21.default.chmodSync(this.file, 384);
|
|
40011
40296
|
} catch {
|
|
40012
40297
|
}
|
|
40013
40298
|
}
|
|
40014
40299
|
}
|
|
40015
40300
|
delete() {
|
|
40016
40301
|
try {
|
|
40017
|
-
|
|
40302
|
+
import_node_fs21.default.unlinkSync(this.file);
|
|
40018
40303
|
} catch {
|
|
40019
40304
|
}
|
|
40020
40305
|
}
|
|
@@ -40029,14 +40314,14 @@ function readDaemonSourceFromEnv(env = process.env) {
|
|
|
40029
40314
|
}
|
|
40030
40315
|
|
|
40031
40316
|
// src/tunnel/tunnel-manager.ts
|
|
40032
|
-
var
|
|
40033
|
-
var
|
|
40317
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
40318
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
40034
40319
|
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
40035
40320
|
var import_node_child_process9 = require("child_process");
|
|
40036
40321
|
|
|
40037
40322
|
// src/tunnel/tunnel-store.ts
|
|
40038
|
-
var
|
|
40039
|
-
var
|
|
40323
|
+
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
40324
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
40040
40325
|
var TunnelStore = class {
|
|
40041
40326
|
constructor(filePath) {
|
|
40042
40327
|
this.filePath = filePath;
|
|
@@ -40044,7 +40329,7 @@ var TunnelStore = class {
|
|
|
40044
40329
|
filePath;
|
|
40045
40330
|
async get() {
|
|
40046
40331
|
try {
|
|
40047
|
-
const raw = await
|
|
40332
|
+
const raw = await import_node_fs22.default.promises.readFile(this.filePath, "utf8");
|
|
40048
40333
|
const obj = JSON.parse(raw);
|
|
40049
40334
|
if (!isPersistedTunnel(obj)) return null;
|
|
40050
40335
|
return obj;
|
|
@@ -40055,22 +40340,22 @@ var TunnelStore = class {
|
|
|
40055
40340
|
}
|
|
40056
40341
|
}
|
|
40057
40342
|
async set(v2) {
|
|
40058
|
-
const dir =
|
|
40059
|
-
await
|
|
40343
|
+
const dir = import_node_path22.default.dirname(this.filePath);
|
|
40344
|
+
await import_node_fs22.default.promises.mkdir(dir, { recursive: true });
|
|
40060
40345
|
const data = JSON.stringify(v2, null, 2);
|
|
40061
40346
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
40062
|
-
await
|
|
40347
|
+
await import_node_fs22.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
40063
40348
|
if (process.platform !== "win32") {
|
|
40064
40349
|
try {
|
|
40065
|
-
await
|
|
40350
|
+
await import_node_fs22.default.promises.chmod(tmp, 384);
|
|
40066
40351
|
} catch {
|
|
40067
40352
|
}
|
|
40068
40353
|
}
|
|
40069
|
-
await
|
|
40354
|
+
await import_node_fs22.default.promises.rename(tmp, this.filePath);
|
|
40070
40355
|
}
|
|
40071
40356
|
async clear() {
|
|
40072
40357
|
try {
|
|
40073
|
-
await
|
|
40358
|
+
await import_node_fs22.default.promises.unlink(this.filePath);
|
|
40074
40359
|
} catch (err) {
|
|
40075
40360
|
const code = err?.code;
|
|
40076
40361
|
if (code !== "ENOENT") throw err;
|
|
@@ -40165,9 +40450,9 @@ function escape(v2) {
|
|
|
40165
40450
|
}
|
|
40166
40451
|
|
|
40167
40452
|
// src/tunnel/frpc-binary.ts
|
|
40168
|
-
var
|
|
40453
|
+
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
40169
40454
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
40170
|
-
var
|
|
40455
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
40171
40456
|
var import_node_child_process7 = require("child_process");
|
|
40172
40457
|
var import_node_stream2 = require("stream");
|
|
40173
40458
|
var import_promises3 = require("stream/promises");
|
|
@@ -40199,20 +40484,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
40199
40484
|
}
|
|
40200
40485
|
async function ensureFrpcBinary(opts) {
|
|
40201
40486
|
if (opts.override) {
|
|
40202
|
-
if (!
|
|
40487
|
+
if (!import_node_fs23.default.existsSync(opts.override)) {
|
|
40203
40488
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
40204
40489
|
}
|
|
40205
40490
|
return opts.override;
|
|
40206
40491
|
}
|
|
40207
40492
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
40208
40493
|
const platform = opts.platform ?? detectPlatform();
|
|
40209
|
-
const binDir =
|
|
40210
|
-
|
|
40494
|
+
const binDir = import_node_path23.default.join(opts.dataDir, "bin");
|
|
40495
|
+
import_node_fs23.default.mkdirSync(binDir, { recursive: true });
|
|
40211
40496
|
cleanupStaleArtifacts(binDir);
|
|
40212
|
-
const stableBin =
|
|
40213
|
-
if (
|
|
40497
|
+
const stableBin = import_node_path23.default.join(binDir, "frpc");
|
|
40498
|
+
if (import_node_fs23.default.existsSync(stableBin)) return stableBin;
|
|
40214
40499
|
const partialBin = `${stableBin}.partial`;
|
|
40215
|
-
const tarballPath =
|
|
40500
|
+
const tarballPath = import_node_path23.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
40216
40501
|
try {
|
|
40217
40502
|
const url = frpcDownloadUrl(version2, platform);
|
|
40218
40503
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -40221,8 +40506,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
40221
40506
|
} else {
|
|
40222
40507
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
40223
40508
|
}
|
|
40224
|
-
|
|
40225
|
-
|
|
40509
|
+
import_node_fs23.default.chmodSync(partialBin, 493);
|
|
40510
|
+
import_node_fs23.default.renameSync(partialBin, stableBin);
|
|
40226
40511
|
} finally {
|
|
40227
40512
|
safeUnlink(tarballPath);
|
|
40228
40513
|
safeUnlink(partialBin);
|
|
@@ -40232,15 +40517,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
40232
40517
|
function cleanupStaleArtifacts(binDir) {
|
|
40233
40518
|
let entries;
|
|
40234
40519
|
try {
|
|
40235
|
-
entries =
|
|
40520
|
+
entries = import_node_fs23.default.readdirSync(binDir);
|
|
40236
40521
|
} catch {
|
|
40237
40522
|
return;
|
|
40238
40523
|
}
|
|
40239
40524
|
for (const name of entries) {
|
|
40240
40525
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
40241
|
-
const full =
|
|
40526
|
+
const full = import_node_path23.default.join(binDir, name);
|
|
40242
40527
|
try {
|
|
40243
|
-
|
|
40528
|
+
import_node_fs23.default.rmSync(full, { recursive: true, force: true });
|
|
40244
40529
|
} catch {
|
|
40245
40530
|
}
|
|
40246
40531
|
}
|
|
@@ -40248,7 +40533,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
40248
40533
|
}
|
|
40249
40534
|
function safeUnlink(p2) {
|
|
40250
40535
|
try {
|
|
40251
|
-
|
|
40536
|
+
import_node_fs23.default.unlinkSync(p2);
|
|
40252
40537
|
} catch {
|
|
40253
40538
|
}
|
|
40254
40539
|
}
|
|
@@ -40259,13 +40544,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
40259
40544
|
if (!res.ok || !res.body) {
|
|
40260
40545
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
40261
40546
|
}
|
|
40262
|
-
const out =
|
|
40547
|
+
const out = import_node_fs23.default.createWriteStream(dest);
|
|
40263
40548
|
const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
|
|
40264
40549
|
await (0, import_promises3.pipeline)(nodeStream, out);
|
|
40265
40550
|
}
|
|
40266
40551
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
40267
|
-
const work =
|
|
40268
|
-
|
|
40552
|
+
const work = import_node_path23.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
40553
|
+
import_node_fs23.default.mkdirSync(work, { recursive: true });
|
|
40269
40554
|
try {
|
|
40270
40555
|
await new Promise((resolve6, reject) => {
|
|
40271
40556
|
const proc = (0, import_node_child_process7.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -40273,32 +40558,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
40273
40558
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
40274
40559
|
});
|
|
40275
40560
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
40276
|
-
const src =
|
|
40277
|
-
if (!
|
|
40561
|
+
const src = import_node_path23.default.join(work, dirName, "frpc");
|
|
40562
|
+
if (!import_node_fs23.default.existsSync(src)) {
|
|
40278
40563
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
40279
40564
|
}
|
|
40280
|
-
|
|
40565
|
+
import_node_fs23.default.copyFileSync(src, destBin);
|
|
40281
40566
|
} finally {
|
|
40282
|
-
|
|
40567
|
+
import_node_fs23.default.rmSync(work, { recursive: true, force: true });
|
|
40283
40568
|
}
|
|
40284
40569
|
}
|
|
40285
40570
|
|
|
40286
40571
|
// src/tunnel/frpc-process.ts
|
|
40287
|
-
var
|
|
40288
|
-
var
|
|
40572
|
+
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
40573
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
40289
40574
|
var import_node_child_process8 = require("child_process");
|
|
40290
40575
|
function frpcPidFilePath(dataDir) {
|
|
40291
|
-
return
|
|
40576
|
+
return import_node_path24.default.join(dataDir, "frpc.pid");
|
|
40292
40577
|
}
|
|
40293
40578
|
function writeFrpcPid(dataDir, pid) {
|
|
40294
40579
|
try {
|
|
40295
|
-
|
|
40580
|
+
import_node_fs24.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
40296
40581
|
} catch {
|
|
40297
40582
|
}
|
|
40298
40583
|
}
|
|
40299
40584
|
function clearFrpcPid(dataDir) {
|
|
40300
40585
|
try {
|
|
40301
|
-
|
|
40586
|
+
import_node_fs24.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
40302
40587
|
} catch {
|
|
40303
40588
|
}
|
|
40304
40589
|
}
|
|
@@ -40314,7 +40599,7 @@ function defaultIsPidAlive(pid) {
|
|
|
40314
40599
|
}
|
|
40315
40600
|
function defaultReadPidFile(file) {
|
|
40316
40601
|
try {
|
|
40317
|
-
return
|
|
40602
|
+
return import_node_fs24.default.readFileSync(file, "utf8");
|
|
40318
40603
|
} catch {
|
|
40319
40604
|
return null;
|
|
40320
40605
|
}
|
|
@@ -40330,7 +40615,7 @@ function defaultSleep(ms) {
|
|
|
40330
40615
|
}
|
|
40331
40616
|
async function killStaleFrpc(deps) {
|
|
40332
40617
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
40333
|
-
const tomlPath =
|
|
40618
|
+
const tomlPath = import_node_path24.default.join(deps.dataDir, "frpc.toml");
|
|
40334
40619
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
40335
40620
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
40336
40621
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -40354,7 +40639,7 @@ async function killStaleFrpc(deps) {
|
|
|
40354
40639
|
}
|
|
40355
40640
|
if (victims.size === 0) {
|
|
40356
40641
|
try {
|
|
40357
|
-
|
|
40642
|
+
import_node_fs24.default.unlinkSync(pidFile);
|
|
40358
40643
|
} catch {
|
|
40359
40644
|
}
|
|
40360
40645
|
return;
|
|
@@ -40365,7 +40650,7 @@ async function killStaleFrpc(deps) {
|
|
|
40365
40650
|
}
|
|
40366
40651
|
await sleep(deps.reapWaitMs ?? 300);
|
|
40367
40652
|
try {
|
|
40368
|
-
|
|
40653
|
+
import_node_fs24.default.unlinkSync(pidFile);
|
|
40369
40654
|
} catch {
|
|
40370
40655
|
}
|
|
40371
40656
|
}
|
|
@@ -40402,7 +40687,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
40402
40687
|
var TunnelManager = class {
|
|
40403
40688
|
constructor(deps) {
|
|
40404
40689
|
this.deps = deps;
|
|
40405
|
-
this.store = deps.store ?? new TunnelStore(
|
|
40690
|
+
this.store = deps.store ?? new TunnelStore(import_node_path25.default.join(deps.dataDir, "tunnel.json"));
|
|
40406
40691
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
40407
40692
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
40408
40693
|
}
|
|
@@ -40529,7 +40814,7 @@ var TunnelManager = class {
|
|
|
40529
40814
|
dataDir: this.deps.dataDir,
|
|
40530
40815
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
40531
40816
|
});
|
|
40532
|
-
const tomlPath =
|
|
40817
|
+
const tomlPath = import_node_path25.default.join(this.deps.dataDir, "frpc.toml");
|
|
40533
40818
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto7.default.randomBytes(3).toString("hex")}`;
|
|
40534
40819
|
const toml = buildFrpcToml({
|
|
40535
40820
|
serverAddr: t.frpsHost,
|
|
@@ -40540,12 +40825,12 @@ var TunnelManager = class {
|
|
|
40540
40825
|
localPort,
|
|
40541
40826
|
logLevel: "info"
|
|
40542
40827
|
});
|
|
40543
|
-
await
|
|
40828
|
+
await import_node_fs25.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
40544
40829
|
const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
|
|
40545
40830
|
stdio: ["ignore", "pipe", "pipe"]
|
|
40546
40831
|
});
|
|
40547
|
-
const logFilePath =
|
|
40548
|
-
const logStream =
|
|
40832
|
+
const logFilePath = import_node_path25.default.join(this.deps.dataDir, "frpc.log");
|
|
40833
|
+
const logStream = import_node_fs25.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
40549
40834
|
logStream.on("error", () => {
|
|
40550
40835
|
});
|
|
40551
40836
|
const tee = (chunk) => {
|
|
@@ -40628,27 +40913,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
40628
40913
|
|
|
40629
40914
|
// src/tunnel/device-key.ts
|
|
40630
40915
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
40631
|
-
var
|
|
40916
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
40632
40917
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
40633
40918
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
40634
40919
|
function deriveStableDeviceKey(opts = {}) {
|
|
40635
40920
|
const hostname = opts.hostname ?? import_node_os12.default.hostname();
|
|
40636
40921
|
const uid = opts.uid ?? (typeof import_node_os12.default.userInfo === "function" ? import_node_os12.default.userInfo().uid : 0);
|
|
40637
40922
|
const home = opts.home ?? import_node_os12.default.homedir();
|
|
40638
|
-
const defaultDataDir =
|
|
40639
|
-
const normalizedDataDir = opts.dataDir ?
|
|
40923
|
+
const defaultDataDir = import_node_path26.default.resolve(import_node_path26.default.join(home, ".clawd"));
|
|
40924
|
+
const normalizedDataDir = opts.dataDir ? import_node_path26.default.resolve(opts.dataDir) : null;
|
|
40640
40925
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
40641
40926
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
40642
40927
|
return import_node_crypto8.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
40643
40928
|
}
|
|
40644
40929
|
|
|
40645
40930
|
// src/auth-store.ts
|
|
40646
|
-
var
|
|
40647
|
-
var
|
|
40931
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
40932
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
40648
40933
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
40649
40934
|
var AUTH_FILE_NAME = "auth.json";
|
|
40650
40935
|
function authFilePath(dataDir) {
|
|
40651
|
-
return
|
|
40936
|
+
return import_node_path27.default.join(dataDir, AUTH_FILE_NAME);
|
|
40652
40937
|
}
|
|
40653
40938
|
function loadOrCreateAuthFile(opts) {
|
|
40654
40939
|
const file = authFilePath(opts.dataDir);
|
|
@@ -40682,7 +40967,7 @@ function defaultGenerateOwnerPrincipalId() {
|
|
|
40682
40967
|
}
|
|
40683
40968
|
function readAuthFile(file) {
|
|
40684
40969
|
try {
|
|
40685
|
-
const raw =
|
|
40970
|
+
const raw = import_node_fs26.default.readFileSync(file, "utf8");
|
|
40686
40971
|
const parsed = JSON.parse(raw);
|
|
40687
40972
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
40688
40973
|
return null;
|
|
@@ -40701,25 +40986,25 @@ function readAuthFile(file) {
|
|
|
40701
40986
|
}
|
|
40702
40987
|
}
|
|
40703
40988
|
function writeAuthFile(file, content) {
|
|
40704
|
-
|
|
40705
|
-
|
|
40989
|
+
import_node_fs26.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
|
|
40990
|
+
import_node_fs26.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
40706
40991
|
try {
|
|
40707
|
-
|
|
40992
|
+
import_node_fs26.default.chmodSync(file, 384);
|
|
40708
40993
|
} catch {
|
|
40709
40994
|
}
|
|
40710
40995
|
}
|
|
40711
40996
|
|
|
40712
40997
|
// src/owner-profile.ts
|
|
40713
|
-
var
|
|
40998
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
40714
40999
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
40715
|
-
var
|
|
41000
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
40716
41001
|
var PROFILE_FILENAME = "profile.json";
|
|
40717
41002
|
function loadOwnerDisplayName(dataDir) {
|
|
40718
41003
|
const fallback = import_node_os13.default.userInfo().username;
|
|
40719
|
-
const profilePath =
|
|
41004
|
+
const profilePath = import_node_path28.default.join(dataDir, PROFILE_FILENAME);
|
|
40720
41005
|
let raw;
|
|
40721
41006
|
try {
|
|
40722
|
-
raw =
|
|
41007
|
+
raw = import_node_fs27.default.readFileSync(profilePath, "utf8");
|
|
40723
41008
|
} catch {
|
|
40724
41009
|
return fallback;
|
|
40725
41010
|
}
|
|
@@ -40742,18 +41027,18 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
40742
41027
|
}
|
|
40743
41028
|
|
|
40744
41029
|
// src/feishu-auth/owner-identity-store.ts
|
|
40745
|
-
var
|
|
40746
|
-
var
|
|
41030
|
+
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
41031
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
40747
41032
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
40748
41033
|
var OwnerIdentityStore = class {
|
|
40749
41034
|
file;
|
|
40750
41035
|
constructor(dataDir) {
|
|
40751
|
-
this.file =
|
|
41036
|
+
this.file = import_node_path29.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
40752
41037
|
}
|
|
40753
41038
|
read() {
|
|
40754
41039
|
let raw;
|
|
40755
41040
|
try {
|
|
40756
|
-
raw =
|
|
41041
|
+
raw = import_node_fs28.default.readFileSync(this.file, "utf8");
|
|
40757
41042
|
} catch {
|
|
40758
41043
|
return null;
|
|
40759
41044
|
}
|
|
@@ -40780,16 +41065,16 @@ var OwnerIdentityStore = class {
|
|
|
40780
41065
|
};
|
|
40781
41066
|
}
|
|
40782
41067
|
write(record) {
|
|
40783
|
-
|
|
40784
|
-
|
|
41068
|
+
import_node_fs28.default.mkdirSync(import_node_path29.default.dirname(this.file), { recursive: true });
|
|
41069
|
+
import_node_fs28.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
40785
41070
|
try {
|
|
40786
|
-
|
|
41071
|
+
import_node_fs28.default.chmodSync(this.file, 384);
|
|
40787
41072
|
} catch {
|
|
40788
41073
|
}
|
|
40789
41074
|
}
|
|
40790
41075
|
clear() {
|
|
40791
41076
|
try {
|
|
40792
|
-
|
|
41077
|
+
import_node_fs28.default.unlinkSync(this.file);
|
|
40793
41078
|
} catch (err) {
|
|
40794
41079
|
const code = err?.code;
|
|
40795
41080
|
if (code !== "ENOENT") throw err;
|
|
@@ -40908,9 +41193,9 @@ var CentralClientError = class extends Error {
|
|
|
40908
41193
|
code;
|
|
40909
41194
|
cause;
|
|
40910
41195
|
};
|
|
40911
|
-
async function centralRequest(opts,
|
|
41196
|
+
async function centralRequest(opts, path59, init) {
|
|
40912
41197
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
40913
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
41198
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path59}`;
|
|
40914
41199
|
const ctrl = new AbortController();
|
|
40915
41200
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
40916
41201
|
let res;
|
|
@@ -41052,8 +41337,8 @@ function verifyConnectToken(args) {
|
|
|
41052
41337
|
}
|
|
41053
41338
|
|
|
41054
41339
|
// src/feishu-auth/server-key.ts
|
|
41055
|
-
var
|
|
41056
|
-
var
|
|
41340
|
+
var fs37 = __toESM(require("fs"), 1);
|
|
41341
|
+
var path38 = __toESM(require("path"), 1);
|
|
41057
41342
|
var FILE_NAME2 = "server-signing-key.json";
|
|
41058
41343
|
var ServerKeyStore = class {
|
|
41059
41344
|
constructor(dataDir) {
|
|
@@ -41061,12 +41346,12 @@ var ServerKeyStore = class {
|
|
|
41061
41346
|
}
|
|
41062
41347
|
dataDir;
|
|
41063
41348
|
filePath() {
|
|
41064
|
-
return
|
|
41349
|
+
return path38.join(this.dataDir, FILE_NAME2);
|
|
41065
41350
|
}
|
|
41066
41351
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
41067
41352
|
read() {
|
|
41068
41353
|
try {
|
|
41069
|
-
const raw =
|
|
41354
|
+
const raw = fs37.readFileSync(this.filePath(), "utf8");
|
|
41070
41355
|
const parsed = JSON.parse(raw);
|
|
41071
41356
|
if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
|
|
41072
41357
|
return parsed.publicKeyPem;
|
|
@@ -41081,12 +41366,12 @@ var ServerKeyStore = class {
|
|
|
41081
41366
|
publicKeyPem,
|
|
41082
41367
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
41083
41368
|
};
|
|
41084
|
-
|
|
41085
|
-
|
|
41369
|
+
fs37.mkdirSync(this.dataDir, { recursive: true });
|
|
41370
|
+
fs37.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
|
|
41086
41371
|
}
|
|
41087
41372
|
clear() {
|
|
41088
41373
|
try {
|
|
41089
|
-
|
|
41374
|
+
fs37.unlinkSync(this.filePath());
|
|
41090
41375
|
} catch {
|
|
41091
41376
|
}
|
|
41092
41377
|
}
|
|
@@ -41099,12 +41384,12 @@ init_protocol();
|
|
|
41099
41384
|
init_protocol();
|
|
41100
41385
|
|
|
41101
41386
|
// src/session/fork.ts
|
|
41102
|
-
var
|
|
41387
|
+
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
41103
41388
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
41104
|
-
var
|
|
41389
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
41105
41390
|
init_claude_history();
|
|
41106
41391
|
function readJsonlEntries(file) {
|
|
41107
|
-
const raw =
|
|
41392
|
+
const raw = import_node_fs29.default.readFileSync(file, "utf8");
|
|
41108
41393
|
const out = [];
|
|
41109
41394
|
for (const line of raw.split("\n")) {
|
|
41110
41395
|
const t = line.trim();
|
|
@@ -41117,10 +41402,10 @@ function readJsonlEntries(file) {
|
|
|
41117
41402
|
return out;
|
|
41118
41403
|
}
|
|
41119
41404
|
function forkSession(input) {
|
|
41120
|
-
const baseDir = input.baseDir ??
|
|
41121
|
-
const projectDir =
|
|
41122
|
-
const sourceFile =
|
|
41123
|
-
if (!
|
|
41405
|
+
const baseDir = input.baseDir ?? import_node_path30.default.join(import_node_os14.default.homedir(), ".claude");
|
|
41406
|
+
const projectDir = import_node_path30.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
41407
|
+
const sourceFile = import_node_path30.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
41408
|
+
if (!import_node_fs29.default.existsSync(sourceFile)) {
|
|
41124
41409
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
41125
41410
|
}
|
|
41126
41411
|
const entries = readJsonlEntries(sourceFile);
|
|
@@ -41150,9 +41435,9 @@ function forkSession(input) {
|
|
|
41150
41435
|
}
|
|
41151
41436
|
forkedLines.push(JSON.stringify(forked));
|
|
41152
41437
|
}
|
|
41153
|
-
const forkedFilePath =
|
|
41154
|
-
|
|
41155
|
-
|
|
41438
|
+
const forkedFilePath = import_node_path30.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
41439
|
+
import_node_fs29.default.mkdirSync(projectDir, { recursive: true });
|
|
41440
|
+
import_node_fs29.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
41156
41441
|
return { forkedToolSessionId, forkedFilePath };
|
|
41157
41442
|
}
|
|
41158
41443
|
|
|
@@ -41528,7 +41813,7 @@ function buildPermissionHandlers(deps) {
|
|
|
41528
41813
|
}
|
|
41529
41814
|
|
|
41530
41815
|
// src/handlers/history.ts
|
|
41531
|
-
var
|
|
41816
|
+
var path41 = __toESM(require("path"), 1);
|
|
41532
41817
|
init_protocol();
|
|
41533
41818
|
|
|
41534
41819
|
// src/session/recent-dirs.ts
|
|
@@ -41546,7 +41831,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
41546
41831
|
}
|
|
41547
41832
|
|
|
41548
41833
|
// src/permission/persona-paths.ts
|
|
41549
|
-
var
|
|
41834
|
+
var path40 = __toESM(require("path"), 1);
|
|
41550
41835
|
function getAllowedPersonaIds(grants, action) {
|
|
41551
41836
|
const ids = /* @__PURE__ */ new Set();
|
|
41552
41837
|
for (const g2 of grants) {
|
|
@@ -41559,31 +41844,31 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
41559
41844
|
return ids;
|
|
41560
41845
|
}
|
|
41561
41846
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
41562
|
-
const target =
|
|
41847
|
+
const target = path40.resolve(absPath);
|
|
41563
41848
|
if (userWorkDir) {
|
|
41564
|
-
const u =
|
|
41565
|
-
const usep = u.endsWith(
|
|
41849
|
+
const u = path40.resolve(userWorkDir);
|
|
41850
|
+
const usep = u.endsWith(path40.sep) ? "" : path40.sep;
|
|
41566
41851
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
41567
41852
|
}
|
|
41568
|
-
const root =
|
|
41569
|
-
const sep2 = root.endsWith(
|
|
41853
|
+
const root = path40.resolve(personaRoot);
|
|
41854
|
+
const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
|
|
41570
41855
|
if (!target.startsWith(root + sep2)) return false;
|
|
41571
|
-
const rel =
|
|
41856
|
+
const rel = path40.relative(root, target);
|
|
41572
41857
|
if (!rel || rel.startsWith("..")) return false;
|
|
41573
|
-
const personaId = rel.split(
|
|
41858
|
+
const personaId = rel.split(path40.sep)[0];
|
|
41574
41859
|
if (!personaId) return false;
|
|
41575
41860
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
41576
41861
|
if (allowed === "*") return true;
|
|
41577
41862
|
return allowed.has(personaId);
|
|
41578
41863
|
}
|
|
41579
41864
|
function personaIdFromPath(absPath, personaRoot) {
|
|
41580
|
-
const root =
|
|
41581
|
-
const target =
|
|
41582
|
-
const sep2 = root.endsWith(
|
|
41865
|
+
const root = path40.resolve(personaRoot);
|
|
41866
|
+
const target = path40.resolve(absPath);
|
|
41867
|
+
const sep2 = root.endsWith(path40.sep) ? "" : path40.sep;
|
|
41583
41868
|
if (!target.startsWith(root + sep2)) return null;
|
|
41584
|
-
const rel =
|
|
41869
|
+
const rel = path40.relative(root, target);
|
|
41585
41870
|
if (!rel || rel.startsWith("..")) return null;
|
|
41586
|
-
const id = rel.split(
|
|
41871
|
+
const id = rel.split(path40.sep)[0];
|
|
41587
41872
|
return id || null;
|
|
41588
41873
|
}
|
|
41589
41874
|
|
|
@@ -41610,7 +41895,7 @@ function buildHistoryHandlers(deps) {
|
|
|
41610
41895
|
if (!pid) return false;
|
|
41611
41896
|
return isGuestPathAllowed(
|
|
41612
41897
|
ctx.grants,
|
|
41613
|
-
|
|
41898
|
+
path41.join(personaRoot, pid),
|
|
41614
41899
|
personaRoot,
|
|
41615
41900
|
"read",
|
|
41616
41901
|
userWorkDir
|
|
@@ -41622,7 +41907,7 @@ function buildHistoryHandlers(deps) {
|
|
|
41622
41907
|
};
|
|
41623
41908
|
const list = async (frame, _client, ctx) => {
|
|
41624
41909
|
const args = HistoryListArgs.parse(frame);
|
|
41625
|
-
assertGuestPath(ctx,
|
|
41910
|
+
assertGuestPath(ctx, path41.resolve(args.projectPath), personaRoot, "history:list");
|
|
41626
41911
|
const sessions = await history.listSessions(args);
|
|
41627
41912
|
return { response: { type: "history:list", sessions } };
|
|
41628
41913
|
};
|
|
@@ -41654,13 +41939,13 @@ function buildHistoryHandlers(deps) {
|
|
|
41654
41939
|
};
|
|
41655
41940
|
const subagents = async (frame, _client, ctx) => {
|
|
41656
41941
|
const args = HistorySubagentsArgs.parse(frame);
|
|
41657
|
-
assertGuestPath(ctx,
|
|
41942
|
+
assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
41658
41943
|
const subs = await history.listSubagents(args);
|
|
41659
41944
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
41660
41945
|
};
|
|
41661
41946
|
const subagentRead = async (frame, _client, ctx) => {
|
|
41662
41947
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
41663
|
-
assertGuestPath(ctx,
|
|
41948
|
+
assertGuestPath(ctx, path41.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
41664
41949
|
const res = await history.readSubagent(args);
|
|
41665
41950
|
return { response: { type: "history:subagent-read", ...res } };
|
|
41666
41951
|
};
|
|
@@ -41669,7 +41954,7 @@ function buildHistoryHandlers(deps) {
|
|
|
41669
41954
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
41670
41955
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
41671
41956
|
const filtered = dirs.filter(
|
|
41672
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
41957
|
+
(d) => isGuestPathAllowed(ctx.grants, path41.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
41673
41958
|
);
|
|
41674
41959
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
41675
41960
|
}
|
|
@@ -41686,7 +41971,7 @@ function buildHistoryHandlers(deps) {
|
|
|
41686
41971
|
}
|
|
41687
41972
|
|
|
41688
41973
|
// src/handlers/workspace.ts
|
|
41689
|
-
var
|
|
41974
|
+
var path42 = __toESM(require("path"), 1);
|
|
41690
41975
|
var os15 = __toESM(require("os"), 1);
|
|
41691
41976
|
init_protocol();
|
|
41692
41977
|
init_protocol();
|
|
@@ -41728,22 +42013,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
41728
42013
|
const args = WorkspaceListArgs.parse(frame);
|
|
41729
42014
|
const isGuest = ctx?.principal.kind === "guest";
|
|
41730
42015
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os15.homedir();
|
|
41731
|
-
const resolvedCwd =
|
|
41732
|
-
const target = args.path ?
|
|
42016
|
+
const resolvedCwd = path42.resolve(args.cwd ?? fallbackCwd);
|
|
42017
|
+
const target = args.path ? path42.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
41733
42018
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
41734
42019
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
41735
42020
|
return { response: { type: "workspace:list", ...res } };
|
|
41736
42021
|
};
|
|
41737
42022
|
const read = async (frame, _client, ctx) => {
|
|
41738
42023
|
const args = WorkspaceReadArgs.parse(frame);
|
|
41739
|
-
const target =
|
|
42024
|
+
const target = path42.isAbsolute(args.path) ? path42.resolve(args.path) : path42.resolve(args.cwd, args.path);
|
|
41740
42025
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
41741
42026
|
const res = workspace.read(args);
|
|
41742
42027
|
return { response: { type: "workspace:read", ...res } };
|
|
41743
42028
|
};
|
|
41744
42029
|
const skillsList = async (frame, _client, ctx) => {
|
|
41745
42030
|
const args = SkillsListArgs.parse(frame);
|
|
41746
|
-
const cwdAbs =
|
|
42031
|
+
const cwdAbs = path42.resolve(args.cwd);
|
|
41747
42032
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
41748
42033
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
41749
42034
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -41755,7 +42040,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
41755
42040
|
};
|
|
41756
42041
|
const agentsList = async (frame, _client, ctx) => {
|
|
41757
42042
|
const args = AgentsListArgs.parse(frame);
|
|
41758
|
-
const cwdAbs =
|
|
42043
|
+
const cwdAbs = path42.resolve(args.cwd);
|
|
41759
42044
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
41760
42045
|
if (args.tool === "codex") {
|
|
41761
42046
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -41777,20 +42062,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
41777
42062
|
}
|
|
41778
42063
|
|
|
41779
42064
|
// src/handlers/git.ts
|
|
41780
|
-
var
|
|
42065
|
+
var path44 = __toESM(require("path"), 1);
|
|
41781
42066
|
init_protocol();
|
|
41782
42067
|
init_protocol();
|
|
41783
42068
|
|
|
41784
42069
|
// src/workspace/git.ts
|
|
41785
42070
|
var import_node_child_process10 = require("child_process");
|
|
41786
|
-
var
|
|
41787
|
-
var
|
|
42071
|
+
var import_node_fs30 = __toESM(require("fs"), 1);
|
|
42072
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
41788
42073
|
var import_node_util = require("util");
|
|
41789
42074
|
var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
|
|
41790
42075
|
function normalizePath(p2) {
|
|
41791
|
-
const resolved =
|
|
42076
|
+
const resolved = import_node_path31.default.resolve(p2);
|
|
41792
42077
|
try {
|
|
41793
|
-
return
|
|
42078
|
+
return import_node_fs30.default.realpathSync(resolved);
|
|
41794
42079
|
} catch {
|
|
41795
42080
|
return resolved;
|
|
41796
42081
|
}
|
|
@@ -41864,7 +42149,7 @@ async function listGitBranches(cwd) {
|
|
|
41864
42149
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
41865
42150
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
41866
42151
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
41867
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
42152
|
+
if (!isGuestPathAllowed(ctx.grants, path44.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
41868
42153
|
throw new ClawdError(
|
|
41869
42154
|
ERROR_CODES.UNAUTHORIZED,
|
|
41870
42155
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -42378,7 +42663,7 @@ function buildPersonaHandlers(deps) {
|
|
|
42378
42663
|
}
|
|
42379
42664
|
|
|
42380
42665
|
// src/handlers/attachment.ts
|
|
42381
|
-
var
|
|
42666
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
42382
42667
|
init_protocol();
|
|
42383
42668
|
init_protocol();
|
|
42384
42669
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -42433,12 +42718,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
42433
42718
|
`session ${args.sessionId} scope unresolved`
|
|
42434
42719
|
);
|
|
42435
42720
|
}
|
|
42436
|
-
const cwdAbs =
|
|
42437
|
-
const candidateAbs =
|
|
42721
|
+
const cwdAbs = import_node_path32.default.resolve(sessionFile.cwd);
|
|
42722
|
+
const candidateAbs = import_node_path32.default.isAbsolute(args.relPath) ? import_node_path32.default.resolve(args.relPath) : import_node_path32.default.resolve(cwdAbs, args.relPath);
|
|
42438
42723
|
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl", deps.usersRoot);
|
|
42439
42724
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
42440
42725
|
const entry = entries.find((e) => {
|
|
42441
|
-
const storedAbs =
|
|
42726
|
+
const storedAbs = import_node_path32.default.isAbsolute(e.relPath) ? import_node_path32.default.resolve(e.relPath) : import_node_path32.default.resolve(cwdAbs, e.relPath);
|
|
42442
42727
|
return storedAbs === candidateAbs && !e.stale;
|
|
42443
42728
|
});
|
|
42444
42729
|
if (!entry) {
|
|
@@ -42462,7 +42747,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
42462
42747
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
42463
42748
|
const f = deps.sessionStore.read(sessionId);
|
|
42464
42749
|
if (!f) return;
|
|
42465
|
-
assertGuestAttachmentPath(ctx,
|
|
42750
|
+
assertGuestAttachmentPath(ctx, import_node_path32.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
42466
42751
|
}
|
|
42467
42752
|
const groupAdd = async (frame, _client, ctx) => {
|
|
42468
42753
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -42534,19 +42819,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
42534
42819
|
|
|
42535
42820
|
// src/handlers/extension.ts
|
|
42536
42821
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
42537
|
-
var
|
|
42822
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
42538
42823
|
init_protocol();
|
|
42539
42824
|
|
|
42540
42825
|
// src/extension/bundle-zip.ts
|
|
42541
42826
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
42542
|
-
var
|
|
42827
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
42543
42828
|
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
42544
42829
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
42545
42830
|
async function bundleExtensionDir(dir) {
|
|
42546
42831
|
const entries = await listFilesSorted(dir);
|
|
42547
42832
|
const zip = new import_jszip2.default();
|
|
42548
42833
|
for (const rel of entries) {
|
|
42549
|
-
const abs =
|
|
42834
|
+
const abs = import_node_path33.default.join(dir, rel);
|
|
42550
42835
|
const content = await import_promises4.default.readFile(abs);
|
|
42551
42836
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
42552
42837
|
}
|
|
@@ -42567,7 +42852,7 @@ async function listFilesSorted(rootDir) {
|
|
|
42567
42852
|
return out;
|
|
42568
42853
|
}
|
|
42569
42854
|
async function walk(absRoot, relPrefix, out) {
|
|
42570
|
-
const dirAbs =
|
|
42855
|
+
const dirAbs = import_node_path33.default.join(absRoot, relPrefix);
|
|
42571
42856
|
const entries = await import_promises4.default.readdir(dirAbs, { withFileTypes: true });
|
|
42572
42857
|
for (const e of entries) {
|
|
42573
42858
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -42621,25 +42906,25 @@ function computePublishCheck(args) {
|
|
|
42621
42906
|
|
|
42622
42907
|
// src/extension/install-flow.ts
|
|
42623
42908
|
var import_promises5 = __toESM(require("fs/promises"), 1);
|
|
42624
|
-
var
|
|
42909
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
42625
42910
|
var import_node_os17 = __toESM(require("os"), 1);
|
|
42626
42911
|
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
42627
42912
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
42628
42913
|
|
|
42629
42914
|
// src/extension/paths.ts
|
|
42630
42915
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
42631
|
-
var
|
|
42916
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
42632
42917
|
function clawdHomeRoot(override) {
|
|
42633
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
42918
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path34.default.join(import_node_os16.default.homedir(), ".clawd");
|
|
42634
42919
|
}
|
|
42635
42920
|
function extensionsRoot(override) {
|
|
42636
|
-
return
|
|
42921
|
+
return import_node_path34.default.join(clawdHomeRoot(override), "extensions");
|
|
42637
42922
|
}
|
|
42638
42923
|
function publishedChannelsFile(override) {
|
|
42639
|
-
return
|
|
42924
|
+
return import_node_path34.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
42640
42925
|
}
|
|
42641
42926
|
function bundleCacheRoot(override) {
|
|
42642
|
-
return
|
|
42927
|
+
return import_node_path34.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
42643
42928
|
}
|
|
42644
42929
|
|
|
42645
42930
|
// src/extension/install-flow.ts
|
|
@@ -42666,7 +42951,7 @@ async function installFromChannel(args, deps) {
|
|
|
42666
42951
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
42667
42952
|
}
|
|
42668
42953
|
for (const name of Object.keys(zip.files)) {
|
|
42669
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
42954
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
|
|
42670
42955
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
42671
42956
|
}
|
|
42672
42957
|
}
|
|
@@ -42698,7 +42983,7 @@ async function installFromChannel(args, deps) {
|
|
|
42698
42983
|
);
|
|
42699
42984
|
}
|
|
42700
42985
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
42701
|
-
const destDir =
|
|
42986
|
+
const destDir = import_node_path35.default.join(deps.extensionsRoot, localExtId);
|
|
42702
42987
|
let destExists = false;
|
|
42703
42988
|
try {
|
|
42704
42989
|
await import_promises5.default.access(destDir);
|
|
@@ -42712,16 +42997,16 @@ async function installFromChannel(args, deps) {
|
|
|
42712
42997
|
);
|
|
42713
42998
|
}
|
|
42714
42999
|
const stage = await import_promises5.default.mkdtemp(
|
|
42715
|
-
|
|
43000
|
+
import_node_path35.default.join(import_node_os17.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
42716
43001
|
);
|
|
42717
43002
|
try {
|
|
42718
43003
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
42719
|
-
const dest =
|
|
43004
|
+
const dest = import_node_path35.default.join(stage, name);
|
|
42720
43005
|
if (entry.dir) {
|
|
42721
43006
|
await import_promises5.default.mkdir(dest, { recursive: true });
|
|
42722
43007
|
continue;
|
|
42723
43008
|
}
|
|
42724
|
-
await import_promises5.default.mkdir(
|
|
43009
|
+
await import_promises5.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
|
|
42725
43010
|
if (name === "manifest.json") {
|
|
42726
43011
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
42727
43012
|
await import_promises5.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -42742,7 +43027,7 @@ async function installFromChannel(args, deps) {
|
|
|
42742
43027
|
|
|
42743
43028
|
// src/extension/update-flow.ts
|
|
42744
43029
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
42745
|
-
var
|
|
43030
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
42746
43031
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
42747
43032
|
var import_node_crypto13 = __toESM(require("crypto"), 1);
|
|
42748
43033
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
@@ -42759,11 +43044,11 @@ async function updateFromChannel(args, deps) {
|
|
|
42759
43044
|
channelRef.extId,
|
|
42760
43045
|
channelRef.ownerPrincipalId
|
|
42761
43046
|
);
|
|
42762
|
-
const liveDir =
|
|
43047
|
+
const liveDir = import_node_path36.default.join(deps.extensionsRoot, localExtId);
|
|
42763
43048
|
const prevDir = `${liveDir}.prev`;
|
|
42764
43049
|
let existingVersion;
|
|
42765
43050
|
try {
|
|
42766
|
-
const raw = await import_promises6.default.readFile(
|
|
43051
|
+
const raw = await import_promises6.default.readFile(import_node_path36.default.join(liveDir, "manifest.json"), "utf8");
|
|
42767
43052
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
42768
43053
|
if (!parsed2.success) {
|
|
42769
43054
|
throw new UpdateError(
|
|
@@ -42796,7 +43081,7 @@ async function updateFromChannel(args, deps) {
|
|
|
42796
43081
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
42797
43082
|
}
|
|
42798
43083
|
for (const name of Object.keys(zip.files)) {
|
|
42799
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
43084
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path36.default.isAbsolute(name)) {
|
|
42800
43085
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
42801
43086
|
}
|
|
42802
43087
|
}
|
|
@@ -42831,16 +43116,16 @@ async function updateFromChannel(args, deps) {
|
|
|
42831
43116
|
await import_promises6.default.rm(prevDir, { recursive: true, force: true });
|
|
42832
43117
|
await import_promises6.default.rename(liveDir, prevDir);
|
|
42833
43118
|
const stage = await import_promises6.default.mkdtemp(
|
|
42834
|
-
|
|
43119
|
+
import_node_path36.default.join(import_node_os18.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
42835
43120
|
);
|
|
42836
43121
|
try {
|
|
42837
43122
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
42838
|
-
const dest =
|
|
43123
|
+
const dest = import_node_path36.default.join(stage, name);
|
|
42839
43124
|
if (entry.dir) {
|
|
42840
43125
|
await import_promises6.default.mkdir(dest, { recursive: true });
|
|
42841
43126
|
continue;
|
|
42842
43127
|
}
|
|
42843
|
-
await import_promises6.default.mkdir(
|
|
43128
|
+
await import_promises6.default.mkdir(import_node_path36.default.dirname(dest), { recursive: true });
|
|
42844
43129
|
if (name === "manifest.json") {
|
|
42845
43130
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
42846
43131
|
await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -42933,7 +43218,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
42933
43218
|
);
|
|
42934
43219
|
}
|
|
42935
43220
|
}
|
|
42936
|
-
const manifestPath =
|
|
43221
|
+
const manifestPath = import_node_path37.default.join(root, extId, "manifest.json");
|
|
42937
43222
|
const manifest = await readManifest(root, extId);
|
|
42938
43223
|
const next = { ...manifest, version: newVersion };
|
|
42939
43224
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -42941,7 +43226,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
42941
43226
|
await import_promises7.default.rename(tmp, manifestPath);
|
|
42942
43227
|
}
|
|
42943
43228
|
async function readManifest(root, extId) {
|
|
42944
|
-
const file =
|
|
43229
|
+
const file = import_node_path37.default.join(root, extId, "manifest.json");
|
|
42945
43230
|
let raw;
|
|
42946
43231
|
try {
|
|
42947
43232
|
raw = await import_promises7.default.readFile(file, "utf8");
|
|
@@ -43032,7 +43317,7 @@ function buildExtensionHandlers(deps) {
|
|
|
43032
43317
|
};
|
|
43033
43318
|
async function buildSnapshotMeta(extId) {
|
|
43034
43319
|
const manifest = await readManifest(deps.root, extId);
|
|
43035
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
43320
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path37.default.join(deps.root, extId));
|
|
43036
43321
|
return { manifest, contentHash: sha256, buffer };
|
|
43037
43322
|
}
|
|
43038
43323
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -43328,8 +43613,8 @@ var PublishJobRegistry = class {
|
|
|
43328
43613
|
|
|
43329
43614
|
// src/app-builder/publish-job-runner.ts
|
|
43330
43615
|
var import_node_child_process12 = require("child_process");
|
|
43331
|
-
var
|
|
43332
|
-
var
|
|
43616
|
+
var import_node_fs31 = require("fs");
|
|
43617
|
+
var import_node_path38 = require("path");
|
|
43333
43618
|
|
|
43334
43619
|
// src/app-builder/publish-stage-parser.ts
|
|
43335
43620
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -43361,10 +43646,10 @@ async function startPublishJob(deps, args) {
|
|
|
43361
43646
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
43362
43647
|
}
|
|
43363
43648
|
const projDir = projectDir(args.name);
|
|
43364
|
-
const logPath = (0,
|
|
43649
|
+
const logPath = (0, import_node_path38.join)(projDir, ".publish.log");
|
|
43365
43650
|
let logStream = null;
|
|
43366
43651
|
try {
|
|
43367
|
-
logStream = (0,
|
|
43652
|
+
logStream = (0, import_node_fs31.createWriteStream)(logPath, { flags: "w" });
|
|
43368
43653
|
} catch {
|
|
43369
43654
|
logStream = null;
|
|
43370
43655
|
}
|
|
@@ -43621,8 +43906,8 @@ async function recoverInterruptedJobs(deps) {
|
|
|
43621
43906
|
|
|
43622
43907
|
// src/handlers/app-builder.ts
|
|
43623
43908
|
init_protocol();
|
|
43624
|
-
var
|
|
43625
|
-
var
|
|
43909
|
+
var import_node_path39 = require("path");
|
|
43910
|
+
var import_node_fs32 = require("fs");
|
|
43626
43911
|
var APP_BUILDER_PERSONAS = ["persona-app-builder"];
|
|
43627
43912
|
var PUBLISH_SCRIPT_REL = "extension-kit/scripts/publish.sh";
|
|
43628
43913
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
@@ -43704,7 +43989,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
43704
43989
|
async function listAllUsersProjects() {
|
|
43705
43990
|
if (!deps.usersRoot || !deps.getStore) return [];
|
|
43706
43991
|
const getStore = deps.getStore;
|
|
43707
|
-
const userIds = await
|
|
43992
|
+
const userIds = await import_node_fs32.promises.readdir(deps.usersRoot).catch(() => []);
|
|
43708
43993
|
const perUser = await Promise.all(
|
|
43709
43994
|
userIds.map((uid) => getStore(uid).list().catch(() => []))
|
|
43710
43995
|
);
|
|
@@ -43998,7 +44283,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
43998
44283
|
});
|
|
43999
44284
|
await userStore.clearPublishJob(args.name);
|
|
44000
44285
|
}
|
|
44001
|
-
const scriptPath = (0,
|
|
44286
|
+
const scriptPath = (0, import_node_path39.join)(deps.personaRoot, PUBLISH_SCRIPT_REL);
|
|
44002
44287
|
deps.logger?.info("app-builder.publish.start", {
|
|
44003
44288
|
name: args.name,
|
|
44004
44289
|
sessionId: boundSession.sessionId,
|
|
@@ -44092,7 +44377,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
44092
44377
|
|
|
44093
44378
|
// src/extension/registry.ts
|
|
44094
44379
|
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
44095
|
-
var
|
|
44380
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
44096
44381
|
async function loadAll(root) {
|
|
44097
44382
|
let entries;
|
|
44098
44383
|
try {
|
|
@@ -44105,13 +44390,13 @@ async function loadAll(root) {
|
|
|
44105
44390
|
for (const ent of entries) {
|
|
44106
44391
|
if (!ent.isDirectory()) continue;
|
|
44107
44392
|
if (ent.name.startsWith(".")) continue;
|
|
44108
|
-
records.push(await loadOne(
|
|
44393
|
+
records.push(await loadOne(import_node_path40.default.join(root, ent.name), ent.name));
|
|
44109
44394
|
}
|
|
44110
44395
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
44111
44396
|
return records;
|
|
44112
44397
|
}
|
|
44113
44398
|
async function loadOne(dir, dirName) {
|
|
44114
|
-
const manifestPath =
|
|
44399
|
+
const manifestPath = import_node_path40.default.join(dir, "manifest.json");
|
|
44115
44400
|
let raw;
|
|
44116
44401
|
try {
|
|
44117
44402
|
raw = await import_promises8.default.readFile(manifestPath, "utf8");
|
|
@@ -44156,7 +44441,7 @@ async function loadOne(dir, dirName) {
|
|
|
44156
44441
|
|
|
44157
44442
|
// src/extension/uninstall.ts
|
|
44158
44443
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
44159
|
-
var
|
|
44444
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
44160
44445
|
var UninstallError = class extends Error {
|
|
44161
44446
|
constructor(code, message) {
|
|
44162
44447
|
super(message);
|
|
@@ -44165,7 +44450,7 @@ var UninstallError = class extends Error {
|
|
|
44165
44450
|
code;
|
|
44166
44451
|
};
|
|
44167
44452
|
async function uninstall(deps) {
|
|
44168
|
-
const dir =
|
|
44453
|
+
const dir = import_node_path41.default.join(deps.root, deps.extId);
|
|
44169
44454
|
try {
|
|
44170
44455
|
await import_promises9.default.access(dir);
|
|
44171
44456
|
} catch {
|
|
@@ -44244,9 +44529,9 @@ function buildMethodHandlers(deps) {
|
|
|
44244
44529
|
}
|
|
44245
44530
|
|
|
44246
44531
|
// src/app-builder/project-store.ts
|
|
44247
|
-
var
|
|
44532
|
+
var import_node_fs33 = require("fs");
|
|
44248
44533
|
var import_node_child_process13 = require("child_process");
|
|
44249
|
-
var
|
|
44534
|
+
var import_node_path42 = require("path");
|
|
44250
44535
|
init_protocol();
|
|
44251
44536
|
var PROJECTS_DIR = "projects";
|
|
44252
44537
|
var META_FILE = ".clawd-project.json";
|
|
@@ -44261,19 +44546,19 @@ var ProjectStore = class {
|
|
|
44261
44546
|
root;
|
|
44262
44547
|
/** projects/<name>/.clawd-project.json 路径 */
|
|
44263
44548
|
metaPath(name) {
|
|
44264
|
-
return (0,
|
|
44549
|
+
return (0, import_node_path42.join)(this.projectsRoot(), name, META_FILE);
|
|
44265
44550
|
}
|
|
44266
44551
|
/** projects/<name>/ 目录路径(cwd 用) */
|
|
44267
44552
|
projectDir(name) {
|
|
44268
|
-
return (0,
|
|
44553
|
+
return (0, import_node_path42.join)(this.projectsRoot(), name);
|
|
44269
44554
|
}
|
|
44270
44555
|
projectsRoot() {
|
|
44271
|
-
return (0,
|
|
44556
|
+
return (0, import_node_path42.join)(this.root, PROJECTS_DIR);
|
|
44272
44557
|
}
|
|
44273
44558
|
async list() {
|
|
44274
44559
|
let entries;
|
|
44275
44560
|
try {
|
|
44276
|
-
entries = await
|
|
44561
|
+
entries = await import_node_fs33.promises.readdir(this.projectsRoot());
|
|
44277
44562
|
} catch (err) {
|
|
44278
44563
|
if (err.code === "ENOENT") return [];
|
|
44279
44564
|
throw err;
|
|
@@ -44281,7 +44566,7 @@ var ProjectStore = class {
|
|
|
44281
44566
|
const out = [];
|
|
44282
44567
|
for (const name of entries) {
|
|
44283
44568
|
try {
|
|
44284
|
-
const raw = await
|
|
44569
|
+
const raw = await import_node_fs33.promises.readFile(this.metaPath(name), "utf8");
|
|
44285
44570
|
const json = JSON.parse(raw);
|
|
44286
44571
|
let migrated = false;
|
|
44287
44572
|
if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
|
|
@@ -44292,7 +44577,7 @@ var ProjectStore = class {
|
|
|
44292
44577
|
if (parsed.success) {
|
|
44293
44578
|
out.push(parsed.data);
|
|
44294
44579
|
if (migrated) {
|
|
44295
|
-
void
|
|
44580
|
+
void import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
|
|
44296
44581
|
});
|
|
44297
44582
|
}
|
|
44298
44583
|
}
|
|
@@ -44336,8 +44621,8 @@ var ProjectStore = class {
|
|
|
44336
44621
|
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
44337
44622
|
}
|
|
44338
44623
|
const dir = this.projectDir(name);
|
|
44339
|
-
await
|
|
44340
|
-
await
|
|
44624
|
+
await import_node_fs33.promises.mkdir(dir, { recursive: true });
|
|
44625
|
+
await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
44341
44626
|
return meta;
|
|
44342
44627
|
}
|
|
44343
44628
|
/**
|
|
@@ -44349,7 +44634,7 @@ var ProjectStore = class {
|
|
|
44349
44634
|
* 代码再参考"。assistant 进 project 时目录已是完整模板,直接 pnpm install 即可。
|
|
44350
44635
|
*/
|
|
44351
44636
|
async scaffold(name, template = DEFAULT_TEMPLATE, personaRoot = this.root) {
|
|
44352
|
-
const scriptPath = (0,
|
|
44637
|
+
const scriptPath = (0, import_node_path42.join)(personaRoot, SCAFFOLD_SCRIPT_REL);
|
|
44353
44638
|
const destDir = this.projectDir(name);
|
|
44354
44639
|
return await new Promise((resolve6, reject) => {
|
|
44355
44640
|
const child = (0, import_node_child_process13.spawn)("bash", [scriptPath, name, template, destDir], {
|
|
@@ -44382,7 +44667,7 @@ var ProjectStore = class {
|
|
|
44382
44667
|
}
|
|
44383
44668
|
async delete(name) {
|
|
44384
44669
|
const dir = this.projectDir(name);
|
|
44385
|
-
await
|
|
44670
|
+
await import_node_fs33.promises.rm(dir, { recursive: true, force: true });
|
|
44386
44671
|
}
|
|
44387
44672
|
async updatePort(name, newPort) {
|
|
44388
44673
|
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
@@ -44398,7 +44683,7 @@ var ProjectStore = class {
|
|
|
44398
44683
|
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
44399
44684
|
}
|
|
44400
44685
|
const updated = { ...target, port: newPort };
|
|
44401
|
-
await
|
|
44686
|
+
await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
44402
44687
|
return updated;
|
|
44403
44688
|
}
|
|
44404
44689
|
/**
|
|
@@ -44415,7 +44700,7 @@ var ProjectStore = class {
|
|
|
44415
44700
|
if (!validated.success) {
|
|
44416
44701
|
throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
|
|
44417
44702
|
}
|
|
44418
|
-
await
|
|
44703
|
+
await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
44419
44704
|
return validated.data;
|
|
44420
44705
|
}
|
|
44421
44706
|
/**
|
|
@@ -44436,7 +44721,7 @@ var ProjectStore = class {
|
|
|
44436
44721
|
if (!validated.success) {
|
|
44437
44722
|
throw new Error(`invalid publishJob: ${validated.error.message}`);
|
|
44438
44723
|
}
|
|
44439
|
-
await
|
|
44724
|
+
await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
44440
44725
|
return validated.data;
|
|
44441
44726
|
}
|
|
44442
44727
|
/** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
|
|
@@ -44451,7 +44736,7 @@ var ProjectStore = class {
|
|
|
44451
44736
|
if (!validated.success) {
|
|
44452
44737
|
throw new Error(`failed to clear publishJob: ${validated.error.message}`);
|
|
44453
44738
|
}
|
|
44454
|
-
await
|
|
44739
|
+
await import_node_fs33.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
44455
44740
|
return validated.data;
|
|
44456
44741
|
}
|
|
44457
44742
|
};
|
|
@@ -44887,7 +45172,7 @@ function computeGrantForFrame(method, frame) {
|
|
|
44887
45172
|
|
|
44888
45173
|
// src/extension/runtime.ts
|
|
44889
45174
|
var import_node_child_process15 = require("child_process");
|
|
44890
|
-
var
|
|
45175
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
44891
45176
|
var import_promises10 = require("timers/promises");
|
|
44892
45177
|
|
|
44893
45178
|
// src/extension/port-allocator.ts
|
|
@@ -44988,7 +45273,7 @@ var Runtime = class {
|
|
|
44988
45273
|
/\$CLAWOS_EXT_PORT/g,
|
|
44989
45274
|
String(port)
|
|
44990
45275
|
);
|
|
44991
|
-
const dir =
|
|
45276
|
+
const dir = import_node_path43.default.join(this.root, extId);
|
|
44992
45277
|
const env = {
|
|
44993
45278
|
...process.env,
|
|
44994
45279
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -45100,7 +45385,7 @@ ${handle.stderrTail}`
|
|
|
45100
45385
|
|
|
45101
45386
|
// src/extension/published-channels.ts
|
|
45102
45387
|
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
45103
|
-
var
|
|
45388
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
45104
45389
|
init_zod();
|
|
45105
45390
|
var PublishedChannelsError = class extends Error {
|
|
45106
45391
|
constructor(code, message) {
|
|
@@ -45199,7 +45484,7 @@ var PublishedChannelStore = class {
|
|
|
45199
45484
|
)
|
|
45200
45485
|
};
|
|
45201
45486
|
const tmp = `${this.filePath}.tmp`;
|
|
45202
|
-
await import_promises11.default.mkdir(
|
|
45487
|
+
await import_promises11.default.mkdir(import_node_path44.default.dirname(this.filePath), { recursive: true });
|
|
45203
45488
|
await import_promises11.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
45204
45489
|
await import_promises11.default.rename(tmp, this.filePath);
|
|
45205
45490
|
}
|
|
@@ -45207,7 +45492,7 @@ var PublishedChannelStore = class {
|
|
|
45207
45492
|
|
|
45208
45493
|
// src/extension/bundle-cache.ts
|
|
45209
45494
|
var import_promises12 = __toESM(require("fs/promises"), 1);
|
|
45210
|
-
var
|
|
45495
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
45211
45496
|
var BundleCache = class {
|
|
45212
45497
|
constructor(rootDir) {
|
|
45213
45498
|
this.rootDir = rootDir;
|
|
@@ -45216,14 +45501,14 @@ var BundleCache = class {
|
|
|
45216
45501
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
45217
45502
|
async write(snapshotHash, buffer) {
|
|
45218
45503
|
await import_promises12.default.mkdir(this.rootDir, { recursive: true });
|
|
45219
|
-
const file =
|
|
45504
|
+
const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
45220
45505
|
const tmp = `${file}.tmp`;
|
|
45221
45506
|
await import_promises12.default.writeFile(tmp, buffer, { mode: 384 });
|
|
45222
45507
|
await import_promises12.default.rename(tmp, file);
|
|
45223
45508
|
}
|
|
45224
45509
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
45225
45510
|
async read(snapshotHash) {
|
|
45226
|
-
const file =
|
|
45511
|
+
const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
45227
45512
|
try {
|
|
45228
45513
|
return await import_promises12.default.readFile(file);
|
|
45229
45514
|
} catch (e) {
|
|
@@ -45233,16 +45518,17 @@ var BundleCache = class {
|
|
|
45233
45518
|
}
|
|
45234
45519
|
/** Idempotent — missing file is not an error. */
|
|
45235
45520
|
async delete(snapshotHash) {
|
|
45236
|
-
const file =
|
|
45521
|
+
const file = import_node_path45.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
45237
45522
|
await import_promises12.default.rm(file, { force: true });
|
|
45238
45523
|
}
|
|
45239
45524
|
};
|
|
45240
45525
|
|
|
45241
45526
|
// src/index.ts
|
|
45527
|
+
var import_meta4 = {};
|
|
45242
45528
|
async function startDaemon(config) {
|
|
45243
45529
|
const logger = createLogger({
|
|
45244
45530
|
level: config.logLevel,
|
|
45245
|
-
file:
|
|
45531
|
+
file: import_node_path46.default.join(config.dataDir, "clawd.log")
|
|
45246
45532
|
});
|
|
45247
45533
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
45248
45534
|
const stateMgr = new StateFileManager({ dataDir: config.dataDir });
|
|
@@ -45378,8 +45664,8 @@ async function startDaemon(config) {
|
|
|
45378
45664
|
const agents = new AgentsScanner();
|
|
45379
45665
|
const history = new ClaudeHistoryReader();
|
|
45380
45666
|
let transport = null;
|
|
45381
|
-
const personaStore = new PersonaStore(
|
|
45382
|
-
const usersRoot =
|
|
45667
|
+
const personaStore = new PersonaStore(import_node_path46.default.join(config.dataDir, "personas"));
|
|
45668
|
+
const usersRoot = import_node_path46.default.join(config.dataDir, "users");
|
|
45383
45669
|
const defaultsRoot = findDefaultsRoot();
|
|
45384
45670
|
if (defaultsRoot) {
|
|
45385
45671
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -45390,6 +45676,33 @@ async function startDaemon(config) {
|
|
|
45390
45676
|
migrateAgentsMirror({ store: personaStore, logger });
|
|
45391
45677
|
migrateCodexSandbox({ store: personaStore, logger });
|
|
45392
45678
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
45679
|
+
const personaDispatchManager = new PersonaDispatchManager({ genId: () => v4_default() });
|
|
45680
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path46.default.dirname((0, import_node_url2.fileURLToPath)(import_meta4.url));
|
|
45681
|
+
const dispatchServerCandidates = [
|
|
45682
|
+
import_node_path46.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
45683
|
+
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
45684
|
+
import_node_path46.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
45685
|
+
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
45686
|
+
];
|
|
45687
|
+
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs34.default.existsSync(p2));
|
|
45688
|
+
let dispatchMcpConfigPath2;
|
|
45689
|
+
if (dispatchServerScriptPath) {
|
|
45690
|
+
const dispatchLogPath = import_node_path46.default.join(config.dataDir, "dispatch-mcp-server.log");
|
|
45691
|
+
dispatchMcpConfigPath2 = writeDispatchMcpConfig({
|
|
45692
|
+
dataDir: config.dataDir,
|
|
45693
|
+
serverScriptPath: dispatchServerScriptPath,
|
|
45694
|
+
logPath: dispatchLogPath
|
|
45695
|
+
});
|
|
45696
|
+
logger.info("dispatch.mcp.json written", {
|
|
45697
|
+
path: dispatchMcpConfigPath2,
|
|
45698
|
+
server: dispatchServerScriptPath,
|
|
45699
|
+
serverLog: dispatchLogPath
|
|
45700
|
+
});
|
|
45701
|
+
} else {
|
|
45702
|
+
logger.warn("dispatch-mcp-server.cjs not found; persona dispatch disabled (dev tsx \u6A21\u5F0F\u4E0B\u9700\u5148\u8DD1\u8FC7 build)", {
|
|
45703
|
+
tried: dispatchServerCandidates
|
|
45704
|
+
});
|
|
45705
|
+
}
|
|
45393
45706
|
const manager = new SessionManager({
|
|
45394
45707
|
store,
|
|
45395
45708
|
// Phase 2 (capability platform plan §1): factory 注入后 manager.storeFor 走
|
|
@@ -45399,7 +45712,7 @@ async function startDaemon(config) {
|
|
|
45399
45712
|
getAdapter,
|
|
45400
45713
|
historyReader: history,
|
|
45401
45714
|
dataDir: config.dataDir,
|
|
45402
|
-
personaRoot:
|
|
45715
|
+
personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
|
|
45403
45716
|
usersRoot,
|
|
45404
45717
|
personaStore,
|
|
45405
45718
|
ownerDisplayName,
|
|
@@ -45410,6 +45723,12 @@ async function startDaemon(config) {
|
|
|
45410
45723
|
// 127.0.0.1(不是 config.host)—— cc 跑在本机,loopback 最稳;外部访问限制 + http-router
|
|
45411
45724
|
// 的 isLoopback 兜底已确保安全。
|
|
45412
45725
|
getDaemonUrl: () => `http://127.0.0.1:${config.port}`,
|
|
45726
|
+
// Persona dispatch (Task 8): manager 通过这两个 deps 跟 PersonaDispatchManager 协作。
|
|
45727
|
+
// - personaDispatchManager: manager.createDispatchedSession 用它 registerBSession;
|
|
45728
|
+
// reducer 通过闭包反查 dispatchId 注 CLAWD_DISPATCH_ID env。
|
|
45729
|
+
// - dispatchMcpConfigPath: reducer 透传到 SpawnContext,cc spawn 加 --mcp-config flag。
|
|
45730
|
+
personaDispatchManager,
|
|
45731
|
+
dispatchMcpConfigPath: dispatchMcpConfigPath2,
|
|
45413
45732
|
broadcastFrame: (frame, target) => {
|
|
45414
45733
|
if (target === "all") {
|
|
45415
45734
|
transport?.broadcastAll(frame);
|
|
@@ -45429,10 +45748,10 @@ async function startDaemon(config) {
|
|
|
45429
45748
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
45430
45749
|
attachmentGroup: {
|
|
45431
45750
|
onFileEdit: (input) => {
|
|
45432
|
-
const absPath =
|
|
45751
|
+
const absPath = import_node_path46.default.isAbsolute(input.relPath) ? input.relPath : import_node_path46.default.join(input.cwd, input.relPath);
|
|
45433
45752
|
let size = 0;
|
|
45434
45753
|
try {
|
|
45435
|
-
size =
|
|
45754
|
+
size = import_node_fs34.default.statSync(absPath).size;
|
|
45436
45755
|
} catch (err) {
|
|
45437
45756
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
45438
45757
|
sessionId: input.sessionId,
|
|
@@ -45618,11 +45937,11 @@ async function startDaemon(config) {
|
|
|
45618
45937
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
45619
45938
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
45620
45939
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
45621
|
-
personaRoot:
|
|
45940
|
+
personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
|
|
45622
45941
|
usersRoot
|
|
45623
45942
|
},
|
|
45624
45943
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
45625
|
-
personaRoot:
|
|
45944
|
+
personaRoot: import_node_path46.default.join(config.dataDir, "personas"),
|
|
45626
45945
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
45627
45946
|
usersRoot,
|
|
45628
45947
|
// capability:list / delete handler 依赖
|
|
@@ -45711,7 +46030,7 @@ async function startDaemon(config) {
|
|
|
45711
46030
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
45712
46031
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
45713
46032
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
45714
|
-
appBuilderPersonaRoot:
|
|
46033
|
+
appBuilderPersonaRoot: import_node_path46.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
45715
46034
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
45716
46035
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
45717
46036
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -45732,6 +46051,41 @@ async function startDaemon(config) {
|
|
|
45732
46051
|
logger
|
|
45733
46052
|
});
|
|
45734
46053
|
let handlers = makeHandlers();
|
|
46054
|
+
const dispatchHandlers = buildPersonaDispatchHandlers({
|
|
46055
|
+
personaDispatchManager,
|
|
46056
|
+
logger,
|
|
46057
|
+
spawnB: async (args) => {
|
|
46058
|
+
logger.info("dispatch.spawnB.start", {
|
|
46059
|
+
dispatchId: args.dispatchId,
|
|
46060
|
+
targetPersona: args.targetPersona,
|
|
46061
|
+
sourceSessionId: args.sourceSessionId
|
|
46062
|
+
});
|
|
46063
|
+
const sourceFile = manager.findOwnedSession(args.sourceSessionId);
|
|
46064
|
+
if (!sourceFile) {
|
|
46065
|
+
throw new Error(`personaDispatch:run source session not found: ${args.sourceSessionId}`);
|
|
46066
|
+
}
|
|
46067
|
+
const sourceJsonlPath = sourceFile.toolSessionId ? import_node_path46.default.join(
|
|
46068
|
+
import_node_os19.default.homedir(),
|
|
46069
|
+
".claude",
|
|
46070
|
+
"projects",
|
|
46071
|
+
cwdToHashDir(sourceFile.cwd),
|
|
46072
|
+
`${sourceFile.toolSessionId}.jsonl`
|
|
46073
|
+
) : "(no transcript yet \u2014 operate from the task description alone)";
|
|
46074
|
+
logger.info("dispatch.spawnB.source-resolved", {
|
|
46075
|
+
dispatchId: args.dispatchId,
|
|
46076
|
+
sourceJsonlPath,
|
|
46077
|
+
hasToolSessionId: Boolean(sourceFile.toolSessionId)
|
|
46078
|
+
});
|
|
46079
|
+
manager.createDispatchedSession({
|
|
46080
|
+
dispatchId: args.dispatchId,
|
|
46081
|
+
sourceSessionId: args.sourceSessionId,
|
|
46082
|
+
targetPersona: args.targetPersona,
|
|
46083
|
+
prompt: args.prompt,
|
|
46084
|
+
sourceJsonlPath
|
|
46085
|
+
});
|
|
46086
|
+
}
|
|
46087
|
+
});
|
|
46088
|
+
handlers = { ...handlers, ...dispatchHandlers };
|
|
45735
46089
|
const authResolver = new AuthContextResolver({
|
|
45736
46090
|
ownerToken: resolvedAuthToken
|
|
45737
46091
|
});
|
|
@@ -45960,8 +46314,8 @@ async function startDaemon(config) {
|
|
|
45960
46314
|
const lines = [
|
|
45961
46315
|
`Tunnel: ${r.url}`,
|
|
45962
46316
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
45963
|
-
`Frpc config: ${
|
|
45964
|
-
`Frpc log: ${
|
|
46317
|
+
`Frpc config: ${import_node_path46.default.join(config.dataDir, "frpc.toml")}`,
|
|
46318
|
+
`Frpc log: ${import_node_path46.default.join(config.dataDir, "frpc.log")}`
|
|
45965
46319
|
];
|
|
45966
46320
|
const width = Math.max(...lines.map((l) => l.length));
|
|
45967
46321
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -45974,8 +46328,8 @@ ${bar}
|
|
|
45974
46328
|
|
|
45975
46329
|
`);
|
|
45976
46330
|
try {
|
|
45977
|
-
const connectPath =
|
|
45978
|
-
|
|
46331
|
+
const connectPath = import_node_path46.default.join(config.dataDir, "connect.txt");
|
|
46332
|
+
import_node_fs34.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
45979
46333
|
} catch {
|
|
45980
46334
|
}
|
|
45981
46335
|
} catch (err) {
|
|
@@ -46046,9 +46400,9 @@ ${bar}
|
|
|
46046
46400
|
};
|
|
46047
46401
|
}
|
|
46048
46402
|
function migrateDropPersonsDir(dataDir) {
|
|
46049
|
-
const dir =
|
|
46403
|
+
const dir = import_node_path46.default.join(dataDir, "persons");
|
|
46050
46404
|
try {
|
|
46051
|
-
|
|
46405
|
+
import_node_fs34.default.rmSync(dir, { recursive: true, force: true });
|
|
46052
46406
|
} catch {
|
|
46053
46407
|
}
|
|
46054
46408
|
}
|