@clawos-dev/clawd 0.2.247 → 0.2.248
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 +768 -493
- package/dist/dispatch/mcp-server.cjs +85 -18443
- package/dist/share-ui/assets/{guest-CPSTbS2R.js → guest-DeJiT1im.js} +125 -125
- package/dist/share-ui/guest.html +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -751,8 +751,8 @@ var init_parseUtil = __esm({
|
|
|
751
751
|
init_errors2();
|
|
752
752
|
init_en();
|
|
753
753
|
makeIssue = (params) => {
|
|
754
|
-
const { data, path:
|
|
755
|
-
const fullPath = [...
|
|
754
|
+
const { data, path: path71, errorMaps, issueData } = params;
|
|
755
|
+
const fullPath = [...path71, ...issueData.path || []];
|
|
756
756
|
const fullIssue = {
|
|
757
757
|
...issueData,
|
|
758
758
|
path: fullPath
|
|
@@ -1063,11 +1063,11 @@ var init_types = __esm({
|
|
|
1063
1063
|
init_parseUtil();
|
|
1064
1064
|
init_util();
|
|
1065
1065
|
ParseInputLazyPath = class {
|
|
1066
|
-
constructor(parent, value,
|
|
1066
|
+
constructor(parent, value, path71, key) {
|
|
1067
1067
|
this._cachedPath = [];
|
|
1068
1068
|
this.parent = parent;
|
|
1069
1069
|
this.data = value;
|
|
1070
|
-
this._path =
|
|
1070
|
+
this._path = path71;
|
|
1071
1071
|
this._key = key;
|
|
1072
1072
|
}
|
|
1073
1073
|
get path() {
|
|
@@ -6187,7 +6187,7 @@ var init_feishu_auth = __esm({
|
|
|
6187
6187
|
});
|
|
6188
6188
|
|
|
6189
6189
|
// ../protocol/src/dispatch.ts
|
|
6190
|
-
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema;
|
|
6190
|
+
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema, DISPATCH_STATUSES, DispatchStatusSchema, DispatchRecordSchema, DispatchListArgsSchema, DispatchListResultSchema;
|
|
6191
6191
|
var init_dispatch = __esm({
|
|
6192
6192
|
"../protocol/src/dispatch.ts"() {
|
|
6193
6193
|
"use strict";
|
|
@@ -6219,6 +6219,32 @@ var init_dispatch = __esm({
|
|
|
6219
6219
|
dispatchId: external_exports.string().min(1),
|
|
6220
6220
|
outcome: DispatchOutcomeSchema
|
|
6221
6221
|
});
|
|
6222
|
+
DISPATCH_STATUSES = ["running", "completed", "failed"];
|
|
6223
|
+
DispatchStatusSchema = external_exports.enum(DISPATCH_STATUSES);
|
|
6224
|
+
DispatchRecordSchema = external_exports.object({
|
|
6225
|
+
dispatchId: external_exports.string().min(1),
|
|
6226
|
+
sourceSessionId: external_exports.string().min(1),
|
|
6227
|
+
sourcePersonaId: external_exports.string().min(1).optional(),
|
|
6228
|
+
targetPersonaId: external_exports.string().min(1),
|
|
6229
|
+
/** B 的 sessionId;registerBSession 后回填 */
|
|
6230
|
+
workerSessionId: external_exports.string().min(1).optional(),
|
|
6231
|
+
/** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
|
|
6232
|
+
taskText: external_exports.string(),
|
|
6233
|
+
status: DispatchStatusSchema,
|
|
6234
|
+
outcome: DispatchOutcomeSchema.optional(),
|
|
6235
|
+
/** 上层消费者语义(如司礼监的口谕/验收状态),daemon 不解释 */
|
|
6236
|
+
meta: external_exports.record(external_exports.unknown()).optional(),
|
|
6237
|
+
createdAt: external_exports.string().min(1),
|
|
6238
|
+
completedAt: external_exports.string().min(1).optional(),
|
|
6239
|
+
/** 结果注入 source session 成功时戳,兼当投递 dedup 标记 */
|
|
6240
|
+
deliveredAt: external_exports.string().min(1).optional()
|
|
6241
|
+
});
|
|
6242
|
+
DispatchListArgsSchema = external_exports.object({
|
|
6243
|
+
sourceSessionId: external_exports.string().min(1).optional()
|
|
6244
|
+
});
|
|
6245
|
+
DispatchListResultSchema = external_exports.object({
|
|
6246
|
+
records: external_exports.array(DispatchRecordSchema)
|
|
6247
|
+
});
|
|
6222
6248
|
}
|
|
6223
6249
|
});
|
|
6224
6250
|
|
|
@@ -6571,8 +6597,8 @@ var require_req = __commonJS({
|
|
|
6571
6597
|
if (req.originalUrl) {
|
|
6572
6598
|
_req.url = req.originalUrl;
|
|
6573
6599
|
} else {
|
|
6574
|
-
const
|
|
6575
|
-
_req.url = typeof
|
|
6600
|
+
const path71 = req.path;
|
|
6601
|
+
_req.url = typeof path71 === "string" ? path71 : req.url ? req.url.path || req.url : void 0;
|
|
6576
6602
|
}
|
|
6577
6603
|
if (req.query) {
|
|
6578
6604
|
_req.query = req.query;
|
|
@@ -6737,14 +6763,14 @@ var require_redact = __commonJS({
|
|
|
6737
6763
|
}
|
|
6738
6764
|
return obj;
|
|
6739
6765
|
}
|
|
6740
|
-
function parsePath(
|
|
6766
|
+
function parsePath(path71) {
|
|
6741
6767
|
const parts = [];
|
|
6742
6768
|
let current = "";
|
|
6743
6769
|
let inBrackets = false;
|
|
6744
6770
|
let inQuotes = false;
|
|
6745
6771
|
let quoteChar = "";
|
|
6746
|
-
for (let i = 0; i <
|
|
6747
|
-
const char =
|
|
6772
|
+
for (let i = 0; i < path71.length; i++) {
|
|
6773
|
+
const char = path71[i];
|
|
6748
6774
|
if (!inBrackets && char === ".") {
|
|
6749
6775
|
if (current) {
|
|
6750
6776
|
parts.push(current);
|
|
@@ -6875,10 +6901,10 @@ var require_redact = __commonJS({
|
|
|
6875
6901
|
return current;
|
|
6876
6902
|
}
|
|
6877
6903
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
6878
|
-
for (const
|
|
6879
|
-
const parts = parsePath(
|
|
6904
|
+
for (const path71 of paths) {
|
|
6905
|
+
const parts = parsePath(path71);
|
|
6880
6906
|
if (parts.includes("*")) {
|
|
6881
|
-
redactWildcardPath(obj, parts, censor,
|
|
6907
|
+
redactWildcardPath(obj, parts, censor, path71, remove);
|
|
6882
6908
|
} else {
|
|
6883
6909
|
if (remove) {
|
|
6884
6910
|
removeKey(obj, parts);
|
|
@@ -6963,8 +6989,8 @@ var require_redact = __commonJS({
|
|
|
6963
6989
|
}
|
|
6964
6990
|
} else {
|
|
6965
6991
|
if (afterWildcard.includes("*")) {
|
|
6966
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6967
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
6992
|
+
const wrappedCensor = typeof censor === "function" ? (value, path71) => {
|
|
6993
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path71];
|
|
6968
6994
|
return censor(value, fullPath);
|
|
6969
6995
|
} : censor;
|
|
6970
6996
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6999,8 +7025,8 @@ var require_redact = __commonJS({
|
|
|
6999
7025
|
return null;
|
|
7000
7026
|
}
|
|
7001
7027
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
7002
|
-
for (const
|
|
7003
|
-
const parts = parsePath(
|
|
7028
|
+
for (const path71 of pathsToClone) {
|
|
7029
|
+
const parts = parsePath(path71);
|
|
7004
7030
|
let current = pathStructure;
|
|
7005
7031
|
for (let i = 0; i < parts.length; i++) {
|
|
7006
7032
|
const part = parts[i];
|
|
@@ -7052,24 +7078,24 @@ var require_redact = __commonJS({
|
|
|
7052
7078
|
}
|
|
7053
7079
|
return cloneSelectively(obj, pathStructure);
|
|
7054
7080
|
}
|
|
7055
|
-
function validatePath(
|
|
7056
|
-
if (typeof
|
|
7081
|
+
function validatePath(path71) {
|
|
7082
|
+
if (typeof path71 !== "string") {
|
|
7057
7083
|
throw new Error("Paths must be (non-empty) strings");
|
|
7058
7084
|
}
|
|
7059
|
-
if (
|
|
7085
|
+
if (path71 === "") {
|
|
7060
7086
|
throw new Error("Invalid redaction path ()");
|
|
7061
7087
|
}
|
|
7062
|
-
if (
|
|
7063
|
-
throw new Error(`Invalid redaction path (${
|
|
7088
|
+
if (path71.includes("..")) {
|
|
7089
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7064
7090
|
}
|
|
7065
|
-
if (
|
|
7066
|
-
throw new Error(`Invalid redaction path (${
|
|
7091
|
+
if (path71.includes(",")) {
|
|
7092
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7067
7093
|
}
|
|
7068
7094
|
let bracketCount = 0;
|
|
7069
7095
|
let inQuotes = false;
|
|
7070
7096
|
let quoteChar = "";
|
|
7071
|
-
for (let i = 0; i <
|
|
7072
|
-
const char =
|
|
7097
|
+
for (let i = 0; i < path71.length; i++) {
|
|
7098
|
+
const char = path71[i];
|
|
7073
7099
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
7074
7100
|
if (!inQuotes) {
|
|
7075
7101
|
inQuotes = true;
|
|
@@ -7083,20 +7109,20 @@ var require_redact = __commonJS({
|
|
|
7083
7109
|
} else if (char === "]" && !inQuotes) {
|
|
7084
7110
|
bracketCount--;
|
|
7085
7111
|
if (bracketCount < 0) {
|
|
7086
|
-
throw new Error(`Invalid redaction path (${
|
|
7112
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7087
7113
|
}
|
|
7088
7114
|
}
|
|
7089
7115
|
}
|
|
7090
7116
|
if (bracketCount !== 0) {
|
|
7091
|
-
throw new Error(`Invalid redaction path (${
|
|
7117
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7092
7118
|
}
|
|
7093
7119
|
}
|
|
7094
7120
|
function validatePaths(paths) {
|
|
7095
7121
|
if (!Array.isArray(paths)) {
|
|
7096
7122
|
throw new TypeError("paths must be an array");
|
|
7097
7123
|
}
|
|
7098
|
-
for (const
|
|
7099
|
-
validatePath(
|
|
7124
|
+
for (const path71 of paths) {
|
|
7125
|
+
validatePath(path71);
|
|
7100
7126
|
}
|
|
7101
7127
|
}
|
|
7102
7128
|
function slowRedact(options = {}) {
|
|
@@ -7264,8 +7290,8 @@ var require_redaction = __commonJS({
|
|
|
7264
7290
|
if (shape[k2] === null) {
|
|
7265
7291
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
7266
7292
|
} else {
|
|
7267
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
7268
|
-
return censor(value, [k2, ...
|
|
7293
|
+
const wrappedCensor = typeof censor === "function" ? (value, path71) => {
|
|
7294
|
+
return censor(value, [k2, ...path71]);
|
|
7269
7295
|
} : censor;
|
|
7270
7296
|
o[k2] = Redact({
|
|
7271
7297
|
paths: shape[k2],
|
|
@@ -7483,10 +7509,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
7483
7509
|
var require_sonic_boom = __commonJS({
|
|
7484
7510
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
7485
7511
|
"use strict";
|
|
7486
|
-
var
|
|
7512
|
+
var fs65 = require("fs");
|
|
7487
7513
|
var EventEmitter3 = require("events");
|
|
7488
7514
|
var inherits = require("util").inherits;
|
|
7489
|
-
var
|
|
7515
|
+
var path71 = require("path");
|
|
7490
7516
|
var sleep2 = require_atomic_sleep();
|
|
7491
7517
|
var assert = require("assert");
|
|
7492
7518
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -7540,20 +7566,20 @@ var require_sonic_boom = __commonJS({
|
|
|
7540
7566
|
const mode = sonic.mode;
|
|
7541
7567
|
if (sonic.sync) {
|
|
7542
7568
|
try {
|
|
7543
|
-
if (sonic.mkdir)
|
|
7544
|
-
const fd =
|
|
7569
|
+
if (sonic.mkdir) fs65.mkdirSync(path71.dirname(file), { recursive: true });
|
|
7570
|
+
const fd = fs65.openSync(file, flags, mode);
|
|
7545
7571
|
fileOpened(null, fd);
|
|
7546
7572
|
} catch (err) {
|
|
7547
7573
|
fileOpened(err);
|
|
7548
7574
|
throw err;
|
|
7549
7575
|
}
|
|
7550
7576
|
} else if (sonic.mkdir) {
|
|
7551
|
-
|
|
7577
|
+
fs65.mkdir(path71.dirname(file), { recursive: true }, (err) => {
|
|
7552
7578
|
if (err) return fileOpened(err);
|
|
7553
|
-
|
|
7579
|
+
fs65.open(file, flags, mode, fileOpened);
|
|
7554
7580
|
});
|
|
7555
7581
|
} else {
|
|
7556
|
-
|
|
7582
|
+
fs65.open(file, flags, mode, fileOpened);
|
|
7557
7583
|
}
|
|
7558
7584
|
}
|
|
7559
7585
|
function SonicBoom(opts) {
|
|
@@ -7594,8 +7620,8 @@ var require_sonic_boom = __commonJS({
|
|
|
7594
7620
|
this.flush = flushBuffer;
|
|
7595
7621
|
this.flushSync = flushBufferSync;
|
|
7596
7622
|
this._actualWrite = actualWriteBuffer;
|
|
7597
|
-
fsWriteSync = () =>
|
|
7598
|
-
fsWrite = () =>
|
|
7623
|
+
fsWriteSync = () => fs65.writeSync(this.fd, this._writingBuf);
|
|
7624
|
+
fsWrite = () => fs65.write(this.fd, this._writingBuf, this.release);
|
|
7599
7625
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
7600
7626
|
this._writingBuf = "";
|
|
7601
7627
|
this.write = write;
|
|
@@ -7604,15 +7630,15 @@ var require_sonic_boom = __commonJS({
|
|
|
7604
7630
|
this._actualWrite = actualWrite;
|
|
7605
7631
|
fsWriteSync = () => {
|
|
7606
7632
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7607
|
-
return
|
|
7633
|
+
return fs65.writeSync(this.fd, this._writingBuf);
|
|
7608
7634
|
}
|
|
7609
|
-
return
|
|
7635
|
+
return fs65.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7610
7636
|
};
|
|
7611
7637
|
fsWrite = () => {
|
|
7612
7638
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7613
|
-
return
|
|
7639
|
+
return fs65.write(this.fd, this._writingBuf, this.release);
|
|
7614
7640
|
}
|
|
7615
|
-
return
|
|
7641
|
+
return fs65.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
7616
7642
|
};
|
|
7617
7643
|
} else {
|
|
7618
7644
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -7669,7 +7695,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7669
7695
|
}
|
|
7670
7696
|
}
|
|
7671
7697
|
if (this._fsync) {
|
|
7672
|
-
|
|
7698
|
+
fs65.fsyncSync(this.fd);
|
|
7673
7699
|
}
|
|
7674
7700
|
const len = this._len;
|
|
7675
7701
|
if (this._reopening) {
|
|
@@ -7783,7 +7809,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7783
7809
|
const onDrain = () => {
|
|
7784
7810
|
if (!this._fsync) {
|
|
7785
7811
|
try {
|
|
7786
|
-
|
|
7812
|
+
fs65.fsync(this.fd, (err) => {
|
|
7787
7813
|
this._flushPending = false;
|
|
7788
7814
|
cb(err);
|
|
7789
7815
|
});
|
|
@@ -7885,7 +7911,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7885
7911
|
const fd = this.fd;
|
|
7886
7912
|
this.once("ready", () => {
|
|
7887
7913
|
if (fd !== this.fd) {
|
|
7888
|
-
|
|
7914
|
+
fs65.close(fd, (err) => {
|
|
7889
7915
|
if (err) {
|
|
7890
7916
|
return this.emit("error", err);
|
|
7891
7917
|
}
|
|
@@ -7934,7 +7960,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7934
7960
|
buf = this._bufs[0];
|
|
7935
7961
|
}
|
|
7936
7962
|
try {
|
|
7937
|
-
const n = Buffer.isBuffer(buf) ?
|
|
7963
|
+
const n = Buffer.isBuffer(buf) ? fs65.writeSync(this.fd, buf) : fs65.writeSync(this.fd, buf, "utf8");
|
|
7938
7964
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
7939
7965
|
buf = releasedBufObj.writingBuf;
|
|
7940
7966
|
this._len = releasedBufObj.len;
|
|
@@ -7950,7 +7976,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7950
7976
|
}
|
|
7951
7977
|
}
|
|
7952
7978
|
try {
|
|
7953
|
-
|
|
7979
|
+
fs65.fsyncSync(this.fd);
|
|
7954
7980
|
} catch {
|
|
7955
7981
|
}
|
|
7956
7982
|
}
|
|
@@ -7971,7 +7997,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7971
7997
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
7972
7998
|
}
|
|
7973
7999
|
try {
|
|
7974
|
-
const n =
|
|
8000
|
+
const n = fs65.writeSync(this.fd, buf);
|
|
7975
8001
|
buf = buf.subarray(n);
|
|
7976
8002
|
this._len = Math.max(this._len - n, 0);
|
|
7977
8003
|
if (buf.length <= 0) {
|
|
@@ -7999,13 +8025,13 @@ var require_sonic_boom = __commonJS({
|
|
|
7999
8025
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
8000
8026
|
if (this.sync) {
|
|
8001
8027
|
try {
|
|
8002
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
8028
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs65.writeSync(this.fd, this._writingBuf) : fs65.writeSync(this.fd, this._writingBuf, "utf8");
|
|
8003
8029
|
release(null, written);
|
|
8004
8030
|
} catch (err) {
|
|
8005
8031
|
release(err);
|
|
8006
8032
|
}
|
|
8007
8033
|
} else {
|
|
8008
|
-
|
|
8034
|
+
fs65.write(this.fd, this._writingBuf, release);
|
|
8009
8035
|
}
|
|
8010
8036
|
}
|
|
8011
8037
|
function actualWriteBuffer() {
|
|
@@ -8014,7 +8040,7 @@ var require_sonic_boom = __commonJS({
|
|
|
8014
8040
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
8015
8041
|
if (this.sync) {
|
|
8016
8042
|
try {
|
|
8017
|
-
const written =
|
|
8043
|
+
const written = fs65.writeSync(this.fd, this._writingBuf);
|
|
8018
8044
|
release(null, written);
|
|
8019
8045
|
} catch (err) {
|
|
8020
8046
|
release(err);
|
|
@@ -8023,7 +8049,7 @@ var require_sonic_boom = __commonJS({
|
|
|
8023
8049
|
if (kCopyBuffer) {
|
|
8024
8050
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
8025
8051
|
}
|
|
8026
|
-
|
|
8052
|
+
fs65.write(this.fd, this._writingBuf, release);
|
|
8027
8053
|
}
|
|
8028
8054
|
}
|
|
8029
8055
|
function actualClose(sonic) {
|
|
@@ -8039,12 +8065,12 @@ var require_sonic_boom = __commonJS({
|
|
|
8039
8065
|
sonic._lens = [];
|
|
8040
8066
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
8041
8067
|
try {
|
|
8042
|
-
|
|
8068
|
+
fs65.fsync(sonic.fd, closeWrapped);
|
|
8043
8069
|
} catch {
|
|
8044
8070
|
}
|
|
8045
8071
|
function closeWrapped() {
|
|
8046
8072
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
8047
|
-
|
|
8073
|
+
fs65.close(sonic.fd, done);
|
|
8048
8074
|
} else {
|
|
8049
8075
|
done();
|
|
8050
8076
|
}
|
|
@@ -11179,11 +11205,11 @@ var init_lib = __esm({
|
|
|
11179
11205
|
}
|
|
11180
11206
|
}
|
|
11181
11207
|
},
|
|
11182
|
-
addToPath: function addToPath(
|
|
11183
|
-
var last =
|
|
11208
|
+
addToPath: function addToPath(path71, added, removed, oldPosInc, options) {
|
|
11209
|
+
var last = path71.lastComponent;
|
|
11184
11210
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
11185
11211
|
return {
|
|
11186
|
-
oldPos:
|
|
11212
|
+
oldPos: path71.oldPos + oldPosInc,
|
|
11187
11213
|
lastComponent: {
|
|
11188
11214
|
count: last.count + 1,
|
|
11189
11215
|
added,
|
|
@@ -11193,7 +11219,7 @@ var init_lib = __esm({
|
|
|
11193
11219
|
};
|
|
11194
11220
|
} else {
|
|
11195
11221
|
return {
|
|
11196
|
-
oldPos:
|
|
11222
|
+
oldPos: path71.oldPos + oldPosInc,
|
|
11197
11223
|
lastComponent: {
|
|
11198
11224
|
count: 1,
|
|
11199
11225
|
added,
|
|
@@ -11702,10 +11728,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
11702
11728
|
const memories = raw.map((m2) => {
|
|
11703
11729
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11704
11730
|
const rec3 = m2;
|
|
11705
|
-
const
|
|
11731
|
+
const path71 = typeof rec3.path === "string" ? rec3.path : null;
|
|
11706
11732
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
11707
|
-
if (!
|
|
11708
|
-
const entry = { path:
|
|
11733
|
+
if (!path71 || content == null) return null;
|
|
11734
|
+
const entry = { path: path71, content };
|
|
11709
11735
|
if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
|
|
11710
11736
|
return entry;
|
|
11711
11737
|
}).filter((m2) => m2 !== null);
|
|
@@ -12508,10 +12534,10 @@ function parseAttachment(obj) {
|
|
|
12508
12534
|
const memories = raw.map((m2) => {
|
|
12509
12535
|
if (!m2 || typeof m2 !== "object") return null;
|
|
12510
12536
|
const rec3 = m2;
|
|
12511
|
-
const
|
|
12537
|
+
const path71 = typeof rec3.path === "string" ? rec3.path : null;
|
|
12512
12538
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
12513
|
-
if (!
|
|
12514
|
-
const out = { path:
|
|
12539
|
+
if (!path71 || content == null) return null;
|
|
12540
|
+
const out = { path: path71, content };
|
|
12515
12541
|
if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
|
|
12516
12542
|
return out;
|
|
12517
12543
|
}).filter((m2) => m2 !== null);
|
|
@@ -33480,8 +33506,8 @@ var require_utils = __commonJS({
|
|
|
33480
33506
|
var result = transform[inputType][outputType](input);
|
|
33481
33507
|
return result;
|
|
33482
33508
|
};
|
|
33483
|
-
exports2.resolve = function(
|
|
33484
|
-
var parts =
|
|
33509
|
+
exports2.resolve = function(path71) {
|
|
33510
|
+
var parts = path71.split("/");
|
|
33485
33511
|
var result = [];
|
|
33486
33512
|
for (var index = 0; index < parts.length; index++) {
|
|
33487
33513
|
var part = parts[index];
|
|
@@ -39334,18 +39360,18 @@ var require_object = __commonJS({
|
|
|
39334
39360
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
39335
39361
|
this.files[name] = object;
|
|
39336
39362
|
};
|
|
39337
|
-
var parentFolder = function(
|
|
39338
|
-
if (
|
|
39339
|
-
|
|
39363
|
+
var parentFolder = function(path71) {
|
|
39364
|
+
if (path71.slice(-1) === "/") {
|
|
39365
|
+
path71 = path71.substring(0, path71.length - 1);
|
|
39340
39366
|
}
|
|
39341
|
-
var lastSlash =
|
|
39342
|
-
return lastSlash > 0 ?
|
|
39367
|
+
var lastSlash = path71.lastIndexOf("/");
|
|
39368
|
+
return lastSlash > 0 ? path71.substring(0, lastSlash) : "";
|
|
39343
39369
|
};
|
|
39344
|
-
var forceTrailingSlash = function(
|
|
39345
|
-
if (
|
|
39346
|
-
|
|
39370
|
+
var forceTrailingSlash = function(path71) {
|
|
39371
|
+
if (path71.slice(-1) !== "/") {
|
|
39372
|
+
path71 += "/";
|
|
39347
39373
|
}
|
|
39348
|
-
return
|
|
39374
|
+
return path71;
|
|
39349
39375
|
};
|
|
39350
39376
|
var folderAdd = function(name, createFolders) {
|
|
39351
39377
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -40347,7 +40373,7 @@ var require_lib3 = __commonJS({
|
|
|
40347
40373
|
// src/run-case/recorder.ts
|
|
40348
40374
|
function startRunCaseRecorder(opts) {
|
|
40349
40375
|
const now = opts.now ?? Date.now;
|
|
40350
|
-
const dir =
|
|
40376
|
+
const dir = import_node_path59.default.dirname(opts.recordPath);
|
|
40351
40377
|
let stream = null;
|
|
40352
40378
|
let closing = false;
|
|
40353
40379
|
let closedSettled = false;
|
|
@@ -40387,12 +40413,12 @@ function startRunCaseRecorder(opts) {
|
|
|
40387
40413
|
};
|
|
40388
40414
|
return { tap, close, closed };
|
|
40389
40415
|
}
|
|
40390
|
-
var import_node_fs46,
|
|
40416
|
+
var import_node_fs46, import_node_path59;
|
|
40391
40417
|
var init_recorder = __esm({
|
|
40392
40418
|
"src/run-case/recorder.ts"() {
|
|
40393
40419
|
"use strict";
|
|
40394
40420
|
import_node_fs46 = __toESM(require("fs"), 1);
|
|
40395
|
-
|
|
40421
|
+
import_node_path59 = __toESM(require("path"), 1);
|
|
40396
40422
|
}
|
|
40397
40423
|
});
|
|
40398
40424
|
|
|
@@ -40435,7 +40461,7 @@ var init_wire = __esm({
|
|
|
40435
40461
|
// src/run-case/controller.ts
|
|
40436
40462
|
async function runController(opts) {
|
|
40437
40463
|
const now = opts.now ?? Date.now;
|
|
40438
|
-
const cwd = opts.cwd ?? (0, import_node_fs47.mkdtempSync)(
|
|
40464
|
+
const cwd = opts.cwd ?? (0, import_node_fs47.mkdtempSync)(import_node_path60.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
|
|
40439
40465
|
const ownsCwd = opts.cwd === void 0;
|
|
40440
40466
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
40441
40467
|
const spawnCtx = { cwd };
|
|
@@ -40602,13 +40628,13 @@ async function runController(opts) {
|
|
|
40602
40628
|
}
|
|
40603
40629
|
return exitCode ?? 0;
|
|
40604
40630
|
}
|
|
40605
|
-
var import_node_fs47, import_node_os23,
|
|
40631
|
+
var import_node_fs47, import_node_os23, import_node_path60;
|
|
40606
40632
|
var init_controller = __esm({
|
|
40607
40633
|
"src/run-case/controller.ts"() {
|
|
40608
40634
|
"use strict";
|
|
40609
40635
|
import_node_fs47 = require("fs");
|
|
40610
40636
|
import_node_os23 = __toESM(require("os"), 1);
|
|
40611
|
-
|
|
40637
|
+
import_node_path60 = __toESM(require("path"), 1);
|
|
40612
40638
|
init_claude();
|
|
40613
40639
|
init_stdout_splitter();
|
|
40614
40640
|
init_permission_stdio();
|
|
@@ -40870,7 +40896,7 @@ Env (advanced):
|
|
|
40870
40896
|
`;
|
|
40871
40897
|
|
|
40872
40898
|
// src/index.ts
|
|
40873
|
-
var
|
|
40899
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
40874
40900
|
var import_node_fs45 = __toESM(require("fs"), 1);
|
|
40875
40901
|
var import_node_os22 = __toESM(require("os"), 1);
|
|
40876
40902
|
|
|
@@ -41735,6 +41761,28 @@ function dispatchShiftEnd(info, settle, killImpl) {
|
|
|
41735
41761
|
throw new Error(`dispatchShiftEnd: unhandled kind ${JSON.stringify(_exhaustive)}`);
|
|
41736
41762
|
}
|
|
41737
41763
|
|
|
41764
|
+
// src/dispatch/delivery.ts
|
|
41765
|
+
function selectPendingForDelivery(records, sourceSessionId) {
|
|
41766
|
+
return records.filter(
|
|
41767
|
+
(r) => r.sourceSessionId === sourceSessionId && (r.status === "completed" || r.status === "failed") && !r.deliveredAt
|
|
41768
|
+
).slice().sort((a, b2) => a.createdAt < b2.createdAt ? -1 : a.createdAt > b2.createdAt ? 1 : 0);
|
|
41769
|
+
}
|
|
41770
|
+
function formatDeliveryText(records) {
|
|
41771
|
+
const blocks = records.map((r) => {
|
|
41772
|
+
const head = `[dispatch ${r.dispatchId} \u2192 ${r.targetPersonaId}]`;
|
|
41773
|
+
if (r.outcome?.kind === "success") {
|
|
41774
|
+
const files = r.outcome.filePaths && r.outcome.filePaths.length > 0 ? `
|
|
41775
|
+
Related files:
|
|
41776
|
+
${r.outcome.filePaths.map((p2) => `- ${p2}`).join("\n")}` : "";
|
|
41777
|
+
return `${head} \u5B8C\u6210\uFF1A
|
|
41778
|
+
${r.outcome.text}${files}`;
|
|
41779
|
+
}
|
|
41780
|
+
const reason = r.outcome?.kind === "failure" ? r.outcome.reason : "unknown failure";
|
|
41781
|
+
return `${head} \u5931\u8D25\uFF1A${reason}`;
|
|
41782
|
+
});
|
|
41783
|
+
return ["\u4F60\u4E4B\u524D\u59D4\u6D3E\u51FA\u53BB\u7684\u4EFB\u52A1\u6709\u4E86\u7ED3\u679C\uFF1A", "", blocks.join("\n\n")].join("\n");
|
|
41784
|
+
}
|
|
41785
|
+
|
|
41738
41786
|
// src/session/runner.ts
|
|
41739
41787
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
41740
41788
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
@@ -41862,7 +41910,7 @@ var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A perso
|
|
|
41862
41910
|
- \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
|
|
41863
41911
|
- \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
|
|
41864
41912
|
|
|
41865
|
-
tool \u4F1A\
|
|
41913
|
+
tool \u4F1A**\u7ACB\u5373\u8FD4\u56DE** dispatchId\uFF08\u5F02\u6B65\u59D4\u6D3E\uFF09\uFF0C\u5BF9\u65B9\u4EBA\u683C\u5728\u540E\u53F0\u5E72\u6D3B\u3002\u4F60\u544A\u8BC9\u7528\u6237"\u4EFB\u52A1\u5DF2\u4EA4\u529E"\u5373\u53EF\u7ED3\u675F\u672C\u8F6E\u2014\u2014**\u4E0D\u8981\u7B49\u5F85\u3001\u4E0D\u8981\u8F6E\u8BE2**\u3002\u5BF9\u65B9\u5E72\u5B8C\u540E\uFF0C\u7ED3\u679C\u4F1A\u4F5C\u4E3A\u4E00\u6761\u65B0\u6D88\u606F\u81EA\u52A8\u6CE8\u5165\u56DE\u4F60\u7684 session\uFF0C\u4F60\u5C4A\u65F6\u518D\u7EFC\u5408\u8F6C\u8FBE\u7ED9\u7528\u6237\u3002\u60F3\u67E5\u8FDB\u5C55\u65F6\uFF08\u7528\u6237\u95EE\u8D77\uFF09\u8C03 \`mcp__clawd-dispatch__personaDispatchList\`\u3002
|
|
41866
41914
|
|
|
41867
41915
|
- **\u4E0D\u8981**\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF08\u4F60\u4E0D\u662F\u90A3\u4E2A persona\uFF09
|
|
41868
41916
|
- **\u4E0D\u8981** in-place \u6A21\u4EFF\u5BF9\u65B9\u4EBA\u683C \u2014\u2014 dispatch \u662F\u771F\u5207\u5230\u53E6\u4E00\u4E2A\u72EC\u7ACB session
|
|
@@ -41875,7 +41923,7 @@ tool \u4F1A\u963B\u585E\u6302\u8D77\u7B49\u5BF9\u65B9\u4EBA\u683C\u5E72\u5B8C\uF
|
|
|
41875
41923
|
|
|
41876
41924
|
- \`targetDeviceId = <token \u7B2C\u4E8C\u6BB5\u7684 deviceId\uFF0C\u539F\u6837\u586B>\`
|
|
41877
41925
|
|
|
41878
|
-
deviceId \u76F4\u63A5\u53D6\u81EA token\uFF0C\u4E0D\u8981\u6539\u5199\u6216\u731C\u6D4B\u3002\u5BF9\u65B9\u4E0D\u53EF\u8FBE / \u76EE\u6807 persona \u672A\u516C\u5F00\u4F1A\
|
|
41926
|
+
deviceId \u76F4\u63A5\u53D6\u81EA token\uFF0C\u4E0D\u8981\u6539\u5199\u6216\u731C\u6D4B\u3002\u5BF9\u65B9\u4E0D\u53EF\u8FBE / \u76EE\u6807 persona \u672A\u516C\u5F00\u4F1A\u5728\u7ED3\u679C\u56DE\u6D41\u65F6\u62A5\u5931\u8D25\uFF0C\u7167\u5E38\u8F6C\u8FF0\u7ED9\u7528\u6237\u5373\u53EF\u3002\u5176\u4F59\u884C\u4E3A\uFF08\u79D2\u56DE dispatchId\u3001\u7ED3\u679C\u81EA\u52A8\u6CE8\u5165\u3001\u5931\u8D25\u4E0D\u91CD\u8BD5\uFF09\u4E0E\u672C\u5730\u59D4\u6D3E\u4E00\u81F4\u3002
|
|
41879
41927
|
|
|
41880
41928
|
## \u88AB dispatch \u63A5\u5230\u4EFB\u52A1
|
|
41881
41929
|
|
|
@@ -43725,6 +43773,13 @@ var SessionManager = class {
|
|
|
43725
43773
|
}
|
|
43726
43774
|
}
|
|
43727
43775
|
}
|
|
43776
|
+
if (compressed.type === "session:status" && this.deps.dispatchStore) {
|
|
43777
|
+
const s = compressed;
|
|
43778
|
+
if (s.sessionId && s.status !== "running") {
|
|
43779
|
+
const sid = s.sessionId;
|
|
43780
|
+
setTimeout(() => this.deliverPending(sid), 0);
|
|
43781
|
+
}
|
|
43782
|
+
}
|
|
43728
43783
|
if (this.currentCollector) {
|
|
43729
43784
|
this.currentCollector.push({ frame: compressed, target });
|
|
43730
43785
|
return;
|
|
@@ -44051,6 +44106,67 @@ var SessionManager = class {
|
|
|
44051
44106
|
});
|
|
44052
44107
|
return { response: { ok: true }, broadcast };
|
|
44053
44108
|
}
|
|
44109
|
+
/**
|
|
44110
|
+
* Dispatch 结果投递(spec 2026-07-20 §5):查台账里该 source session 名下已完成
|
|
44111
|
+
* 且未投递的行,合并成一段 plain text 结果包注入回 source session。
|
|
44112
|
+
*
|
|
44113
|
+
* 触发点两个:complete 钩子(PersonaDispatchManager.onCompleted)+ source turn-end
|
|
44114
|
+
* 兜底 sweep(routeFromRunner 的 session:status 钩子)。幂等:投递成功盖 deliveredAt,
|
|
44115
|
+
* 再次调用查无未投递行直接返回。
|
|
44116
|
+
*
|
|
44117
|
+
* 判定口径:source 当前 running(含 reducer spawning,压缩后同 running)→ 不打扰,
|
|
44118
|
+
* 结果躺台账等下次 sweep。send 抛错(session 已删等)→ 记 log 不盖 deliveredAt,
|
|
44119
|
+
* 下次 sweep 自然重试。注入直接走 runner.input(无 collector),frames 经
|
|
44120
|
+
* routeFromRunner 正常广播上 wire。
|
|
44121
|
+
*/
|
|
44122
|
+
deliverPending(sourceSessionId) {
|
|
44123
|
+
const store = this.deps.dispatchStore;
|
|
44124
|
+
if (!store) return;
|
|
44125
|
+
const pending = selectPendingForDelivery(store.list({ sourceSessionId }), sourceSessionId);
|
|
44126
|
+
if (pending.length === 0) return;
|
|
44127
|
+
const state = this.tryGetState(sourceSessionId);
|
|
44128
|
+
if (state && compressStatus(state.status) === "running") return;
|
|
44129
|
+
if (!this.deps.ownerPrincipalId) {
|
|
44130
|
+
this.deps.logger?.warn("dispatch.deliver.no-owner-principal", { sourceSessionId });
|
|
44131
|
+
return;
|
|
44132
|
+
}
|
|
44133
|
+
const sender = principalToSender(
|
|
44134
|
+
makeOwnerPrincipal(
|
|
44135
|
+
this.deps.ownerPrincipalId,
|
|
44136
|
+
this.deps.ownerDisplayName ?? "Owner",
|
|
44137
|
+
this.deps.ownerFeishuUnionId
|
|
44138
|
+
)
|
|
44139
|
+
);
|
|
44140
|
+
try {
|
|
44141
|
+
const file = this.findOwnedSession(sourceSessionId);
|
|
44142
|
+
if (!file) {
|
|
44143
|
+
this.deps.logger?.info("dispatch.deliver.source-gone", { sourceSessionId });
|
|
44144
|
+
return;
|
|
44145
|
+
}
|
|
44146
|
+
const runner = this.ensureRunnerForScope(file, this.scopeForFile(file));
|
|
44147
|
+
runner.input({
|
|
44148
|
+
kind: "command",
|
|
44149
|
+
command: {
|
|
44150
|
+
kind: "send",
|
|
44151
|
+
text: formatDeliveryText(pending),
|
|
44152
|
+
senderPrincipal: sender
|
|
44153
|
+
}
|
|
44154
|
+
});
|
|
44155
|
+
} catch (err) {
|
|
44156
|
+
this.deps.logger?.warn("dispatch.deliver.send-failed", {
|
|
44157
|
+
sourceSessionId,
|
|
44158
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
44159
|
+
});
|
|
44160
|
+
return;
|
|
44161
|
+
}
|
|
44162
|
+
const nowIso3 = new Date(this.deps.now?.() ?? Date.now()).toISOString();
|
|
44163
|
+
for (const r of pending) store.update(r.dispatchId, { deliveredAt: nowIso3 });
|
|
44164
|
+
this.deps.logger?.info("dispatch.deliver.ok", {
|
|
44165
|
+
sourceSessionId,
|
|
44166
|
+
count: pending.length,
|
|
44167
|
+
dispatchIds: pending.map((r) => r.dispatchId)
|
|
44168
|
+
});
|
|
44169
|
+
}
|
|
44054
44170
|
/**
|
|
44055
44171
|
* 只读拿 SessionState;session 不存在返 null(不 throw)。
|
|
44056
44172
|
* handlers/session.ts:currentTurnSender 用(loopback HTTP RPC 绝对不能因不存在的 sid 崩)。
|
|
@@ -46657,8 +46773,8 @@ function turnStartInput(text) {
|
|
|
46657
46773
|
const items = [];
|
|
46658
46774
|
let leftover = text;
|
|
46659
46775
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
46660
|
-
const [marker, name,
|
|
46661
|
-
items.push({ type: "skill", name, path:
|
|
46776
|
+
const [marker, name, path71] = m2;
|
|
46777
|
+
items.push({ type: "skill", name, path: path71 });
|
|
46662
46778
|
leftover = leftover.replace(marker, "");
|
|
46663
46779
|
}
|
|
46664
46780
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -48157,35 +48273,60 @@ var PersonaDispatchManager = class {
|
|
|
48157
48273
|
dispatchId,
|
|
48158
48274
|
sourceSessionId: args.sourceSessionId,
|
|
48159
48275
|
targetPersona: args.targetPersona,
|
|
48160
|
-
waiters: []
|
|
48161
|
-
|
|
48276
|
+
waiters: []
|
|
48277
|
+
});
|
|
48278
|
+
this.deps.store.add({
|
|
48279
|
+
dispatchId,
|
|
48280
|
+
sourceSessionId: args.sourceSessionId,
|
|
48281
|
+
...args.sourcePersonaId ? { sourcePersonaId: args.sourcePersonaId } : {},
|
|
48282
|
+
targetPersonaId: args.targetPersona,
|
|
48283
|
+
taskText: args.taskText
|
|
48162
48284
|
});
|
|
48163
48285
|
return { dispatchId };
|
|
48164
48286
|
}
|
|
48165
48287
|
get(dispatchId) {
|
|
48166
48288
|
return this.map.get(dispatchId);
|
|
48167
48289
|
}
|
|
48168
|
-
|
|
48290
|
+
complete(dispatchId, outcome) {
|
|
48291
|
+
const state = this.map.get(dispatchId);
|
|
48292
|
+
const status = outcome.kind === "success" ? "completed" : "failed";
|
|
48293
|
+
const updated = this.deps.store.update(dispatchId, {
|
|
48294
|
+
status,
|
|
48295
|
+
outcome,
|
|
48296
|
+
completedAt: new Date(this.deps.now()).toISOString()
|
|
48297
|
+
});
|
|
48298
|
+
if (state) {
|
|
48299
|
+
const waiters = state.waiters;
|
|
48300
|
+
state.waiters = [];
|
|
48301
|
+
for (const w2 of waiters) w2.resolve(outcome);
|
|
48302
|
+
this.map.delete(dispatchId);
|
|
48303
|
+
}
|
|
48304
|
+
const sourceSessionId = updated?.sourceSessionId ?? state?.sourceSessionId;
|
|
48305
|
+
if (sourceSessionId) this.deps.onCompleted?.(sourceSessionId);
|
|
48306
|
+
}
|
|
48307
|
+
/**
|
|
48308
|
+
* mesh B 角色 hold 专用(跨设备 dispatch 的 peer 侧):guest B-role handler 用它
|
|
48309
|
+
* 挂住 /rpc HTTP 响应直到 complete,把 outcome 回传给 A 侧 daemon 的 forwardToPeer
|
|
48310
|
+
* (A 侧后台 await,A 的 tool call 不受影响照样秒回)。
|
|
48311
|
+
* 本地 dispatch 链路**不用**这个——本地 outcome 只走台账 + deliverPending。
|
|
48312
|
+
*/
|
|
48313
|
+
async waitForOutcome(dispatchId) {
|
|
48169
48314
|
const state = this.map.get(dispatchId);
|
|
48170
|
-
if (!state)
|
|
48171
|
-
|
|
48315
|
+
if (!state) {
|
|
48316
|
+
const rec3 = this.deps.store.get(dispatchId);
|
|
48317
|
+
if (rec3?.outcome) return rec3.outcome;
|
|
48318
|
+
throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
48319
|
+
}
|
|
48172
48320
|
const d = defer();
|
|
48173
48321
|
state.waiters.push(d);
|
|
48174
48322
|
return d.promise;
|
|
48175
48323
|
}
|
|
48176
|
-
complete(dispatchId, outcome) {
|
|
48177
|
-
const state = this.map.get(dispatchId);
|
|
48178
|
-
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
48179
|
-
state.outcome = outcome;
|
|
48180
|
-
const waiters = state.waiters;
|
|
48181
|
-
state.waiters = [];
|
|
48182
|
-
for (const w2 of waiters) w2.resolve(outcome);
|
|
48183
|
-
}
|
|
48184
48324
|
/** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
|
|
48185
48325
|
registerBSession(dispatchId, bSessionId) {
|
|
48186
48326
|
const state = this.map.get(dispatchId);
|
|
48187
48327
|
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
48188
48328
|
state.bSessionId = bSessionId;
|
|
48329
|
+
this.deps.store.update(dispatchId, { workerSessionId: bSessionId });
|
|
48189
48330
|
}
|
|
48190
48331
|
/** reducer buildSpawnContext 调,按 B 的 sessionId 反查 dispatchId(用于注 CLAWD_DISPATCH_ID env) */
|
|
48191
48332
|
lookupDispatchByBSessionId(bSessionId) {
|
|
@@ -48196,11 +48337,112 @@ var PersonaDispatchManager = class {
|
|
|
48196
48337
|
}
|
|
48197
48338
|
};
|
|
48198
48339
|
|
|
48340
|
+
// src/dispatch/store.ts
|
|
48341
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
48342
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
48343
|
+
|
|
48344
|
+
// src/shift/constants.ts
|
|
48345
|
+
var MAX_RUNS_PER_SHIFT = 30;
|
|
48346
|
+
var DEFAULT_TIMEOUT_MS = 30 * 6e4;
|
|
48347
|
+
var CONSECUTIVE_ERROR_THRESHOLD = 5;
|
|
48348
|
+
var TICK_INTERVAL_MS = 1e4;
|
|
48349
|
+
var STORE_FLUSH_DEBOUNCE_MS = 500;
|
|
48350
|
+
var CLOCK_JUMP_THRESHOLD_MS = 5 * 6e4;
|
|
48351
|
+
|
|
48352
|
+
// src/dispatch/store.ts
|
|
48353
|
+
var TASK_TEXT_MAX = 500;
|
|
48354
|
+
function createDispatchStore(deps) {
|
|
48355
|
+
let records = [];
|
|
48356
|
+
let flushTimer = null;
|
|
48357
|
+
async function load() {
|
|
48358
|
+
let raw;
|
|
48359
|
+
try {
|
|
48360
|
+
raw = await import_promises.default.readFile(deps.filePath, "utf8");
|
|
48361
|
+
} catch (e) {
|
|
48362
|
+
if (e.code === "ENOENT") {
|
|
48363
|
+
records = [];
|
|
48364
|
+
return;
|
|
48365
|
+
}
|
|
48366
|
+
throw e;
|
|
48367
|
+
}
|
|
48368
|
+
const parsed = JSON.parse(raw);
|
|
48369
|
+
if (parsed.version !== 1) {
|
|
48370
|
+
throw new Error(`dispatch.json: unsupported version ${parsed.version}`);
|
|
48371
|
+
}
|
|
48372
|
+
records = parsed.records ?? [];
|
|
48373
|
+
}
|
|
48374
|
+
async function flushNow() {
|
|
48375
|
+
if (flushTimer) {
|
|
48376
|
+
clearTimeout(flushTimer);
|
|
48377
|
+
flushTimer = null;
|
|
48378
|
+
}
|
|
48379
|
+
const content = { version: 1, records };
|
|
48380
|
+
await import_promises.default.mkdir(import_node_path16.default.dirname(deps.filePath), { recursive: true });
|
|
48381
|
+
const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
|
|
48382
|
+
await import_promises.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
|
|
48383
|
+
await import_promises.default.rename(tmp, deps.filePath);
|
|
48384
|
+
}
|
|
48385
|
+
function scheduleFlush() {
|
|
48386
|
+
if (flushTimer) return;
|
|
48387
|
+
flushTimer = setTimeout(() => {
|
|
48388
|
+
flushTimer = null;
|
|
48389
|
+
flushNow().catch((err) => {
|
|
48390
|
+
deps.onFlushError?.(err);
|
|
48391
|
+
});
|
|
48392
|
+
}, STORE_FLUSH_DEBOUNCE_MS);
|
|
48393
|
+
}
|
|
48394
|
+
function get(dispatchId) {
|
|
48395
|
+
return records.find((r) => r.dispatchId === dispatchId);
|
|
48396
|
+
}
|
|
48397
|
+
function add(input) {
|
|
48398
|
+
const rec3 = {
|
|
48399
|
+
dispatchId: input.dispatchId,
|
|
48400
|
+
sourceSessionId: input.sourceSessionId,
|
|
48401
|
+
...input.sourcePersonaId ? { sourcePersonaId: input.sourcePersonaId } : {},
|
|
48402
|
+
targetPersonaId: input.targetPersonaId,
|
|
48403
|
+
taskText: input.taskText.slice(0, TASK_TEXT_MAX),
|
|
48404
|
+
status: "running",
|
|
48405
|
+
...input.meta ? { meta: input.meta } : {},
|
|
48406
|
+
createdAt: new Date(deps.now()).toISOString()
|
|
48407
|
+
};
|
|
48408
|
+
records.push(rec3);
|
|
48409
|
+
scheduleFlush();
|
|
48410
|
+
return rec3;
|
|
48411
|
+
}
|
|
48412
|
+
function update(dispatchId, patch) {
|
|
48413
|
+
const idx = records.findIndex((r) => r.dispatchId === dispatchId);
|
|
48414
|
+
if (idx < 0) return void 0;
|
|
48415
|
+
const merged = { ...records[idx], ...patch };
|
|
48416
|
+
records[idx] = merged;
|
|
48417
|
+
scheduleFlush();
|
|
48418
|
+
return merged;
|
|
48419
|
+
}
|
|
48420
|
+
function list(filter) {
|
|
48421
|
+
return records.filter((r) => !filter?.sourceSessionId || r.sourceSessionId === filter.sourceSessionId).slice().sort((a, b2) => a.createdAt < b2.createdAt ? 1 : a.createdAt > b2.createdAt ? -1 : 0);
|
|
48422
|
+
}
|
|
48423
|
+
function markInterruptedAsFailed(nowIso3) {
|
|
48424
|
+
let touched = false;
|
|
48425
|
+
for (const r of records) {
|
|
48426
|
+
if (r.status === "running") {
|
|
48427
|
+
r.status = "failed";
|
|
48428
|
+
r.outcome = {
|
|
48429
|
+
kind: "failure",
|
|
48430
|
+
reason: "daemon restarted while dispatch in flight"
|
|
48431
|
+
};
|
|
48432
|
+
r.completedAt = nowIso3;
|
|
48433
|
+
touched = true;
|
|
48434
|
+
}
|
|
48435
|
+
}
|
|
48436
|
+
if (touched) scheduleFlush();
|
|
48437
|
+
}
|
|
48438
|
+
return { load, flushNow, add, update, list, get, markInterruptedAsFailed };
|
|
48439
|
+
}
|
|
48440
|
+
|
|
48199
48441
|
// src/dispatch/mcp-config.ts
|
|
48200
48442
|
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
48201
|
-
var
|
|
48443
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
48202
48444
|
function dispatchMcpConfigPath(dataDir) {
|
|
48203
|
-
return
|
|
48445
|
+
return import_node_path17.default.join(dataDir, "dispatch.mcp.json");
|
|
48204
48446
|
}
|
|
48205
48447
|
function writeDispatchMcpConfig(args) {
|
|
48206
48448
|
const cfgPath = dispatchMcpConfigPath(args.dataDir);
|
|
@@ -48222,9 +48464,9 @@ function writeDispatchMcpConfig(args) {
|
|
|
48222
48464
|
|
|
48223
48465
|
// src/ticket/mcp-config.ts
|
|
48224
48466
|
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
48225
|
-
var
|
|
48467
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
48226
48468
|
function ticketMcpConfigPath(dataDir) {
|
|
48227
|
-
return
|
|
48469
|
+
return import_node_path18.default.join(dataDir, "ticket.mcp.json");
|
|
48228
48470
|
}
|
|
48229
48471
|
function writeTicketMcpConfig(args) {
|
|
48230
48472
|
const cfgPath = ticketMcpConfigPath(args.dataDir);
|
|
@@ -48251,9 +48493,9 @@ function writeTicketMcpConfig(args) {
|
|
|
48251
48493
|
|
|
48252
48494
|
// src/shift/mcp-config.ts
|
|
48253
48495
|
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
48254
|
-
var
|
|
48496
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
48255
48497
|
function shiftMcpConfigPath(dataDir) {
|
|
48256
|
-
return
|
|
48498
|
+
return import_node_path19.default.join(dataDir, "shift.mcp.json");
|
|
48257
48499
|
}
|
|
48258
48500
|
async function writeShiftMcpConfig(args) {
|
|
48259
48501
|
const cfgPath = shiftMcpConfigPath(args.dataDir);
|
|
@@ -48275,9 +48517,9 @@ async function writeShiftMcpConfig(args) {
|
|
|
48275
48517
|
|
|
48276
48518
|
// src/inbox/mcp-config.ts
|
|
48277
48519
|
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
48278
|
-
var
|
|
48520
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
48279
48521
|
function inboxMcpConfigPath(dataDir) {
|
|
48280
|
-
return
|
|
48522
|
+
return import_node_path20.default.join(dataDir, "inbox.mcp.json");
|
|
48281
48523
|
}
|
|
48282
48524
|
async function writeInboxMcpConfig(args) {
|
|
48283
48525
|
const cfgPath = inboxMcpConfigPath(args.dataDir);
|
|
@@ -48299,9 +48541,9 @@ async function writeInboxMcpConfig(args) {
|
|
|
48299
48541
|
|
|
48300
48542
|
// src/peer-ops/mcp-config.ts
|
|
48301
48543
|
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
48302
|
-
var
|
|
48544
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
48303
48545
|
function peerOpsMcpConfigPath(dataDir) {
|
|
48304
|
-
return
|
|
48546
|
+
return import_node_path21.default.join(dataDir, "peer-ops.mcp.json");
|
|
48305
48547
|
}
|
|
48306
48548
|
function writePeerOpsMcpConfig(args) {
|
|
48307
48549
|
const cfgPath = peerOpsMcpConfigPath(args.dataDir);
|
|
@@ -48320,18 +48562,10 @@ function writePeerOpsMcpConfig(args) {
|
|
|
48320
48562
|
}
|
|
48321
48563
|
|
|
48322
48564
|
// src/shift/store.ts
|
|
48323
|
-
var
|
|
48324
|
-
var
|
|
48565
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
48566
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
48325
48567
|
var import_node_crypto6 = require("crypto");
|
|
48326
48568
|
|
|
48327
|
-
// src/shift/constants.ts
|
|
48328
|
-
var MAX_RUNS_PER_SHIFT = 30;
|
|
48329
|
-
var DEFAULT_TIMEOUT_MS = 30 * 6e4;
|
|
48330
|
-
var CONSECUTIVE_ERROR_THRESHOLD = 5;
|
|
48331
|
-
var TICK_INTERVAL_MS = 1e4;
|
|
48332
|
-
var STORE_FLUSH_DEBOUNCE_MS = 500;
|
|
48333
|
-
var CLOCK_JUMP_THRESHOLD_MS = 5 * 6e4;
|
|
48334
|
-
|
|
48335
48569
|
// src/shift/schedule.ts
|
|
48336
48570
|
var import_cron_parser = __toESM(require_dist(), 1);
|
|
48337
48571
|
function computeNextRunAtMs(schedule, fromMs) {
|
|
@@ -48376,7 +48610,7 @@ function createShiftStore(deps) {
|
|
|
48376
48610
|
async function load() {
|
|
48377
48611
|
let raw;
|
|
48378
48612
|
try {
|
|
48379
|
-
raw = await
|
|
48613
|
+
raw = await import_promises2.default.readFile(deps.filePath, "utf8");
|
|
48380
48614
|
} catch (e) {
|
|
48381
48615
|
if (e.code === "ENOENT") {
|
|
48382
48616
|
shifts = [];
|
|
@@ -48404,10 +48638,10 @@ function createShiftStore(deps) {
|
|
|
48404
48638
|
flushTimer = null;
|
|
48405
48639
|
}
|
|
48406
48640
|
const content = { version: 1, shifts };
|
|
48407
|
-
await
|
|
48641
|
+
await import_promises2.default.mkdir(import_node_path22.default.dirname(deps.filePath), { recursive: true });
|
|
48408
48642
|
const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
|
|
48409
|
-
await
|
|
48410
|
-
await
|
|
48643
|
+
await import_promises2.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
|
|
48644
|
+
await import_promises2.default.rename(tmp, deps.filePath);
|
|
48411
48645
|
}
|
|
48412
48646
|
function scheduleFlush() {
|
|
48413
48647
|
if (flushTimer) return;
|
|
@@ -48842,18 +49076,33 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48842
49076
|
if (!deps.forwardToPeer) {
|
|
48843
49077
|
throw new Error("cross-device dispatch not wired (forwardToPeer missing)");
|
|
48844
49078
|
}
|
|
49079
|
+
if (!sourceSessionId) {
|
|
49080
|
+
throw new Error(
|
|
49081
|
+
"personaDispatch:run requires sessionId (caller must pass x-clawd-session-id header)"
|
|
49082
|
+
);
|
|
49083
|
+
}
|
|
49084
|
+
const { dispatchId: dispatchId2 } = mgr.start({
|
|
49085
|
+
sourceSessionId,
|
|
49086
|
+
targetPersona: args.targetPersona,
|
|
49087
|
+
taskText: args.prompt
|
|
49088
|
+
});
|
|
48845
49089
|
logger?.info("dispatch.run.forward", {
|
|
49090
|
+
dispatchId: dispatchId2,
|
|
48846
49091
|
targetDeviceId: args.targetDeviceId,
|
|
48847
49092
|
targetPersona: args.targetPersona
|
|
48848
49093
|
});
|
|
48849
|
-
|
|
49094
|
+
void deps.forwardToPeer({
|
|
48850
49095
|
targetDeviceId: args.targetDeviceId,
|
|
48851
49096
|
targetPersona: args.targetPersona,
|
|
48852
49097
|
prompt: args.prompt,
|
|
48853
49098
|
...args.model ? { model: args.model } : {}
|
|
49099
|
+
}).then((outcome) => mgr.complete(dispatchId2, outcome)).catch((err) => {
|
|
49100
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
49101
|
+
logger?.warn("dispatch.forward.failed", { dispatchId: dispatchId2, reason });
|
|
49102
|
+
mgr.complete(dispatchId2, { kind: "failure", reason });
|
|
48854
49103
|
});
|
|
48855
49104
|
return {
|
|
48856
|
-
response: { type: "personaDispatch:run:ok",
|
|
49105
|
+
response: { type: "personaDispatch:run:ok", dispatchId: dispatchId2 }
|
|
48857
49106
|
};
|
|
48858
49107
|
}
|
|
48859
49108
|
if (ctx?.principal.kind === "guest") {
|
|
@@ -48866,7 +49115,8 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48866
49115
|
}
|
|
48867
49116
|
const { dispatchId: dispatchId2 } = mgr.start({
|
|
48868
49117
|
sourceSessionId: ctx.principal.id,
|
|
48869
|
-
targetPersona: args.targetPersona
|
|
49118
|
+
targetPersona: args.targetPersona,
|
|
49119
|
+
taskText: args.prompt
|
|
48870
49120
|
});
|
|
48871
49121
|
logger?.info("dispatch.run.received.guest", {
|
|
48872
49122
|
dispatchId: dispatchId2,
|
|
@@ -48892,9 +49142,9 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48892
49142
|
reason: `failed to spawn B: ${reason}`
|
|
48893
49143
|
});
|
|
48894
49144
|
});
|
|
48895
|
-
const
|
|
49145
|
+
const outcome = await mgr.waitForOutcome(dispatchId2);
|
|
48896
49146
|
return {
|
|
48897
|
-
response: { type: "personaDispatch:run:ok", outcome
|
|
49147
|
+
response: { type: "personaDispatch:run:ok", outcome }
|
|
48898
49148
|
};
|
|
48899
49149
|
}
|
|
48900
49150
|
if (!sourceSessionId) {
|
|
@@ -48904,7 +49154,8 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48904
49154
|
}
|
|
48905
49155
|
const { dispatchId } = mgr.start({
|
|
48906
49156
|
sourceSessionId,
|
|
48907
|
-
targetPersona: args.targetPersona
|
|
49157
|
+
targetPersona: args.targetPersona,
|
|
49158
|
+
taskText: args.prompt
|
|
48908
49159
|
});
|
|
48909
49160
|
logger?.info("dispatch.run.received", {
|
|
48910
49161
|
dispatchId,
|
|
@@ -48928,14 +49179,8 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48928
49179
|
reason: `failed to spawn B: ${reason}`
|
|
48929
49180
|
});
|
|
48930
49181
|
});
|
|
48931
|
-
logger?.info("dispatch.run.waiting", { dispatchId });
|
|
48932
|
-
const outcome = await mgr.wait(dispatchId);
|
|
48933
|
-
logger?.info("dispatch.run.resolved", {
|
|
48934
|
-
dispatchId,
|
|
48935
|
-
outcomeKind: outcome.kind
|
|
48936
|
-
});
|
|
48937
49182
|
return {
|
|
48938
|
-
response: { type: "personaDispatch:run:ok",
|
|
49183
|
+
response: { type: "personaDispatch:run:ok", dispatchId }
|
|
48939
49184
|
};
|
|
48940
49185
|
};
|
|
48941
49186
|
const complete = async (frame) => {
|
|
@@ -48950,9 +49195,20 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48950
49195
|
response: { type: "personaDispatch:complete:ok" }
|
|
48951
49196
|
};
|
|
48952
49197
|
};
|
|
49198
|
+
const list = async (frame) => {
|
|
49199
|
+
const { type: _t, requestId: _r, ...rest } = frame;
|
|
49200
|
+
const args = DispatchListArgsSchema.parse(rest);
|
|
49201
|
+
const records = deps.store.list(
|
|
49202
|
+
args.sourceSessionId ? { sourceSessionId: args.sourceSessionId } : void 0
|
|
49203
|
+
);
|
|
49204
|
+
return {
|
|
49205
|
+
response: { type: "personaDispatch:list:ok", records }
|
|
49206
|
+
};
|
|
49207
|
+
};
|
|
48953
49208
|
return {
|
|
48954
49209
|
"personaDispatch:run": run,
|
|
48955
|
-
"personaDispatch:complete": complete
|
|
49210
|
+
"personaDispatch:complete": complete,
|
|
49211
|
+
"personaDispatch:list": list
|
|
48956
49212
|
};
|
|
48957
49213
|
}
|
|
48958
49214
|
|
|
@@ -49258,13 +49514,13 @@ function mapSkillsListResponse(res) {
|
|
|
49258
49514
|
const r = s ?? {};
|
|
49259
49515
|
const name = str3(r.name);
|
|
49260
49516
|
if (!name) continue;
|
|
49261
|
-
const
|
|
49517
|
+
const path71 = str3(r.path);
|
|
49262
49518
|
const description = str3(r.description);
|
|
49263
49519
|
const isPlugin = name.includes(":");
|
|
49264
49520
|
out.push({
|
|
49265
49521
|
name,
|
|
49266
49522
|
source: isPlugin ? "plugin" : "project",
|
|
49267
|
-
...
|
|
49523
|
+
...path71 ? { path: path71 } : {},
|
|
49268
49524
|
...description ? { description } : {},
|
|
49269
49525
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
49270
49526
|
});
|
|
@@ -49305,14 +49561,14 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
49305
49561
|
// src/workspace/browser.ts
|
|
49306
49562
|
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
49307
49563
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
49308
|
-
var
|
|
49564
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
49309
49565
|
init_protocol();
|
|
49310
49566
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
49311
49567
|
function resolveInsideCwd(cwd, subpath) {
|
|
49312
|
-
const absCwd =
|
|
49313
|
-
const joined =
|
|
49314
|
-
const rel =
|
|
49315
|
-
if (rel.startsWith("..") ||
|
|
49568
|
+
const absCwd = import_node_path23.default.resolve(cwd);
|
|
49569
|
+
const joined = import_node_path23.default.resolve(absCwd, subpath ?? ".");
|
|
49570
|
+
const rel = import_node_path23.default.relative(absCwd, joined);
|
|
49571
|
+
if (rel.startsWith("..") || import_node_path23.default.isAbsolute(rel)) {
|
|
49316
49572
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
49317
49573
|
}
|
|
49318
49574
|
return joined;
|
|
@@ -49343,7 +49599,7 @@ var WorkspaceBrowser = class {
|
|
|
49343
49599
|
mtime: ""
|
|
49344
49600
|
};
|
|
49345
49601
|
try {
|
|
49346
|
-
const st = import_node_fs24.default.statSync(
|
|
49602
|
+
const st = import_node_fs24.default.statSync(import_node_path23.default.join(full, d.name));
|
|
49347
49603
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
49348
49604
|
if (d.isFile()) entry.size = st.size;
|
|
49349
49605
|
} catch {
|
|
@@ -49390,7 +49646,7 @@ var WorkspaceBrowser = class {
|
|
|
49390
49646
|
// src/skills/agents-scanner.ts
|
|
49391
49647
|
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
49392
49648
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
49393
|
-
var
|
|
49649
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
49394
49650
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
49395
49651
|
function isDirLikeSync2(p2) {
|
|
49396
49652
|
try {
|
|
@@ -49428,10 +49684,10 @@ function scanAgentsDir(dir, source, seen, out) {
|
|
|
49428
49684
|
}
|
|
49429
49685
|
for (const ent of entries) {
|
|
49430
49686
|
if (!ent.name.endsWith(".md")) continue;
|
|
49431
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
49687
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path24.default.join(dir, ent.name)))) {
|
|
49432
49688
|
continue;
|
|
49433
49689
|
}
|
|
49434
|
-
const filePath =
|
|
49690
|
+
const filePath = import_node_path24.default.join(dir, ent.name);
|
|
49435
49691
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
49436
49692
|
if (seen.has(baseName)) continue;
|
|
49437
49693
|
seen.add(baseName);
|
|
@@ -49454,7 +49710,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
49454
49710
|
return;
|
|
49455
49711
|
}
|
|
49456
49712
|
for (const ent of entries) {
|
|
49457
|
-
const childPath =
|
|
49713
|
+
const childPath = import_node_path24.default.join(dir, ent.name);
|
|
49458
49714
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
49459
49715
|
walk2(childPath, [...namespaces, ent.name]);
|
|
49460
49716
|
continue;
|
|
@@ -49479,9 +49735,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
49479
49735
|
walk2(root, []);
|
|
49480
49736
|
}
|
|
49481
49737
|
function readInstalledPlugins2(home) {
|
|
49482
|
-
const pluginsDir =
|
|
49483
|
-
const v2 =
|
|
49484
|
-
const v1 =
|
|
49738
|
+
const pluginsDir = import_node_path24.default.join(home, ".claude", "plugins");
|
|
49739
|
+
const v2 = import_node_path24.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
49740
|
+
const v1 = import_node_path24.default.join(pluginsDir, "installed_plugins.json");
|
|
49485
49741
|
let raw = null;
|
|
49486
49742
|
for (const candidate of [v2, v1]) {
|
|
49487
49743
|
try {
|
|
@@ -49510,19 +49766,19 @@ function readInstalledPlugins2(home) {
|
|
|
49510
49766
|
return out;
|
|
49511
49767
|
}
|
|
49512
49768
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
49513
|
-
let cur =
|
|
49514
|
-
const fsRoot =
|
|
49769
|
+
let cur = import_node_path24.default.resolve(startCwd);
|
|
49770
|
+
const fsRoot = import_node_path24.default.parse(cur).root;
|
|
49515
49771
|
while (true) {
|
|
49516
|
-
scanAgentsDir(
|
|
49772
|
+
scanAgentsDir(import_node_path24.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
49517
49773
|
let hasGit = false;
|
|
49518
49774
|
try {
|
|
49519
|
-
hasGit = import_node_fs25.default.existsSync(
|
|
49775
|
+
hasGit = import_node_fs25.default.existsSync(import_node_path24.default.join(cur, ".git"));
|
|
49520
49776
|
} catch {
|
|
49521
49777
|
}
|
|
49522
49778
|
if (hasGit) return;
|
|
49523
49779
|
if (cur === home) return;
|
|
49524
49780
|
if (cur === fsRoot) return;
|
|
49525
|
-
const parent =
|
|
49781
|
+
const parent = import_node_path24.default.dirname(cur);
|
|
49526
49782
|
if (parent === cur) return;
|
|
49527
49783
|
cur = parent;
|
|
49528
49784
|
}
|
|
@@ -49557,7 +49813,7 @@ var AgentsScanner = class {
|
|
|
49557
49813
|
}
|
|
49558
49814
|
const fsBlock = [];
|
|
49559
49815
|
scanAgentsDir(
|
|
49560
|
-
|
|
49816
|
+
import_node_path24.default.join(this.home, ".claude", "agents"),
|
|
49561
49817
|
"global",
|
|
49562
49818
|
seen,
|
|
49563
49819
|
fsBlock
|
|
@@ -49571,7 +49827,7 @@ var AgentsScanner = class {
|
|
|
49571
49827
|
...this.extraPluginRoots
|
|
49572
49828
|
];
|
|
49573
49829
|
for (const { name, root } of plugins) {
|
|
49574
|
-
const agentsRoot =
|
|
49830
|
+
const agentsRoot = import_node_path24.default.join(root, "agents");
|
|
49575
49831
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
49576
49832
|
}
|
|
49577
49833
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -49581,13 +49837,13 @@ var AgentsScanner = class {
|
|
|
49581
49837
|
// src/observer/session-observer.ts
|
|
49582
49838
|
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
49583
49839
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
49584
|
-
var
|
|
49840
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
49585
49841
|
init_claude_history();
|
|
49586
49842
|
|
|
49587
49843
|
// src/observer/subagent-meta-observer.ts
|
|
49588
49844
|
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
49589
49845
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
49590
|
-
var
|
|
49846
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
49591
49847
|
init_claude_history();
|
|
49592
49848
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
49593
49849
|
var SubagentMetaObserver = class {
|
|
@@ -49600,7 +49856,7 @@ var SubagentMetaObserver = class {
|
|
|
49600
49856
|
watches = /* @__PURE__ */ new Map();
|
|
49601
49857
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
49602
49858
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
49603
|
-
return
|
|
49859
|
+
return import_node_path25.default.join(
|
|
49604
49860
|
this.home,
|
|
49605
49861
|
".claude",
|
|
49606
49862
|
"projects",
|
|
@@ -49656,7 +49912,7 @@ var SubagentMetaObserver = class {
|
|
|
49656
49912
|
if (!m2) return;
|
|
49657
49913
|
const agentId = m2[1];
|
|
49658
49914
|
if (w2.emitted.has(agentId)) return;
|
|
49659
|
-
const file =
|
|
49915
|
+
const file = import_node_path25.default.join(w2.dirPath, name);
|
|
49660
49916
|
let raw;
|
|
49661
49917
|
try {
|
|
49662
49918
|
raw = import_node_fs26.default.readFileSync(file, "utf8");
|
|
@@ -49716,7 +49972,7 @@ var SessionObserver = class {
|
|
|
49716
49972
|
metaObserver;
|
|
49717
49973
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
49718
49974
|
if (override) return override;
|
|
49719
|
-
return
|
|
49975
|
+
return import_node_path26.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
49720
49976
|
}
|
|
49721
49977
|
start(args) {
|
|
49722
49978
|
this.stop(args.sessionId);
|
|
@@ -49742,10 +49998,10 @@ var SessionObserver = class {
|
|
|
49742
49998
|
lastDeriveMs: 0
|
|
49743
49999
|
};
|
|
49744
50000
|
try {
|
|
49745
|
-
import_node_fs27.default.mkdirSync(
|
|
50001
|
+
import_node_fs27.default.mkdirSync(import_node_path26.default.dirname(filePath), { recursive: true });
|
|
49746
50002
|
} catch {
|
|
49747
50003
|
}
|
|
49748
|
-
w2.watcher = import_node_fs27.default.watch(
|
|
50004
|
+
w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
49749
50005
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
49750
50006
|
this.poll(w2);
|
|
49751
50007
|
});
|
|
@@ -49842,7 +50098,7 @@ var SessionObserver = class {
|
|
|
49842
50098
|
const now = Date.now();
|
|
49843
50099
|
if (now - w2.lastRelocateScanMs < 1e3) return;
|
|
49844
50100
|
w2.lastRelocateScanMs = now;
|
|
49845
|
-
const projectsRoot =
|
|
50101
|
+
const projectsRoot = import_node_path26.default.join(this.home, ".claude", "projects");
|
|
49846
50102
|
const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
|
|
49847
50103
|
if (!found || found === w2.filePath) return;
|
|
49848
50104
|
try {
|
|
@@ -49851,7 +50107,7 @@ var SessionObserver = class {
|
|
|
49851
50107
|
}
|
|
49852
50108
|
w2.filePath = found;
|
|
49853
50109
|
try {
|
|
49854
|
-
w2.watcher = import_node_fs27.default.watch(
|
|
50110
|
+
w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(found), { persistent: false }, (_event, changedName) => {
|
|
49855
50111
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
49856
50112
|
this.poll(w2);
|
|
49857
50113
|
});
|
|
@@ -50435,13 +50691,13 @@ var EXPOSED_RPC_METHODS = [
|
|
|
50435
50691
|
// dataclaw-builder:persona 建页时取建页人身份(含 union_id)写进生成 app 的配置。
|
|
50436
50692
|
// 路由到 handlers['auth:getIdentity'],只返 identity、绝不带 ttcToken(见 handlers/feishu-auth.ts)。
|
|
50437
50693
|
"auth.getIdentity",
|
|
50438
|
-
// Persona dispatch
|
|
50439
|
-
// B
|
|
50440
|
-
// protocol/src/dispatch.ts。
|
|
50694
|
+
// Persona dispatch(异步,spec 2026-07-20):A 端 dispatch MCP server 调 run(秒回 dispatchId);
|
|
50695
|
+
// B 端调 complete(带 outcome → 台账 + 投递);发起方调 list 查台账。详见 protocol/src/dispatch.ts。
|
|
50441
50696
|
"personaDispatch.run",
|
|
50442
50697
|
// 跨设备 exec(spec 2026-07-16):A 侧本地 cc 经 /api/rpc 调,带 peerDeviceId → daemon forward。
|
|
50443
50698
|
"peerExec.run",
|
|
50444
50699
|
"personaDispatch.complete",
|
|
50700
|
+
"personaDispatch.list",
|
|
50445
50701
|
// clawd-shift v1 (spec 2026-06-24-clawd-shift):cc 子进程内的 shift MCP server 调
|
|
50446
50702
|
// 这 5 个 method 管理 owner 的 shift(fire-and-forget 排班)。鉴权靠 body.personaId
|
|
50447
50703
|
// (mcp-server 从 process.env.CLAWD_PERSONA_ID 读,源 = SessionFile.ownerPersonaId)。
|
|
@@ -50706,14 +50962,14 @@ async function authenticate(token, deps) {
|
|
|
50706
50962
|
}
|
|
50707
50963
|
|
|
50708
50964
|
// src/permission/capability-store.ts
|
|
50709
|
-
var
|
|
50710
|
-
var
|
|
50965
|
+
var fs32 = __toESM(require("fs"), 1);
|
|
50966
|
+
var path31 = __toESM(require("path"), 1);
|
|
50711
50967
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
50712
50968
|
var FILE_VERSION = 1;
|
|
50713
50969
|
var CapabilityStore = class {
|
|
50714
50970
|
constructor(dataDir) {
|
|
50715
50971
|
this.dataDir = dataDir;
|
|
50716
|
-
|
|
50972
|
+
fs32.mkdirSync(dataDir, { recursive: true });
|
|
50717
50973
|
this.cache = this.readFromDisk();
|
|
50718
50974
|
}
|
|
50719
50975
|
dataDir;
|
|
@@ -50737,13 +50993,13 @@ var CapabilityStore = class {
|
|
|
50737
50993
|
this.flush();
|
|
50738
50994
|
}
|
|
50739
50995
|
filePath() {
|
|
50740
|
-
return
|
|
50996
|
+
return path31.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
50741
50997
|
}
|
|
50742
50998
|
readFromDisk() {
|
|
50743
50999
|
const file = this.filePath();
|
|
50744
51000
|
let raw;
|
|
50745
51001
|
try {
|
|
50746
|
-
raw =
|
|
51002
|
+
raw = fs32.readFileSync(file, "utf8");
|
|
50747
51003
|
} catch (err) {
|
|
50748
51004
|
if (err?.code === "ENOENT") return [];
|
|
50749
51005
|
return [];
|
|
@@ -50771,10 +51027,10 @@ var CapabilityStore = class {
|
|
|
50771
51027
|
}
|
|
50772
51028
|
atomicWrite(file, content) {
|
|
50773
51029
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
50774
|
-
|
|
50775
|
-
|
|
51030
|
+
fs32.writeFileSync(tmp, content, { mode: 384 });
|
|
51031
|
+
fs32.renameSync(tmp, file);
|
|
50776
51032
|
try {
|
|
50777
|
-
|
|
51033
|
+
fs32.chmodSync(file, 384);
|
|
50778
51034
|
} catch {
|
|
50779
51035
|
}
|
|
50780
51036
|
}
|
|
@@ -50867,14 +51123,14 @@ var CapabilityManager = class {
|
|
|
50867
51123
|
};
|
|
50868
51124
|
|
|
50869
51125
|
// src/permission/cleanup.ts
|
|
50870
|
-
var
|
|
51126
|
+
var fs33 = __toESM(require("fs"), 1);
|
|
50871
51127
|
function cleanupGuestSessionsForCapability(cap, factory) {
|
|
50872
51128
|
const removed = [];
|
|
50873
51129
|
for (const g2 of cap.grants) {
|
|
50874
51130
|
if (g2.resource.type !== "persona") continue;
|
|
50875
51131
|
const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
|
|
50876
51132
|
try {
|
|
50877
|
-
|
|
51133
|
+
fs33.rmSync(dir, { recursive: true, force: true });
|
|
50878
51134
|
removed.push(dir);
|
|
50879
51135
|
} catch {
|
|
50880
51136
|
}
|
|
@@ -50883,13 +51139,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
50883
51139
|
}
|
|
50884
51140
|
|
|
50885
51141
|
// src/inbox/inbox-store.ts
|
|
50886
|
-
var
|
|
50887
|
-
var
|
|
51142
|
+
var fs34 = __toESM(require("fs"), 1);
|
|
51143
|
+
var path32 = __toESM(require("path"), 1);
|
|
50888
51144
|
var INBOX_SUBDIR = "inbox";
|
|
50889
51145
|
var InboxStore = class {
|
|
50890
51146
|
constructor(dataDir) {
|
|
50891
51147
|
this.dataDir = dataDir;
|
|
50892
|
-
|
|
51148
|
+
fs34.mkdirSync(this.dirPath(), { recursive: true });
|
|
50893
51149
|
}
|
|
50894
51150
|
dataDir;
|
|
50895
51151
|
/**
|
|
@@ -50901,7 +51157,7 @@ var InboxStore = class {
|
|
|
50901
51157
|
const file = this.filePath(peerDeviceId);
|
|
50902
51158
|
let raw;
|
|
50903
51159
|
try {
|
|
50904
|
-
raw =
|
|
51160
|
+
raw = fs34.readFileSync(file, "utf8");
|
|
50905
51161
|
} catch (err) {
|
|
50906
51162
|
if (err?.code === "ENOENT") return [];
|
|
50907
51163
|
return [];
|
|
@@ -50917,7 +51173,7 @@ var InboxStore = class {
|
|
|
50917
51173
|
const dir = this.dirPath();
|
|
50918
51174
|
let entries;
|
|
50919
51175
|
try {
|
|
50920
|
-
entries =
|
|
51176
|
+
entries = fs34.readdirSync(dir);
|
|
50921
51177
|
} catch (err) {
|
|
50922
51178
|
if (err?.code === "ENOENT") return [];
|
|
50923
51179
|
return [];
|
|
@@ -50933,9 +51189,9 @@ var InboxStore = class {
|
|
|
50933
51189
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
50934
51190
|
const file = this.filePath(message.peerDeviceId);
|
|
50935
51191
|
const line = JSON.stringify(message) + "\n";
|
|
50936
|
-
|
|
51192
|
+
fs34.appendFileSync(file, line, { mode: 384 });
|
|
50937
51193
|
try {
|
|
50938
|
-
|
|
51194
|
+
fs34.chmodSync(file, 384);
|
|
50939
51195
|
} catch {
|
|
50940
51196
|
}
|
|
50941
51197
|
}
|
|
@@ -50965,7 +51221,7 @@ var InboxStore = class {
|
|
|
50965
51221
|
removeByPeerDeviceId(peerDeviceId) {
|
|
50966
51222
|
const file = this.filePath(peerDeviceId);
|
|
50967
51223
|
try {
|
|
50968
|
-
|
|
51224
|
+
fs34.unlinkSync(file);
|
|
50969
51225
|
} catch (err) {
|
|
50970
51226
|
if (err?.code === "ENOENT") return;
|
|
50971
51227
|
}
|
|
@@ -50974,18 +51230,18 @@ var InboxStore = class {
|
|
|
50974
51230
|
const file = this.filePath(peerDeviceId);
|
|
50975
51231
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
50976
51232
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
50977
|
-
|
|
50978
|
-
|
|
51233
|
+
fs34.writeFileSync(tmp, content, { mode: 384 });
|
|
51234
|
+
fs34.renameSync(tmp, file);
|
|
50979
51235
|
try {
|
|
50980
|
-
|
|
51236
|
+
fs34.chmodSync(file, 384);
|
|
50981
51237
|
} catch {
|
|
50982
51238
|
}
|
|
50983
51239
|
}
|
|
50984
51240
|
dirPath() {
|
|
50985
|
-
return
|
|
51241
|
+
return path32.join(this.dataDir, INBOX_SUBDIR);
|
|
50986
51242
|
}
|
|
50987
51243
|
filePath(peerDeviceId) {
|
|
50988
|
-
return
|
|
51244
|
+
return path32.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
50989
51245
|
}
|
|
50990
51246
|
};
|
|
50991
51247
|
function parseAllLines(raw) {
|
|
@@ -51073,8 +51329,8 @@ var InboxManager = class {
|
|
|
51073
51329
|
};
|
|
51074
51330
|
|
|
51075
51331
|
// src/state/contact-store.ts
|
|
51076
|
-
var
|
|
51077
|
-
var
|
|
51332
|
+
var fs35 = __toESM(require("fs"), 1);
|
|
51333
|
+
var path33 = __toESM(require("path"), 1);
|
|
51078
51334
|
var FILE_NAME = "contacts.json";
|
|
51079
51335
|
var ContactStore = class {
|
|
51080
51336
|
constructor(dataDir) {
|
|
@@ -51084,10 +51340,10 @@ var ContactStore = class {
|
|
|
51084
51340
|
contacts = /* @__PURE__ */ new Map();
|
|
51085
51341
|
load() {
|
|
51086
51342
|
this.contacts.clear();
|
|
51087
|
-
const file =
|
|
51343
|
+
const file = path33.join(this.dataDir, FILE_NAME);
|
|
51088
51344
|
let raw;
|
|
51089
51345
|
try {
|
|
51090
|
-
raw =
|
|
51346
|
+
raw = fs35.readFileSync(file, "utf8");
|
|
51091
51347
|
} catch (err) {
|
|
51092
51348
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
51093
51349
|
return;
|
|
@@ -51156,20 +51412,20 @@ var ContactStore = class {
|
|
|
51156
51412
|
return true;
|
|
51157
51413
|
}
|
|
51158
51414
|
flush() {
|
|
51159
|
-
const file =
|
|
51415
|
+
const file = path33.join(this.dataDir, FILE_NAME);
|
|
51160
51416
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
51161
51417
|
const content = JSON.stringify(
|
|
51162
51418
|
{ contacts: Array.from(this.contacts.values()) },
|
|
51163
51419
|
null,
|
|
51164
51420
|
2
|
|
51165
51421
|
);
|
|
51166
|
-
|
|
51167
|
-
|
|
51168
|
-
|
|
51422
|
+
fs35.mkdirSync(this.dataDir, { recursive: true });
|
|
51423
|
+
fs35.writeFileSync(tmp, content, { mode: 384 });
|
|
51424
|
+
fs35.renameSync(tmp, file);
|
|
51169
51425
|
}
|
|
51170
51426
|
renameBak(file) {
|
|
51171
51427
|
try {
|
|
51172
|
-
|
|
51428
|
+
fs35.renameSync(file, `${file}.bak`);
|
|
51173
51429
|
} catch {
|
|
51174
51430
|
}
|
|
51175
51431
|
}
|
|
@@ -51322,61 +51578,61 @@ async function autoReverseContact(args) {
|
|
|
51322
51578
|
}
|
|
51323
51579
|
|
|
51324
51580
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
51325
|
-
var
|
|
51326
|
-
var
|
|
51581
|
+
var fs36 = __toESM(require("fs"), 1);
|
|
51582
|
+
var path34 = __toESM(require("path"), 1);
|
|
51327
51583
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
51328
51584
|
function migrateFlattenSessions(opts) {
|
|
51329
51585
|
const dataDir = opts.dataDir;
|
|
51330
51586
|
const now = opts.now ?? Date.now;
|
|
51331
|
-
const sessionsDir =
|
|
51332
|
-
const flagPath =
|
|
51587
|
+
const sessionsDir = path34.join(dataDir, "sessions");
|
|
51588
|
+
const flagPath = path34.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
51333
51589
|
if (existsSync3(flagPath)) {
|
|
51334
51590
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
51335
51591
|
}
|
|
51336
51592
|
let movedBare = 0;
|
|
51337
51593
|
let movedVmOwner = 0;
|
|
51338
51594
|
let archivedListener = 0;
|
|
51339
|
-
const defaultDir =
|
|
51595
|
+
const defaultDir = path34.join(sessionsDir, "default");
|
|
51340
51596
|
if (existsSync3(defaultDir)) {
|
|
51341
51597
|
for (const entry of readdirSafe(defaultDir)) {
|
|
51342
51598
|
if (!entry.endsWith(".json")) continue;
|
|
51343
|
-
const src =
|
|
51344
|
-
const dst =
|
|
51345
|
-
|
|
51599
|
+
const src = path34.join(defaultDir, entry);
|
|
51600
|
+
const dst = path34.join(sessionsDir, entry);
|
|
51601
|
+
fs36.renameSync(src, dst);
|
|
51346
51602
|
movedBare += 1;
|
|
51347
51603
|
}
|
|
51348
51604
|
rmdirIfEmpty(defaultDir);
|
|
51349
51605
|
}
|
|
51350
51606
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
51351
|
-
const personaDir =
|
|
51607
|
+
const personaDir = path34.join(sessionsDir, pid);
|
|
51352
51608
|
if (!isDir(personaDir)) continue;
|
|
51353
51609
|
if (pid === "default") continue;
|
|
51354
|
-
const ownerSrc =
|
|
51610
|
+
const ownerSrc = path34.join(personaDir, "owner");
|
|
51355
51611
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
51356
|
-
const ownerDst =
|
|
51357
|
-
|
|
51612
|
+
const ownerDst = path34.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
51613
|
+
fs36.mkdirSync(ownerDst, { recursive: true });
|
|
51358
51614
|
for (const file of readdirSafe(ownerSrc)) {
|
|
51359
51615
|
if (!file.endsWith(".json")) continue;
|
|
51360
|
-
|
|
51616
|
+
fs36.renameSync(path34.join(ownerSrc, file), path34.join(ownerDst, file));
|
|
51361
51617
|
movedVmOwner += 1;
|
|
51362
51618
|
}
|
|
51363
51619
|
rmdirIfEmpty(ownerSrc);
|
|
51364
51620
|
}
|
|
51365
|
-
const listenerSrc =
|
|
51621
|
+
const listenerSrc = path34.join(personaDir, "listener");
|
|
51366
51622
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
51367
|
-
const archiveDst =
|
|
51368
|
-
|
|
51623
|
+
const archiveDst = path34.join(dataDir, ".legacy", `listener-${pid}`);
|
|
51624
|
+
fs36.mkdirSync(archiveDst, { recursive: true });
|
|
51369
51625
|
for (const file of readdirSafe(listenerSrc)) {
|
|
51370
51626
|
if (!file.endsWith(".json")) continue;
|
|
51371
|
-
|
|
51627
|
+
fs36.renameSync(path34.join(listenerSrc, file), path34.join(archiveDst, file));
|
|
51372
51628
|
archivedListener += 1;
|
|
51373
51629
|
}
|
|
51374
51630
|
rmdirIfEmpty(listenerSrc);
|
|
51375
51631
|
}
|
|
51376
51632
|
rmdirIfEmpty(personaDir);
|
|
51377
51633
|
}
|
|
51378
|
-
|
|
51379
|
-
|
|
51634
|
+
fs36.mkdirSync(sessionsDir, { recursive: true });
|
|
51635
|
+
fs36.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
51380
51636
|
return {
|
|
51381
51637
|
skipped: false,
|
|
51382
51638
|
flagWritten: true,
|
|
@@ -51387,7 +51643,7 @@ function migrateFlattenSessions(opts) {
|
|
|
51387
51643
|
}
|
|
51388
51644
|
function existsSync3(p2) {
|
|
51389
51645
|
try {
|
|
51390
|
-
|
|
51646
|
+
fs36.statSync(p2);
|
|
51391
51647
|
return true;
|
|
51392
51648
|
} catch {
|
|
51393
51649
|
return false;
|
|
@@ -51395,31 +51651,31 @@ function existsSync3(p2) {
|
|
|
51395
51651
|
}
|
|
51396
51652
|
function isDir(p2) {
|
|
51397
51653
|
try {
|
|
51398
|
-
return
|
|
51654
|
+
return fs36.statSync(p2).isDirectory();
|
|
51399
51655
|
} catch {
|
|
51400
51656
|
return false;
|
|
51401
51657
|
}
|
|
51402
51658
|
}
|
|
51403
51659
|
function readdirSafe(p2) {
|
|
51404
51660
|
try {
|
|
51405
|
-
return
|
|
51661
|
+
return fs36.readdirSync(p2);
|
|
51406
51662
|
} catch {
|
|
51407
51663
|
return [];
|
|
51408
51664
|
}
|
|
51409
51665
|
}
|
|
51410
51666
|
function rmdirIfEmpty(p2) {
|
|
51411
51667
|
try {
|
|
51412
|
-
|
|
51668
|
+
fs36.rmdirSync(p2);
|
|
51413
51669
|
} catch {
|
|
51414
51670
|
}
|
|
51415
51671
|
}
|
|
51416
51672
|
|
|
51417
51673
|
// src/transport/http-router.ts
|
|
51418
51674
|
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
51419
|
-
var
|
|
51675
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
51420
51676
|
|
|
51421
51677
|
// src/attachment/mime.ts
|
|
51422
|
-
var
|
|
51678
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
51423
51679
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
51424
51680
|
var EXT_TO_NATIVE_MIME = {
|
|
51425
51681
|
// 图片
|
|
@@ -51526,7 +51782,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
51526
51782
|
".mk"
|
|
51527
51783
|
]);
|
|
51528
51784
|
function lookupMime(filePathOrName) {
|
|
51529
|
-
const ext =
|
|
51785
|
+
const ext = import_node_path27.default.extname(filePathOrName).toLowerCase();
|
|
51530
51786
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
51531
51787
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
51532
51788
|
return "application/octet-stream";
|
|
@@ -51596,9 +51852,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
51596
51852
|
|
|
51597
51853
|
// src/attachment/upload.ts
|
|
51598
51854
|
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
51599
|
-
var
|
|
51855
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
51600
51856
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
51601
|
-
var
|
|
51857
|
+
var import_promises3 = require("stream/promises");
|
|
51602
51858
|
var UploadError = class extends Error {
|
|
51603
51859
|
constructor(code, message) {
|
|
51604
51860
|
super(message);
|
|
@@ -51608,14 +51864,14 @@ var UploadError = class extends Error {
|
|
|
51608
51864
|
code;
|
|
51609
51865
|
};
|
|
51610
51866
|
function assertValidFileName(fileName) {
|
|
51611
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
51867
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path28.default.basename(fileName)) {
|
|
51612
51868
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
51613
51869
|
}
|
|
51614
51870
|
}
|
|
51615
51871
|
var HASH_PREFIX_LEN = 16;
|
|
51616
51872
|
async function writeUploadedAttachment(args) {
|
|
51617
51873
|
assertValidFileName(args.fileName);
|
|
51618
|
-
const attachmentsRoot =
|
|
51874
|
+
const attachmentsRoot = import_node_path28.default.join(args.sessionDir, ".attachments");
|
|
51619
51875
|
try {
|
|
51620
51876
|
import_node_fs28.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
51621
51877
|
} catch (err) {
|
|
@@ -51623,12 +51879,12 @@ async function writeUploadedAttachment(args) {
|
|
|
51623
51879
|
}
|
|
51624
51880
|
const hasher = import_node_crypto8.default.createHash("sha256");
|
|
51625
51881
|
let actualSize = 0;
|
|
51626
|
-
const tmpPath =
|
|
51882
|
+
const tmpPath = import_node_path28.default.join(
|
|
51627
51883
|
attachmentsRoot,
|
|
51628
51884
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
|
|
51629
51885
|
);
|
|
51630
51886
|
try {
|
|
51631
|
-
await (0,
|
|
51887
|
+
await (0, import_promises3.pipeline)(
|
|
51632
51888
|
args.body,
|
|
51633
51889
|
async function* (source) {
|
|
51634
51890
|
for await (const chunk of source) {
|
|
@@ -51658,7 +51914,7 @@ async function writeUploadedAttachment(args) {
|
|
|
51658
51914
|
);
|
|
51659
51915
|
}
|
|
51660
51916
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
51661
|
-
const hashDir =
|
|
51917
|
+
const hashDir = import_node_path28.default.join(attachmentsRoot, attachmentId);
|
|
51662
51918
|
let finalFileName;
|
|
51663
51919
|
let hashDirExists = false;
|
|
51664
51920
|
try {
|
|
@@ -51676,7 +51932,7 @@ async function writeUploadedAttachment(args) {
|
|
|
51676
51932
|
try {
|
|
51677
51933
|
import_node_fs28.default.mkdirSync(hashDir, { recursive: true });
|
|
51678
51934
|
finalFileName = args.fileName;
|
|
51679
|
-
import_node_fs28.default.renameSync(tmpPath,
|
|
51935
|
+
import_node_fs28.default.renameSync(tmpPath, import_node_path28.default.join(hashDir, finalFileName));
|
|
51680
51936
|
} catch (err) {
|
|
51681
51937
|
try {
|
|
51682
51938
|
import_node_fs28.default.unlinkSync(tmpPath);
|
|
@@ -51685,8 +51941,8 @@ async function writeUploadedAttachment(args) {
|
|
|
51685
51941
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
51686
51942
|
}
|
|
51687
51943
|
}
|
|
51688
|
-
const absPath =
|
|
51689
|
-
const relPath =
|
|
51944
|
+
const absPath = import_node_path28.default.join(hashDir, finalFileName);
|
|
51945
|
+
const relPath = import_node_path28.default.relative(args.sessionDir, absPath);
|
|
51690
51946
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
51691
51947
|
relPath: absPath,
|
|
51692
51948
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -51699,8 +51955,8 @@ async function writeUploadedAttachment(args) {
|
|
|
51699
51955
|
}
|
|
51700
51956
|
|
|
51701
51957
|
// src/extension/import.ts
|
|
51702
|
-
var
|
|
51703
|
-
var
|
|
51958
|
+
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
51959
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
51704
51960
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
51705
51961
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
51706
51962
|
var ImportError = class extends Error {
|
|
@@ -51718,7 +51974,7 @@ async function importZip(buf, root) {
|
|
|
51718
51974
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
51719
51975
|
}
|
|
51720
51976
|
for (const name of Object.keys(zip.files)) {
|
|
51721
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
51977
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path29.default.isAbsolute(name)) {
|
|
51722
51978
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
51723
51979
|
}
|
|
51724
51980
|
}
|
|
@@ -51751,33 +52007,33 @@ async function importZip(buf, root) {
|
|
|
51751
52007
|
);
|
|
51752
52008
|
}
|
|
51753
52009
|
}
|
|
51754
|
-
const destDir =
|
|
52010
|
+
const destDir = import_node_path29.default.join(root, manifest.id);
|
|
51755
52011
|
let destExists = false;
|
|
51756
52012
|
try {
|
|
51757
|
-
await
|
|
52013
|
+
await import_promises4.default.access(destDir);
|
|
51758
52014
|
destExists = true;
|
|
51759
52015
|
} catch {
|
|
51760
52016
|
}
|
|
51761
52017
|
if (destExists) {
|
|
51762
52018
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
51763
52019
|
}
|
|
51764
|
-
const stage = await
|
|
52020
|
+
const stage = await import_promises4.default.mkdtemp(import_node_path29.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
51765
52021
|
try {
|
|
51766
52022
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
51767
|
-
const dest =
|
|
52023
|
+
const dest = import_node_path29.default.join(stage, name);
|
|
51768
52024
|
if (entry.dir) {
|
|
51769
|
-
await
|
|
52025
|
+
await import_promises4.default.mkdir(dest, { recursive: true });
|
|
51770
52026
|
continue;
|
|
51771
52027
|
}
|
|
51772
|
-
await
|
|
52028
|
+
await import_promises4.default.mkdir(import_node_path29.default.dirname(dest), { recursive: true });
|
|
51773
52029
|
const content = await entry.async("nodebuffer");
|
|
51774
|
-
await
|
|
52030
|
+
await import_promises4.default.writeFile(dest, content);
|
|
51775
52031
|
}
|
|
51776
|
-
await
|
|
51777
|
-
await
|
|
52032
|
+
await import_promises4.default.mkdir(root, { recursive: true });
|
|
52033
|
+
await import_promises4.default.rename(stage, destDir);
|
|
51778
52034
|
return { extId: manifest.id };
|
|
51779
52035
|
} catch (e) {
|
|
51780
|
-
await
|
|
52036
|
+
await import_promises4.default.rm(stage, { recursive: true, force: true }).catch(() => {
|
|
51781
52037
|
});
|
|
51782
52038
|
throw e;
|
|
51783
52039
|
}
|
|
@@ -51800,7 +52056,7 @@ var SHARE_UI_ASSET_MIME = {
|
|
|
51800
52056
|
".wasm": "application/wasm"
|
|
51801
52057
|
};
|
|
51802
52058
|
function shareUiAssetMime(filePath) {
|
|
51803
|
-
const ext =
|
|
52059
|
+
const ext = import_node_path30.default.extname(filePath).toLowerCase();
|
|
51804
52060
|
return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
|
|
51805
52061
|
}
|
|
51806
52062
|
var DISPATCH_HEARTBEAT_MS = 25e3;
|
|
@@ -51887,7 +52143,7 @@ function isValidUploadFileName(fileName) {
|
|
|
51887
52143
|
if (fileName === "." || fileName === "..") return false;
|
|
51888
52144
|
if (fileName.startsWith(".")) return false;
|
|
51889
52145
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
51890
|
-
return fileName ===
|
|
52146
|
+
return fileName === import_node_path30.default.basename(fileName);
|
|
51891
52147
|
}
|
|
51892
52148
|
function createHttpRouter(deps) {
|
|
51893
52149
|
return async (req, res) => {
|
|
@@ -52183,7 +52439,7 @@ function createHttpRouter(deps) {
|
|
|
52183
52439
|
sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
|
|
52184
52440
|
return true;
|
|
52185
52441
|
}
|
|
52186
|
-
sendHtml(res, 200, loader.renderViewerHtml(
|
|
52442
|
+
sendHtml(res, 200, loader.renderViewerHtml(import_node_path30.default.basename(r.absPath)));
|
|
52187
52443
|
return true;
|
|
52188
52444
|
}
|
|
52189
52445
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
@@ -52304,7 +52560,7 @@ function createHttpRouter(deps) {
|
|
|
52304
52560
|
return true;
|
|
52305
52561
|
}
|
|
52306
52562
|
let absPath;
|
|
52307
|
-
if (
|
|
52563
|
+
if (import_node_path30.default.isAbsolute(pathParam)) {
|
|
52308
52564
|
absPath = pathParam;
|
|
52309
52565
|
} else if (deps.sessionStore) {
|
|
52310
52566
|
const file = deps.sessionStore.read(sid);
|
|
@@ -52312,7 +52568,7 @@ function createHttpRouter(deps) {
|
|
|
52312
52568
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
52313
52569
|
return true;
|
|
52314
52570
|
}
|
|
52315
|
-
absPath =
|
|
52571
|
+
absPath = import_node_path30.default.join(file.cwd, pathParam);
|
|
52316
52572
|
} else {
|
|
52317
52573
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
52318
52574
|
return true;
|
|
@@ -52414,7 +52670,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52414
52670
|
return;
|
|
52415
52671
|
}
|
|
52416
52672
|
const mime = lookupMime(absPath);
|
|
52417
|
-
const basename =
|
|
52673
|
+
const basename = import_node_path30.default.basename(absPath);
|
|
52418
52674
|
res.writeHead(200, {
|
|
52419
52675
|
"Content-Type": mime,
|
|
52420
52676
|
"Content-Length": String(stat.size),
|
|
@@ -52432,7 +52688,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52432
52688
|
|
|
52433
52689
|
// src/attachment/gc.ts
|
|
52434
52690
|
var import_node_fs30 = __toESM(require("fs"), 1);
|
|
52435
|
-
var
|
|
52691
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
52436
52692
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
52437
52693
|
function runAttachmentGc(args) {
|
|
52438
52694
|
const now = (args.now ?? Date.now)();
|
|
@@ -52441,17 +52697,17 @@ function runAttachmentGc(args) {
|
|
|
52441
52697
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52442
52698
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
52443
52699
|
if (entry.stale) continue;
|
|
52444
|
-
if (
|
|
52700
|
+
if (import_node_path31.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
52445
52701
|
}
|
|
52446
52702
|
}
|
|
52447
52703
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52448
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
52704
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path31.default.join(
|
|
52449
52705
|
args.dataDir,
|
|
52450
52706
|
"sessions",
|
|
52451
52707
|
...scopeSubPath(scope).map(safeFileName),
|
|
52452
52708
|
safeFileName(sessionId)
|
|
52453
52709
|
);
|
|
52454
|
-
const attRoot =
|
|
52710
|
+
const attRoot = import_node_path31.default.join(sessionDir, ".attachments");
|
|
52455
52711
|
let hashDirs;
|
|
52456
52712
|
try {
|
|
52457
52713
|
hashDirs = import_node_fs30.default.readdirSync(attRoot);
|
|
@@ -52461,7 +52717,7 @@ function runAttachmentGc(args) {
|
|
|
52461
52717
|
continue;
|
|
52462
52718
|
}
|
|
52463
52719
|
for (const hashDir of hashDirs) {
|
|
52464
|
-
const hashDirAbs =
|
|
52720
|
+
const hashDirAbs = import_node_path31.default.join(attRoot, hashDir);
|
|
52465
52721
|
let files;
|
|
52466
52722
|
try {
|
|
52467
52723
|
files = import_node_fs30.default.readdirSync(hashDirAbs);
|
|
@@ -52469,7 +52725,7 @@ function runAttachmentGc(args) {
|
|
|
52469
52725
|
continue;
|
|
52470
52726
|
}
|
|
52471
52727
|
for (const name of files) {
|
|
52472
|
-
const file =
|
|
52728
|
+
const file = import_node_path31.default.join(hashDirAbs, name);
|
|
52473
52729
|
let stat;
|
|
52474
52730
|
try {
|
|
52475
52731
|
stat = import_node_fs30.default.statSync(file);
|
|
@@ -52500,7 +52756,7 @@ function runAttachmentGc(args) {
|
|
|
52500
52756
|
|
|
52501
52757
|
// src/attachment/group.ts
|
|
52502
52758
|
var import_node_fs31 = __toESM(require("fs"), 1);
|
|
52503
|
-
var
|
|
52759
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
52504
52760
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
52505
52761
|
init_protocol();
|
|
52506
52762
|
var GroupFileStore = class {
|
|
@@ -52512,11 +52768,11 @@ var GroupFileStore = class {
|
|
|
52512
52768
|
this.logger = opts.logger;
|
|
52513
52769
|
}
|
|
52514
52770
|
rootForScope(scope) {
|
|
52515
|
-
return
|
|
52771
|
+
return import_node_path32.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
52516
52772
|
}
|
|
52517
52773
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
52518
52774
|
filePath(scope, sessionId) {
|
|
52519
|
-
return
|
|
52775
|
+
return import_node_path32.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
52520
52776
|
}
|
|
52521
52777
|
cacheKey(scope, sessionId) {
|
|
52522
52778
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -52551,7 +52807,7 @@ var GroupFileStore = class {
|
|
|
52551
52807
|
}
|
|
52552
52808
|
writeFile(scope, sessionId, entries) {
|
|
52553
52809
|
const file = this.filePath(scope, sessionId);
|
|
52554
|
-
import_node_fs31.default.mkdirSync(
|
|
52810
|
+
import_node_fs31.default.mkdirSync(import_node_path32.default.dirname(file), { recursive: true });
|
|
52555
52811
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
52556
52812
|
import_node_fs31.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
52557
52813
|
import_node_fs31.default.renameSync(tmp, file);
|
|
@@ -52641,9 +52897,9 @@ var GroupFileStore = class {
|
|
|
52641
52897
|
|
|
52642
52898
|
// src/discovery/state-file.ts
|
|
52643
52899
|
var import_node_fs32 = __toESM(require("fs"), 1);
|
|
52644
|
-
var
|
|
52900
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
52645
52901
|
function defaultStateFilePath(dataDir) {
|
|
52646
|
-
return
|
|
52902
|
+
return import_node_path33.default.join(dataDir, "state.json");
|
|
52647
52903
|
}
|
|
52648
52904
|
function isPidAlive(pid) {
|
|
52649
52905
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -52679,7 +52935,7 @@ var StateFileManager = class {
|
|
|
52679
52935
|
return { status: "stale", existing };
|
|
52680
52936
|
}
|
|
52681
52937
|
write(state) {
|
|
52682
|
-
import_node_fs32.default.mkdirSync(
|
|
52938
|
+
import_node_fs32.default.mkdirSync(import_node_path33.default.dirname(this.file), { recursive: true });
|
|
52683
52939
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
52684
52940
|
import_node_fs32.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
52685
52941
|
import_node_fs32.default.renameSync(tmp, this.file);
|
|
@@ -52707,13 +52963,13 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
|
|
|
52707
52963
|
|
|
52708
52964
|
// src/tunnel/tunnel-manager.ts
|
|
52709
52965
|
var import_node_fs36 = __toESM(require("fs"), 1);
|
|
52710
|
-
var
|
|
52966
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
52711
52967
|
var import_node_crypto10 = __toESM(require("crypto"), 1);
|
|
52712
52968
|
var import_node_child_process9 = require("child_process");
|
|
52713
52969
|
|
|
52714
52970
|
// src/tunnel/tunnel-store.ts
|
|
52715
52971
|
var import_node_fs33 = __toESM(require("fs"), 1);
|
|
52716
|
-
var
|
|
52972
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
52717
52973
|
var TunnelStore = class {
|
|
52718
52974
|
constructor(filePath) {
|
|
52719
52975
|
this.filePath = filePath;
|
|
@@ -52732,7 +52988,7 @@ var TunnelStore = class {
|
|
|
52732
52988
|
}
|
|
52733
52989
|
}
|
|
52734
52990
|
async set(v2) {
|
|
52735
|
-
const dir =
|
|
52991
|
+
const dir = import_node_path34.default.dirname(this.filePath);
|
|
52736
52992
|
await import_node_fs33.default.promises.mkdir(dir, { recursive: true });
|
|
52737
52993
|
const data = JSON.stringify(v2, null, 2);
|
|
52738
52994
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
@@ -52844,10 +53100,10 @@ function escape(v2) {
|
|
|
52844
53100
|
// src/tunnel/frpc-binary.ts
|
|
52845
53101
|
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
52846
53102
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
52847
|
-
var
|
|
53103
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
52848
53104
|
var import_node_child_process7 = require("child_process");
|
|
52849
53105
|
var import_node_stream3 = require("stream");
|
|
52850
|
-
var
|
|
53106
|
+
var import_promises5 = require("stream/promises");
|
|
52851
53107
|
var FRPC_VERSION = "0.68.0";
|
|
52852
53108
|
var UnsupportedPlatformError = class extends Error {
|
|
52853
53109
|
constructor(platform, arch) {
|
|
@@ -52883,13 +53139,13 @@ async function ensureFrpcBinary(opts) {
|
|
|
52883
53139
|
}
|
|
52884
53140
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
52885
53141
|
const platform = opts.platform ?? detectPlatform();
|
|
52886
|
-
const binDir =
|
|
53142
|
+
const binDir = import_node_path35.default.join(opts.dataDir, "bin");
|
|
52887
53143
|
import_node_fs34.default.mkdirSync(binDir, { recursive: true });
|
|
52888
53144
|
cleanupStaleArtifacts(binDir);
|
|
52889
|
-
const stableBin =
|
|
53145
|
+
const stableBin = import_node_path35.default.join(binDir, "frpc");
|
|
52890
53146
|
if (import_node_fs34.default.existsSync(stableBin)) return stableBin;
|
|
52891
53147
|
const partialBin = `${stableBin}.partial`;
|
|
52892
|
-
const tarballPath =
|
|
53148
|
+
const tarballPath = import_node_path35.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
52893
53149
|
try {
|
|
52894
53150
|
const url = frpcDownloadUrl(version2, platform);
|
|
52895
53151
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -52915,7 +53171,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
52915
53171
|
}
|
|
52916
53172
|
for (const name of entries) {
|
|
52917
53173
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
52918
|
-
const full =
|
|
53174
|
+
const full = import_node_path35.default.join(binDir, name);
|
|
52919
53175
|
try {
|
|
52920
53176
|
import_node_fs34.default.rmSync(full, { recursive: true, force: true });
|
|
52921
53177
|
} catch {
|
|
@@ -52938,10 +53194,10 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
52938
53194
|
}
|
|
52939
53195
|
const out = import_node_fs34.default.createWriteStream(dest);
|
|
52940
53196
|
const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
|
|
52941
|
-
await (0,
|
|
53197
|
+
await (0, import_promises5.pipeline)(nodeStream, out);
|
|
52942
53198
|
}
|
|
52943
53199
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
52944
|
-
const work =
|
|
53200
|
+
const work = import_node_path35.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
52945
53201
|
import_node_fs34.default.mkdirSync(work, { recursive: true });
|
|
52946
53202
|
try {
|
|
52947
53203
|
await new Promise((resolve6, reject) => {
|
|
@@ -52950,7 +53206,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
52950
53206
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
52951
53207
|
});
|
|
52952
53208
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
52953
|
-
const src =
|
|
53209
|
+
const src = import_node_path35.default.join(work, dirName, "frpc");
|
|
52954
53210
|
if (!import_node_fs34.default.existsSync(src)) {
|
|
52955
53211
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
52956
53212
|
}
|
|
@@ -52962,10 +53218,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
52962
53218
|
|
|
52963
53219
|
// src/tunnel/frpc-process.ts
|
|
52964
53220
|
var import_node_fs35 = __toESM(require("fs"), 1);
|
|
52965
|
-
var
|
|
53221
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
52966
53222
|
var import_node_child_process8 = require("child_process");
|
|
52967
53223
|
function frpcPidFilePath(dataDir) {
|
|
52968
|
-
return
|
|
53224
|
+
return import_node_path36.default.join(dataDir, "frpc.pid");
|
|
52969
53225
|
}
|
|
52970
53226
|
function writeFrpcPid(dataDir, pid) {
|
|
52971
53227
|
try {
|
|
@@ -53007,7 +53263,7 @@ function defaultSleep(ms) {
|
|
|
53007
53263
|
}
|
|
53008
53264
|
async function killStaleFrpc(deps) {
|
|
53009
53265
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
53010
|
-
const tomlPath =
|
|
53266
|
+
const tomlPath = import_node_path36.default.join(deps.dataDir, "frpc.toml");
|
|
53011
53267
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
53012
53268
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
53013
53269
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -53079,7 +53335,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
53079
53335
|
var TunnelManager = class {
|
|
53080
53336
|
constructor(deps) {
|
|
53081
53337
|
this.deps = deps;
|
|
53082
|
-
this.store = deps.store ?? new TunnelStore(
|
|
53338
|
+
this.store = deps.store ?? new TunnelStore(import_node_path37.default.join(deps.dataDir, "tunnel.json"));
|
|
53083
53339
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
53084
53340
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
53085
53341
|
}
|
|
@@ -53206,7 +53462,7 @@ var TunnelManager = class {
|
|
|
53206
53462
|
dataDir: this.deps.dataDir,
|
|
53207
53463
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
53208
53464
|
});
|
|
53209
|
-
const tomlPath =
|
|
53465
|
+
const tomlPath = import_node_path37.default.join(this.deps.dataDir, "frpc.toml");
|
|
53210
53466
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
|
|
53211
53467
|
const toml = buildFrpcToml({
|
|
53212
53468
|
serverAddr: t.frpsHost,
|
|
@@ -53221,9 +53477,9 @@ var TunnelManager = class {
|
|
|
53221
53477
|
const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
|
|
53222
53478
|
stdio: ["ignore", "pipe", "pipe"]
|
|
53223
53479
|
});
|
|
53224
|
-
const logDir =
|
|
53480
|
+
const logDir = import_node_path37.default.join(this.deps.dataDir, "log");
|
|
53225
53481
|
import_node_fs36.default.mkdirSync(logDir, { recursive: true });
|
|
53226
|
-
const logFilePath =
|
|
53482
|
+
const logFilePath = import_node_path37.default.join(logDir, "frpc.log");
|
|
53227
53483
|
const logStream = import_node_fs36.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
53228
53484
|
logStream.on("error", () => {
|
|
53229
53485
|
});
|
|
@@ -53307,15 +53563,15 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
53307
53563
|
|
|
53308
53564
|
// src/tunnel/device-key.ts
|
|
53309
53565
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
53310
|
-
var
|
|
53566
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
53311
53567
|
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
53312
53568
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
53313
53569
|
function deriveStableDeviceKey(opts = {}) {
|
|
53314
53570
|
const hostname = opts.hostname ?? import_node_os14.default.hostname();
|
|
53315
53571
|
const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
|
|
53316
53572
|
const home = opts.home ?? import_node_os14.default.homedir();
|
|
53317
|
-
const defaultDataDir =
|
|
53318
|
-
const normalizedDataDir = opts.dataDir ?
|
|
53573
|
+
const defaultDataDir = import_node_path38.default.resolve(import_node_path38.default.join(home, ".clawd"));
|
|
53574
|
+
const normalizedDataDir = opts.dataDir ? import_node_path38.default.resolve(opts.dataDir) : null;
|
|
53319
53575
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
53320
53576
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
53321
53577
|
return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
@@ -53323,11 +53579,11 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
53323
53579
|
|
|
53324
53580
|
// src/auth-store.ts
|
|
53325
53581
|
var import_node_fs37 = __toESM(require("fs"), 1);
|
|
53326
|
-
var
|
|
53582
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
53327
53583
|
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
53328
53584
|
var AUTH_FILE_NAME = "auth.json";
|
|
53329
53585
|
function authFilePath(dataDir) {
|
|
53330
|
-
return
|
|
53586
|
+
return import_node_path39.default.join(dataDir, AUTH_FILE_NAME);
|
|
53331
53587
|
}
|
|
53332
53588
|
function loadOrCreateAuthFile(opts) {
|
|
53333
53589
|
const file = authFilePath(opts.dataDir);
|
|
@@ -53383,7 +53639,7 @@ function readAuthFile(file) {
|
|
|
53383
53639
|
}
|
|
53384
53640
|
}
|
|
53385
53641
|
function writeAuthFile(file, content) {
|
|
53386
|
-
import_node_fs37.default.mkdirSync(
|
|
53642
|
+
import_node_fs37.default.mkdirSync(import_node_path39.default.dirname(file), { recursive: true });
|
|
53387
53643
|
import_node_fs37.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
53388
53644
|
try {
|
|
53389
53645
|
import_node_fs37.default.chmodSync(file, 384);
|
|
@@ -53394,11 +53650,11 @@ function writeAuthFile(file, content) {
|
|
|
53394
53650
|
// src/owner-profile.ts
|
|
53395
53651
|
var import_node_fs38 = __toESM(require("fs"), 1);
|
|
53396
53652
|
var import_node_os15 = __toESM(require("os"), 1);
|
|
53397
|
-
var
|
|
53653
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
53398
53654
|
var PROFILE_FILENAME = "profile.json";
|
|
53399
53655
|
function loadOwnerDisplayName(dataDir) {
|
|
53400
53656
|
const fallback = import_node_os15.default.userInfo().username;
|
|
53401
|
-
const profilePath =
|
|
53657
|
+
const profilePath = import_node_path40.default.join(dataDir, PROFILE_FILENAME);
|
|
53402
53658
|
let raw;
|
|
53403
53659
|
try {
|
|
53404
53660
|
raw = import_node_fs38.default.readFileSync(profilePath, "utf8");
|
|
@@ -53425,12 +53681,12 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
53425
53681
|
|
|
53426
53682
|
// src/feishu-auth/owner-identity-store.ts
|
|
53427
53683
|
var import_node_fs39 = __toESM(require("fs"), 1);
|
|
53428
|
-
var
|
|
53684
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
53429
53685
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
53430
53686
|
var OwnerIdentityStore = class {
|
|
53431
53687
|
file;
|
|
53432
53688
|
constructor(dataDir) {
|
|
53433
|
-
this.file =
|
|
53689
|
+
this.file = import_node_path41.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
53434
53690
|
}
|
|
53435
53691
|
read() {
|
|
53436
53692
|
let raw;
|
|
@@ -53463,7 +53719,7 @@ var OwnerIdentityStore = class {
|
|
|
53463
53719
|
};
|
|
53464
53720
|
}
|
|
53465
53721
|
write(record) {
|
|
53466
|
-
import_node_fs39.default.mkdirSync(
|
|
53722
|
+
import_node_fs39.default.mkdirSync(import_node_path41.default.dirname(this.file), { recursive: true });
|
|
53467
53723
|
import_node_fs39.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
53468
53724
|
try {
|
|
53469
53725
|
import_node_fs39.default.chmodSync(this.file, 384);
|
|
@@ -53609,9 +53865,9 @@ var CentralClientError = class extends Error {
|
|
|
53609
53865
|
code;
|
|
53610
53866
|
cause;
|
|
53611
53867
|
};
|
|
53612
|
-
async function centralRequest(opts,
|
|
53868
|
+
async function centralRequest(opts, path71, init) {
|
|
53613
53869
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
53614
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
53870
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path71}`;
|
|
53615
53871
|
const ctrl = new AbortController();
|
|
53616
53872
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
53617
53873
|
let res;
|
|
@@ -53805,8 +54061,8 @@ function verifyConnectToken(args) {
|
|
|
53805
54061
|
}
|
|
53806
54062
|
|
|
53807
54063
|
// src/feishu-auth/server-key.ts
|
|
53808
|
-
var
|
|
53809
|
-
var
|
|
54064
|
+
var fs50 = __toESM(require("fs"), 1);
|
|
54065
|
+
var path50 = __toESM(require("path"), 1);
|
|
53810
54066
|
var FILE_NAME2 = "server-signing-key.json";
|
|
53811
54067
|
var ServerKeyStore = class {
|
|
53812
54068
|
constructor(dataDir) {
|
|
@@ -53814,12 +54070,12 @@ var ServerKeyStore = class {
|
|
|
53814
54070
|
}
|
|
53815
54071
|
dataDir;
|
|
53816
54072
|
filePath() {
|
|
53817
|
-
return
|
|
54073
|
+
return path50.join(this.dataDir, FILE_NAME2);
|
|
53818
54074
|
}
|
|
53819
54075
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
53820
54076
|
read() {
|
|
53821
54077
|
try {
|
|
53822
|
-
const raw =
|
|
54078
|
+
const raw = fs50.readFileSync(this.filePath(), "utf8");
|
|
53823
54079
|
const parsed = JSON.parse(raw);
|
|
53824
54080
|
if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
|
|
53825
54081
|
return parsed.publicKeyPem;
|
|
@@ -53834,12 +54090,12 @@ var ServerKeyStore = class {
|
|
|
53834
54090
|
publicKeyPem,
|
|
53835
54091
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
53836
54092
|
};
|
|
53837
|
-
|
|
53838
|
-
|
|
54093
|
+
fs50.mkdirSync(this.dataDir, { recursive: true });
|
|
54094
|
+
fs50.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
|
|
53839
54095
|
}
|
|
53840
54096
|
clear() {
|
|
53841
54097
|
try {
|
|
53842
|
-
|
|
54098
|
+
fs50.unlinkSync(this.filePath());
|
|
53843
54099
|
} catch {
|
|
53844
54100
|
}
|
|
53845
54101
|
}
|
|
@@ -53854,7 +54110,7 @@ init_protocol();
|
|
|
53854
54110
|
// src/session/fork.ts
|
|
53855
54111
|
var import_node_fs40 = __toESM(require("fs"), 1);
|
|
53856
54112
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
53857
|
-
var
|
|
54113
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
53858
54114
|
init_claude_history();
|
|
53859
54115
|
function readJsonlEntries(file) {
|
|
53860
54116
|
const raw = import_node_fs40.default.readFileSync(file, "utf8");
|
|
@@ -53870,19 +54126,19 @@ function readJsonlEntries(file) {
|
|
|
53870
54126
|
return out;
|
|
53871
54127
|
}
|
|
53872
54128
|
function forkSession(input) {
|
|
53873
|
-
const baseDir = input.baseDir ??
|
|
53874
|
-
let projectDir =
|
|
53875
|
-
let sourceFile =
|
|
54129
|
+
const baseDir = input.baseDir ?? import_node_path42.default.join(import_node_os16.default.homedir(), ".claude");
|
|
54130
|
+
let projectDir = import_node_path42.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
54131
|
+
let sourceFile = import_node_path42.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
53876
54132
|
if (!import_node_fs40.default.existsSync(sourceFile)) {
|
|
53877
54133
|
const found = findTranscriptByToolSessionId(
|
|
53878
|
-
|
|
54134
|
+
import_node_path42.default.join(baseDir, "projects"),
|
|
53879
54135
|
input.toolSessionId
|
|
53880
54136
|
);
|
|
53881
54137
|
if (!found) {
|
|
53882
54138
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
53883
54139
|
}
|
|
53884
54140
|
sourceFile = found;
|
|
53885
|
-
projectDir =
|
|
54141
|
+
projectDir = import_node_path42.default.dirname(found);
|
|
53886
54142
|
}
|
|
53887
54143
|
const entries = readJsonlEntries(sourceFile);
|
|
53888
54144
|
const mainEntries = entries.filter((e) => e.isSidechain !== true);
|
|
@@ -53911,7 +54167,7 @@ function forkSession(input) {
|
|
|
53911
54167
|
}
|
|
53912
54168
|
forkedLines.push(JSON.stringify(forked));
|
|
53913
54169
|
}
|
|
53914
|
-
const forkedFilePath =
|
|
54170
|
+
const forkedFilePath = import_node_path42.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
53915
54171
|
import_node_fs40.default.mkdirSync(projectDir, { recursive: true });
|
|
53916
54172
|
import_node_fs40.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
53917
54173
|
return { forkedToolSessionId, forkedFilePath };
|
|
@@ -54311,7 +54567,7 @@ function buildPermissionHandlers(deps) {
|
|
|
54311
54567
|
}
|
|
54312
54568
|
|
|
54313
54569
|
// src/handlers/history.ts
|
|
54314
|
-
var
|
|
54570
|
+
var path53 = __toESM(require("path"), 1);
|
|
54315
54571
|
init_protocol();
|
|
54316
54572
|
|
|
54317
54573
|
// src/session/recent-dirs.ts
|
|
@@ -54329,7 +54585,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
54329
54585
|
}
|
|
54330
54586
|
|
|
54331
54587
|
// src/permission/persona-paths.ts
|
|
54332
|
-
var
|
|
54588
|
+
var path52 = __toESM(require("path"), 1);
|
|
54333
54589
|
function getAllowedPersonaIds(grants, action) {
|
|
54334
54590
|
const ids = /* @__PURE__ */ new Set();
|
|
54335
54591
|
for (const g2 of grants) {
|
|
@@ -54342,42 +54598,42 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
54342
54598
|
return ids;
|
|
54343
54599
|
}
|
|
54344
54600
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
54345
|
-
const target =
|
|
54601
|
+
const target = path52.resolve(absPath);
|
|
54346
54602
|
if (userWorkDir) {
|
|
54347
|
-
const u =
|
|
54348
|
-
const usep = u.endsWith(
|
|
54603
|
+
const u = path52.resolve(userWorkDir);
|
|
54604
|
+
const usep = u.endsWith(path52.sep) ? "" : path52.sep;
|
|
54349
54605
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
54350
54606
|
}
|
|
54351
|
-
const root =
|
|
54352
|
-
const sep3 = root.endsWith(
|
|
54607
|
+
const root = path52.resolve(personaRoot);
|
|
54608
|
+
const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
|
|
54353
54609
|
if (!target.startsWith(root + sep3)) return false;
|
|
54354
|
-
const rel =
|
|
54610
|
+
const rel = path52.relative(root, target);
|
|
54355
54611
|
if (!rel || rel.startsWith("..")) return false;
|
|
54356
|
-
const personaId = rel.split(
|
|
54612
|
+
const personaId = rel.split(path52.sep)[0];
|
|
54357
54613
|
if (!personaId) return false;
|
|
54358
54614
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
54359
54615
|
if (allowed === "*") return true;
|
|
54360
54616
|
return allowed.has(personaId);
|
|
54361
54617
|
}
|
|
54362
54618
|
function personaIdFromPath(absPath, personaRoot) {
|
|
54363
|
-
const root =
|
|
54364
|
-
const target =
|
|
54365
|
-
const sep3 = root.endsWith(
|
|
54619
|
+
const root = path52.resolve(personaRoot);
|
|
54620
|
+
const target = path52.resolve(absPath);
|
|
54621
|
+
const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
|
|
54366
54622
|
if (!target.startsWith(root + sep3)) return null;
|
|
54367
|
-
const rel =
|
|
54623
|
+
const rel = path52.relative(root, target);
|
|
54368
54624
|
if (!rel || rel.startsWith("..")) return null;
|
|
54369
|
-
const id = rel.split(
|
|
54625
|
+
const id = rel.split(path52.sep)[0];
|
|
54370
54626
|
return id || null;
|
|
54371
54627
|
}
|
|
54372
54628
|
function isPathWithin(dir, absPath) {
|
|
54373
|
-
const d =
|
|
54374
|
-
const t =
|
|
54375
|
-
const sep3 = d.endsWith(
|
|
54629
|
+
const d = path52.resolve(dir);
|
|
54630
|
+
const t = path52.resolve(absPath);
|
|
54631
|
+
const sep3 = d.endsWith(path52.sep) ? "" : path52.sep;
|
|
54376
54632
|
return t === d || t.startsWith(d + sep3);
|
|
54377
54633
|
}
|
|
54378
54634
|
function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
|
|
54379
54635
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
54380
|
-
return personaIdFromPath(
|
|
54636
|
+
return personaIdFromPath(path52.resolve(absPath), personaRoot) === personaId;
|
|
54381
54637
|
}
|
|
54382
54638
|
|
|
54383
54639
|
// src/handlers/history.ts
|
|
@@ -54429,7 +54685,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54429
54685
|
if (!pid) return false;
|
|
54430
54686
|
return isGuestPathAllowed(
|
|
54431
54687
|
ctx.grants,
|
|
54432
|
-
|
|
54688
|
+
path53.join(personaRoot, pid),
|
|
54433
54689
|
personaRoot,
|
|
54434
54690
|
"read",
|
|
54435
54691
|
userWorkDir
|
|
@@ -54441,7 +54697,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54441
54697
|
};
|
|
54442
54698
|
const list = async (frame, _client, ctx) => {
|
|
54443
54699
|
const args = HistoryListArgs.parse(frame);
|
|
54444
|
-
assertGuestPath(ctx,
|
|
54700
|
+
assertGuestPath(ctx, path53.resolve(args.projectPath), personaRoot, "history:list");
|
|
54445
54701
|
const sessions = await history.listSessions(args);
|
|
54446
54702
|
return { response: { type: "history:list", sessions } };
|
|
54447
54703
|
};
|
|
@@ -54474,13 +54730,13 @@ function buildHistoryHandlers(deps) {
|
|
|
54474
54730
|
};
|
|
54475
54731
|
const subagents = async (frame, _client, ctx) => {
|
|
54476
54732
|
const args = HistorySubagentsArgs.parse(frame);
|
|
54477
|
-
assertGuestPath(ctx,
|
|
54733
|
+
assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
54478
54734
|
const subs = await history.listSubagents(args);
|
|
54479
54735
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
54480
54736
|
};
|
|
54481
54737
|
const subagentRead = async (frame, _client, ctx) => {
|
|
54482
54738
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
54483
|
-
assertGuestPath(ctx,
|
|
54739
|
+
assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
54484
54740
|
const res = await history.readSubagent(args);
|
|
54485
54741
|
return { response: { type: "history:subagent-read", ...res } };
|
|
54486
54742
|
};
|
|
@@ -54489,7 +54745,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54489
54745
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
54490
54746
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
54491
54747
|
const filtered = dirs.filter(
|
|
54492
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
54748
|
+
(d) => isGuestPathAllowed(ctx.grants, path53.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
54493
54749
|
);
|
|
54494
54750
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
54495
54751
|
}
|
|
@@ -54506,7 +54762,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54506
54762
|
}
|
|
54507
54763
|
|
|
54508
54764
|
// src/handlers/workspace.ts
|
|
54509
|
-
var
|
|
54765
|
+
var path54 = __toESM(require("path"), 1);
|
|
54510
54766
|
var os16 = __toESM(require("os"), 1);
|
|
54511
54767
|
init_protocol();
|
|
54512
54768
|
init_protocol();
|
|
@@ -54548,22 +54804,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54548
54804
|
const args = WorkspaceListArgs.parse(frame);
|
|
54549
54805
|
const isGuest = ctx?.principal.kind === "guest";
|
|
54550
54806
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
|
|
54551
|
-
const resolvedCwd =
|
|
54552
|
-
const target = args.path ?
|
|
54807
|
+
const resolvedCwd = path54.resolve(args.cwd ?? fallbackCwd);
|
|
54808
|
+
const target = args.path ? path54.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
54553
54809
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
54554
54810
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
54555
54811
|
return { response: { type: "workspace:list", ...res } };
|
|
54556
54812
|
};
|
|
54557
54813
|
const read = async (frame, _client, ctx) => {
|
|
54558
54814
|
const args = WorkspaceReadArgs.parse(frame);
|
|
54559
|
-
const target =
|
|
54815
|
+
const target = path54.isAbsolute(args.path) ? path54.resolve(args.path) : path54.resolve(args.cwd, args.path);
|
|
54560
54816
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
54561
54817
|
const res = workspace.read(args);
|
|
54562
54818
|
return { response: { type: "workspace:read", ...res } };
|
|
54563
54819
|
};
|
|
54564
54820
|
const skillsList = async (frame, _client, ctx) => {
|
|
54565
54821
|
const args = SkillsListArgs.parse(frame);
|
|
54566
|
-
const cwdAbs =
|
|
54822
|
+
const cwdAbs = path54.resolve(args.cwd);
|
|
54567
54823
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
54568
54824
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
54569
54825
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -54575,7 +54831,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54575
54831
|
};
|
|
54576
54832
|
const agentsList = async (frame, _client, ctx) => {
|
|
54577
54833
|
const args = AgentsListArgs.parse(frame);
|
|
54578
|
-
const cwdAbs =
|
|
54834
|
+
const cwdAbs = path54.resolve(args.cwd);
|
|
54579
54835
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
54580
54836
|
if (args.tool === "codex") {
|
|
54581
54837
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -54597,18 +54853,18 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54597
54853
|
}
|
|
54598
54854
|
|
|
54599
54855
|
// src/handlers/git.ts
|
|
54600
|
-
var
|
|
54856
|
+
var path56 = __toESM(require("path"), 1);
|
|
54601
54857
|
init_protocol();
|
|
54602
54858
|
init_protocol();
|
|
54603
54859
|
|
|
54604
54860
|
// src/workspace/git.ts
|
|
54605
54861
|
var import_node_child_process10 = require("child_process");
|
|
54606
54862
|
var import_node_fs41 = __toESM(require("fs"), 1);
|
|
54607
|
-
var
|
|
54863
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
54608
54864
|
var import_node_util = require("util");
|
|
54609
54865
|
var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
|
|
54610
54866
|
function normalizePath(p2) {
|
|
54611
|
-
const resolved =
|
|
54867
|
+
const resolved = import_node_path43.default.resolve(p2);
|
|
54612
54868
|
try {
|
|
54613
54869
|
return import_node_fs41.default.realpathSync(resolved);
|
|
54614
54870
|
} catch {
|
|
@@ -54684,7 +54940,7 @@ async function listGitBranches(cwd) {
|
|
|
54684
54940
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
54685
54941
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
54686
54942
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
54687
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
54943
|
+
if (!isGuestPathAllowed(ctx.grants, path56.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
54688
54944
|
throw new ClawdError(
|
|
54689
54945
|
ERROR_CODES.UNAUTHORIZED,
|
|
54690
54946
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -55370,7 +55626,7 @@ function buildPersonaHandlers(deps) {
|
|
|
55370
55626
|
}
|
|
55371
55627
|
|
|
55372
55628
|
// src/handlers/attachment.ts
|
|
55373
|
-
var
|
|
55629
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
55374
55630
|
init_protocol();
|
|
55375
55631
|
init_protocol();
|
|
55376
55632
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -55450,12 +55706,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
55450
55706
|
`session ${args.sessionId} scope unresolved`
|
|
55451
55707
|
);
|
|
55452
55708
|
}
|
|
55453
|
-
const cwdAbs =
|
|
55454
|
-
const candidateAbs =
|
|
55709
|
+
const cwdAbs = import_node_path44.default.resolve(sessionFile.cwd);
|
|
55710
|
+
const candidateAbs = import_node_path44.default.isAbsolute(args.relPath) ? import_node_path44.default.resolve(args.relPath) : import_node_path44.default.resolve(cwdAbs, args.relPath);
|
|
55455
55711
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
|
|
55456
55712
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
55457
55713
|
const entry = entries.find((e) => {
|
|
55458
|
-
const storedAbs =
|
|
55714
|
+
const storedAbs = import_node_path44.default.isAbsolute(e.relPath) ? import_node_path44.default.resolve(e.relPath) : import_node_path44.default.resolve(cwdAbs, e.relPath);
|
|
55459
55715
|
return storedAbs === candidateAbs && !e.stale;
|
|
55460
55716
|
});
|
|
55461
55717
|
if (!entry) {
|
|
@@ -55480,7 +55736,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
55480
55736
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
55481
55737
|
const f = deps.sessionStore.read(sessionId);
|
|
55482
55738
|
if (!f) return;
|
|
55483
|
-
assertGuestAttachmentPath(ctx,
|
|
55739
|
+
assertGuestAttachmentPath(ctx, import_node_path44.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
55484
55740
|
}
|
|
55485
55741
|
const groupAdd = async (frame, _client, ctx) => {
|
|
55486
55742
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -55495,8 +55751,8 @@ function buildAttachmentHandlers(deps) {
|
|
|
55495
55751
|
if (!scope) {
|
|
55496
55752
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
|
|
55497
55753
|
}
|
|
55498
|
-
const cwdAbs =
|
|
55499
|
-
const candidateAbs =
|
|
55754
|
+
const cwdAbs = import_node_path44.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
|
|
55755
|
+
const candidateAbs = import_node_path44.default.isAbsolute(args.relPath) ? import_node_path44.default.resolve(args.relPath) : import_node_path44.default.resolve(cwdAbs, args.relPath);
|
|
55500
55756
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
|
|
55501
55757
|
const from = ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
55502
55758
|
const size = 0;
|
|
@@ -55554,21 +55810,21 @@ function buildAttachmentHandlers(deps) {
|
|
|
55554
55810
|
}
|
|
55555
55811
|
|
|
55556
55812
|
// src/handlers/extension.ts
|
|
55557
|
-
var
|
|
55558
|
-
var
|
|
55813
|
+
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
55814
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
55559
55815
|
init_protocol();
|
|
55560
55816
|
|
|
55561
55817
|
// src/extension/bundle-zip.ts
|
|
55562
|
-
var
|
|
55563
|
-
var
|
|
55818
|
+
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
55819
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
55564
55820
|
var import_node_crypto14 = __toESM(require("crypto"), 1);
|
|
55565
55821
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
55566
55822
|
async function bundleExtensionDir(dir) {
|
|
55567
55823
|
const entries = await listFilesSorted(dir);
|
|
55568
55824
|
const zip = new import_jszip2.default();
|
|
55569
55825
|
for (const rel of entries) {
|
|
55570
|
-
const abs =
|
|
55571
|
-
const content = await
|
|
55826
|
+
const abs = import_node_path45.default.join(dir, rel);
|
|
55827
|
+
const content = await import_promises6.default.readFile(abs);
|
|
55572
55828
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
55573
55829
|
}
|
|
55574
55830
|
const buffer = await zip.generateAsync({
|
|
@@ -55588,8 +55844,8 @@ async function listFilesSorted(rootDir) {
|
|
|
55588
55844
|
return out;
|
|
55589
55845
|
}
|
|
55590
55846
|
async function walk(absRoot, relPrefix, out) {
|
|
55591
|
-
const dirAbs =
|
|
55592
|
-
const entries = await
|
|
55847
|
+
const dirAbs = import_node_path45.default.join(absRoot, relPrefix);
|
|
55848
|
+
const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
|
|
55593
55849
|
for (const e of entries) {
|
|
55594
55850
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
55595
55851
|
const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
|
|
@@ -55641,26 +55897,26 @@ function computePublishCheck(args) {
|
|
|
55641
55897
|
}
|
|
55642
55898
|
|
|
55643
55899
|
// src/extension/install-flow.ts
|
|
55644
|
-
var
|
|
55645
|
-
var
|
|
55900
|
+
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
55901
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
55646
55902
|
var import_node_os19 = __toESM(require("os"), 1);
|
|
55647
55903
|
var import_node_crypto15 = __toESM(require("crypto"), 1);
|
|
55648
55904
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
55649
55905
|
|
|
55650
55906
|
// src/extension/paths.ts
|
|
55651
55907
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
55652
|
-
var
|
|
55908
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
55653
55909
|
function clawdHomeRoot(override) {
|
|
55654
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
55910
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path46.default.join(import_node_os18.default.homedir(), ".clawd");
|
|
55655
55911
|
}
|
|
55656
55912
|
function extensionsRoot(override) {
|
|
55657
|
-
return
|
|
55913
|
+
return import_node_path46.default.join(clawdHomeRoot(override), "extensions");
|
|
55658
55914
|
}
|
|
55659
55915
|
function publishedChannelsFile(override) {
|
|
55660
|
-
return
|
|
55916
|
+
return import_node_path46.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
55661
55917
|
}
|
|
55662
55918
|
function bundleCacheRoot(override) {
|
|
55663
|
-
return
|
|
55919
|
+
return import_node_path46.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
55664
55920
|
}
|
|
55665
55921
|
|
|
55666
55922
|
// src/extension/install-flow.ts
|
|
@@ -55687,7 +55943,7 @@ async function installFromChannel(args, deps) {
|
|
|
55687
55943
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
55688
55944
|
}
|
|
55689
55945
|
for (const name of Object.keys(zip.files)) {
|
|
55690
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
55946
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path47.default.isAbsolute(name)) {
|
|
55691
55947
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
55692
55948
|
}
|
|
55693
55949
|
}
|
|
@@ -55719,10 +55975,10 @@ async function installFromChannel(args, deps) {
|
|
|
55719
55975
|
);
|
|
55720
55976
|
}
|
|
55721
55977
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
55722
|
-
const destDir =
|
|
55978
|
+
const destDir = import_node_path47.default.join(deps.extensionsRoot, localExtId);
|
|
55723
55979
|
let destExists = false;
|
|
55724
55980
|
try {
|
|
55725
|
-
await
|
|
55981
|
+
await import_promises7.default.access(destDir);
|
|
55726
55982
|
destExists = true;
|
|
55727
55983
|
} catch {
|
|
55728
55984
|
}
|
|
@@ -55732,28 +55988,28 @@ async function installFromChannel(args, deps) {
|
|
|
55732
55988
|
`extension ${localExtId} already installed locally (from owner ${channelRef.ownerPrincipalId})`
|
|
55733
55989
|
);
|
|
55734
55990
|
}
|
|
55735
|
-
const stage = await
|
|
55736
|
-
|
|
55991
|
+
const stage = await import_promises7.default.mkdtemp(
|
|
55992
|
+
import_node_path47.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
55737
55993
|
);
|
|
55738
55994
|
try {
|
|
55739
55995
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
55740
|
-
const dest =
|
|
55996
|
+
const dest = import_node_path47.default.join(stage, name);
|
|
55741
55997
|
if (entry.dir) {
|
|
55742
|
-
await
|
|
55998
|
+
await import_promises7.default.mkdir(dest, { recursive: true });
|
|
55743
55999
|
continue;
|
|
55744
56000
|
}
|
|
55745
|
-
await
|
|
56001
|
+
await import_promises7.default.mkdir(import_node_path47.default.dirname(dest), { recursive: true });
|
|
55746
56002
|
if (name === "manifest.json") {
|
|
55747
56003
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
55748
|
-
await
|
|
56004
|
+
await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
55749
56005
|
} else {
|
|
55750
|
-
await
|
|
56006
|
+
await import_promises7.default.writeFile(dest, await entry.async("nodebuffer"));
|
|
55751
56007
|
}
|
|
55752
56008
|
}
|
|
55753
|
-
await
|
|
55754
|
-
await
|
|
56009
|
+
await import_promises7.default.mkdir(deps.extensionsRoot, { recursive: true });
|
|
56010
|
+
await import_promises7.default.rename(stage, destDir);
|
|
55755
56011
|
} catch (e) {
|
|
55756
|
-
await
|
|
56012
|
+
await import_promises7.default.rm(stage, { recursive: true, force: true }).catch(() => {
|
|
55757
56013
|
});
|
|
55758
56014
|
throw e;
|
|
55759
56015
|
}
|
|
@@ -55762,8 +56018,8 @@ async function installFromChannel(args, deps) {
|
|
|
55762
56018
|
}
|
|
55763
56019
|
|
|
55764
56020
|
// src/extension/update-flow.ts
|
|
55765
|
-
var
|
|
55766
|
-
var
|
|
56021
|
+
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
56022
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
55767
56023
|
var import_node_os20 = __toESM(require("os"), 1);
|
|
55768
56024
|
var import_node_crypto16 = __toESM(require("crypto"), 1);
|
|
55769
56025
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
@@ -55780,11 +56036,11 @@ async function updateFromChannel(args, deps) {
|
|
|
55780
56036
|
channelRef.extId,
|
|
55781
56037
|
channelRef.ownerPrincipalId
|
|
55782
56038
|
);
|
|
55783
|
-
const liveDir =
|
|
56039
|
+
const liveDir = import_node_path48.default.join(deps.extensionsRoot, localExtId);
|
|
55784
56040
|
const prevDir = `${liveDir}.prev`;
|
|
55785
56041
|
let existingVersion;
|
|
55786
56042
|
try {
|
|
55787
|
-
const raw = await
|
|
56043
|
+
const raw = await import_promises8.default.readFile(import_node_path48.default.join(liveDir, "manifest.json"), "utf8");
|
|
55788
56044
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
55789
56045
|
if (!parsed2.success) {
|
|
55790
56046
|
throw new UpdateError(
|
|
@@ -55817,7 +56073,7 @@ async function updateFromChannel(args, deps) {
|
|
|
55817
56073
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
55818
56074
|
}
|
|
55819
56075
|
for (const name of Object.keys(zip.files)) {
|
|
55820
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
56076
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path48.default.isAbsolute(name)) {
|
|
55821
56077
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
55822
56078
|
}
|
|
55823
56079
|
}
|
|
@@ -55849,31 +56105,31 @@ async function updateFromChannel(args, deps) {
|
|
|
55849
56105
|
);
|
|
55850
56106
|
}
|
|
55851
56107
|
await deps.runtime.close(localExtId);
|
|
55852
|
-
await
|
|
55853
|
-
await
|
|
55854
|
-
const stage = await
|
|
55855
|
-
|
|
56108
|
+
await import_promises8.default.rm(prevDir, { recursive: true, force: true });
|
|
56109
|
+
await import_promises8.default.rename(liveDir, prevDir);
|
|
56110
|
+
const stage = await import_promises8.default.mkdtemp(
|
|
56111
|
+
import_node_path48.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
55856
56112
|
);
|
|
55857
56113
|
try {
|
|
55858
56114
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
55859
|
-
const dest =
|
|
56115
|
+
const dest = import_node_path48.default.join(stage, name);
|
|
55860
56116
|
if (entry.dir) {
|
|
55861
|
-
await
|
|
56117
|
+
await import_promises8.default.mkdir(dest, { recursive: true });
|
|
55862
56118
|
continue;
|
|
55863
56119
|
}
|
|
55864
|
-
await
|
|
56120
|
+
await import_promises8.default.mkdir(import_node_path48.default.dirname(dest), { recursive: true });
|
|
55865
56121
|
if (name === "manifest.json") {
|
|
55866
56122
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
55867
|
-
await
|
|
56123
|
+
await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
55868
56124
|
} else {
|
|
55869
|
-
await
|
|
56125
|
+
await import_promises8.default.writeFile(dest, await entry.async("nodebuffer"));
|
|
55870
56126
|
}
|
|
55871
56127
|
}
|
|
55872
|
-
await
|
|
56128
|
+
await import_promises8.default.rename(stage, liveDir);
|
|
55873
56129
|
} catch (e) {
|
|
55874
|
-
await
|
|
56130
|
+
await import_promises8.default.rm(stage, { recursive: true, force: true }).catch(() => {
|
|
55875
56131
|
});
|
|
55876
|
-
await
|
|
56132
|
+
await import_promises8.default.rename(prevDir, liveDir).catch(() => {
|
|
55877
56133
|
});
|
|
55878
56134
|
await deps.runtime.open(localExtId).catch(() => {
|
|
55879
56135
|
});
|
|
@@ -55895,7 +56151,7 @@ async function updateFromChannel(args, deps) {
|
|
|
55895
56151
|
reason: e.message
|
|
55896
56152
|
};
|
|
55897
56153
|
}
|
|
55898
|
-
await
|
|
56154
|
+
await import_promises8.default.rm(prevDir, { recursive: true, force: true });
|
|
55899
56155
|
return {
|
|
55900
56156
|
kind: "updated",
|
|
55901
56157
|
extId: localExtId,
|
|
@@ -55903,9 +56159,9 @@ async function updateFromChannel(args, deps) {
|
|
|
55903
56159
|
};
|
|
55904
56160
|
}
|
|
55905
56161
|
async function rollback(deps, localExtId, liveDir, prevDir) {
|
|
55906
|
-
await
|
|
56162
|
+
await import_promises8.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
|
|
55907
56163
|
});
|
|
55908
|
-
await
|
|
56164
|
+
await import_promises8.default.rename(prevDir, liveDir).catch(() => {
|
|
55909
56165
|
});
|
|
55910
56166
|
await deps.runtime.open(localExtId).catch(() => {
|
|
55911
56167
|
});
|
|
@@ -55954,18 +56210,18 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
55954
56210
|
);
|
|
55955
56211
|
}
|
|
55956
56212
|
}
|
|
55957
|
-
const manifestPath =
|
|
56213
|
+
const manifestPath = import_node_path49.default.join(root, extId, "manifest.json");
|
|
55958
56214
|
const manifest = await readManifest(root, extId);
|
|
55959
56215
|
const next = { ...manifest, version: newVersion };
|
|
55960
56216
|
const tmp = `${manifestPath}.tmp`;
|
|
55961
|
-
await
|
|
55962
|
-
await
|
|
56217
|
+
await import_promises9.default.writeFile(tmp, JSON.stringify(next, null, 2));
|
|
56218
|
+
await import_promises9.default.rename(tmp, manifestPath);
|
|
55963
56219
|
}
|
|
55964
56220
|
async function readManifest(root, extId) {
|
|
55965
|
-
const file =
|
|
56221
|
+
const file = import_node_path49.default.join(root, extId, "manifest.json");
|
|
55966
56222
|
let raw;
|
|
55967
56223
|
try {
|
|
55968
|
-
raw = await
|
|
56224
|
+
raw = await import_promises9.default.readFile(file, "utf8");
|
|
55969
56225
|
} catch (e) {
|
|
55970
56226
|
if (e.code === "ENOENT") {
|
|
55971
56227
|
throw new ClawdError(ERROR_CODES.INVALID_PARAM, `extension ${extId} not installed`);
|
|
@@ -56053,7 +56309,7 @@ function buildExtensionHandlers(deps) {
|
|
|
56053
56309
|
};
|
|
56054
56310
|
async function buildSnapshotMeta(extId) {
|
|
56055
56311
|
const manifest = await readManifest(deps.root, extId);
|
|
56056
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
56312
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path49.default.join(deps.root, extId));
|
|
56057
56313
|
return { manifest, contentHash: sha256, buffer };
|
|
56058
56314
|
}
|
|
56059
56315
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -56236,7 +56492,7 @@ function buildExtensionHandlers(deps) {
|
|
|
56236
56492
|
// src/app-builder/project-store.ts
|
|
56237
56493
|
var import_node_fs42 = require("fs");
|
|
56238
56494
|
var import_node_child_process11 = require("child_process");
|
|
56239
|
-
var
|
|
56495
|
+
var import_node_path50 = require("path");
|
|
56240
56496
|
init_protocol();
|
|
56241
56497
|
var PROJECTS_DIR = "projects";
|
|
56242
56498
|
var META_FILE = ".clawd-project.json";
|
|
@@ -56250,14 +56506,14 @@ var ProjectStore = class {
|
|
|
56250
56506
|
root;
|
|
56251
56507
|
/** projects/<name>/.clawd-project.json 路径 */
|
|
56252
56508
|
metaPath(name) {
|
|
56253
|
-
return (0,
|
|
56509
|
+
return (0, import_node_path50.join)(this.projectsRoot(), name, META_FILE);
|
|
56254
56510
|
}
|
|
56255
56511
|
/** projects/<name>/ 目录路径(cwd 用) */
|
|
56256
56512
|
projectDir(name) {
|
|
56257
|
-
return (0,
|
|
56513
|
+
return (0, import_node_path50.join)(this.projectsRoot(), name);
|
|
56258
56514
|
}
|
|
56259
56515
|
projectsRoot() {
|
|
56260
|
-
return (0,
|
|
56516
|
+
return (0, import_node_path50.join)(this.root, PROJECTS_DIR);
|
|
56261
56517
|
}
|
|
56262
56518
|
async list() {
|
|
56263
56519
|
let entries;
|
|
@@ -56560,7 +56816,7 @@ var PublishJobRegistry = class {
|
|
|
56560
56816
|
// src/app-builder/publish-job-runner.ts
|
|
56561
56817
|
var import_node_child_process13 = require("child_process");
|
|
56562
56818
|
var import_node_fs43 = require("fs");
|
|
56563
|
-
var
|
|
56819
|
+
var import_node_path51 = require("path");
|
|
56564
56820
|
|
|
56565
56821
|
// src/app-builder/publish-stage-parser.ts
|
|
56566
56822
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -56592,7 +56848,7 @@ async function startPublishJob(deps, args) {
|
|
|
56592
56848
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
56593
56849
|
}
|
|
56594
56850
|
const projDir = projectDir(args.name);
|
|
56595
|
-
const logPath = (0,
|
|
56851
|
+
const logPath = (0, import_node_path51.join)(projDir, ".publish.log");
|
|
56596
56852
|
let logStream = null;
|
|
56597
56853
|
try {
|
|
56598
56854
|
logStream = (0, import_node_fs43.createWriteStream)(logPath, { flags: "w" });
|
|
@@ -56852,7 +57108,7 @@ async function recoverInterruptedJobs(deps) {
|
|
|
56852
57108
|
|
|
56853
57109
|
// src/handlers/app-builder.ts
|
|
56854
57110
|
init_protocol();
|
|
56855
|
-
var
|
|
57111
|
+
var import_node_path52 = require("path");
|
|
56856
57112
|
var import_node_fs44 = require("fs");
|
|
56857
57113
|
var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
|
|
56858
57114
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
@@ -57010,8 +57266,8 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57010
57266
|
const project = await userStore.create(f.name, reservedPorts);
|
|
57011
57267
|
try {
|
|
57012
57268
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
|
|
57013
|
-
const templateSrcDir = (0,
|
|
57014
|
-
const scaffoldScript = (0,
|
|
57269
|
+
const templateSrcDir = (0, import_node_path52.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
|
|
57270
|
+
const scaffoldScript = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
|
|
57015
57271
|
const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
|
|
57016
57272
|
deps.logger?.info("app-builder.scaffold.done", {
|
|
57017
57273
|
name: project.name,
|
|
@@ -57232,7 +57488,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57232
57488
|
await userStore.clearPublishJob(args.name);
|
|
57233
57489
|
}
|
|
57234
57490
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
|
|
57235
|
-
const scriptPath = (0,
|
|
57491
|
+
const scriptPath = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "publish.sh");
|
|
57236
57492
|
deps.logger?.info("app-builder.publish.start", {
|
|
57237
57493
|
name: args.name,
|
|
57238
57494
|
sessionId: boundSession.sessionId,
|
|
@@ -57407,12 +57663,12 @@ function buildVisitorHandlers(deps) {
|
|
|
57407
57663
|
}
|
|
57408
57664
|
|
|
57409
57665
|
// src/extension/registry.ts
|
|
57410
|
-
var
|
|
57411
|
-
var
|
|
57666
|
+
var import_promises10 = __toESM(require("fs/promises"), 1);
|
|
57667
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
57412
57668
|
async function loadAll(root) {
|
|
57413
57669
|
let entries;
|
|
57414
57670
|
try {
|
|
57415
|
-
entries = await
|
|
57671
|
+
entries = await import_promises10.default.readdir(root, { withFileTypes: true });
|
|
57416
57672
|
} catch (e) {
|
|
57417
57673
|
if (e.code === "ENOENT") return [];
|
|
57418
57674
|
throw e;
|
|
@@ -57421,16 +57677,16 @@ async function loadAll(root) {
|
|
|
57421
57677
|
for (const ent of entries) {
|
|
57422
57678
|
if (!ent.isDirectory()) continue;
|
|
57423
57679
|
if (ent.name.startsWith(".")) continue;
|
|
57424
|
-
records.push(await loadOne(
|
|
57680
|
+
records.push(await loadOne(import_node_path53.default.join(root, ent.name), ent.name));
|
|
57425
57681
|
}
|
|
57426
57682
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
57427
57683
|
return records;
|
|
57428
57684
|
}
|
|
57429
57685
|
async function loadOne(dir, dirName) {
|
|
57430
|
-
const manifestPath =
|
|
57686
|
+
const manifestPath = import_node_path53.default.join(dir, "manifest.json");
|
|
57431
57687
|
let raw;
|
|
57432
57688
|
try {
|
|
57433
|
-
raw = await
|
|
57689
|
+
raw = await import_promises10.default.readFile(manifestPath, "utf8");
|
|
57434
57690
|
} catch {
|
|
57435
57691
|
return {
|
|
57436
57692
|
extId: dirName,
|
|
@@ -57471,8 +57727,8 @@ async function loadOne(dir, dirName) {
|
|
|
57471
57727
|
}
|
|
57472
57728
|
|
|
57473
57729
|
// src/extension/uninstall.ts
|
|
57474
|
-
var
|
|
57475
|
-
var
|
|
57730
|
+
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
57731
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
57476
57732
|
var UninstallError = class extends Error {
|
|
57477
57733
|
constructor(code, message) {
|
|
57478
57734
|
super(message);
|
|
@@ -57481,14 +57737,14 @@ var UninstallError = class extends Error {
|
|
|
57481
57737
|
code;
|
|
57482
57738
|
};
|
|
57483
57739
|
async function uninstall(deps) {
|
|
57484
|
-
const dir =
|
|
57740
|
+
const dir = import_node_path54.default.join(deps.root, deps.extId);
|
|
57485
57741
|
try {
|
|
57486
|
-
await
|
|
57742
|
+
await import_promises11.default.access(dir);
|
|
57487
57743
|
} catch {
|
|
57488
57744
|
throw new UninstallError("NOT_FOUND", `extension ${deps.extId} not installed`);
|
|
57489
57745
|
}
|
|
57490
57746
|
await deps.runtime.close(deps.extId);
|
|
57491
|
-
await
|
|
57747
|
+
await import_promises11.default.rm(dir, { recursive: true, force: true });
|
|
57492
57748
|
}
|
|
57493
57749
|
|
|
57494
57750
|
// src/handlers/index.ts
|
|
@@ -58201,8 +58457,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
|
|
|
58201
58457
|
|
|
58202
58458
|
// src/extension/runtime.ts
|
|
58203
58459
|
var import_node_child_process16 = require("child_process");
|
|
58204
|
-
var
|
|
58205
|
-
var
|
|
58460
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
58461
|
+
var import_promises12 = require("timers/promises");
|
|
58206
58462
|
|
|
58207
58463
|
// src/extension/port-allocator.ts
|
|
58208
58464
|
var import_node_net2 = __toESM(require("net"), 1);
|
|
@@ -58302,7 +58558,7 @@ var Runtime = class {
|
|
|
58302
58558
|
/\$CLAWOS_EXT_PORT/g,
|
|
58303
58559
|
String(port)
|
|
58304
58560
|
);
|
|
58305
|
-
const dir =
|
|
58561
|
+
const dir = import_node_path55.default.join(this.root, extId);
|
|
58306
58562
|
const env = {
|
|
58307
58563
|
...process.env,
|
|
58308
58564
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -58378,7 +58634,7 @@ ${handle.stderrTail}`
|
|
|
58378
58634
|
if (res.ok) return;
|
|
58379
58635
|
} catch {
|
|
58380
58636
|
}
|
|
58381
|
-
await (0,
|
|
58637
|
+
await (0, import_promises12.setTimeout)(this.healthzIntervalMs);
|
|
58382
58638
|
}
|
|
58383
58639
|
throw new RuntimeError(
|
|
58384
58640
|
"HEALTHZ_FAILED",
|
|
@@ -58403,7 +58659,7 @@ ${handle.stderrTail}`
|
|
|
58403
58659
|
};
|
|
58404
58660
|
killGroup("SIGTERM");
|
|
58405
58661
|
const exited = new Promise((resolve6) => child.once("exit", () => resolve6()));
|
|
58406
|
-
const timed = (0,
|
|
58662
|
+
const timed = (0, import_promises12.setTimeout)(5e3).then(() => "timeout");
|
|
58407
58663
|
const winner = await Promise.race([exited.then(() => "exited"), timed]);
|
|
58408
58664
|
if (winner === "timeout" && child.exitCode === null) {
|
|
58409
58665
|
killGroup("SIGKILL");
|
|
@@ -58413,8 +58669,8 @@ ${handle.stderrTail}`
|
|
|
58413
58669
|
};
|
|
58414
58670
|
|
|
58415
58671
|
// src/extension/published-channels.ts
|
|
58416
|
-
var
|
|
58417
|
-
var
|
|
58672
|
+
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
58673
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
58418
58674
|
init_zod();
|
|
58419
58675
|
var PublishedChannelsError = class extends Error {
|
|
58420
58676
|
constructor(code, message) {
|
|
@@ -58444,7 +58700,7 @@ var PublishedChannelStore = class {
|
|
|
58444
58700
|
this.channels.clear();
|
|
58445
58701
|
let raw;
|
|
58446
58702
|
try {
|
|
58447
|
-
raw = await
|
|
58703
|
+
raw = await import_promises13.default.readFile(this.filePath, "utf8");
|
|
58448
58704
|
} catch (e) {
|
|
58449
58705
|
if (e.code === "ENOENT") {
|
|
58450
58706
|
this.loaded = true;
|
|
@@ -58513,15 +58769,15 @@ var PublishedChannelStore = class {
|
|
|
58513
58769
|
)
|
|
58514
58770
|
};
|
|
58515
58771
|
const tmp = `${this.filePath}.tmp`;
|
|
58516
|
-
await
|
|
58517
|
-
await
|
|
58518
|
-
await
|
|
58772
|
+
await import_promises13.default.mkdir(import_node_path56.default.dirname(this.filePath), { recursive: true });
|
|
58773
|
+
await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
58774
|
+
await import_promises13.default.rename(tmp, this.filePath);
|
|
58519
58775
|
}
|
|
58520
58776
|
};
|
|
58521
58777
|
|
|
58522
58778
|
// src/extension/bundle-cache.ts
|
|
58523
|
-
var
|
|
58524
|
-
var
|
|
58779
|
+
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
58780
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
58525
58781
|
var BundleCache = class {
|
|
58526
58782
|
constructor(rootDir) {
|
|
58527
58783
|
this.rootDir = rootDir;
|
|
@@ -58529,17 +58785,17 @@ var BundleCache = class {
|
|
|
58529
58785
|
rootDir;
|
|
58530
58786
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
58531
58787
|
async write(snapshotHash, buffer) {
|
|
58532
|
-
await
|
|
58533
|
-
const file =
|
|
58788
|
+
await import_promises14.default.mkdir(this.rootDir, { recursive: true });
|
|
58789
|
+
const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58534
58790
|
const tmp = `${file}.tmp`;
|
|
58535
|
-
await
|
|
58536
|
-
await
|
|
58791
|
+
await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
|
|
58792
|
+
await import_promises14.default.rename(tmp, file);
|
|
58537
58793
|
}
|
|
58538
58794
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
58539
58795
|
async read(snapshotHash) {
|
|
58540
|
-
const file =
|
|
58796
|
+
const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58541
58797
|
try {
|
|
58542
|
-
return await
|
|
58798
|
+
return await import_promises14.default.readFile(file);
|
|
58543
58799
|
} catch (e) {
|
|
58544
58800
|
if (e.code === "ENOENT") return null;
|
|
58545
58801
|
throw e;
|
|
@@ -58547,8 +58803,8 @@ var BundleCache = class {
|
|
|
58547
58803
|
}
|
|
58548
58804
|
/** Idempotent — missing file is not an error. */
|
|
58549
58805
|
async delete(snapshotHash) {
|
|
58550
|
-
const file =
|
|
58551
|
-
await
|
|
58806
|
+
const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58807
|
+
await import_promises14.default.rm(file, { force: true });
|
|
58552
58808
|
}
|
|
58553
58809
|
};
|
|
58554
58810
|
|
|
@@ -58570,24 +58826,24 @@ async function startDaemon(config) {
|
|
|
58570
58826
|
sampling: logShippingCfg.sampling,
|
|
58571
58827
|
homeDir: import_node_os22.default.homedir()
|
|
58572
58828
|
});
|
|
58573
|
-
const logDir =
|
|
58829
|
+
const logDir = import_node_path58.default.join(config.dataDir, "log");
|
|
58574
58830
|
import_node_fs45.default.mkdirSync(logDir, { recursive: true });
|
|
58575
58831
|
const logger = createLogger({
|
|
58576
58832
|
level: config.logLevel,
|
|
58577
|
-
file:
|
|
58833
|
+
file: import_node_path58.default.join(logDir, "clawd.log"),
|
|
58578
58834
|
logClient
|
|
58579
58835
|
});
|
|
58580
58836
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
58581
58837
|
const screenIdleProbeLogger = createFileOnlyLogger({
|
|
58582
|
-
file:
|
|
58838
|
+
file: import_node_path58.default.join(logDir, "screen-idle-probe.log"),
|
|
58583
58839
|
level: "debug"
|
|
58584
58840
|
});
|
|
58585
58841
|
logger.info("screen-idle probe logger enabled", {
|
|
58586
|
-
file:
|
|
58842
|
+
file: import_node_path58.default.join(logDir, "screen-idle-probe.log")
|
|
58587
58843
|
});
|
|
58588
58844
|
const CAP_TARGETS = [
|
|
58589
|
-
|
|
58590
|
-
|
|
58845
|
+
import_node_path58.default.join(logDir, "clawd.log"),
|
|
58846
|
+
import_node_path58.default.join(logDir, "screen-idle-probe.log")
|
|
58591
58847
|
];
|
|
58592
58848
|
const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
|
|
58593
58849
|
const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
|
|
@@ -58741,8 +58997,8 @@ async function startDaemon(config) {
|
|
|
58741
58997
|
const agents = new AgentsScanner();
|
|
58742
58998
|
const history = new ClaudeHistoryReader();
|
|
58743
58999
|
let transport = null;
|
|
58744
|
-
const personaStore = new PersonaStore(
|
|
58745
|
-
const usersRoot =
|
|
59000
|
+
const personaStore = new PersonaStore(import_node_path58.default.join(config.dataDir, "personas"));
|
|
59001
|
+
const usersRoot = import_node_path58.default.join(config.dataDir, "users");
|
|
58746
59002
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
58747
59003
|
if (defaultsRoot) {
|
|
58748
59004
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -58761,18 +59017,33 @@ async function startDaemon(config) {
|
|
|
58761
59017
|
migrateAgentsMirror({ store: personaStore, logger });
|
|
58762
59018
|
migrateCodexSandbox({ store: personaStore, logger });
|
|
58763
59019
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
58764
|
-
const
|
|
58765
|
-
|
|
59020
|
+
const dispatchStore = createDispatchStore({
|
|
59021
|
+
filePath: import_node_path58.default.join(config.dataDir, "dispatch.json"),
|
|
59022
|
+
now: () => Date.now(),
|
|
59023
|
+
onFlushError: (err) => logger.error("dispatch store flush failed", {
|
|
59024
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
59025
|
+
})
|
|
59026
|
+
});
|
|
59027
|
+
await dispatchStore.load();
|
|
59028
|
+
dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
|
|
59029
|
+
let deliverPendingRef;
|
|
59030
|
+
const personaDispatchManager = new PersonaDispatchManager({
|
|
59031
|
+
genId: () => v4_default(),
|
|
59032
|
+
store: dispatchStore,
|
|
59033
|
+
now: () => Date.now(),
|
|
59034
|
+
onCompleted: (sid) => deliverPendingRef?.(sid)
|
|
59035
|
+
});
|
|
59036
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path58.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
|
|
58766
59037
|
const mcpConfigs = [];
|
|
58767
59038
|
const dispatchServerCandidates = [
|
|
58768
|
-
|
|
59039
|
+
import_node_path58.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
58769
59040
|
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
58770
|
-
|
|
59041
|
+
import_node_path58.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
58771
59042
|
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
58772
59043
|
];
|
|
58773
59044
|
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58774
59045
|
if (dispatchServerScriptPath) {
|
|
58775
|
-
const dispatchLogPath =
|
|
59046
|
+
const dispatchLogPath = import_node_path58.default.join(logDir, "dispatch-mcp-server.log");
|
|
58776
59047
|
const dispatchCfgPath = writeDispatchMcpConfig({
|
|
58777
59048
|
dataDir: config.dataDir,
|
|
58778
59049
|
serverScriptPath: dispatchServerScriptPath,
|
|
@@ -58790,12 +59061,12 @@ async function startDaemon(config) {
|
|
|
58790
59061
|
});
|
|
58791
59062
|
}
|
|
58792
59063
|
const ticketServerCandidates = [
|
|
58793
|
-
|
|
58794
|
-
|
|
59064
|
+
import_node_path58.default.join(here, "ticket", "mcp-server.cjs"),
|
|
59065
|
+
import_node_path58.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
58795
59066
|
];
|
|
58796
59067
|
const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58797
59068
|
if (ticketServerScriptPath) {
|
|
58798
|
-
const ticketLogPath =
|
|
59069
|
+
const ticketLogPath = import_node_path58.default.join(logDir, "ticket-mcp-server.log");
|
|
58799
59070
|
const ticketCfgPath = writeTicketMcpConfig({
|
|
58800
59071
|
dataDir: config.dataDir,
|
|
58801
59072
|
serverScriptPath: ticketServerScriptPath,
|
|
@@ -58815,12 +59086,12 @@ async function startDaemon(config) {
|
|
|
58815
59086
|
});
|
|
58816
59087
|
}
|
|
58817
59088
|
const shiftServerCandidates = [
|
|
58818
|
-
|
|
58819
|
-
|
|
59089
|
+
import_node_path58.default.join(here, "shift", "mcp-server.cjs"),
|
|
59090
|
+
import_node_path58.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
|
|
58820
59091
|
];
|
|
58821
59092
|
const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58822
59093
|
if (shiftServerScriptPath) {
|
|
58823
|
-
const shiftLogPath =
|
|
59094
|
+
const shiftLogPath = import_node_path58.default.join(logDir, "shift-mcp-server.log");
|
|
58824
59095
|
const shiftCfgPath = await writeShiftMcpConfig({
|
|
58825
59096
|
dataDir: config.dataDir,
|
|
58826
59097
|
serverScriptPath: shiftServerScriptPath,
|
|
@@ -58839,12 +59110,12 @@ async function startDaemon(config) {
|
|
|
58839
59110
|
);
|
|
58840
59111
|
}
|
|
58841
59112
|
const inboxServerCandidates = [
|
|
58842
|
-
|
|
58843
|
-
|
|
59113
|
+
import_node_path58.default.join(here, "inbox", "mcp-server.cjs"),
|
|
59114
|
+
import_node_path58.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
|
|
58844
59115
|
];
|
|
58845
59116
|
const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58846
59117
|
if (inboxServerScriptPath) {
|
|
58847
|
-
const inboxLogPath =
|
|
59118
|
+
const inboxLogPath = import_node_path58.default.join(logDir, "inbox-mcp-server.log");
|
|
58848
59119
|
const inboxCfgPath = await writeInboxMcpConfig({
|
|
58849
59120
|
dataDir: config.dataDir,
|
|
58850
59121
|
serverScriptPath: inboxServerScriptPath,
|
|
@@ -58863,8 +59134,8 @@ async function startDaemon(config) {
|
|
|
58863
59134
|
);
|
|
58864
59135
|
}
|
|
58865
59136
|
const peerOpsServerCandidates = [
|
|
58866
|
-
|
|
58867
|
-
|
|
59137
|
+
import_node_path58.default.join(here, "peer-ops", "mcp-server.cjs"),
|
|
59138
|
+
import_node_path58.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
|
|
58868
59139
|
];
|
|
58869
59140
|
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58870
59141
|
if (peerOpsServerScriptPath) {
|
|
@@ -58884,7 +59155,7 @@ async function startDaemon(config) {
|
|
|
58884
59155
|
);
|
|
58885
59156
|
}
|
|
58886
59157
|
const shiftStore = createShiftStore({
|
|
58887
|
-
filePath:
|
|
59158
|
+
filePath: import_node_path58.default.join(config.dataDir, "shift.json"),
|
|
58888
59159
|
ownerIdProvider: () => ownerPrincipalId,
|
|
58889
59160
|
now: () => Date.now()
|
|
58890
59161
|
});
|
|
@@ -58906,7 +59177,7 @@ async function startDaemon(config) {
|
|
|
58906
59177
|
getAdapter,
|
|
58907
59178
|
historyReader: history,
|
|
58908
59179
|
dataDir: config.dataDir,
|
|
58909
|
-
personaRoot:
|
|
59180
|
+
personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
|
|
58910
59181
|
usersRoot,
|
|
58911
59182
|
personaStore,
|
|
58912
59183
|
ownerDisplayName,
|
|
@@ -58922,6 +59193,8 @@ async function startDaemon(config) {
|
|
|
58922
59193
|
// Persona dispatch (Task 8): manager.createDispatchedSession 用 personaDispatchManager
|
|
58923
59194
|
// registerBSession;reducer 通过闭包反查 dispatchId 注 CLAWD_DISPATCH_ID env。
|
|
58924
59195
|
personaDispatchManager,
|
|
59196
|
+
// Dispatch 结果投递:deliverPending 查台账 + turn-end sweep(spec 2026-07-20 §5)。
|
|
59197
|
+
dispatchStore,
|
|
58925
59198
|
// daemon 级 MCP server 登记表(dispatch / ticket / shift / inbox / ...,上方各 writer
|
|
58926
59199
|
// 块写盘成功即登记);reducer 透传到 SpawnContext.mcpConfigs,cc spawn 逐项 --mcp-config。
|
|
58927
59200
|
mcpConfigs,
|
|
@@ -58944,7 +59217,7 @@ async function startDaemon(config) {
|
|
|
58944
59217
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
58945
59218
|
attachmentGroup: {
|
|
58946
59219
|
onFileEdit: (input) => {
|
|
58947
|
-
const absPath =
|
|
59220
|
+
const absPath = import_node_path58.default.isAbsolute(input.relPath) ? input.relPath : import_node_path58.default.join(input.cwd, input.relPath);
|
|
58948
59221
|
let size = 0;
|
|
58949
59222
|
try {
|
|
58950
59223
|
size = import_node_fs45.default.statSync(absPath).size;
|
|
@@ -59010,6 +59283,7 @@ async function startDaemon(config) {
|
|
|
59010
59283
|
}
|
|
59011
59284
|
});
|
|
59012
59285
|
manager.attachObserver(observer);
|
|
59286
|
+
deliverPendingRef = (sid) => manager.deliverPending(sid);
|
|
59013
59287
|
const claudeAdapter = config.mode === "tui" ? new ClaudeTuiAdapter({
|
|
59014
59288
|
logger,
|
|
59015
59289
|
historyReader: new ClaudeHistoryReader(),
|
|
@@ -59176,11 +59450,11 @@ async function startDaemon(config) {
|
|
|
59176
59450
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
59177
59451
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
59178
59452
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
59179
|
-
personaRoot:
|
|
59453
|
+
personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
|
|
59180
59454
|
usersRoot
|
|
59181
59455
|
},
|
|
59182
59456
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
59183
|
-
personaRoot:
|
|
59457
|
+
personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
|
|
59184
59458
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
59185
59459
|
usersRoot,
|
|
59186
59460
|
// capability:list / delete handler 依赖
|
|
@@ -59291,11 +59565,11 @@ async function startDaemon(config) {
|
|
|
59291
59565
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
59292
59566
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
59293
59567
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
59294
|
-
appBuilderPersonaRoot:
|
|
59568
|
+
appBuilderPersonaRoot: import_node_path58.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
59295
59569
|
// 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
|
|
59296
|
-
deployKitRoot:
|
|
59570
|
+
deployKitRoot: import_node_path58.default.join(config.dataDir, "deploy-kit"),
|
|
59297
59571
|
// scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
|
|
59298
|
-
resolvePersonaRoot: (personaId) =>
|
|
59572
|
+
resolvePersonaRoot: (personaId) => import_node_path58.default.join(config.dataDir, "personas", personaId),
|
|
59299
59573
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
59300
59574
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
59301
59575
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -59325,6 +59599,7 @@ async function startDaemon(config) {
|
|
|
59325
59599
|
let handlers = makeHandlers();
|
|
59326
59600
|
const dispatchHandlers = buildPersonaDispatchHandlers({
|
|
59327
59601
|
personaDispatchManager,
|
|
59602
|
+
store: dispatchStore,
|
|
59328
59603
|
logger,
|
|
59329
59604
|
spawnB: async (args) => {
|
|
59330
59605
|
logger.info("dispatch.spawnB.start", {
|
|
@@ -59338,7 +59613,7 @@ async function startDaemon(config) {
|
|
|
59338
59613
|
}
|
|
59339
59614
|
let sourceJsonlPath = "(no transcript yet \u2014 operate from the task description alone)";
|
|
59340
59615
|
if (sourceFile && sourceFile.toolSessionId) {
|
|
59341
|
-
sourceJsonlPath =
|
|
59616
|
+
sourceJsonlPath = import_node_path58.default.join(
|
|
59342
59617
|
import_node_os22.default.homedir(),
|
|
59343
59618
|
".claude",
|
|
59344
59619
|
"projects",
|
|
@@ -59656,8 +59931,8 @@ async function startDaemon(config) {
|
|
|
59656
59931
|
const lines = [
|
|
59657
59932
|
`Tunnel: ${r.url}`,
|
|
59658
59933
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
59659
|
-
`Frpc config: ${
|
|
59660
|
-
`Frpc log: ${
|
|
59934
|
+
`Frpc config: ${import_node_path58.default.join(config.dataDir, "frpc.toml")}`,
|
|
59935
|
+
`Frpc log: ${import_node_path58.default.join(logDir, "frpc.log")}`
|
|
59661
59936
|
];
|
|
59662
59937
|
const width = Math.max(...lines.map((l) => l.length));
|
|
59663
59938
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -59670,7 +59945,7 @@ ${bar}
|
|
|
59670
59945
|
|
|
59671
59946
|
`);
|
|
59672
59947
|
try {
|
|
59673
|
-
const connectPath =
|
|
59948
|
+
const connectPath = import_node_path58.default.join(config.dataDir, "connect.txt");
|
|
59674
59949
|
import_node_fs45.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
59675
59950
|
} catch {
|
|
59676
59951
|
}
|
|
@@ -59743,7 +60018,7 @@ ${bar}
|
|
|
59743
60018
|
};
|
|
59744
60019
|
}
|
|
59745
60020
|
function migrateDropPersonsDir(dataDir) {
|
|
59746
|
-
const dir =
|
|
60021
|
+
const dir = import_node_path58.default.join(dataDir, "persons");
|
|
59747
60022
|
try {
|
|
59748
60023
|
import_node_fs45.default.rmSync(dir, { recursive: true, force: true });
|
|
59749
60024
|
} catch {
|