@clawos-dev/clawd 0.2.247 → 0.2.249
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 +781 -496
- package/dist/dispatch/mcp-server.cjs +97 -18446
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +13 -13
- package/dist/share-ui/assets/{guest-CPSTbS2R.js → guest-DsrUx2Ku.js} +125 -125
- package/dist/share-ui/assets/guest-k2RPEdy5.css +32 -0
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-E3E4Ik_Z.css +0 -32
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() {
|
|
@@ -5132,12 +5132,21 @@ var init_schemas = __esm({
|
|
|
5132
5132
|
SessionListArgs = external_exports.object({
|
|
5133
5133
|
/** true = 只返回 mirror(originOwnerPrincipalId 非空,即「我在朋友 daemon 上创建」的本机存证)。 */
|
|
5134
5134
|
originOnly: external_exports.boolean().optional(),
|
|
5135
|
+
/**
|
|
5136
|
+
* 按 own persona 窄化(2026-07-21 self-persona-sessions 追加):只留
|
|
5137
|
+
* `s.ownerPersonaId === args.ownerPersonaId` 的 sessions。
|
|
5138
|
+
* - mirror 行(`ownerPersonaId` 恒 null)天然排除
|
|
5139
|
+
* - 与 `originOnly=true` 同传恒返 0
|
|
5140
|
+
* - 老 daemon 不识别时忽略字段返回全量,客户端消费侧本就自带过滤/截断,天然向后兼容
|
|
5141
|
+
*/
|
|
5142
|
+
ownerPersonaId: external_exports.string().min(1).optional(),
|
|
5135
5143
|
/** 按 updatedAt desc(list 的既有排序)截断前 N 条。 */
|
|
5136
5144
|
limit: external_exports.number().int().positive().optional(),
|
|
5137
5145
|
/**
|
|
5138
|
-
* 分页起点(2026-07-18 android-tasks-tab 迭代追加):originOnly 过滤后、
|
|
5139
|
-
*
|
|
5140
|
-
*
|
|
5146
|
+
* 分页起点(2026-07-18 android-tasks-tab 迭代追加):originOnly / ownerPersonaId 过滤后、
|
|
5147
|
+
* limit 截断前跳过前 N 条。与 limit 组合 = updatedAt desc 序上的一页。响应带 total
|
|
5148
|
+
* (过滤后总数,见 handler)供客户端判 hasMore。老 daemon 不识别时忽略 → 回全量,
|
|
5149
|
+
* 客户端按全量兼容。
|
|
5141
5150
|
*/
|
|
5142
5151
|
offset: external_exports.number().int().nonnegative().optional()
|
|
5143
5152
|
});
|
|
@@ -6187,7 +6196,7 @@ var init_feishu_auth = __esm({
|
|
|
6187
6196
|
});
|
|
6188
6197
|
|
|
6189
6198
|
// ../protocol/src/dispatch.ts
|
|
6190
|
-
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema;
|
|
6199
|
+
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema, DISPATCH_STATUSES, DispatchStatusSchema, DispatchRecordSchema, DispatchListArgsSchema, DispatchListResultSchema;
|
|
6191
6200
|
var init_dispatch = __esm({
|
|
6192
6201
|
"../protocol/src/dispatch.ts"() {
|
|
6193
6202
|
"use strict";
|
|
@@ -6219,6 +6228,32 @@ var init_dispatch = __esm({
|
|
|
6219
6228
|
dispatchId: external_exports.string().min(1),
|
|
6220
6229
|
outcome: DispatchOutcomeSchema
|
|
6221
6230
|
});
|
|
6231
|
+
DISPATCH_STATUSES = ["running", "completed", "failed"];
|
|
6232
|
+
DispatchStatusSchema = external_exports.enum(DISPATCH_STATUSES);
|
|
6233
|
+
DispatchRecordSchema = external_exports.object({
|
|
6234
|
+
dispatchId: external_exports.string().min(1),
|
|
6235
|
+
sourceSessionId: external_exports.string().min(1),
|
|
6236
|
+
sourcePersonaId: external_exports.string().min(1).optional(),
|
|
6237
|
+
targetPersonaId: external_exports.string().min(1),
|
|
6238
|
+
/** B 的 sessionId;registerBSession 后回填 */
|
|
6239
|
+
workerSessionId: external_exports.string().min(1).optional(),
|
|
6240
|
+
/** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
|
|
6241
|
+
taskText: external_exports.string(),
|
|
6242
|
+
status: DispatchStatusSchema,
|
|
6243
|
+
outcome: DispatchOutcomeSchema.optional(),
|
|
6244
|
+
/** 上层消费者语义(如司礼监的口谕/验收状态),daemon 不解释 */
|
|
6245
|
+
meta: external_exports.record(external_exports.unknown()).optional(),
|
|
6246
|
+
createdAt: external_exports.string().min(1),
|
|
6247
|
+
completedAt: external_exports.string().min(1).optional(),
|
|
6248
|
+
/** 结果注入 source session 成功时戳,兼当投递 dedup 标记 */
|
|
6249
|
+
deliveredAt: external_exports.string().min(1).optional()
|
|
6250
|
+
});
|
|
6251
|
+
DispatchListArgsSchema = external_exports.object({
|
|
6252
|
+
sourceSessionId: external_exports.string().min(1).optional()
|
|
6253
|
+
});
|
|
6254
|
+
DispatchListResultSchema = external_exports.object({
|
|
6255
|
+
records: external_exports.array(DispatchRecordSchema)
|
|
6256
|
+
});
|
|
6222
6257
|
}
|
|
6223
6258
|
});
|
|
6224
6259
|
|
|
@@ -6571,8 +6606,8 @@ var require_req = __commonJS({
|
|
|
6571
6606
|
if (req.originalUrl) {
|
|
6572
6607
|
_req.url = req.originalUrl;
|
|
6573
6608
|
} else {
|
|
6574
|
-
const
|
|
6575
|
-
_req.url = typeof
|
|
6609
|
+
const path71 = req.path;
|
|
6610
|
+
_req.url = typeof path71 === "string" ? path71 : req.url ? req.url.path || req.url : void 0;
|
|
6576
6611
|
}
|
|
6577
6612
|
if (req.query) {
|
|
6578
6613
|
_req.query = req.query;
|
|
@@ -6737,14 +6772,14 @@ var require_redact = __commonJS({
|
|
|
6737
6772
|
}
|
|
6738
6773
|
return obj;
|
|
6739
6774
|
}
|
|
6740
|
-
function parsePath(
|
|
6775
|
+
function parsePath(path71) {
|
|
6741
6776
|
const parts = [];
|
|
6742
6777
|
let current = "";
|
|
6743
6778
|
let inBrackets = false;
|
|
6744
6779
|
let inQuotes = false;
|
|
6745
6780
|
let quoteChar = "";
|
|
6746
|
-
for (let i = 0; i <
|
|
6747
|
-
const char =
|
|
6781
|
+
for (let i = 0; i < path71.length; i++) {
|
|
6782
|
+
const char = path71[i];
|
|
6748
6783
|
if (!inBrackets && char === ".") {
|
|
6749
6784
|
if (current) {
|
|
6750
6785
|
parts.push(current);
|
|
@@ -6875,10 +6910,10 @@ var require_redact = __commonJS({
|
|
|
6875
6910
|
return current;
|
|
6876
6911
|
}
|
|
6877
6912
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
6878
|
-
for (const
|
|
6879
|
-
const parts = parsePath(
|
|
6913
|
+
for (const path71 of paths) {
|
|
6914
|
+
const parts = parsePath(path71);
|
|
6880
6915
|
if (parts.includes("*")) {
|
|
6881
|
-
redactWildcardPath(obj, parts, censor,
|
|
6916
|
+
redactWildcardPath(obj, parts, censor, path71, remove);
|
|
6882
6917
|
} else {
|
|
6883
6918
|
if (remove) {
|
|
6884
6919
|
removeKey(obj, parts);
|
|
@@ -6963,8 +6998,8 @@ var require_redact = __commonJS({
|
|
|
6963
6998
|
}
|
|
6964
6999
|
} else {
|
|
6965
7000
|
if (afterWildcard.includes("*")) {
|
|
6966
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6967
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
7001
|
+
const wrappedCensor = typeof censor === "function" ? (value, path71) => {
|
|
7002
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path71];
|
|
6968
7003
|
return censor(value, fullPath);
|
|
6969
7004
|
} : censor;
|
|
6970
7005
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6999,8 +7034,8 @@ var require_redact = __commonJS({
|
|
|
6999
7034
|
return null;
|
|
7000
7035
|
}
|
|
7001
7036
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
7002
|
-
for (const
|
|
7003
|
-
const parts = parsePath(
|
|
7037
|
+
for (const path71 of pathsToClone) {
|
|
7038
|
+
const parts = parsePath(path71);
|
|
7004
7039
|
let current = pathStructure;
|
|
7005
7040
|
for (let i = 0; i < parts.length; i++) {
|
|
7006
7041
|
const part = parts[i];
|
|
@@ -7052,24 +7087,24 @@ var require_redact = __commonJS({
|
|
|
7052
7087
|
}
|
|
7053
7088
|
return cloneSelectively(obj, pathStructure);
|
|
7054
7089
|
}
|
|
7055
|
-
function validatePath(
|
|
7056
|
-
if (typeof
|
|
7090
|
+
function validatePath(path71) {
|
|
7091
|
+
if (typeof path71 !== "string") {
|
|
7057
7092
|
throw new Error("Paths must be (non-empty) strings");
|
|
7058
7093
|
}
|
|
7059
|
-
if (
|
|
7094
|
+
if (path71 === "") {
|
|
7060
7095
|
throw new Error("Invalid redaction path ()");
|
|
7061
7096
|
}
|
|
7062
|
-
if (
|
|
7063
|
-
throw new Error(`Invalid redaction path (${
|
|
7097
|
+
if (path71.includes("..")) {
|
|
7098
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7064
7099
|
}
|
|
7065
|
-
if (
|
|
7066
|
-
throw new Error(`Invalid redaction path (${
|
|
7100
|
+
if (path71.includes(",")) {
|
|
7101
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7067
7102
|
}
|
|
7068
7103
|
let bracketCount = 0;
|
|
7069
7104
|
let inQuotes = false;
|
|
7070
7105
|
let quoteChar = "";
|
|
7071
|
-
for (let i = 0; i <
|
|
7072
|
-
const char =
|
|
7106
|
+
for (let i = 0; i < path71.length; i++) {
|
|
7107
|
+
const char = path71[i];
|
|
7073
7108
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
7074
7109
|
if (!inQuotes) {
|
|
7075
7110
|
inQuotes = true;
|
|
@@ -7083,20 +7118,20 @@ var require_redact = __commonJS({
|
|
|
7083
7118
|
} else if (char === "]" && !inQuotes) {
|
|
7084
7119
|
bracketCount--;
|
|
7085
7120
|
if (bracketCount < 0) {
|
|
7086
|
-
throw new Error(`Invalid redaction path (${
|
|
7121
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7087
7122
|
}
|
|
7088
7123
|
}
|
|
7089
7124
|
}
|
|
7090
7125
|
if (bracketCount !== 0) {
|
|
7091
|
-
throw new Error(`Invalid redaction path (${
|
|
7126
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7092
7127
|
}
|
|
7093
7128
|
}
|
|
7094
7129
|
function validatePaths(paths) {
|
|
7095
7130
|
if (!Array.isArray(paths)) {
|
|
7096
7131
|
throw new TypeError("paths must be an array");
|
|
7097
7132
|
}
|
|
7098
|
-
for (const
|
|
7099
|
-
validatePath(
|
|
7133
|
+
for (const path71 of paths) {
|
|
7134
|
+
validatePath(path71);
|
|
7100
7135
|
}
|
|
7101
7136
|
}
|
|
7102
7137
|
function slowRedact(options = {}) {
|
|
@@ -7264,8 +7299,8 @@ var require_redaction = __commonJS({
|
|
|
7264
7299
|
if (shape[k2] === null) {
|
|
7265
7300
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
7266
7301
|
} else {
|
|
7267
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
7268
|
-
return censor(value, [k2, ...
|
|
7302
|
+
const wrappedCensor = typeof censor === "function" ? (value, path71) => {
|
|
7303
|
+
return censor(value, [k2, ...path71]);
|
|
7269
7304
|
} : censor;
|
|
7270
7305
|
o[k2] = Redact({
|
|
7271
7306
|
paths: shape[k2],
|
|
@@ -7483,10 +7518,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
7483
7518
|
var require_sonic_boom = __commonJS({
|
|
7484
7519
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
7485
7520
|
"use strict";
|
|
7486
|
-
var
|
|
7521
|
+
var fs65 = require("fs");
|
|
7487
7522
|
var EventEmitter3 = require("events");
|
|
7488
7523
|
var inherits = require("util").inherits;
|
|
7489
|
-
var
|
|
7524
|
+
var path71 = require("path");
|
|
7490
7525
|
var sleep2 = require_atomic_sleep();
|
|
7491
7526
|
var assert = require("assert");
|
|
7492
7527
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -7540,20 +7575,20 @@ var require_sonic_boom = __commonJS({
|
|
|
7540
7575
|
const mode = sonic.mode;
|
|
7541
7576
|
if (sonic.sync) {
|
|
7542
7577
|
try {
|
|
7543
|
-
if (sonic.mkdir)
|
|
7544
|
-
const fd =
|
|
7578
|
+
if (sonic.mkdir) fs65.mkdirSync(path71.dirname(file), { recursive: true });
|
|
7579
|
+
const fd = fs65.openSync(file, flags, mode);
|
|
7545
7580
|
fileOpened(null, fd);
|
|
7546
7581
|
} catch (err) {
|
|
7547
7582
|
fileOpened(err);
|
|
7548
7583
|
throw err;
|
|
7549
7584
|
}
|
|
7550
7585
|
} else if (sonic.mkdir) {
|
|
7551
|
-
|
|
7586
|
+
fs65.mkdir(path71.dirname(file), { recursive: true }, (err) => {
|
|
7552
7587
|
if (err) return fileOpened(err);
|
|
7553
|
-
|
|
7588
|
+
fs65.open(file, flags, mode, fileOpened);
|
|
7554
7589
|
});
|
|
7555
7590
|
} else {
|
|
7556
|
-
|
|
7591
|
+
fs65.open(file, flags, mode, fileOpened);
|
|
7557
7592
|
}
|
|
7558
7593
|
}
|
|
7559
7594
|
function SonicBoom(opts) {
|
|
@@ -7594,8 +7629,8 @@ var require_sonic_boom = __commonJS({
|
|
|
7594
7629
|
this.flush = flushBuffer;
|
|
7595
7630
|
this.flushSync = flushBufferSync;
|
|
7596
7631
|
this._actualWrite = actualWriteBuffer;
|
|
7597
|
-
fsWriteSync = () =>
|
|
7598
|
-
fsWrite = () =>
|
|
7632
|
+
fsWriteSync = () => fs65.writeSync(this.fd, this._writingBuf);
|
|
7633
|
+
fsWrite = () => fs65.write(this.fd, this._writingBuf, this.release);
|
|
7599
7634
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
7600
7635
|
this._writingBuf = "";
|
|
7601
7636
|
this.write = write;
|
|
@@ -7604,15 +7639,15 @@ var require_sonic_boom = __commonJS({
|
|
|
7604
7639
|
this._actualWrite = actualWrite;
|
|
7605
7640
|
fsWriteSync = () => {
|
|
7606
7641
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7607
|
-
return
|
|
7642
|
+
return fs65.writeSync(this.fd, this._writingBuf);
|
|
7608
7643
|
}
|
|
7609
|
-
return
|
|
7644
|
+
return fs65.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7610
7645
|
};
|
|
7611
7646
|
fsWrite = () => {
|
|
7612
7647
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7613
|
-
return
|
|
7648
|
+
return fs65.write(this.fd, this._writingBuf, this.release);
|
|
7614
7649
|
}
|
|
7615
|
-
return
|
|
7650
|
+
return fs65.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
7616
7651
|
};
|
|
7617
7652
|
} else {
|
|
7618
7653
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -7669,7 +7704,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7669
7704
|
}
|
|
7670
7705
|
}
|
|
7671
7706
|
if (this._fsync) {
|
|
7672
|
-
|
|
7707
|
+
fs65.fsyncSync(this.fd);
|
|
7673
7708
|
}
|
|
7674
7709
|
const len = this._len;
|
|
7675
7710
|
if (this._reopening) {
|
|
@@ -7783,7 +7818,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7783
7818
|
const onDrain = () => {
|
|
7784
7819
|
if (!this._fsync) {
|
|
7785
7820
|
try {
|
|
7786
|
-
|
|
7821
|
+
fs65.fsync(this.fd, (err) => {
|
|
7787
7822
|
this._flushPending = false;
|
|
7788
7823
|
cb(err);
|
|
7789
7824
|
});
|
|
@@ -7885,7 +7920,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7885
7920
|
const fd = this.fd;
|
|
7886
7921
|
this.once("ready", () => {
|
|
7887
7922
|
if (fd !== this.fd) {
|
|
7888
|
-
|
|
7923
|
+
fs65.close(fd, (err) => {
|
|
7889
7924
|
if (err) {
|
|
7890
7925
|
return this.emit("error", err);
|
|
7891
7926
|
}
|
|
@@ -7934,7 +7969,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7934
7969
|
buf = this._bufs[0];
|
|
7935
7970
|
}
|
|
7936
7971
|
try {
|
|
7937
|
-
const n = Buffer.isBuffer(buf) ?
|
|
7972
|
+
const n = Buffer.isBuffer(buf) ? fs65.writeSync(this.fd, buf) : fs65.writeSync(this.fd, buf, "utf8");
|
|
7938
7973
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
7939
7974
|
buf = releasedBufObj.writingBuf;
|
|
7940
7975
|
this._len = releasedBufObj.len;
|
|
@@ -7950,7 +7985,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7950
7985
|
}
|
|
7951
7986
|
}
|
|
7952
7987
|
try {
|
|
7953
|
-
|
|
7988
|
+
fs65.fsyncSync(this.fd);
|
|
7954
7989
|
} catch {
|
|
7955
7990
|
}
|
|
7956
7991
|
}
|
|
@@ -7971,7 +8006,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7971
8006
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
7972
8007
|
}
|
|
7973
8008
|
try {
|
|
7974
|
-
const n =
|
|
8009
|
+
const n = fs65.writeSync(this.fd, buf);
|
|
7975
8010
|
buf = buf.subarray(n);
|
|
7976
8011
|
this._len = Math.max(this._len - n, 0);
|
|
7977
8012
|
if (buf.length <= 0) {
|
|
@@ -7999,13 +8034,13 @@ var require_sonic_boom = __commonJS({
|
|
|
7999
8034
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
8000
8035
|
if (this.sync) {
|
|
8001
8036
|
try {
|
|
8002
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
8037
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs65.writeSync(this.fd, this._writingBuf) : fs65.writeSync(this.fd, this._writingBuf, "utf8");
|
|
8003
8038
|
release(null, written);
|
|
8004
8039
|
} catch (err) {
|
|
8005
8040
|
release(err);
|
|
8006
8041
|
}
|
|
8007
8042
|
} else {
|
|
8008
|
-
|
|
8043
|
+
fs65.write(this.fd, this._writingBuf, release);
|
|
8009
8044
|
}
|
|
8010
8045
|
}
|
|
8011
8046
|
function actualWriteBuffer() {
|
|
@@ -8014,7 +8049,7 @@ var require_sonic_boom = __commonJS({
|
|
|
8014
8049
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
8015
8050
|
if (this.sync) {
|
|
8016
8051
|
try {
|
|
8017
|
-
const written =
|
|
8052
|
+
const written = fs65.writeSync(this.fd, this._writingBuf);
|
|
8018
8053
|
release(null, written);
|
|
8019
8054
|
} catch (err) {
|
|
8020
8055
|
release(err);
|
|
@@ -8023,7 +8058,7 @@ var require_sonic_boom = __commonJS({
|
|
|
8023
8058
|
if (kCopyBuffer) {
|
|
8024
8059
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
8025
8060
|
}
|
|
8026
|
-
|
|
8061
|
+
fs65.write(this.fd, this._writingBuf, release);
|
|
8027
8062
|
}
|
|
8028
8063
|
}
|
|
8029
8064
|
function actualClose(sonic) {
|
|
@@ -8039,12 +8074,12 @@ var require_sonic_boom = __commonJS({
|
|
|
8039
8074
|
sonic._lens = [];
|
|
8040
8075
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
8041
8076
|
try {
|
|
8042
|
-
|
|
8077
|
+
fs65.fsync(sonic.fd, closeWrapped);
|
|
8043
8078
|
} catch {
|
|
8044
8079
|
}
|
|
8045
8080
|
function closeWrapped() {
|
|
8046
8081
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
8047
|
-
|
|
8082
|
+
fs65.close(sonic.fd, done);
|
|
8048
8083
|
} else {
|
|
8049
8084
|
done();
|
|
8050
8085
|
}
|
|
@@ -11179,11 +11214,11 @@ var init_lib = __esm({
|
|
|
11179
11214
|
}
|
|
11180
11215
|
}
|
|
11181
11216
|
},
|
|
11182
|
-
addToPath: function addToPath(
|
|
11183
|
-
var last =
|
|
11217
|
+
addToPath: function addToPath(path71, added, removed, oldPosInc, options) {
|
|
11218
|
+
var last = path71.lastComponent;
|
|
11184
11219
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
11185
11220
|
return {
|
|
11186
|
-
oldPos:
|
|
11221
|
+
oldPos: path71.oldPos + oldPosInc,
|
|
11187
11222
|
lastComponent: {
|
|
11188
11223
|
count: last.count + 1,
|
|
11189
11224
|
added,
|
|
@@ -11193,7 +11228,7 @@ var init_lib = __esm({
|
|
|
11193
11228
|
};
|
|
11194
11229
|
} else {
|
|
11195
11230
|
return {
|
|
11196
|
-
oldPos:
|
|
11231
|
+
oldPos: path71.oldPos + oldPosInc,
|
|
11197
11232
|
lastComponent: {
|
|
11198
11233
|
count: 1,
|
|
11199
11234
|
added,
|
|
@@ -11702,10 +11737,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
11702
11737
|
const memories = raw.map((m2) => {
|
|
11703
11738
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11704
11739
|
const rec3 = m2;
|
|
11705
|
-
const
|
|
11740
|
+
const path71 = typeof rec3.path === "string" ? rec3.path : null;
|
|
11706
11741
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
11707
|
-
if (!
|
|
11708
|
-
const entry = { path:
|
|
11742
|
+
if (!path71 || content == null) return null;
|
|
11743
|
+
const entry = { path: path71, content };
|
|
11709
11744
|
if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
|
|
11710
11745
|
return entry;
|
|
11711
11746
|
}).filter((m2) => m2 !== null);
|
|
@@ -12508,10 +12543,10 @@ function parseAttachment(obj) {
|
|
|
12508
12543
|
const memories = raw.map((m2) => {
|
|
12509
12544
|
if (!m2 || typeof m2 !== "object") return null;
|
|
12510
12545
|
const rec3 = m2;
|
|
12511
|
-
const
|
|
12546
|
+
const path71 = typeof rec3.path === "string" ? rec3.path : null;
|
|
12512
12547
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
12513
|
-
if (!
|
|
12514
|
-
const out = { path:
|
|
12548
|
+
if (!path71 || content == null) return null;
|
|
12549
|
+
const out = { path: path71, content };
|
|
12515
12550
|
if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
|
|
12516
12551
|
return out;
|
|
12517
12552
|
}).filter((m2) => m2 !== null);
|
|
@@ -33480,8 +33515,8 @@ var require_utils = __commonJS({
|
|
|
33480
33515
|
var result = transform[inputType][outputType](input);
|
|
33481
33516
|
return result;
|
|
33482
33517
|
};
|
|
33483
|
-
exports2.resolve = function(
|
|
33484
|
-
var parts =
|
|
33518
|
+
exports2.resolve = function(path71) {
|
|
33519
|
+
var parts = path71.split("/");
|
|
33485
33520
|
var result = [];
|
|
33486
33521
|
for (var index = 0; index < parts.length; index++) {
|
|
33487
33522
|
var part = parts[index];
|
|
@@ -39334,18 +39369,18 @@ var require_object = __commonJS({
|
|
|
39334
39369
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
39335
39370
|
this.files[name] = object;
|
|
39336
39371
|
};
|
|
39337
|
-
var parentFolder = function(
|
|
39338
|
-
if (
|
|
39339
|
-
|
|
39372
|
+
var parentFolder = function(path71) {
|
|
39373
|
+
if (path71.slice(-1) === "/") {
|
|
39374
|
+
path71 = path71.substring(0, path71.length - 1);
|
|
39340
39375
|
}
|
|
39341
|
-
var lastSlash =
|
|
39342
|
-
return lastSlash > 0 ?
|
|
39376
|
+
var lastSlash = path71.lastIndexOf("/");
|
|
39377
|
+
return lastSlash > 0 ? path71.substring(0, lastSlash) : "";
|
|
39343
39378
|
};
|
|
39344
|
-
var forceTrailingSlash = function(
|
|
39345
|
-
if (
|
|
39346
|
-
|
|
39379
|
+
var forceTrailingSlash = function(path71) {
|
|
39380
|
+
if (path71.slice(-1) !== "/") {
|
|
39381
|
+
path71 += "/";
|
|
39347
39382
|
}
|
|
39348
|
-
return
|
|
39383
|
+
return path71;
|
|
39349
39384
|
};
|
|
39350
39385
|
var folderAdd = function(name, createFolders) {
|
|
39351
39386
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -40347,7 +40382,7 @@ var require_lib3 = __commonJS({
|
|
|
40347
40382
|
// src/run-case/recorder.ts
|
|
40348
40383
|
function startRunCaseRecorder(opts) {
|
|
40349
40384
|
const now = opts.now ?? Date.now;
|
|
40350
|
-
const dir =
|
|
40385
|
+
const dir = import_node_path59.default.dirname(opts.recordPath);
|
|
40351
40386
|
let stream = null;
|
|
40352
40387
|
let closing = false;
|
|
40353
40388
|
let closedSettled = false;
|
|
@@ -40387,12 +40422,12 @@ function startRunCaseRecorder(opts) {
|
|
|
40387
40422
|
};
|
|
40388
40423
|
return { tap, close, closed };
|
|
40389
40424
|
}
|
|
40390
|
-
var import_node_fs46,
|
|
40425
|
+
var import_node_fs46, import_node_path59;
|
|
40391
40426
|
var init_recorder = __esm({
|
|
40392
40427
|
"src/run-case/recorder.ts"() {
|
|
40393
40428
|
"use strict";
|
|
40394
40429
|
import_node_fs46 = __toESM(require("fs"), 1);
|
|
40395
|
-
|
|
40430
|
+
import_node_path59 = __toESM(require("path"), 1);
|
|
40396
40431
|
}
|
|
40397
40432
|
});
|
|
40398
40433
|
|
|
@@ -40435,7 +40470,7 @@ var init_wire = __esm({
|
|
|
40435
40470
|
// src/run-case/controller.ts
|
|
40436
40471
|
async function runController(opts) {
|
|
40437
40472
|
const now = opts.now ?? Date.now;
|
|
40438
|
-
const cwd = opts.cwd ?? (0, import_node_fs47.mkdtempSync)(
|
|
40473
|
+
const cwd = opts.cwd ?? (0, import_node_fs47.mkdtempSync)(import_node_path60.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
|
|
40439
40474
|
const ownsCwd = opts.cwd === void 0;
|
|
40440
40475
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
40441
40476
|
const spawnCtx = { cwd };
|
|
@@ -40602,13 +40637,13 @@ async function runController(opts) {
|
|
|
40602
40637
|
}
|
|
40603
40638
|
return exitCode ?? 0;
|
|
40604
40639
|
}
|
|
40605
|
-
var import_node_fs47, import_node_os23,
|
|
40640
|
+
var import_node_fs47, import_node_os23, import_node_path60;
|
|
40606
40641
|
var init_controller = __esm({
|
|
40607
40642
|
"src/run-case/controller.ts"() {
|
|
40608
40643
|
"use strict";
|
|
40609
40644
|
import_node_fs47 = require("fs");
|
|
40610
40645
|
import_node_os23 = __toESM(require("os"), 1);
|
|
40611
|
-
|
|
40646
|
+
import_node_path60 = __toESM(require("path"), 1);
|
|
40612
40647
|
init_claude();
|
|
40613
40648
|
init_stdout_splitter();
|
|
40614
40649
|
init_permission_stdio();
|
|
@@ -40870,7 +40905,7 @@ Env (advanced):
|
|
|
40870
40905
|
`;
|
|
40871
40906
|
|
|
40872
40907
|
// src/index.ts
|
|
40873
|
-
var
|
|
40908
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
40874
40909
|
var import_node_fs45 = __toESM(require("fs"), 1);
|
|
40875
40910
|
var import_node_os22 = __toESM(require("os"), 1);
|
|
40876
40911
|
|
|
@@ -41735,6 +41770,28 @@ function dispatchShiftEnd(info, settle, killImpl) {
|
|
|
41735
41770
|
throw new Error(`dispatchShiftEnd: unhandled kind ${JSON.stringify(_exhaustive)}`);
|
|
41736
41771
|
}
|
|
41737
41772
|
|
|
41773
|
+
// src/dispatch/delivery.ts
|
|
41774
|
+
function selectPendingForDelivery(records, sourceSessionId) {
|
|
41775
|
+
return records.filter(
|
|
41776
|
+
(r) => r.sourceSessionId === sourceSessionId && (r.status === "completed" || r.status === "failed") && !r.deliveredAt
|
|
41777
|
+
).slice().sort((a, b2) => a.createdAt < b2.createdAt ? -1 : a.createdAt > b2.createdAt ? 1 : 0);
|
|
41778
|
+
}
|
|
41779
|
+
function formatDeliveryText(records) {
|
|
41780
|
+
const blocks = records.map((r) => {
|
|
41781
|
+
const head = `[dispatch ${r.dispatchId} \u2192 ${r.targetPersonaId}]`;
|
|
41782
|
+
if (r.outcome?.kind === "success") {
|
|
41783
|
+
const files = r.outcome.filePaths && r.outcome.filePaths.length > 0 ? `
|
|
41784
|
+
Related files:
|
|
41785
|
+
${r.outcome.filePaths.map((p2) => `- ${p2}`).join("\n")}` : "";
|
|
41786
|
+
return `${head} \u5B8C\u6210\uFF1A
|
|
41787
|
+
${r.outcome.text}${files}`;
|
|
41788
|
+
}
|
|
41789
|
+
const reason = r.outcome?.kind === "failure" ? r.outcome.reason : "unknown failure";
|
|
41790
|
+
return `${head} \u5931\u8D25\uFF1A${reason}`;
|
|
41791
|
+
});
|
|
41792
|
+
return ["\u4F60\u4E4B\u524D\u59D4\u6D3E\u51FA\u53BB\u7684\u4EFB\u52A1\u6709\u4E86\u7ED3\u679C\uFF1A", "", blocks.join("\n\n")].join("\n");
|
|
41793
|
+
}
|
|
41794
|
+
|
|
41738
41795
|
// src/session/runner.ts
|
|
41739
41796
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
41740
41797
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
@@ -41862,7 +41919,7 @@ var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A perso
|
|
|
41862
41919
|
- \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
|
|
41863
41920
|
- \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
|
|
41864
41921
|
|
|
41865
|
-
tool \u4F1A\
|
|
41922
|
+
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
41923
|
|
|
41867
41924
|
- **\u4E0D\u8981**\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF08\u4F60\u4E0D\u662F\u90A3\u4E2A persona\uFF09
|
|
41868
41925
|
- **\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 +41932,7 @@ tool \u4F1A\u963B\u585E\u6302\u8D77\u7B49\u5BF9\u65B9\u4EBA\u683C\u5E72\u5B8C\uF
|
|
|
41875
41932
|
|
|
41876
41933
|
- \`targetDeviceId = <token \u7B2C\u4E8C\u6BB5\u7684 deviceId\uFF0C\u539F\u6837\u586B>\`
|
|
41877
41934
|
|
|
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\
|
|
41935
|
+
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
41936
|
|
|
41880
41937
|
## \u88AB dispatch \u63A5\u5230\u4EFB\u52A1
|
|
41881
41938
|
|
|
@@ -43725,6 +43782,13 @@ var SessionManager = class {
|
|
|
43725
43782
|
}
|
|
43726
43783
|
}
|
|
43727
43784
|
}
|
|
43785
|
+
if (compressed.type === "session:status" && this.deps.dispatchStore) {
|
|
43786
|
+
const s = compressed;
|
|
43787
|
+
if (s.sessionId && s.status !== "running") {
|
|
43788
|
+
const sid = s.sessionId;
|
|
43789
|
+
setTimeout(() => this.deliverPending(sid), 0);
|
|
43790
|
+
}
|
|
43791
|
+
}
|
|
43728
43792
|
if (this.currentCollector) {
|
|
43729
43793
|
this.currentCollector.push({ frame: compressed, target });
|
|
43730
43794
|
return;
|
|
@@ -44051,6 +44115,67 @@ var SessionManager = class {
|
|
|
44051
44115
|
});
|
|
44052
44116
|
return { response: { ok: true }, broadcast };
|
|
44053
44117
|
}
|
|
44118
|
+
/**
|
|
44119
|
+
* Dispatch 结果投递(spec 2026-07-20 §5):查台账里该 source session 名下已完成
|
|
44120
|
+
* 且未投递的行,合并成一段 plain text 结果包注入回 source session。
|
|
44121
|
+
*
|
|
44122
|
+
* 触发点两个:complete 钩子(PersonaDispatchManager.onCompleted)+ source turn-end
|
|
44123
|
+
* 兜底 sweep(routeFromRunner 的 session:status 钩子)。幂等:投递成功盖 deliveredAt,
|
|
44124
|
+
* 再次调用查无未投递行直接返回。
|
|
44125
|
+
*
|
|
44126
|
+
* 判定口径:source 当前 running(含 reducer spawning,压缩后同 running)→ 不打扰,
|
|
44127
|
+
* 结果躺台账等下次 sweep。send 抛错(session 已删等)→ 记 log 不盖 deliveredAt,
|
|
44128
|
+
* 下次 sweep 自然重试。注入直接走 runner.input(无 collector),frames 经
|
|
44129
|
+
* routeFromRunner 正常广播上 wire。
|
|
44130
|
+
*/
|
|
44131
|
+
deliverPending(sourceSessionId) {
|
|
44132
|
+
const store = this.deps.dispatchStore;
|
|
44133
|
+
if (!store) return;
|
|
44134
|
+
const pending = selectPendingForDelivery(store.list({ sourceSessionId }), sourceSessionId);
|
|
44135
|
+
if (pending.length === 0) return;
|
|
44136
|
+
const state = this.tryGetState(sourceSessionId);
|
|
44137
|
+
if (state && compressStatus(state.status) === "running") return;
|
|
44138
|
+
if (!this.deps.ownerPrincipalId) {
|
|
44139
|
+
this.deps.logger?.warn("dispatch.deliver.no-owner-principal", { sourceSessionId });
|
|
44140
|
+
return;
|
|
44141
|
+
}
|
|
44142
|
+
const sender = principalToSender(
|
|
44143
|
+
makeOwnerPrincipal(
|
|
44144
|
+
this.deps.ownerPrincipalId,
|
|
44145
|
+
this.deps.ownerDisplayName ?? "Owner",
|
|
44146
|
+
this.deps.ownerFeishuUnionId
|
|
44147
|
+
)
|
|
44148
|
+
);
|
|
44149
|
+
try {
|
|
44150
|
+
const file = this.findOwnedSession(sourceSessionId);
|
|
44151
|
+
if (!file) {
|
|
44152
|
+
this.deps.logger?.info("dispatch.deliver.source-gone", { sourceSessionId });
|
|
44153
|
+
return;
|
|
44154
|
+
}
|
|
44155
|
+
const runner = this.ensureRunnerForScope(file, this.scopeForFile(file));
|
|
44156
|
+
runner.input({
|
|
44157
|
+
kind: "command",
|
|
44158
|
+
command: {
|
|
44159
|
+
kind: "send",
|
|
44160
|
+
text: formatDeliveryText(pending),
|
|
44161
|
+
senderPrincipal: sender
|
|
44162
|
+
}
|
|
44163
|
+
});
|
|
44164
|
+
} catch (err) {
|
|
44165
|
+
this.deps.logger?.warn("dispatch.deliver.send-failed", {
|
|
44166
|
+
sourceSessionId,
|
|
44167
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
44168
|
+
});
|
|
44169
|
+
return;
|
|
44170
|
+
}
|
|
44171
|
+
const nowIso3 = new Date(this.deps.now?.() ?? Date.now()).toISOString();
|
|
44172
|
+
for (const r of pending) store.update(r.dispatchId, { deliveredAt: nowIso3 });
|
|
44173
|
+
this.deps.logger?.info("dispatch.deliver.ok", {
|
|
44174
|
+
sourceSessionId,
|
|
44175
|
+
count: pending.length,
|
|
44176
|
+
dispatchIds: pending.map((r) => r.dispatchId)
|
|
44177
|
+
});
|
|
44178
|
+
}
|
|
44054
44179
|
/**
|
|
44055
44180
|
* 只读拿 SessionState;session 不存在返 null(不 throw)。
|
|
44056
44181
|
* handlers/session.ts:currentTurnSender 用(loopback HTTP RPC 绝对不能因不存在的 sid 崩)。
|
|
@@ -46657,8 +46782,8 @@ function turnStartInput(text) {
|
|
|
46657
46782
|
const items = [];
|
|
46658
46783
|
let leftover = text;
|
|
46659
46784
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
46660
|
-
const [marker, name,
|
|
46661
|
-
items.push({ type: "skill", name, path:
|
|
46785
|
+
const [marker, name, path71] = m2;
|
|
46786
|
+
items.push({ type: "skill", name, path: path71 });
|
|
46662
46787
|
leftover = leftover.replace(marker, "");
|
|
46663
46788
|
}
|
|
46664
46789
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -48157,35 +48282,60 @@ var PersonaDispatchManager = class {
|
|
|
48157
48282
|
dispatchId,
|
|
48158
48283
|
sourceSessionId: args.sourceSessionId,
|
|
48159
48284
|
targetPersona: args.targetPersona,
|
|
48160
|
-
waiters: []
|
|
48161
|
-
|
|
48285
|
+
waiters: []
|
|
48286
|
+
});
|
|
48287
|
+
this.deps.store.add({
|
|
48288
|
+
dispatchId,
|
|
48289
|
+
sourceSessionId: args.sourceSessionId,
|
|
48290
|
+
...args.sourcePersonaId ? { sourcePersonaId: args.sourcePersonaId } : {},
|
|
48291
|
+
targetPersonaId: args.targetPersona,
|
|
48292
|
+
taskText: args.taskText
|
|
48162
48293
|
});
|
|
48163
48294
|
return { dispatchId };
|
|
48164
48295
|
}
|
|
48165
48296
|
get(dispatchId) {
|
|
48166
48297
|
return this.map.get(dispatchId);
|
|
48167
48298
|
}
|
|
48168
|
-
|
|
48299
|
+
complete(dispatchId, outcome) {
|
|
48169
48300
|
const state = this.map.get(dispatchId);
|
|
48170
|
-
|
|
48171
|
-
|
|
48301
|
+
const status = outcome.kind === "success" ? "completed" : "failed";
|
|
48302
|
+
const updated = this.deps.store.update(dispatchId, {
|
|
48303
|
+
status,
|
|
48304
|
+
outcome,
|
|
48305
|
+
completedAt: new Date(this.deps.now()).toISOString()
|
|
48306
|
+
});
|
|
48307
|
+
if (state) {
|
|
48308
|
+
const waiters = state.waiters;
|
|
48309
|
+
state.waiters = [];
|
|
48310
|
+
for (const w2 of waiters) w2.resolve(outcome);
|
|
48311
|
+
this.map.delete(dispatchId);
|
|
48312
|
+
}
|
|
48313
|
+
const sourceSessionId = updated?.sourceSessionId ?? state?.sourceSessionId;
|
|
48314
|
+
if (sourceSessionId) this.deps.onCompleted?.(sourceSessionId);
|
|
48315
|
+
}
|
|
48316
|
+
/**
|
|
48317
|
+
* mesh B 角色 hold 专用(跨设备 dispatch 的 peer 侧):guest B-role handler 用它
|
|
48318
|
+
* 挂住 /rpc HTTP 响应直到 complete,把 outcome 回传给 A 侧 daemon 的 forwardToPeer
|
|
48319
|
+
* (A 侧后台 await,A 的 tool call 不受影响照样秒回)。
|
|
48320
|
+
* 本地 dispatch 链路**不用**这个——本地 outcome 只走台账 + deliverPending。
|
|
48321
|
+
*/
|
|
48322
|
+
async waitForOutcome(dispatchId) {
|
|
48323
|
+
const state = this.map.get(dispatchId);
|
|
48324
|
+
if (!state) {
|
|
48325
|
+
const rec3 = this.deps.store.get(dispatchId);
|
|
48326
|
+
if (rec3?.outcome) return rec3.outcome;
|
|
48327
|
+
throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
48328
|
+
}
|
|
48172
48329
|
const d = defer();
|
|
48173
48330
|
state.waiters.push(d);
|
|
48174
48331
|
return d.promise;
|
|
48175
48332
|
}
|
|
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
48333
|
/** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
|
|
48185
48334
|
registerBSession(dispatchId, bSessionId) {
|
|
48186
48335
|
const state = this.map.get(dispatchId);
|
|
48187
48336
|
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
48188
48337
|
state.bSessionId = bSessionId;
|
|
48338
|
+
this.deps.store.update(dispatchId, { workerSessionId: bSessionId });
|
|
48189
48339
|
}
|
|
48190
48340
|
/** reducer buildSpawnContext 调,按 B 的 sessionId 反查 dispatchId(用于注 CLAWD_DISPATCH_ID env) */
|
|
48191
48341
|
lookupDispatchByBSessionId(bSessionId) {
|
|
@@ -48196,11 +48346,112 @@ var PersonaDispatchManager = class {
|
|
|
48196
48346
|
}
|
|
48197
48347
|
};
|
|
48198
48348
|
|
|
48349
|
+
// src/dispatch/store.ts
|
|
48350
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
48351
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
48352
|
+
|
|
48353
|
+
// src/shift/constants.ts
|
|
48354
|
+
var MAX_RUNS_PER_SHIFT = 30;
|
|
48355
|
+
var DEFAULT_TIMEOUT_MS = 30 * 6e4;
|
|
48356
|
+
var CONSECUTIVE_ERROR_THRESHOLD = 5;
|
|
48357
|
+
var TICK_INTERVAL_MS = 1e4;
|
|
48358
|
+
var STORE_FLUSH_DEBOUNCE_MS = 500;
|
|
48359
|
+
var CLOCK_JUMP_THRESHOLD_MS = 5 * 6e4;
|
|
48360
|
+
|
|
48361
|
+
// src/dispatch/store.ts
|
|
48362
|
+
var TASK_TEXT_MAX = 500;
|
|
48363
|
+
function createDispatchStore(deps) {
|
|
48364
|
+
let records = [];
|
|
48365
|
+
let flushTimer = null;
|
|
48366
|
+
async function load() {
|
|
48367
|
+
let raw;
|
|
48368
|
+
try {
|
|
48369
|
+
raw = await import_promises.default.readFile(deps.filePath, "utf8");
|
|
48370
|
+
} catch (e) {
|
|
48371
|
+
if (e.code === "ENOENT") {
|
|
48372
|
+
records = [];
|
|
48373
|
+
return;
|
|
48374
|
+
}
|
|
48375
|
+
throw e;
|
|
48376
|
+
}
|
|
48377
|
+
const parsed = JSON.parse(raw);
|
|
48378
|
+
if (parsed.version !== 1) {
|
|
48379
|
+
throw new Error(`dispatch.json: unsupported version ${parsed.version}`);
|
|
48380
|
+
}
|
|
48381
|
+
records = parsed.records ?? [];
|
|
48382
|
+
}
|
|
48383
|
+
async function flushNow() {
|
|
48384
|
+
if (flushTimer) {
|
|
48385
|
+
clearTimeout(flushTimer);
|
|
48386
|
+
flushTimer = null;
|
|
48387
|
+
}
|
|
48388
|
+
const content = { version: 1, records };
|
|
48389
|
+
await import_promises.default.mkdir(import_node_path16.default.dirname(deps.filePath), { recursive: true });
|
|
48390
|
+
const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
|
|
48391
|
+
await import_promises.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
|
|
48392
|
+
await import_promises.default.rename(tmp, deps.filePath);
|
|
48393
|
+
}
|
|
48394
|
+
function scheduleFlush() {
|
|
48395
|
+
if (flushTimer) return;
|
|
48396
|
+
flushTimer = setTimeout(() => {
|
|
48397
|
+
flushTimer = null;
|
|
48398
|
+
flushNow().catch((err) => {
|
|
48399
|
+
deps.onFlushError?.(err);
|
|
48400
|
+
});
|
|
48401
|
+
}, STORE_FLUSH_DEBOUNCE_MS);
|
|
48402
|
+
}
|
|
48403
|
+
function get(dispatchId) {
|
|
48404
|
+
return records.find((r) => r.dispatchId === dispatchId);
|
|
48405
|
+
}
|
|
48406
|
+
function add(input) {
|
|
48407
|
+
const rec3 = {
|
|
48408
|
+
dispatchId: input.dispatchId,
|
|
48409
|
+
sourceSessionId: input.sourceSessionId,
|
|
48410
|
+
...input.sourcePersonaId ? { sourcePersonaId: input.sourcePersonaId } : {},
|
|
48411
|
+
targetPersonaId: input.targetPersonaId,
|
|
48412
|
+
taskText: input.taskText.slice(0, TASK_TEXT_MAX),
|
|
48413
|
+
status: "running",
|
|
48414
|
+
...input.meta ? { meta: input.meta } : {},
|
|
48415
|
+
createdAt: new Date(deps.now()).toISOString()
|
|
48416
|
+
};
|
|
48417
|
+
records.push(rec3);
|
|
48418
|
+
scheduleFlush();
|
|
48419
|
+
return rec3;
|
|
48420
|
+
}
|
|
48421
|
+
function update(dispatchId, patch) {
|
|
48422
|
+
const idx = records.findIndex((r) => r.dispatchId === dispatchId);
|
|
48423
|
+
if (idx < 0) return void 0;
|
|
48424
|
+
const merged = { ...records[idx], ...patch };
|
|
48425
|
+
records[idx] = merged;
|
|
48426
|
+
scheduleFlush();
|
|
48427
|
+
return merged;
|
|
48428
|
+
}
|
|
48429
|
+
function list(filter) {
|
|
48430
|
+
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);
|
|
48431
|
+
}
|
|
48432
|
+
function markInterruptedAsFailed(nowIso3) {
|
|
48433
|
+
let touched = false;
|
|
48434
|
+
for (const r of records) {
|
|
48435
|
+
if (r.status === "running") {
|
|
48436
|
+
r.status = "failed";
|
|
48437
|
+
r.outcome = {
|
|
48438
|
+
kind: "failure",
|
|
48439
|
+
reason: "daemon restarted while dispatch in flight"
|
|
48440
|
+
};
|
|
48441
|
+
r.completedAt = nowIso3;
|
|
48442
|
+
touched = true;
|
|
48443
|
+
}
|
|
48444
|
+
}
|
|
48445
|
+
if (touched) scheduleFlush();
|
|
48446
|
+
}
|
|
48447
|
+
return { load, flushNow, add, update, list, get, markInterruptedAsFailed };
|
|
48448
|
+
}
|
|
48449
|
+
|
|
48199
48450
|
// src/dispatch/mcp-config.ts
|
|
48200
48451
|
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
48201
|
-
var
|
|
48452
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
48202
48453
|
function dispatchMcpConfigPath(dataDir) {
|
|
48203
|
-
return
|
|
48454
|
+
return import_node_path17.default.join(dataDir, "dispatch.mcp.json");
|
|
48204
48455
|
}
|
|
48205
48456
|
function writeDispatchMcpConfig(args) {
|
|
48206
48457
|
const cfgPath = dispatchMcpConfigPath(args.dataDir);
|
|
@@ -48222,9 +48473,9 @@ function writeDispatchMcpConfig(args) {
|
|
|
48222
48473
|
|
|
48223
48474
|
// src/ticket/mcp-config.ts
|
|
48224
48475
|
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
48225
|
-
var
|
|
48476
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
48226
48477
|
function ticketMcpConfigPath(dataDir) {
|
|
48227
|
-
return
|
|
48478
|
+
return import_node_path18.default.join(dataDir, "ticket.mcp.json");
|
|
48228
48479
|
}
|
|
48229
48480
|
function writeTicketMcpConfig(args) {
|
|
48230
48481
|
const cfgPath = ticketMcpConfigPath(args.dataDir);
|
|
@@ -48251,9 +48502,9 @@ function writeTicketMcpConfig(args) {
|
|
|
48251
48502
|
|
|
48252
48503
|
// src/shift/mcp-config.ts
|
|
48253
48504
|
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
48254
|
-
var
|
|
48505
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
48255
48506
|
function shiftMcpConfigPath(dataDir) {
|
|
48256
|
-
return
|
|
48507
|
+
return import_node_path19.default.join(dataDir, "shift.mcp.json");
|
|
48257
48508
|
}
|
|
48258
48509
|
async function writeShiftMcpConfig(args) {
|
|
48259
48510
|
const cfgPath = shiftMcpConfigPath(args.dataDir);
|
|
@@ -48275,9 +48526,9 @@ async function writeShiftMcpConfig(args) {
|
|
|
48275
48526
|
|
|
48276
48527
|
// src/inbox/mcp-config.ts
|
|
48277
48528
|
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
48278
|
-
var
|
|
48529
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
48279
48530
|
function inboxMcpConfigPath(dataDir) {
|
|
48280
|
-
return
|
|
48531
|
+
return import_node_path20.default.join(dataDir, "inbox.mcp.json");
|
|
48281
48532
|
}
|
|
48282
48533
|
async function writeInboxMcpConfig(args) {
|
|
48283
48534
|
const cfgPath = inboxMcpConfigPath(args.dataDir);
|
|
@@ -48299,9 +48550,9 @@ async function writeInboxMcpConfig(args) {
|
|
|
48299
48550
|
|
|
48300
48551
|
// src/peer-ops/mcp-config.ts
|
|
48301
48552
|
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
48302
|
-
var
|
|
48553
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
48303
48554
|
function peerOpsMcpConfigPath(dataDir) {
|
|
48304
|
-
return
|
|
48555
|
+
return import_node_path21.default.join(dataDir, "peer-ops.mcp.json");
|
|
48305
48556
|
}
|
|
48306
48557
|
function writePeerOpsMcpConfig(args) {
|
|
48307
48558
|
const cfgPath = peerOpsMcpConfigPath(args.dataDir);
|
|
@@ -48320,18 +48571,10 @@ function writePeerOpsMcpConfig(args) {
|
|
|
48320
48571
|
}
|
|
48321
48572
|
|
|
48322
48573
|
// src/shift/store.ts
|
|
48323
|
-
var
|
|
48324
|
-
var
|
|
48574
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
48575
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
48325
48576
|
var import_node_crypto6 = require("crypto");
|
|
48326
48577
|
|
|
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
48578
|
// src/shift/schedule.ts
|
|
48336
48579
|
var import_cron_parser = __toESM(require_dist(), 1);
|
|
48337
48580
|
function computeNextRunAtMs(schedule, fromMs) {
|
|
@@ -48376,7 +48619,7 @@ function createShiftStore(deps) {
|
|
|
48376
48619
|
async function load() {
|
|
48377
48620
|
let raw;
|
|
48378
48621
|
try {
|
|
48379
|
-
raw = await
|
|
48622
|
+
raw = await import_promises2.default.readFile(deps.filePath, "utf8");
|
|
48380
48623
|
} catch (e) {
|
|
48381
48624
|
if (e.code === "ENOENT") {
|
|
48382
48625
|
shifts = [];
|
|
@@ -48404,10 +48647,10 @@ function createShiftStore(deps) {
|
|
|
48404
48647
|
flushTimer = null;
|
|
48405
48648
|
}
|
|
48406
48649
|
const content = { version: 1, shifts };
|
|
48407
|
-
await
|
|
48650
|
+
await import_promises2.default.mkdir(import_node_path22.default.dirname(deps.filePath), { recursive: true });
|
|
48408
48651
|
const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
|
|
48409
|
-
await
|
|
48410
|
-
await
|
|
48652
|
+
await import_promises2.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
|
|
48653
|
+
await import_promises2.default.rename(tmp, deps.filePath);
|
|
48411
48654
|
}
|
|
48412
48655
|
function scheduleFlush() {
|
|
48413
48656
|
if (flushTimer) return;
|
|
@@ -48842,18 +49085,33 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48842
49085
|
if (!deps.forwardToPeer) {
|
|
48843
49086
|
throw new Error("cross-device dispatch not wired (forwardToPeer missing)");
|
|
48844
49087
|
}
|
|
49088
|
+
if (!sourceSessionId) {
|
|
49089
|
+
throw new Error(
|
|
49090
|
+
"personaDispatch:run requires sessionId (caller must pass x-clawd-session-id header)"
|
|
49091
|
+
);
|
|
49092
|
+
}
|
|
49093
|
+
const { dispatchId: dispatchId2 } = mgr.start({
|
|
49094
|
+
sourceSessionId,
|
|
49095
|
+
targetPersona: args.targetPersona,
|
|
49096
|
+
taskText: args.prompt
|
|
49097
|
+
});
|
|
48845
49098
|
logger?.info("dispatch.run.forward", {
|
|
49099
|
+
dispatchId: dispatchId2,
|
|
48846
49100
|
targetDeviceId: args.targetDeviceId,
|
|
48847
49101
|
targetPersona: args.targetPersona
|
|
48848
49102
|
});
|
|
48849
|
-
|
|
49103
|
+
void deps.forwardToPeer({
|
|
48850
49104
|
targetDeviceId: args.targetDeviceId,
|
|
48851
49105
|
targetPersona: args.targetPersona,
|
|
48852
49106
|
prompt: args.prompt,
|
|
48853
49107
|
...args.model ? { model: args.model } : {}
|
|
49108
|
+
}).then((outcome) => mgr.complete(dispatchId2, outcome)).catch((err) => {
|
|
49109
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
49110
|
+
logger?.warn("dispatch.forward.failed", { dispatchId: dispatchId2, reason });
|
|
49111
|
+
mgr.complete(dispatchId2, { kind: "failure", reason });
|
|
48854
49112
|
});
|
|
48855
49113
|
return {
|
|
48856
|
-
response: { type: "personaDispatch:run:ok",
|
|
49114
|
+
response: { type: "personaDispatch:run:ok", dispatchId: dispatchId2 }
|
|
48857
49115
|
};
|
|
48858
49116
|
}
|
|
48859
49117
|
if (ctx?.principal.kind === "guest") {
|
|
@@ -48866,7 +49124,8 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48866
49124
|
}
|
|
48867
49125
|
const { dispatchId: dispatchId2 } = mgr.start({
|
|
48868
49126
|
sourceSessionId: ctx.principal.id,
|
|
48869
|
-
targetPersona: args.targetPersona
|
|
49127
|
+
targetPersona: args.targetPersona,
|
|
49128
|
+
taskText: args.prompt
|
|
48870
49129
|
});
|
|
48871
49130
|
logger?.info("dispatch.run.received.guest", {
|
|
48872
49131
|
dispatchId: dispatchId2,
|
|
@@ -48892,9 +49151,9 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48892
49151
|
reason: `failed to spawn B: ${reason}`
|
|
48893
49152
|
});
|
|
48894
49153
|
});
|
|
48895
|
-
const
|
|
49154
|
+
const outcome = await mgr.waitForOutcome(dispatchId2);
|
|
48896
49155
|
return {
|
|
48897
|
-
response: { type: "personaDispatch:run:ok", outcome
|
|
49156
|
+
response: { type: "personaDispatch:run:ok", outcome }
|
|
48898
49157
|
};
|
|
48899
49158
|
}
|
|
48900
49159
|
if (!sourceSessionId) {
|
|
@@ -48904,7 +49163,8 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48904
49163
|
}
|
|
48905
49164
|
const { dispatchId } = mgr.start({
|
|
48906
49165
|
sourceSessionId,
|
|
48907
|
-
targetPersona: args.targetPersona
|
|
49166
|
+
targetPersona: args.targetPersona,
|
|
49167
|
+
taskText: args.prompt
|
|
48908
49168
|
});
|
|
48909
49169
|
logger?.info("dispatch.run.received", {
|
|
48910
49170
|
dispatchId,
|
|
@@ -48928,14 +49188,8 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48928
49188
|
reason: `failed to spawn B: ${reason}`
|
|
48929
49189
|
});
|
|
48930
49190
|
});
|
|
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
49191
|
return {
|
|
48938
|
-
response: { type: "personaDispatch:run:ok",
|
|
49192
|
+
response: { type: "personaDispatch:run:ok", dispatchId }
|
|
48939
49193
|
};
|
|
48940
49194
|
};
|
|
48941
49195
|
const complete = async (frame) => {
|
|
@@ -48950,9 +49204,20 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48950
49204
|
response: { type: "personaDispatch:complete:ok" }
|
|
48951
49205
|
};
|
|
48952
49206
|
};
|
|
49207
|
+
const list = async (frame) => {
|
|
49208
|
+
const { type: _t, requestId: _r, ...rest } = frame;
|
|
49209
|
+
const args = DispatchListArgsSchema.parse(rest);
|
|
49210
|
+
const records = deps.store.list(
|
|
49211
|
+
args.sourceSessionId ? { sourceSessionId: args.sourceSessionId } : void 0
|
|
49212
|
+
);
|
|
49213
|
+
return {
|
|
49214
|
+
response: { type: "personaDispatch:list:ok", records }
|
|
49215
|
+
};
|
|
49216
|
+
};
|
|
48953
49217
|
return {
|
|
48954
49218
|
"personaDispatch:run": run,
|
|
48955
|
-
"personaDispatch:complete": complete
|
|
49219
|
+
"personaDispatch:complete": complete,
|
|
49220
|
+
"personaDispatch:list": list
|
|
48956
49221
|
};
|
|
48957
49222
|
}
|
|
48958
49223
|
|
|
@@ -49258,13 +49523,13 @@ function mapSkillsListResponse(res) {
|
|
|
49258
49523
|
const r = s ?? {};
|
|
49259
49524
|
const name = str3(r.name);
|
|
49260
49525
|
if (!name) continue;
|
|
49261
|
-
const
|
|
49526
|
+
const path71 = str3(r.path);
|
|
49262
49527
|
const description = str3(r.description);
|
|
49263
49528
|
const isPlugin = name.includes(":");
|
|
49264
49529
|
out.push({
|
|
49265
49530
|
name,
|
|
49266
49531
|
source: isPlugin ? "plugin" : "project",
|
|
49267
|
-
...
|
|
49532
|
+
...path71 ? { path: path71 } : {},
|
|
49268
49533
|
...description ? { description } : {},
|
|
49269
49534
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
49270
49535
|
});
|
|
@@ -49305,14 +49570,14 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
49305
49570
|
// src/workspace/browser.ts
|
|
49306
49571
|
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
49307
49572
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
49308
|
-
var
|
|
49573
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
49309
49574
|
init_protocol();
|
|
49310
49575
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
49311
49576
|
function resolveInsideCwd(cwd, subpath) {
|
|
49312
|
-
const absCwd =
|
|
49313
|
-
const joined =
|
|
49314
|
-
const rel =
|
|
49315
|
-
if (rel.startsWith("..") ||
|
|
49577
|
+
const absCwd = import_node_path23.default.resolve(cwd);
|
|
49578
|
+
const joined = import_node_path23.default.resolve(absCwd, subpath ?? ".");
|
|
49579
|
+
const rel = import_node_path23.default.relative(absCwd, joined);
|
|
49580
|
+
if (rel.startsWith("..") || import_node_path23.default.isAbsolute(rel)) {
|
|
49316
49581
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
49317
49582
|
}
|
|
49318
49583
|
return joined;
|
|
@@ -49343,7 +49608,7 @@ var WorkspaceBrowser = class {
|
|
|
49343
49608
|
mtime: ""
|
|
49344
49609
|
};
|
|
49345
49610
|
try {
|
|
49346
|
-
const st = import_node_fs24.default.statSync(
|
|
49611
|
+
const st = import_node_fs24.default.statSync(import_node_path23.default.join(full, d.name));
|
|
49347
49612
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
49348
49613
|
if (d.isFile()) entry.size = st.size;
|
|
49349
49614
|
} catch {
|
|
@@ -49390,7 +49655,7 @@ var WorkspaceBrowser = class {
|
|
|
49390
49655
|
// src/skills/agents-scanner.ts
|
|
49391
49656
|
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
49392
49657
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
49393
|
-
var
|
|
49658
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
49394
49659
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
49395
49660
|
function isDirLikeSync2(p2) {
|
|
49396
49661
|
try {
|
|
@@ -49428,10 +49693,10 @@ function scanAgentsDir(dir, source, seen, out) {
|
|
|
49428
49693
|
}
|
|
49429
49694
|
for (const ent of entries) {
|
|
49430
49695
|
if (!ent.name.endsWith(".md")) continue;
|
|
49431
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
49696
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path24.default.join(dir, ent.name)))) {
|
|
49432
49697
|
continue;
|
|
49433
49698
|
}
|
|
49434
|
-
const filePath =
|
|
49699
|
+
const filePath = import_node_path24.default.join(dir, ent.name);
|
|
49435
49700
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
49436
49701
|
if (seen.has(baseName)) continue;
|
|
49437
49702
|
seen.add(baseName);
|
|
@@ -49454,7 +49719,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
49454
49719
|
return;
|
|
49455
49720
|
}
|
|
49456
49721
|
for (const ent of entries) {
|
|
49457
|
-
const childPath =
|
|
49722
|
+
const childPath = import_node_path24.default.join(dir, ent.name);
|
|
49458
49723
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
49459
49724
|
walk2(childPath, [...namespaces, ent.name]);
|
|
49460
49725
|
continue;
|
|
@@ -49479,9 +49744,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
49479
49744
|
walk2(root, []);
|
|
49480
49745
|
}
|
|
49481
49746
|
function readInstalledPlugins2(home) {
|
|
49482
|
-
const pluginsDir =
|
|
49483
|
-
const v2 =
|
|
49484
|
-
const v1 =
|
|
49747
|
+
const pluginsDir = import_node_path24.default.join(home, ".claude", "plugins");
|
|
49748
|
+
const v2 = import_node_path24.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
49749
|
+
const v1 = import_node_path24.default.join(pluginsDir, "installed_plugins.json");
|
|
49485
49750
|
let raw = null;
|
|
49486
49751
|
for (const candidate of [v2, v1]) {
|
|
49487
49752
|
try {
|
|
@@ -49510,19 +49775,19 @@ function readInstalledPlugins2(home) {
|
|
|
49510
49775
|
return out;
|
|
49511
49776
|
}
|
|
49512
49777
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
49513
|
-
let cur =
|
|
49514
|
-
const fsRoot =
|
|
49778
|
+
let cur = import_node_path24.default.resolve(startCwd);
|
|
49779
|
+
const fsRoot = import_node_path24.default.parse(cur).root;
|
|
49515
49780
|
while (true) {
|
|
49516
|
-
scanAgentsDir(
|
|
49781
|
+
scanAgentsDir(import_node_path24.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
49517
49782
|
let hasGit = false;
|
|
49518
49783
|
try {
|
|
49519
|
-
hasGit = import_node_fs25.default.existsSync(
|
|
49784
|
+
hasGit = import_node_fs25.default.existsSync(import_node_path24.default.join(cur, ".git"));
|
|
49520
49785
|
} catch {
|
|
49521
49786
|
}
|
|
49522
49787
|
if (hasGit) return;
|
|
49523
49788
|
if (cur === home) return;
|
|
49524
49789
|
if (cur === fsRoot) return;
|
|
49525
|
-
const parent =
|
|
49790
|
+
const parent = import_node_path24.default.dirname(cur);
|
|
49526
49791
|
if (parent === cur) return;
|
|
49527
49792
|
cur = parent;
|
|
49528
49793
|
}
|
|
@@ -49557,7 +49822,7 @@ var AgentsScanner = class {
|
|
|
49557
49822
|
}
|
|
49558
49823
|
const fsBlock = [];
|
|
49559
49824
|
scanAgentsDir(
|
|
49560
|
-
|
|
49825
|
+
import_node_path24.default.join(this.home, ".claude", "agents"),
|
|
49561
49826
|
"global",
|
|
49562
49827
|
seen,
|
|
49563
49828
|
fsBlock
|
|
@@ -49571,7 +49836,7 @@ var AgentsScanner = class {
|
|
|
49571
49836
|
...this.extraPluginRoots
|
|
49572
49837
|
];
|
|
49573
49838
|
for (const { name, root } of plugins) {
|
|
49574
|
-
const agentsRoot =
|
|
49839
|
+
const agentsRoot = import_node_path24.default.join(root, "agents");
|
|
49575
49840
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
49576
49841
|
}
|
|
49577
49842
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -49581,13 +49846,13 @@ var AgentsScanner = class {
|
|
|
49581
49846
|
// src/observer/session-observer.ts
|
|
49582
49847
|
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
49583
49848
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
49584
|
-
var
|
|
49849
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
49585
49850
|
init_claude_history();
|
|
49586
49851
|
|
|
49587
49852
|
// src/observer/subagent-meta-observer.ts
|
|
49588
49853
|
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
49589
49854
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
49590
|
-
var
|
|
49855
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
49591
49856
|
init_claude_history();
|
|
49592
49857
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
49593
49858
|
var SubagentMetaObserver = class {
|
|
@@ -49600,7 +49865,7 @@ var SubagentMetaObserver = class {
|
|
|
49600
49865
|
watches = /* @__PURE__ */ new Map();
|
|
49601
49866
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
49602
49867
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
49603
|
-
return
|
|
49868
|
+
return import_node_path25.default.join(
|
|
49604
49869
|
this.home,
|
|
49605
49870
|
".claude",
|
|
49606
49871
|
"projects",
|
|
@@ -49656,7 +49921,7 @@ var SubagentMetaObserver = class {
|
|
|
49656
49921
|
if (!m2) return;
|
|
49657
49922
|
const agentId = m2[1];
|
|
49658
49923
|
if (w2.emitted.has(agentId)) return;
|
|
49659
|
-
const file =
|
|
49924
|
+
const file = import_node_path25.default.join(w2.dirPath, name);
|
|
49660
49925
|
let raw;
|
|
49661
49926
|
try {
|
|
49662
49927
|
raw = import_node_fs26.default.readFileSync(file, "utf8");
|
|
@@ -49716,7 +49981,7 @@ var SessionObserver = class {
|
|
|
49716
49981
|
metaObserver;
|
|
49717
49982
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
49718
49983
|
if (override) return override;
|
|
49719
|
-
return
|
|
49984
|
+
return import_node_path26.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
49720
49985
|
}
|
|
49721
49986
|
start(args) {
|
|
49722
49987
|
this.stop(args.sessionId);
|
|
@@ -49742,10 +50007,10 @@ var SessionObserver = class {
|
|
|
49742
50007
|
lastDeriveMs: 0
|
|
49743
50008
|
};
|
|
49744
50009
|
try {
|
|
49745
|
-
import_node_fs27.default.mkdirSync(
|
|
50010
|
+
import_node_fs27.default.mkdirSync(import_node_path26.default.dirname(filePath), { recursive: true });
|
|
49746
50011
|
} catch {
|
|
49747
50012
|
}
|
|
49748
|
-
w2.watcher = import_node_fs27.default.watch(
|
|
50013
|
+
w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
49749
50014
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
49750
50015
|
this.poll(w2);
|
|
49751
50016
|
});
|
|
@@ -49842,7 +50107,7 @@ var SessionObserver = class {
|
|
|
49842
50107
|
const now = Date.now();
|
|
49843
50108
|
if (now - w2.lastRelocateScanMs < 1e3) return;
|
|
49844
50109
|
w2.lastRelocateScanMs = now;
|
|
49845
|
-
const projectsRoot =
|
|
50110
|
+
const projectsRoot = import_node_path26.default.join(this.home, ".claude", "projects");
|
|
49846
50111
|
const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
|
|
49847
50112
|
if (!found || found === w2.filePath) return;
|
|
49848
50113
|
try {
|
|
@@ -49851,7 +50116,7 @@ var SessionObserver = class {
|
|
|
49851
50116
|
}
|
|
49852
50117
|
w2.filePath = found;
|
|
49853
50118
|
try {
|
|
49854
|
-
w2.watcher = import_node_fs27.default.watch(
|
|
50119
|
+
w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(found), { persistent: false }, (_event, changedName) => {
|
|
49855
50120
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
49856
50121
|
this.poll(w2);
|
|
49857
50122
|
});
|
|
@@ -50435,13 +50700,13 @@ var EXPOSED_RPC_METHODS = [
|
|
|
50435
50700
|
// dataclaw-builder:persona 建页时取建页人身份(含 union_id)写进生成 app 的配置。
|
|
50436
50701
|
// 路由到 handlers['auth:getIdentity'],只返 identity、绝不带 ttcToken(见 handlers/feishu-auth.ts)。
|
|
50437
50702
|
"auth.getIdentity",
|
|
50438
|
-
// Persona dispatch
|
|
50439
|
-
// B
|
|
50440
|
-
// protocol/src/dispatch.ts。
|
|
50703
|
+
// Persona dispatch(异步,spec 2026-07-20):A 端 dispatch MCP server 调 run(秒回 dispatchId);
|
|
50704
|
+
// B 端调 complete(带 outcome → 台账 + 投递);发起方调 list 查台账。详见 protocol/src/dispatch.ts。
|
|
50441
50705
|
"personaDispatch.run",
|
|
50442
50706
|
// 跨设备 exec(spec 2026-07-16):A 侧本地 cc 经 /api/rpc 调,带 peerDeviceId → daemon forward。
|
|
50443
50707
|
"peerExec.run",
|
|
50444
50708
|
"personaDispatch.complete",
|
|
50709
|
+
"personaDispatch.list",
|
|
50445
50710
|
// clawd-shift v1 (spec 2026-06-24-clawd-shift):cc 子进程内的 shift MCP server 调
|
|
50446
50711
|
// 这 5 个 method 管理 owner 的 shift(fire-and-forget 排班)。鉴权靠 body.personaId
|
|
50447
50712
|
// (mcp-server 从 process.env.CLAWD_PERSONA_ID 读,源 = SessionFile.ownerPersonaId)。
|
|
@@ -50706,14 +50971,14 @@ async function authenticate(token, deps) {
|
|
|
50706
50971
|
}
|
|
50707
50972
|
|
|
50708
50973
|
// src/permission/capability-store.ts
|
|
50709
|
-
var
|
|
50710
|
-
var
|
|
50974
|
+
var fs32 = __toESM(require("fs"), 1);
|
|
50975
|
+
var path31 = __toESM(require("path"), 1);
|
|
50711
50976
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
50712
50977
|
var FILE_VERSION = 1;
|
|
50713
50978
|
var CapabilityStore = class {
|
|
50714
50979
|
constructor(dataDir) {
|
|
50715
50980
|
this.dataDir = dataDir;
|
|
50716
|
-
|
|
50981
|
+
fs32.mkdirSync(dataDir, { recursive: true });
|
|
50717
50982
|
this.cache = this.readFromDisk();
|
|
50718
50983
|
}
|
|
50719
50984
|
dataDir;
|
|
@@ -50737,13 +51002,13 @@ var CapabilityStore = class {
|
|
|
50737
51002
|
this.flush();
|
|
50738
51003
|
}
|
|
50739
51004
|
filePath() {
|
|
50740
|
-
return
|
|
51005
|
+
return path31.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
50741
51006
|
}
|
|
50742
51007
|
readFromDisk() {
|
|
50743
51008
|
const file = this.filePath();
|
|
50744
51009
|
let raw;
|
|
50745
51010
|
try {
|
|
50746
|
-
raw =
|
|
51011
|
+
raw = fs32.readFileSync(file, "utf8");
|
|
50747
51012
|
} catch (err) {
|
|
50748
51013
|
if (err?.code === "ENOENT") return [];
|
|
50749
51014
|
return [];
|
|
@@ -50771,10 +51036,10 @@ var CapabilityStore = class {
|
|
|
50771
51036
|
}
|
|
50772
51037
|
atomicWrite(file, content) {
|
|
50773
51038
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
50774
|
-
|
|
50775
|
-
|
|
51039
|
+
fs32.writeFileSync(tmp, content, { mode: 384 });
|
|
51040
|
+
fs32.renameSync(tmp, file);
|
|
50776
51041
|
try {
|
|
50777
|
-
|
|
51042
|
+
fs32.chmodSync(file, 384);
|
|
50778
51043
|
} catch {
|
|
50779
51044
|
}
|
|
50780
51045
|
}
|
|
@@ -50867,14 +51132,14 @@ var CapabilityManager = class {
|
|
|
50867
51132
|
};
|
|
50868
51133
|
|
|
50869
51134
|
// src/permission/cleanup.ts
|
|
50870
|
-
var
|
|
51135
|
+
var fs33 = __toESM(require("fs"), 1);
|
|
50871
51136
|
function cleanupGuestSessionsForCapability(cap, factory) {
|
|
50872
51137
|
const removed = [];
|
|
50873
51138
|
for (const g2 of cap.grants) {
|
|
50874
51139
|
if (g2.resource.type !== "persona") continue;
|
|
50875
51140
|
const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
|
|
50876
51141
|
try {
|
|
50877
|
-
|
|
51142
|
+
fs33.rmSync(dir, { recursive: true, force: true });
|
|
50878
51143
|
removed.push(dir);
|
|
50879
51144
|
} catch {
|
|
50880
51145
|
}
|
|
@@ -50883,13 +51148,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
50883
51148
|
}
|
|
50884
51149
|
|
|
50885
51150
|
// src/inbox/inbox-store.ts
|
|
50886
|
-
var
|
|
50887
|
-
var
|
|
51151
|
+
var fs34 = __toESM(require("fs"), 1);
|
|
51152
|
+
var path32 = __toESM(require("path"), 1);
|
|
50888
51153
|
var INBOX_SUBDIR = "inbox";
|
|
50889
51154
|
var InboxStore = class {
|
|
50890
51155
|
constructor(dataDir) {
|
|
50891
51156
|
this.dataDir = dataDir;
|
|
50892
|
-
|
|
51157
|
+
fs34.mkdirSync(this.dirPath(), { recursive: true });
|
|
50893
51158
|
}
|
|
50894
51159
|
dataDir;
|
|
50895
51160
|
/**
|
|
@@ -50901,7 +51166,7 @@ var InboxStore = class {
|
|
|
50901
51166
|
const file = this.filePath(peerDeviceId);
|
|
50902
51167
|
let raw;
|
|
50903
51168
|
try {
|
|
50904
|
-
raw =
|
|
51169
|
+
raw = fs34.readFileSync(file, "utf8");
|
|
50905
51170
|
} catch (err) {
|
|
50906
51171
|
if (err?.code === "ENOENT") return [];
|
|
50907
51172
|
return [];
|
|
@@ -50917,7 +51182,7 @@ var InboxStore = class {
|
|
|
50917
51182
|
const dir = this.dirPath();
|
|
50918
51183
|
let entries;
|
|
50919
51184
|
try {
|
|
50920
|
-
entries =
|
|
51185
|
+
entries = fs34.readdirSync(dir);
|
|
50921
51186
|
} catch (err) {
|
|
50922
51187
|
if (err?.code === "ENOENT") return [];
|
|
50923
51188
|
return [];
|
|
@@ -50933,9 +51198,9 @@ var InboxStore = class {
|
|
|
50933
51198
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
50934
51199
|
const file = this.filePath(message.peerDeviceId);
|
|
50935
51200
|
const line = JSON.stringify(message) + "\n";
|
|
50936
|
-
|
|
51201
|
+
fs34.appendFileSync(file, line, { mode: 384 });
|
|
50937
51202
|
try {
|
|
50938
|
-
|
|
51203
|
+
fs34.chmodSync(file, 384);
|
|
50939
51204
|
} catch {
|
|
50940
51205
|
}
|
|
50941
51206
|
}
|
|
@@ -50965,7 +51230,7 @@ var InboxStore = class {
|
|
|
50965
51230
|
removeByPeerDeviceId(peerDeviceId) {
|
|
50966
51231
|
const file = this.filePath(peerDeviceId);
|
|
50967
51232
|
try {
|
|
50968
|
-
|
|
51233
|
+
fs34.unlinkSync(file);
|
|
50969
51234
|
} catch (err) {
|
|
50970
51235
|
if (err?.code === "ENOENT") return;
|
|
50971
51236
|
}
|
|
@@ -50974,18 +51239,18 @@ var InboxStore = class {
|
|
|
50974
51239
|
const file = this.filePath(peerDeviceId);
|
|
50975
51240
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
50976
51241
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
50977
|
-
|
|
50978
|
-
|
|
51242
|
+
fs34.writeFileSync(tmp, content, { mode: 384 });
|
|
51243
|
+
fs34.renameSync(tmp, file);
|
|
50979
51244
|
try {
|
|
50980
|
-
|
|
51245
|
+
fs34.chmodSync(file, 384);
|
|
50981
51246
|
} catch {
|
|
50982
51247
|
}
|
|
50983
51248
|
}
|
|
50984
51249
|
dirPath() {
|
|
50985
|
-
return
|
|
51250
|
+
return path32.join(this.dataDir, INBOX_SUBDIR);
|
|
50986
51251
|
}
|
|
50987
51252
|
filePath(peerDeviceId) {
|
|
50988
|
-
return
|
|
51253
|
+
return path32.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
50989
51254
|
}
|
|
50990
51255
|
};
|
|
50991
51256
|
function parseAllLines(raw) {
|
|
@@ -51073,8 +51338,8 @@ var InboxManager = class {
|
|
|
51073
51338
|
};
|
|
51074
51339
|
|
|
51075
51340
|
// src/state/contact-store.ts
|
|
51076
|
-
var
|
|
51077
|
-
var
|
|
51341
|
+
var fs35 = __toESM(require("fs"), 1);
|
|
51342
|
+
var path33 = __toESM(require("path"), 1);
|
|
51078
51343
|
var FILE_NAME = "contacts.json";
|
|
51079
51344
|
var ContactStore = class {
|
|
51080
51345
|
constructor(dataDir) {
|
|
@@ -51084,10 +51349,10 @@ var ContactStore = class {
|
|
|
51084
51349
|
contacts = /* @__PURE__ */ new Map();
|
|
51085
51350
|
load() {
|
|
51086
51351
|
this.contacts.clear();
|
|
51087
|
-
const file =
|
|
51352
|
+
const file = path33.join(this.dataDir, FILE_NAME);
|
|
51088
51353
|
let raw;
|
|
51089
51354
|
try {
|
|
51090
|
-
raw =
|
|
51355
|
+
raw = fs35.readFileSync(file, "utf8");
|
|
51091
51356
|
} catch (err) {
|
|
51092
51357
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
51093
51358
|
return;
|
|
@@ -51156,20 +51421,20 @@ var ContactStore = class {
|
|
|
51156
51421
|
return true;
|
|
51157
51422
|
}
|
|
51158
51423
|
flush() {
|
|
51159
|
-
const file =
|
|
51424
|
+
const file = path33.join(this.dataDir, FILE_NAME);
|
|
51160
51425
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
51161
51426
|
const content = JSON.stringify(
|
|
51162
51427
|
{ contacts: Array.from(this.contacts.values()) },
|
|
51163
51428
|
null,
|
|
51164
51429
|
2
|
|
51165
51430
|
);
|
|
51166
|
-
|
|
51167
|
-
|
|
51168
|
-
|
|
51431
|
+
fs35.mkdirSync(this.dataDir, { recursive: true });
|
|
51432
|
+
fs35.writeFileSync(tmp, content, { mode: 384 });
|
|
51433
|
+
fs35.renameSync(tmp, file);
|
|
51169
51434
|
}
|
|
51170
51435
|
renameBak(file) {
|
|
51171
51436
|
try {
|
|
51172
|
-
|
|
51437
|
+
fs35.renameSync(file, `${file}.bak`);
|
|
51173
51438
|
} catch {
|
|
51174
51439
|
}
|
|
51175
51440
|
}
|
|
@@ -51322,61 +51587,61 @@ async function autoReverseContact(args) {
|
|
|
51322
51587
|
}
|
|
51323
51588
|
|
|
51324
51589
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
51325
|
-
var
|
|
51326
|
-
var
|
|
51590
|
+
var fs36 = __toESM(require("fs"), 1);
|
|
51591
|
+
var path34 = __toESM(require("path"), 1);
|
|
51327
51592
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
51328
51593
|
function migrateFlattenSessions(opts) {
|
|
51329
51594
|
const dataDir = opts.dataDir;
|
|
51330
51595
|
const now = opts.now ?? Date.now;
|
|
51331
|
-
const sessionsDir =
|
|
51332
|
-
const flagPath =
|
|
51596
|
+
const sessionsDir = path34.join(dataDir, "sessions");
|
|
51597
|
+
const flagPath = path34.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
51333
51598
|
if (existsSync3(flagPath)) {
|
|
51334
51599
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
51335
51600
|
}
|
|
51336
51601
|
let movedBare = 0;
|
|
51337
51602
|
let movedVmOwner = 0;
|
|
51338
51603
|
let archivedListener = 0;
|
|
51339
|
-
const defaultDir =
|
|
51604
|
+
const defaultDir = path34.join(sessionsDir, "default");
|
|
51340
51605
|
if (existsSync3(defaultDir)) {
|
|
51341
51606
|
for (const entry of readdirSafe(defaultDir)) {
|
|
51342
51607
|
if (!entry.endsWith(".json")) continue;
|
|
51343
|
-
const src =
|
|
51344
|
-
const dst =
|
|
51345
|
-
|
|
51608
|
+
const src = path34.join(defaultDir, entry);
|
|
51609
|
+
const dst = path34.join(sessionsDir, entry);
|
|
51610
|
+
fs36.renameSync(src, dst);
|
|
51346
51611
|
movedBare += 1;
|
|
51347
51612
|
}
|
|
51348
51613
|
rmdirIfEmpty(defaultDir);
|
|
51349
51614
|
}
|
|
51350
51615
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
51351
|
-
const personaDir =
|
|
51616
|
+
const personaDir = path34.join(sessionsDir, pid);
|
|
51352
51617
|
if (!isDir(personaDir)) continue;
|
|
51353
51618
|
if (pid === "default") continue;
|
|
51354
|
-
const ownerSrc =
|
|
51619
|
+
const ownerSrc = path34.join(personaDir, "owner");
|
|
51355
51620
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
51356
|
-
const ownerDst =
|
|
51357
|
-
|
|
51621
|
+
const ownerDst = path34.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
51622
|
+
fs36.mkdirSync(ownerDst, { recursive: true });
|
|
51358
51623
|
for (const file of readdirSafe(ownerSrc)) {
|
|
51359
51624
|
if (!file.endsWith(".json")) continue;
|
|
51360
|
-
|
|
51625
|
+
fs36.renameSync(path34.join(ownerSrc, file), path34.join(ownerDst, file));
|
|
51361
51626
|
movedVmOwner += 1;
|
|
51362
51627
|
}
|
|
51363
51628
|
rmdirIfEmpty(ownerSrc);
|
|
51364
51629
|
}
|
|
51365
|
-
const listenerSrc =
|
|
51630
|
+
const listenerSrc = path34.join(personaDir, "listener");
|
|
51366
51631
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
51367
|
-
const archiveDst =
|
|
51368
|
-
|
|
51632
|
+
const archiveDst = path34.join(dataDir, ".legacy", `listener-${pid}`);
|
|
51633
|
+
fs36.mkdirSync(archiveDst, { recursive: true });
|
|
51369
51634
|
for (const file of readdirSafe(listenerSrc)) {
|
|
51370
51635
|
if (!file.endsWith(".json")) continue;
|
|
51371
|
-
|
|
51636
|
+
fs36.renameSync(path34.join(listenerSrc, file), path34.join(archiveDst, file));
|
|
51372
51637
|
archivedListener += 1;
|
|
51373
51638
|
}
|
|
51374
51639
|
rmdirIfEmpty(listenerSrc);
|
|
51375
51640
|
}
|
|
51376
51641
|
rmdirIfEmpty(personaDir);
|
|
51377
51642
|
}
|
|
51378
|
-
|
|
51379
|
-
|
|
51643
|
+
fs36.mkdirSync(sessionsDir, { recursive: true });
|
|
51644
|
+
fs36.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
51380
51645
|
return {
|
|
51381
51646
|
skipped: false,
|
|
51382
51647
|
flagWritten: true,
|
|
@@ -51387,7 +51652,7 @@ function migrateFlattenSessions(opts) {
|
|
|
51387
51652
|
}
|
|
51388
51653
|
function existsSync3(p2) {
|
|
51389
51654
|
try {
|
|
51390
|
-
|
|
51655
|
+
fs36.statSync(p2);
|
|
51391
51656
|
return true;
|
|
51392
51657
|
} catch {
|
|
51393
51658
|
return false;
|
|
@@ -51395,31 +51660,31 @@ function existsSync3(p2) {
|
|
|
51395
51660
|
}
|
|
51396
51661
|
function isDir(p2) {
|
|
51397
51662
|
try {
|
|
51398
|
-
return
|
|
51663
|
+
return fs36.statSync(p2).isDirectory();
|
|
51399
51664
|
} catch {
|
|
51400
51665
|
return false;
|
|
51401
51666
|
}
|
|
51402
51667
|
}
|
|
51403
51668
|
function readdirSafe(p2) {
|
|
51404
51669
|
try {
|
|
51405
|
-
return
|
|
51670
|
+
return fs36.readdirSync(p2);
|
|
51406
51671
|
} catch {
|
|
51407
51672
|
return [];
|
|
51408
51673
|
}
|
|
51409
51674
|
}
|
|
51410
51675
|
function rmdirIfEmpty(p2) {
|
|
51411
51676
|
try {
|
|
51412
|
-
|
|
51677
|
+
fs36.rmdirSync(p2);
|
|
51413
51678
|
} catch {
|
|
51414
51679
|
}
|
|
51415
51680
|
}
|
|
51416
51681
|
|
|
51417
51682
|
// src/transport/http-router.ts
|
|
51418
51683
|
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
51419
|
-
var
|
|
51684
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
51420
51685
|
|
|
51421
51686
|
// src/attachment/mime.ts
|
|
51422
|
-
var
|
|
51687
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
51423
51688
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
51424
51689
|
var EXT_TO_NATIVE_MIME = {
|
|
51425
51690
|
// 图片
|
|
@@ -51526,7 +51791,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
51526
51791
|
".mk"
|
|
51527
51792
|
]);
|
|
51528
51793
|
function lookupMime(filePathOrName) {
|
|
51529
|
-
const ext =
|
|
51794
|
+
const ext = import_node_path27.default.extname(filePathOrName).toLowerCase();
|
|
51530
51795
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
51531
51796
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
51532
51797
|
return "application/octet-stream";
|
|
@@ -51596,9 +51861,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
51596
51861
|
|
|
51597
51862
|
// src/attachment/upload.ts
|
|
51598
51863
|
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
51599
|
-
var
|
|
51864
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
51600
51865
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
51601
|
-
var
|
|
51866
|
+
var import_promises3 = require("stream/promises");
|
|
51602
51867
|
var UploadError = class extends Error {
|
|
51603
51868
|
constructor(code, message) {
|
|
51604
51869
|
super(message);
|
|
@@ -51608,14 +51873,14 @@ var UploadError = class extends Error {
|
|
|
51608
51873
|
code;
|
|
51609
51874
|
};
|
|
51610
51875
|
function assertValidFileName(fileName) {
|
|
51611
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
51876
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path28.default.basename(fileName)) {
|
|
51612
51877
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
51613
51878
|
}
|
|
51614
51879
|
}
|
|
51615
51880
|
var HASH_PREFIX_LEN = 16;
|
|
51616
51881
|
async function writeUploadedAttachment(args) {
|
|
51617
51882
|
assertValidFileName(args.fileName);
|
|
51618
|
-
const attachmentsRoot =
|
|
51883
|
+
const attachmentsRoot = import_node_path28.default.join(args.sessionDir, ".attachments");
|
|
51619
51884
|
try {
|
|
51620
51885
|
import_node_fs28.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
51621
51886
|
} catch (err) {
|
|
@@ -51623,12 +51888,12 @@ async function writeUploadedAttachment(args) {
|
|
|
51623
51888
|
}
|
|
51624
51889
|
const hasher = import_node_crypto8.default.createHash("sha256");
|
|
51625
51890
|
let actualSize = 0;
|
|
51626
|
-
const tmpPath =
|
|
51891
|
+
const tmpPath = import_node_path28.default.join(
|
|
51627
51892
|
attachmentsRoot,
|
|
51628
51893
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
|
|
51629
51894
|
);
|
|
51630
51895
|
try {
|
|
51631
|
-
await (0,
|
|
51896
|
+
await (0, import_promises3.pipeline)(
|
|
51632
51897
|
args.body,
|
|
51633
51898
|
async function* (source) {
|
|
51634
51899
|
for await (const chunk of source) {
|
|
@@ -51658,7 +51923,7 @@ async function writeUploadedAttachment(args) {
|
|
|
51658
51923
|
);
|
|
51659
51924
|
}
|
|
51660
51925
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
51661
|
-
const hashDir =
|
|
51926
|
+
const hashDir = import_node_path28.default.join(attachmentsRoot, attachmentId);
|
|
51662
51927
|
let finalFileName;
|
|
51663
51928
|
let hashDirExists = false;
|
|
51664
51929
|
try {
|
|
@@ -51676,7 +51941,7 @@ async function writeUploadedAttachment(args) {
|
|
|
51676
51941
|
try {
|
|
51677
51942
|
import_node_fs28.default.mkdirSync(hashDir, { recursive: true });
|
|
51678
51943
|
finalFileName = args.fileName;
|
|
51679
|
-
import_node_fs28.default.renameSync(tmpPath,
|
|
51944
|
+
import_node_fs28.default.renameSync(tmpPath, import_node_path28.default.join(hashDir, finalFileName));
|
|
51680
51945
|
} catch (err) {
|
|
51681
51946
|
try {
|
|
51682
51947
|
import_node_fs28.default.unlinkSync(tmpPath);
|
|
@@ -51685,8 +51950,8 @@ async function writeUploadedAttachment(args) {
|
|
|
51685
51950
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
51686
51951
|
}
|
|
51687
51952
|
}
|
|
51688
|
-
const absPath =
|
|
51689
|
-
const relPath =
|
|
51953
|
+
const absPath = import_node_path28.default.join(hashDir, finalFileName);
|
|
51954
|
+
const relPath = import_node_path28.default.relative(args.sessionDir, absPath);
|
|
51690
51955
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
51691
51956
|
relPath: absPath,
|
|
51692
51957
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -51699,8 +51964,8 @@ async function writeUploadedAttachment(args) {
|
|
|
51699
51964
|
}
|
|
51700
51965
|
|
|
51701
51966
|
// src/extension/import.ts
|
|
51702
|
-
var
|
|
51703
|
-
var
|
|
51967
|
+
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
51968
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
51704
51969
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
51705
51970
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
51706
51971
|
var ImportError = class extends Error {
|
|
@@ -51718,7 +51983,7 @@ async function importZip(buf, root) {
|
|
|
51718
51983
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
51719
51984
|
}
|
|
51720
51985
|
for (const name of Object.keys(zip.files)) {
|
|
51721
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
51986
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path29.default.isAbsolute(name)) {
|
|
51722
51987
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
51723
51988
|
}
|
|
51724
51989
|
}
|
|
@@ -51751,33 +52016,33 @@ async function importZip(buf, root) {
|
|
|
51751
52016
|
);
|
|
51752
52017
|
}
|
|
51753
52018
|
}
|
|
51754
|
-
const destDir =
|
|
52019
|
+
const destDir = import_node_path29.default.join(root, manifest.id);
|
|
51755
52020
|
let destExists = false;
|
|
51756
52021
|
try {
|
|
51757
|
-
await
|
|
52022
|
+
await import_promises4.default.access(destDir);
|
|
51758
52023
|
destExists = true;
|
|
51759
52024
|
} catch {
|
|
51760
52025
|
}
|
|
51761
52026
|
if (destExists) {
|
|
51762
52027
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
51763
52028
|
}
|
|
51764
|
-
const stage = await
|
|
52029
|
+
const stage = await import_promises4.default.mkdtemp(import_node_path29.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
51765
52030
|
try {
|
|
51766
52031
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
51767
|
-
const dest =
|
|
52032
|
+
const dest = import_node_path29.default.join(stage, name);
|
|
51768
52033
|
if (entry.dir) {
|
|
51769
|
-
await
|
|
52034
|
+
await import_promises4.default.mkdir(dest, { recursive: true });
|
|
51770
52035
|
continue;
|
|
51771
52036
|
}
|
|
51772
|
-
await
|
|
52037
|
+
await import_promises4.default.mkdir(import_node_path29.default.dirname(dest), { recursive: true });
|
|
51773
52038
|
const content = await entry.async("nodebuffer");
|
|
51774
|
-
await
|
|
52039
|
+
await import_promises4.default.writeFile(dest, content);
|
|
51775
52040
|
}
|
|
51776
|
-
await
|
|
51777
|
-
await
|
|
52041
|
+
await import_promises4.default.mkdir(root, { recursive: true });
|
|
52042
|
+
await import_promises4.default.rename(stage, destDir);
|
|
51778
52043
|
return { extId: manifest.id };
|
|
51779
52044
|
} catch (e) {
|
|
51780
|
-
await
|
|
52045
|
+
await import_promises4.default.rm(stage, { recursive: true, force: true }).catch(() => {
|
|
51781
52046
|
});
|
|
51782
52047
|
throw e;
|
|
51783
52048
|
}
|
|
@@ -51800,7 +52065,7 @@ var SHARE_UI_ASSET_MIME = {
|
|
|
51800
52065
|
".wasm": "application/wasm"
|
|
51801
52066
|
};
|
|
51802
52067
|
function shareUiAssetMime(filePath) {
|
|
51803
|
-
const ext =
|
|
52068
|
+
const ext = import_node_path30.default.extname(filePath).toLowerCase();
|
|
51804
52069
|
return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
|
|
51805
52070
|
}
|
|
51806
52071
|
var DISPATCH_HEARTBEAT_MS = 25e3;
|
|
@@ -51887,7 +52152,7 @@ function isValidUploadFileName(fileName) {
|
|
|
51887
52152
|
if (fileName === "." || fileName === "..") return false;
|
|
51888
52153
|
if (fileName.startsWith(".")) return false;
|
|
51889
52154
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
51890
|
-
return fileName ===
|
|
52155
|
+
return fileName === import_node_path30.default.basename(fileName);
|
|
51891
52156
|
}
|
|
51892
52157
|
function createHttpRouter(deps) {
|
|
51893
52158
|
return async (req, res) => {
|
|
@@ -52183,7 +52448,7 @@ function createHttpRouter(deps) {
|
|
|
52183
52448
|
sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
|
|
52184
52449
|
return true;
|
|
52185
52450
|
}
|
|
52186
|
-
sendHtml(res, 200, loader.renderViewerHtml(
|
|
52451
|
+
sendHtml(res, 200, loader.renderViewerHtml(import_node_path30.default.basename(r.absPath)));
|
|
52187
52452
|
return true;
|
|
52188
52453
|
}
|
|
52189
52454
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
@@ -52304,7 +52569,7 @@ function createHttpRouter(deps) {
|
|
|
52304
52569
|
return true;
|
|
52305
52570
|
}
|
|
52306
52571
|
let absPath;
|
|
52307
|
-
if (
|
|
52572
|
+
if (import_node_path30.default.isAbsolute(pathParam)) {
|
|
52308
52573
|
absPath = pathParam;
|
|
52309
52574
|
} else if (deps.sessionStore) {
|
|
52310
52575
|
const file = deps.sessionStore.read(sid);
|
|
@@ -52312,7 +52577,7 @@ function createHttpRouter(deps) {
|
|
|
52312
52577
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
52313
52578
|
return true;
|
|
52314
52579
|
}
|
|
52315
|
-
absPath =
|
|
52580
|
+
absPath = import_node_path30.default.join(file.cwd, pathParam);
|
|
52316
52581
|
} else {
|
|
52317
52582
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
52318
52583
|
return true;
|
|
@@ -52414,7 +52679,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52414
52679
|
return;
|
|
52415
52680
|
}
|
|
52416
52681
|
const mime = lookupMime(absPath);
|
|
52417
|
-
const basename =
|
|
52682
|
+
const basename = import_node_path30.default.basename(absPath);
|
|
52418
52683
|
res.writeHead(200, {
|
|
52419
52684
|
"Content-Type": mime,
|
|
52420
52685
|
"Content-Length": String(stat.size),
|
|
@@ -52432,7 +52697,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52432
52697
|
|
|
52433
52698
|
// src/attachment/gc.ts
|
|
52434
52699
|
var import_node_fs30 = __toESM(require("fs"), 1);
|
|
52435
|
-
var
|
|
52700
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
52436
52701
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
52437
52702
|
function runAttachmentGc(args) {
|
|
52438
52703
|
const now = (args.now ?? Date.now)();
|
|
@@ -52441,17 +52706,17 @@ function runAttachmentGc(args) {
|
|
|
52441
52706
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52442
52707
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
52443
52708
|
if (entry.stale) continue;
|
|
52444
|
-
if (
|
|
52709
|
+
if (import_node_path31.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
52445
52710
|
}
|
|
52446
52711
|
}
|
|
52447
52712
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52448
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
52713
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path31.default.join(
|
|
52449
52714
|
args.dataDir,
|
|
52450
52715
|
"sessions",
|
|
52451
52716
|
...scopeSubPath(scope).map(safeFileName),
|
|
52452
52717
|
safeFileName(sessionId)
|
|
52453
52718
|
);
|
|
52454
|
-
const attRoot =
|
|
52719
|
+
const attRoot = import_node_path31.default.join(sessionDir, ".attachments");
|
|
52455
52720
|
let hashDirs;
|
|
52456
52721
|
try {
|
|
52457
52722
|
hashDirs = import_node_fs30.default.readdirSync(attRoot);
|
|
@@ -52461,7 +52726,7 @@ function runAttachmentGc(args) {
|
|
|
52461
52726
|
continue;
|
|
52462
52727
|
}
|
|
52463
52728
|
for (const hashDir of hashDirs) {
|
|
52464
|
-
const hashDirAbs =
|
|
52729
|
+
const hashDirAbs = import_node_path31.default.join(attRoot, hashDir);
|
|
52465
52730
|
let files;
|
|
52466
52731
|
try {
|
|
52467
52732
|
files = import_node_fs30.default.readdirSync(hashDirAbs);
|
|
@@ -52469,7 +52734,7 @@ function runAttachmentGc(args) {
|
|
|
52469
52734
|
continue;
|
|
52470
52735
|
}
|
|
52471
52736
|
for (const name of files) {
|
|
52472
|
-
const file =
|
|
52737
|
+
const file = import_node_path31.default.join(hashDirAbs, name);
|
|
52473
52738
|
let stat;
|
|
52474
52739
|
try {
|
|
52475
52740
|
stat = import_node_fs30.default.statSync(file);
|
|
@@ -52500,7 +52765,7 @@ function runAttachmentGc(args) {
|
|
|
52500
52765
|
|
|
52501
52766
|
// src/attachment/group.ts
|
|
52502
52767
|
var import_node_fs31 = __toESM(require("fs"), 1);
|
|
52503
|
-
var
|
|
52768
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
52504
52769
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
52505
52770
|
init_protocol();
|
|
52506
52771
|
var GroupFileStore = class {
|
|
@@ -52512,11 +52777,11 @@ var GroupFileStore = class {
|
|
|
52512
52777
|
this.logger = opts.logger;
|
|
52513
52778
|
}
|
|
52514
52779
|
rootForScope(scope) {
|
|
52515
|
-
return
|
|
52780
|
+
return import_node_path32.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
52516
52781
|
}
|
|
52517
52782
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
52518
52783
|
filePath(scope, sessionId) {
|
|
52519
|
-
return
|
|
52784
|
+
return import_node_path32.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
52520
52785
|
}
|
|
52521
52786
|
cacheKey(scope, sessionId) {
|
|
52522
52787
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -52551,7 +52816,7 @@ var GroupFileStore = class {
|
|
|
52551
52816
|
}
|
|
52552
52817
|
writeFile(scope, sessionId, entries) {
|
|
52553
52818
|
const file = this.filePath(scope, sessionId);
|
|
52554
|
-
import_node_fs31.default.mkdirSync(
|
|
52819
|
+
import_node_fs31.default.mkdirSync(import_node_path32.default.dirname(file), { recursive: true });
|
|
52555
52820
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
52556
52821
|
import_node_fs31.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
52557
52822
|
import_node_fs31.default.renameSync(tmp, file);
|
|
@@ -52641,9 +52906,9 @@ var GroupFileStore = class {
|
|
|
52641
52906
|
|
|
52642
52907
|
// src/discovery/state-file.ts
|
|
52643
52908
|
var import_node_fs32 = __toESM(require("fs"), 1);
|
|
52644
|
-
var
|
|
52909
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
52645
52910
|
function defaultStateFilePath(dataDir) {
|
|
52646
|
-
return
|
|
52911
|
+
return import_node_path33.default.join(dataDir, "state.json");
|
|
52647
52912
|
}
|
|
52648
52913
|
function isPidAlive(pid) {
|
|
52649
52914
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -52679,7 +52944,7 @@ var StateFileManager = class {
|
|
|
52679
52944
|
return { status: "stale", existing };
|
|
52680
52945
|
}
|
|
52681
52946
|
write(state) {
|
|
52682
|
-
import_node_fs32.default.mkdirSync(
|
|
52947
|
+
import_node_fs32.default.mkdirSync(import_node_path33.default.dirname(this.file), { recursive: true });
|
|
52683
52948
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
52684
52949
|
import_node_fs32.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
52685
52950
|
import_node_fs32.default.renameSync(tmp, this.file);
|
|
@@ -52707,13 +52972,13 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
|
|
|
52707
52972
|
|
|
52708
52973
|
// src/tunnel/tunnel-manager.ts
|
|
52709
52974
|
var import_node_fs36 = __toESM(require("fs"), 1);
|
|
52710
|
-
var
|
|
52975
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
52711
52976
|
var import_node_crypto10 = __toESM(require("crypto"), 1);
|
|
52712
52977
|
var import_node_child_process9 = require("child_process");
|
|
52713
52978
|
|
|
52714
52979
|
// src/tunnel/tunnel-store.ts
|
|
52715
52980
|
var import_node_fs33 = __toESM(require("fs"), 1);
|
|
52716
|
-
var
|
|
52981
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
52717
52982
|
var TunnelStore = class {
|
|
52718
52983
|
constructor(filePath) {
|
|
52719
52984
|
this.filePath = filePath;
|
|
@@ -52732,7 +52997,7 @@ var TunnelStore = class {
|
|
|
52732
52997
|
}
|
|
52733
52998
|
}
|
|
52734
52999
|
async set(v2) {
|
|
52735
|
-
const dir =
|
|
53000
|
+
const dir = import_node_path34.default.dirname(this.filePath);
|
|
52736
53001
|
await import_node_fs33.default.promises.mkdir(dir, { recursive: true });
|
|
52737
53002
|
const data = JSON.stringify(v2, null, 2);
|
|
52738
53003
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
@@ -52844,10 +53109,10 @@ function escape(v2) {
|
|
|
52844
53109
|
// src/tunnel/frpc-binary.ts
|
|
52845
53110
|
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
52846
53111
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
52847
|
-
var
|
|
53112
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
52848
53113
|
var import_node_child_process7 = require("child_process");
|
|
52849
53114
|
var import_node_stream3 = require("stream");
|
|
52850
|
-
var
|
|
53115
|
+
var import_promises5 = require("stream/promises");
|
|
52851
53116
|
var FRPC_VERSION = "0.68.0";
|
|
52852
53117
|
var UnsupportedPlatformError = class extends Error {
|
|
52853
53118
|
constructor(platform, arch) {
|
|
@@ -52883,13 +53148,13 @@ async function ensureFrpcBinary(opts) {
|
|
|
52883
53148
|
}
|
|
52884
53149
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
52885
53150
|
const platform = opts.platform ?? detectPlatform();
|
|
52886
|
-
const binDir =
|
|
53151
|
+
const binDir = import_node_path35.default.join(opts.dataDir, "bin");
|
|
52887
53152
|
import_node_fs34.default.mkdirSync(binDir, { recursive: true });
|
|
52888
53153
|
cleanupStaleArtifacts(binDir);
|
|
52889
|
-
const stableBin =
|
|
53154
|
+
const stableBin = import_node_path35.default.join(binDir, "frpc");
|
|
52890
53155
|
if (import_node_fs34.default.existsSync(stableBin)) return stableBin;
|
|
52891
53156
|
const partialBin = `${stableBin}.partial`;
|
|
52892
|
-
const tarballPath =
|
|
53157
|
+
const tarballPath = import_node_path35.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
52893
53158
|
try {
|
|
52894
53159
|
const url = frpcDownloadUrl(version2, platform);
|
|
52895
53160
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -52915,7 +53180,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
52915
53180
|
}
|
|
52916
53181
|
for (const name of entries) {
|
|
52917
53182
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
52918
|
-
const full =
|
|
53183
|
+
const full = import_node_path35.default.join(binDir, name);
|
|
52919
53184
|
try {
|
|
52920
53185
|
import_node_fs34.default.rmSync(full, { recursive: true, force: true });
|
|
52921
53186
|
} catch {
|
|
@@ -52938,10 +53203,10 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
52938
53203
|
}
|
|
52939
53204
|
const out = import_node_fs34.default.createWriteStream(dest);
|
|
52940
53205
|
const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
|
|
52941
|
-
await (0,
|
|
53206
|
+
await (0, import_promises5.pipeline)(nodeStream, out);
|
|
52942
53207
|
}
|
|
52943
53208
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
52944
|
-
const work =
|
|
53209
|
+
const work = import_node_path35.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
52945
53210
|
import_node_fs34.default.mkdirSync(work, { recursive: true });
|
|
52946
53211
|
try {
|
|
52947
53212
|
await new Promise((resolve6, reject) => {
|
|
@@ -52950,7 +53215,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
52950
53215
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
52951
53216
|
});
|
|
52952
53217
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
52953
|
-
const src =
|
|
53218
|
+
const src = import_node_path35.default.join(work, dirName, "frpc");
|
|
52954
53219
|
if (!import_node_fs34.default.existsSync(src)) {
|
|
52955
53220
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
52956
53221
|
}
|
|
@@ -52962,10 +53227,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
52962
53227
|
|
|
52963
53228
|
// src/tunnel/frpc-process.ts
|
|
52964
53229
|
var import_node_fs35 = __toESM(require("fs"), 1);
|
|
52965
|
-
var
|
|
53230
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
52966
53231
|
var import_node_child_process8 = require("child_process");
|
|
52967
53232
|
function frpcPidFilePath(dataDir) {
|
|
52968
|
-
return
|
|
53233
|
+
return import_node_path36.default.join(dataDir, "frpc.pid");
|
|
52969
53234
|
}
|
|
52970
53235
|
function writeFrpcPid(dataDir, pid) {
|
|
52971
53236
|
try {
|
|
@@ -53007,7 +53272,7 @@ function defaultSleep(ms) {
|
|
|
53007
53272
|
}
|
|
53008
53273
|
async function killStaleFrpc(deps) {
|
|
53009
53274
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
53010
|
-
const tomlPath =
|
|
53275
|
+
const tomlPath = import_node_path36.default.join(deps.dataDir, "frpc.toml");
|
|
53011
53276
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
53012
53277
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
53013
53278
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -53079,7 +53344,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
53079
53344
|
var TunnelManager = class {
|
|
53080
53345
|
constructor(deps) {
|
|
53081
53346
|
this.deps = deps;
|
|
53082
|
-
this.store = deps.store ?? new TunnelStore(
|
|
53347
|
+
this.store = deps.store ?? new TunnelStore(import_node_path37.default.join(deps.dataDir, "tunnel.json"));
|
|
53083
53348
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
53084
53349
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
53085
53350
|
}
|
|
@@ -53206,7 +53471,7 @@ var TunnelManager = class {
|
|
|
53206
53471
|
dataDir: this.deps.dataDir,
|
|
53207
53472
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
53208
53473
|
});
|
|
53209
|
-
const tomlPath =
|
|
53474
|
+
const tomlPath = import_node_path37.default.join(this.deps.dataDir, "frpc.toml");
|
|
53210
53475
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
|
|
53211
53476
|
const toml = buildFrpcToml({
|
|
53212
53477
|
serverAddr: t.frpsHost,
|
|
@@ -53221,9 +53486,9 @@ var TunnelManager = class {
|
|
|
53221
53486
|
const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
|
|
53222
53487
|
stdio: ["ignore", "pipe", "pipe"]
|
|
53223
53488
|
});
|
|
53224
|
-
const logDir =
|
|
53489
|
+
const logDir = import_node_path37.default.join(this.deps.dataDir, "log");
|
|
53225
53490
|
import_node_fs36.default.mkdirSync(logDir, { recursive: true });
|
|
53226
|
-
const logFilePath =
|
|
53491
|
+
const logFilePath = import_node_path37.default.join(logDir, "frpc.log");
|
|
53227
53492
|
const logStream = import_node_fs36.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
53228
53493
|
logStream.on("error", () => {
|
|
53229
53494
|
});
|
|
@@ -53307,15 +53572,15 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
53307
53572
|
|
|
53308
53573
|
// src/tunnel/device-key.ts
|
|
53309
53574
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
53310
|
-
var
|
|
53575
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
53311
53576
|
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
53312
53577
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
53313
53578
|
function deriveStableDeviceKey(opts = {}) {
|
|
53314
53579
|
const hostname = opts.hostname ?? import_node_os14.default.hostname();
|
|
53315
53580
|
const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
|
|
53316
53581
|
const home = opts.home ?? import_node_os14.default.homedir();
|
|
53317
|
-
const defaultDataDir =
|
|
53318
|
-
const normalizedDataDir = opts.dataDir ?
|
|
53582
|
+
const defaultDataDir = import_node_path38.default.resolve(import_node_path38.default.join(home, ".clawd"));
|
|
53583
|
+
const normalizedDataDir = opts.dataDir ? import_node_path38.default.resolve(opts.dataDir) : null;
|
|
53319
53584
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
53320
53585
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
53321
53586
|
return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
@@ -53323,11 +53588,11 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
53323
53588
|
|
|
53324
53589
|
// src/auth-store.ts
|
|
53325
53590
|
var import_node_fs37 = __toESM(require("fs"), 1);
|
|
53326
|
-
var
|
|
53591
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
53327
53592
|
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
53328
53593
|
var AUTH_FILE_NAME = "auth.json";
|
|
53329
53594
|
function authFilePath(dataDir) {
|
|
53330
|
-
return
|
|
53595
|
+
return import_node_path39.default.join(dataDir, AUTH_FILE_NAME);
|
|
53331
53596
|
}
|
|
53332
53597
|
function loadOrCreateAuthFile(opts) {
|
|
53333
53598
|
const file = authFilePath(opts.dataDir);
|
|
@@ -53383,7 +53648,7 @@ function readAuthFile(file) {
|
|
|
53383
53648
|
}
|
|
53384
53649
|
}
|
|
53385
53650
|
function writeAuthFile(file, content) {
|
|
53386
|
-
import_node_fs37.default.mkdirSync(
|
|
53651
|
+
import_node_fs37.default.mkdirSync(import_node_path39.default.dirname(file), { recursive: true });
|
|
53387
53652
|
import_node_fs37.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
53388
53653
|
try {
|
|
53389
53654
|
import_node_fs37.default.chmodSync(file, 384);
|
|
@@ -53394,11 +53659,11 @@ function writeAuthFile(file, content) {
|
|
|
53394
53659
|
// src/owner-profile.ts
|
|
53395
53660
|
var import_node_fs38 = __toESM(require("fs"), 1);
|
|
53396
53661
|
var import_node_os15 = __toESM(require("os"), 1);
|
|
53397
|
-
var
|
|
53662
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
53398
53663
|
var PROFILE_FILENAME = "profile.json";
|
|
53399
53664
|
function loadOwnerDisplayName(dataDir) {
|
|
53400
53665
|
const fallback = import_node_os15.default.userInfo().username;
|
|
53401
|
-
const profilePath =
|
|
53666
|
+
const profilePath = import_node_path40.default.join(dataDir, PROFILE_FILENAME);
|
|
53402
53667
|
let raw;
|
|
53403
53668
|
try {
|
|
53404
53669
|
raw = import_node_fs38.default.readFileSync(profilePath, "utf8");
|
|
@@ -53425,12 +53690,12 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
53425
53690
|
|
|
53426
53691
|
// src/feishu-auth/owner-identity-store.ts
|
|
53427
53692
|
var import_node_fs39 = __toESM(require("fs"), 1);
|
|
53428
|
-
var
|
|
53693
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
53429
53694
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
53430
53695
|
var OwnerIdentityStore = class {
|
|
53431
53696
|
file;
|
|
53432
53697
|
constructor(dataDir) {
|
|
53433
|
-
this.file =
|
|
53698
|
+
this.file = import_node_path41.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
53434
53699
|
}
|
|
53435
53700
|
read() {
|
|
53436
53701
|
let raw;
|
|
@@ -53463,7 +53728,7 @@ var OwnerIdentityStore = class {
|
|
|
53463
53728
|
};
|
|
53464
53729
|
}
|
|
53465
53730
|
write(record) {
|
|
53466
|
-
import_node_fs39.default.mkdirSync(
|
|
53731
|
+
import_node_fs39.default.mkdirSync(import_node_path41.default.dirname(this.file), { recursive: true });
|
|
53467
53732
|
import_node_fs39.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
53468
53733
|
try {
|
|
53469
53734
|
import_node_fs39.default.chmodSync(this.file, 384);
|
|
@@ -53609,9 +53874,9 @@ var CentralClientError = class extends Error {
|
|
|
53609
53874
|
code;
|
|
53610
53875
|
cause;
|
|
53611
53876
|
};
|
|
53612
|
-
async function centralRequest(opts,
|
|
53877
|
+
async function centralRequest(opts, path71, init) {
|
|
53613
53878
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
53614
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
53879
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path71}`;
|
|
53615
53880
|
const ctrl = new AbortController();
|
|
53616
53881
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
53617
53882
|
let res;
|
|
@@ -53805,8 +54070,8 @@ function verifyConnectToken(args) {
|
|
|
53805
54070
|
}
|
|
53806
54071
|
|
|
53807
54072
|
// src/feishu-auth/server-key.ts
|
|
53808
|
-
var
|
|
53809
|
-
var
|
|
54073
|
+
var fs50 = __toESM(require("fs"), 1);
|
|
54074
|
+
var path50 = __toESM(require("path"), 1);
|
|
53810
54075
|
var FILE_NAME2 = "server-signing-key.json";
|
|
53811
54076
|
var ServerKeyStore = class {
|
|
53812
54077
|
constructor(dataDir) {
|
|
@@ -53814,12 +54079,12 @@ var ServerKeyStore = class {
|
|
|
53814
54079
|
}
|
|
53815
54080
|
dataDir;
|
|
53816
54081
|
filePath() {
|
|
53817
|
-
return
|
|
54082
|
+
return path50.join(this.dataDir, FILE_NAME2);
|
|
53818
54083
|
}
|
|
53819
54084
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
53820
54085
|
read() {
|
|
53821
54086
|
try {
|
|
53822
|
-
const raw =
|
|
54087
|
+
const raw = fs50.readFileSync(this.filePath(), "utf8");
|
|
53823
54088
|
const parsed = JSON.parse(raw);
|
|
53824
54089
|
if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
|
|
53825
54090
|
return parsed.publicKeyPem;
|
|
@@ -53834,12 +54099,12 @@ var ServerKeyStore = class {
|
|
|
53834
54099
|
publicKeyPem,
|
|
53835
54100
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
53836
54101
|
};
|
|
53837
|
-
|
|
53838
|
-
|
|
54102
|
+
fs50.mkdirSync(this.dataDir, { recursive: true });
|
|
54103
|
+
fs50.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
|
|
53839
54104
|
}
|
|
53840
54105
|
clear() {
|
|
53841
54106
|
try {
|
|
53842
|
-
|
|
54107
|
+
fs50.unlinkSync(this.filePath());
|
|
53843
54108
|
} catch {
|
|
53844
54109
|
}
|
|
53845
54110
|
}
|
|
@@ -53854,7 +54119,7 @@ init_protocol();
|
|
|
53854
54119
|
// src/session/fork.ts
|
|
53855
54120
|
var import_node_fs40 = __toESM(require("fs"), 1);
|
|
53856
54121
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
53857
|
-
var
|
|
54122
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
53858
54123
|
init_claude_history();
|
|
53859
54124
|
function readJsonlEntries(file) {
|
|
53860
54125
|
const raw = import_node_fs40.default.readFileSync(file, "utf8");
|
|
@@ -53870,19 +54135,19 @@ function readJsonlEntries(file) {
|
|
|
53870
54135
|
return out;
|
|
53871
54136
|
}
|
|
53872
54137
|
function forkSession(input) {
|
|
53873
|
-
const baseDir = input.baseDir ??
|
|
53874
|
-
let projectDir =
|
|
53875
|
-
let sourceFile =
|
|
54138
|
+
const baseDir = input.baseDir ?? import_node_path42.default.join(import_node_os16.default.homedir(), ".claude");
|
|
54139
|
+
let projectDir = import_node_path42.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
54140
|
+
let sourceFile = import_node_path42.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
53876
54141
|
if (!import_node_fs40.default.existsSync(sourceFile)) {
|
|
53877
54142
|
const found = findTranscriptByToolSessionId(
|
|
53878
|
-
|
|
54143
|
+
import_node_path42.default.join(baseDir, "projects"),
|
|
53879
54144
|
input.toolSessionId
|
|
53880
54145
|
);
|
|
53881
54146
|
if (!found) {
|
|
53882
54147
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
53883
54148
|
}
|
|
53884
54149
|
sourceFile = found;
|
|
53885
|
-
projectDir =
|
|
54150
|
+
projectDir = import_node_path42.default.dirname(found);
|
|
53886
54151
|
}
|
|
53887
54152
|
const entries = readJsonlEntries(sourceFile);
|
|
53888
54153
|
const mainEntries = entries.filter((e) => e.isSidechain !== true);
|
|
@@ -53911,7 +54176,7 @@ function forkSession(input) {
|
|
|
53911
54176
|
}
|
|
53912
54177
|
forkedLines.push(JSON.stringify(forked));
|
|
53913
54178
|
}
|
|
53914
|
-
const forkedFilePath =
|
|
54179
|
+
const forkedFilePath = import_node_path42.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
53915
54180
|
import_node_fs40.default.mkdirSync(projectDir, { recursive: true });
|
|
53916
54181
|
import_node_fs40.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
53917
54182
|
return { forkedToolSessionId, forkedFilePath };
|
|
@@ -53971,6 +54236,7 @@ function buildSessionHandlers(deps) {
|
|
|
53971
54236
|
const narrow = (sessions) => {
|
|
53972
54237
|
let out = sessions;
|
|
53973
54238
|
if (args.originOnly) out = out.filter((s) => s.originOwnerPrincipalId != null);
|
|
54239
|
+
if (args.ownerPersonaId) out = out.filter((s) => s.ownerPersonaId === args.ownerPersonaId);
|
|
53974
54240
|
const total = out.length;
|
|
53975
54241
|
const offset = args.offset ?? 0;
|
|
53976
54242
|
if (offset > 0 || args.limit != null) {
|
|
@@ -54311,7 +54577,7 @@ function buildPermissionHandlers(deps) {
|
|
|
54311
54577
|
}
|
|
54312
54578
|
|
|
54313
54579
|
// src/handlers/history.ts
|
|
54314
|
-
var
|
|
54580
|
+
var path53 = __toESM(require("path"), 1);
|
|
54315
54581
|
init_protocol();
|
|
54316
54582
|
|
|
54317
54583
|
// src/session/recent-dirs.ts
|
|
@@ -54329,7 +54595,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
54329
54595
|
}
|
|
54330
54596
|
|
|
54331
54597
|
// src/permission/persona-paths.ts
|
|
54332
|
-
var
|
|
54598
|
+
var path52 = __toESM(require("path"), 1);
|
|
54333
54599
|
function getAllowedPersonaIds(grants, action) {
|
|
54334
54600
|
const ids = /* @__PURE__ */ new Set();
|
|
54335
54601
|
for (const g2 of grants) {
|
|
@@ -54342,42 +54608,42 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
54342
54608
|
return ids;
|
|
54343
54609
|
}
|
|
54344
54610
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
54345
|
-
const target =
|
|
54611
|
+
const target = path52.resolve(absPath);
|
|
54346
54612
|
if (userWorkDir) {
|
|
54347
|
-
const u =
|
|
54348
|
-
const usep = u.endsWith(
|
|
54613
|
+
const u = path52.resolve(userWorkDir);
|
|
54614
|
+
const usep = u.endsWith(path52.sep) ? "" : path52.sep;
|
|
54349
54615
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
54350
54616
|
}
|
|
54351
|
-
const root =
|
|
54352
|
-
const sep3 = root.endsWith(
|
|
54617
|
+
const root = path52.resolve(personaRoot);
|
|
54618
|
+
const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
|
|
54353
54619
|
if (!target.startsWith(root + sep3)) return false;
|
|
54354
|
-
const rel =
|
|
54620
|
+
const rel = path52.relative(root, target);
|
|
54355
54621
|
if (!rel || rel.startsWith("..")) return false;
|
|
54356
|
-
const personaId = rel.split(
|
|
54622
|
+
const personaId = rel.split(path52.sep)[0];
|
|
54357
54623
|
if (!personaId) return false;
|
|
54358
54624
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
54359
54625
|
if (allowed === "*") return true;
|
|
54360
54626
|
return allowed.has(personaId);
|
|
54361
54627
|
}
|
|
54362
54628
|
function personaIdFromPath(absPath, personaRoot) {
|
|
54363
|
-
const root =
|
|
54364
|
-
const target =
|
|
54365
|
-
const sep3 = root.endsWith(
|
|
54629
|
+
const root = path52.resolve(personaRoot);
|
|
54630
|
+
const target = path52.resolve(absPath);
|
|
54631
|
+
const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
|
|
54366
54632
|
if (!target.startsWith(root + sep3)) return null;
|
|
54367
|
-
const rel =
|
|
54633
|
+
const rel = path52.relative(root, target);
|
|
54368
54634
|
if (!rel || rel.startsWith("..")) return null;
|
|
54369
|
-
const id = rel.split(
|
|
54635
|
+
const id = rel.split(path52.sep)[0];
|
|
54370
54636
|
return id || null;
|
|
54371
54637
|
}
|
|
54372
54638
|
function isPathWithin(dir, absPath) {
|
|
54373
|
-
const d =
|
|
54374
|
-
const t =
|
|
54375
|
-
const sep3 = d.endsWith(
|
|
54639
|
+
const d = path52.resolve(dir);
|
|
54640
|
+
const t = path52.resolve(absPath);
|
|
54641
|
+
const sep3 = d.endsWith(path52.sep) ? "" : path52.sep;
|
|
54376
54642
|
return t === d || t.startsWith(d + sep3);
|
|
54377
54643
|
}
|
|
54378
54644
|
function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
|
|
54379
54645
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
54380
|
-
return personaIdFromPath(
|
|
54646
|
+
return personaIdFromPath(path52.resolve(absPath), personaRoot) === personaId;
|
|
54381
54647
|
}
|
|
54382
54648
|
|
|
54383
54649
|
// src/handlers/history.ts
|
|
@@ -54429,7 +54695,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54429
54695
|
if (!pid) return false;
|
|
54430
54696
|
return isGuestPathAllowed(
|
|
54431
54697
|
ctx.grants,
|
|
54432
|
-
|
|
54698
|
+
path53.join(personaRoot, pid),
|
|
54433
54699
|
personaRoot,
|
|
54434
54700
|
"read",
|
|
54435
54701
|
userWorkDir
|
|
@@ -54441,7 +54707,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54441
54707
|
};
|
|
54442
54708
|
const list = async (frame, _client, ctx) => {
|
|
54443
54709
|
const args = HistoryListArgs.parse(frame);
|
|
54444
|
-
assertGuestPath(ctx,
|
|
54710
|
+
assertGuestPath(ctx, path53.resolve(args.projectPath), personaRoot, "history:list");
|
|
54445
54711
|
const sessions = await history.listSessions(args);
|
|
54446
54712
|
return { response: { type: "history:list", sessions } };
|
|
54447
54713
|
};
|
|
@@ -54474,13 +54740,13 @@ function buildHistoryHandlers(deps) {
|
|
|
54474
54740
|
};
|
|
54475
54741
|
const subagents = async (frame, _client, ctx) => {
|
|
54476
54742
|
const args = HistorySubagentsArgs.parse(frame);
|
|
54477
|
-
assertGuestPath(ctx,
|
|
54743
|
+
assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
54478
54744
|
const subs = await history.listSubagents(args);
|
|
54479
54745
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
54480
54746
|
};
|
|
54481
54747
|
const subagentRead = async (frame, _client, ctx) => {
|
|
54482
54748
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
54483
|
-
assertGuestPath(ctx,
|
|
54749
|
+
assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
54484
54750
|
const res = await history.readSubagent(args);
|
|
54485
54751
|
return { response: { type: "history:subagent-read", ...res } };
|
|
54486
54752
|
};
|
|
@@ -54489,7 +54755,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54489
54755
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
54490
54756
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
54491
54757
|
const filtered = dirs.filter(
|
|
54492
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
54758
|
+
(d) => isGuestPathAllowed(ctx.grants, path53.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
54493
54759
|
);
|
|
54494
54760
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
54495
54761
|
}
|
|
@@ -54506,7 +54772,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54506
54772
|
}
|
|
54507
54773
|
|
|
54508
54774
|
// src/handlers/workspace.ts
|
|
54509
|
-
var
|
|
54775
|
+
var path54 = __toESM(require("path"), 1);
|
|
54510
54776
|
var os16 = __toESM(require("os"), 1);
|
|
54511
54777
|
init_protocol();
|
|
54512
54778
|
init_protocol();
|
|
@@ -54548,22 +54814,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54548
54814
|
const args = WorkspaceListArgs.parse(frame);
|
|
54549
54815
|
const isGuest = ctx?.principal.kind === "guest";
|
|
54550
54816
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
|
|
54551
|
-
const resolvedCwd =
|
|
54552
|
-
const target = args.path ?
|
|
54817
|
+
const resolvedCwd = path54.resolve(args.cwd ?? fallbackCwd);
|
|
54818
|
+
const target = args.path ? path54.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
54553
54819
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
54554
54820
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
54555
54821
|
return { response: { type: "workspace:list", ...res } };
|
|
54556
54822
|
};
|
|
54557
54823
|
const read = async (frame, _client, ctx) => {
|
|
54558
54824
|
const args = WorkspaceReadArgs.parse(frame);
|
|
54559
|
-
const target =
|
|
54825
|
+
const target = path54.isAbsolute(args.path) ? path54.resolve(args.path) : path54.resolve(args.cwd, args.path);
|
|
54560
54826
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
54561
54827
|
const res = workspace.read(args);
|
|
54562
54828
|
return { response: { type: "workspace:read", ...res } };
|
|
54563
54829
|
};
|
|
54564
54830
|
const skillsList = async (frame, _client, ctx) => {
|
|
54565
54831
|
const args = SkillsListArgs.parse(frame);
|
|
54566
|
-
const cwdAbs =
|
|
54832
|
+
const cwdAbs = path54.resolve(args.cwd);
|
|
54567
54833
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
54568
54834
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
54569
54835
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -54575,7 +54841,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54575
54841
|
};
|
|
54576
54842
|
const agentsList = async (frame, _client, ctx) => {
|
|
54577
54843
|
const args = AgentsListArgs.parse(frame);
|
|
54578
|
-
const cwdAbs =
|
|
54844
|
+
const cwdAbs = path54.resolve(args.cwd);
|
|
54579
54845
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
54580
54846
|
if (args.tool === "codex") {
|
|
54581
54847
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -54597,18 +54863,18 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54597
54863
|
}
|
|
54598
54864
|
|
|
54599
54865
|
// src/handlers/git.ts
|
|
54600
|
-
var
|
|
54866
|
+
var path56 = __toESM(require("path"), 1);
|
|
54601
54867
|
init_protocol();
|
|
54602
54868
|
init_protocol();
|
|
54603
54869
|
|
|
54604
54870
|
// src/workspace/git.ts
|
|
54605
54871
|
var import_node_child_process10 = require("child_process");
|
|
54606
54872
|
var import_node_fs41 = __toESM(require("fs"), 1);
|
|
54607
|
-
var
|
|
54873
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
54608
54874
|
var import_node_util = require("util");
|
|
54609
54875
|
var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
|
|
54610
54876
|
function normalizePath(p2) {
|
|
54611
|
-
const resolved =
|
|
54877
|
+
const resolved = import_node_path43.default.resolve(p2);
|
|
54612
54878
|
try {
|
|
54613
54879
|
return import_node_fs41.default.realpathSync(resolved);
|
|
54614
54880
|
} catch {
|
|
@@ -54684,7 +54950,7 @@ async function listGitBranches(cwd) {
|
|
|
54684
54950
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
54685
54951
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
54686
54952
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
54687
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
54953
|
+
if (!isGuestPathAllowed(ctx.grants, path56.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
54688
54954
|
throw new ClawdError(
|
|
54689
54955
|
ERROR_CODES.UNAUTHORIZED,
|
|
54690
54956
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -55370,7 +55636,7 @@ function buildPersonaHandlers(deps) {
|
|
|
55370
55636
|
}
|
|
55371
55637
|
|
|
55372
55638
|
// src/handlers/attachment.ts
|
|
55373
|
-
var
|
|
55639
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
55374
55640
|
init_protocol();
|
|
55375
55641
|
init_protocol();
|
|
55376
55642
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -55450,12 +55716,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
55450
55716
|
`session ${args.sessionId} scope unresolved`
|
|
55451
55717
|
);
|
|
55452
55718
|
}
|
|
55453
|
-
const cwdAbs =
|
|
55454
|
-
const candidateAbs =
|
|
55719
|
+
const cwdAbs = import_node_path44.default.resolve(sessionFile.cwd);
|
|
55720
|
+
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
55721
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
|
|
55456
55722
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
55457
55723
|
const entry = entries.find((e) => {
|
|
55458
|
-
const storedAbs =
|
|
55724
|
+
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
55725
|
return storedAbs === candidateAbs && !e.stale;
|
|
55460
55726
|
});
|
|
55461
55727
|
if (!entry) {
|
|
@@ -55480,7 +55746,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
55480
55746
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
55481
55747
|
const f = deps.sessionStore.read(sessionId);
|
|
55482
55748
|
if (!f) return;
|
|
55483
|
-
assertGuestAttachmentPath(ctx,
|
|
55749
|
+
assertGuestAttachmentPath(ctx, import_node_path44.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
55484
55750
|
}
|
|
55485
55751
|
const groupAdd = async (frame, _client, ctx) => {
|
|
55486
55752
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -55495,8 +55761,8 @@ function buildAttachmentHandlers(deps) {
|
|
|
55495
55761
|
if (!scope) {
|
|
55496
55762
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
|
|
55497
55763
|
}
|
|
55498
|
-
const cwdAbs =
|
|
55499
|
-
const candidateAbs =
|
|
55764
|
+
const cwdAbs = import_node_path44.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
|
|
55765
|
+
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
55766
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
|
|
55501
55767
|
const from = ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
55502
55768
|
const size = 0;
|
|
@@ -55554,21 +55820,21 @@ function buildAttachmentHandlers(deps) {
|
|
|
55554
55820
|
}
|
|
55555
55821
|
|
|
55556
55822
|
// src/handlers/extension.ts
|
|
55557
|
-
var
|
|
55558
|
-
var
|
|
55823
|
+
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
55824
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
55559
55825
|
init_protocol();
|
|
55560
55826
|
|
|
55561
55827
|
// src/extension/bundle-zip.ts
|
|
55562
|
-
var
|
|
55563
|
-
var
|
|
55828
|
+
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
55829
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
55564
55830
|
var import_node_crypto14 = __toESM(require("crypto"), 1);
|
|
55565
55831
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
55566
55832
|
async function bundleExtensionDir(dir) {
|
|
55567
55833
|
const entries = await listFilesSorted(dir);
|
|
55568
55834
|
const zip = new import_jszip2.default();
|
|
55569
55835
|
for (const rel of entries) {
|
|
55570
|
-
const abs =
|
|
55571
|
-
const content = await
|
|
55836
|
+
const abs = import_node_path45.default.join(dir, rel);
|
|
55837
|
+
const content = await import_promises6.default.readFile(abs);
|
|
55572
55838
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
55573
55839
|
}
|
|
55574
55840
|
const buffer = await zip.generateAsync({
|
|
@@ -55588,8 +55854,8 @@ async function listFilesSorted(rootDir) {
|
|
|
55588
55854
|
return out;
|
|
55589
55855
|
}
|
|
55590
55856
|
async function walk(absRoot, relPrefix, out) {
|
|
55591
|
-
const dirAbs =
|
|
55592
|
-
const entries = await
|
|
55857
|
+
const dirAbs = import_node_path45.default.join(absRoot, relPrefix);
|
|
55858
|
+
const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
|
|
55593
55859
|
for (const e of entries) {
|
|
55594
55860
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
55595
55861
|
const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
|
|
@@ -55641,26 +55907,26 @@ function computePublishCheck(args) {
|
|
|
55641
55907
|
}
|
|
55642
55908
|
|
|
55643
55909
|
// src/extension/install-flow.ts
|
|
55644
|
-
var
|
|
55645
|
-
var
|
|
55910
|
+
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
55911
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
55646
55912
|
var import_node_os19 = __toESM(require("os"), 1);
|
|
55647
55913
|
var import_node_crypto15 = __toESM(require("crypto"), 1);
|
|
55648
55914
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
55649
55915
|
|
|
55650
55916
|
// src/extension/paths.ts
|
|
55651
55917
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
55652
|
-
var
|
|
55918
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
55653
55919
|
function clawdHomeRoot(override) {
|
|
55654
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
55920
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path46.default.join(import_node_os18.default.homedir(), ".clawd");
|
|
55655
55921
|
}
|
|
55656
55922
|
function extensionsRoot(override) {
|
|
55657
|
-
return
|
|
55923
|
+
return import_node_path46.default.join(clawdHomeRoot(override), "extensions");
|
|
55658
55924
|
}
|
|
55659
55925
|
function publishedChannelsFile(override) {
|
|
55660
|
-
return
|
|
55926
|
+
return import_node_path46.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
55661
55927
|
}
|
|
55662
55928
|
function bundleCacheRoot(override) {
|
|
55663
|
-
return
|
|
55929
|
+
return import_node_path46.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
55664
55930
|
}
|
|
55665
55931
|
|
|
55666
55932
|
// src/extension/install-flow.ts
|
|
@@ -55687,7 +55953,7 @@ async function installFromChannel(args, deps) {
|
|
|
55687
55953
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
55688
55954
|
}
|
|
55689
55955
|
for (const name of Object.keys(zip.files)) {
|
|
55690
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
55956
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path47.default.isAbsolute(name)) {
|
|
55691
55957
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
55692
55958
|
}
|
|
55693
55959
|
}
|
|
@@ -55719,10 +55985,10 @@ async function installFromChannel(args, deps) {
|
|
|
55719
55985
|
);
|
|
55720
55986
|
}
|
|
55721
55987
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
55722
|
-
const destDir =
|
|
55988
|
+
const destDir = import_node_path47.default.join(deps.extensionsRoot, localExtId);
|
|
55723
55989
|
let destExists = false;
|
|
55724
55990
|
try {
|
|
55725
|
-
await
|
|
55991
|
+
await import_promises7.default.access(destDir);
|
|
55726
55992
|
destExists = true;
|
|
55727
55993
|
} catch {
|
|
55728
55994
|
}
|
|
@@ -55732,28 +55998,28 @@ async function installFromChannel(args, deps) {
|
|
|
55732
55998
|
`extension ${localExtId} already installed locally (from owner ${channelRef.ownerPrincipalId})`
|
|
55733
55999
|
);
|
|
55734
56000
|
}
|
|
55735
|
-
const stage = await
|
|
55736
|
-
|
|
56001
|
+
const stage = await import_promises7.default.mkdtemp(
|
|
56002
|
+
import_node_path47.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
55737
56003
|
);
|
|
55738
56004
|
try {
|
|
55739
56005
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
55740
|
-
const dest =
|
|
56006
|
+
const dest = import_node_path47.default.join(stage, name);
|
|
55741
56007
|
if (entry.dir) {
|
|
55742
|
-
await
|
|
56008
|
+
await import_promises7.default.mkdir(dest, { recursive: true });
|
|
55743
56009
|
continue;
|
|
55744
56010
|
}
|
|
55745
|
-
await
|
|
56011
|
+
await import_promises7.default.mkdir(import_node_path47.default.dirname(dest), { recursive: true });
|
|
55746
56012
|
if (name === "manifest.json") {
|
|
55747
56013
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
55748
|
-
await
|
|
56014
|
+
await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
55749
56015
|
} else {
|
|
55750
|
-
await
|
|
56016
|
+
await import_promises7.default.writeFile(dest, await entry.async("nodebuffer"));
|
|
55751
56017
|
}
|
|
55752
56018
|
}
|
|
55753
|
-
await
|
|
55754
|
-
await
|
|
56019
|
+
await import_promises7.default.mkdir(deps.extensionsRoot, { recursive: true });
|
|
56020
|
+
await import_promises7.default.rename(stage, destDir);
|
|
55755
56021
|
} catch (e) {
|
|
55756
|
-
await
|
|
56022
|
+
await import_promises7.default.rm(stage, { recursive: true, force: true }).catch(() => {
|
|
55757
56023
|
});
|
|
55758
56024
|
throw e;
|
|
55759
56025
|
}
|
|
@@ -55762,8 +56028,8 @@ async function installFromChannel(args, deps) {
|
|
|
55762
56028
|
}
|
|
55763
56029
|
|
|
55764
56030
|
// src/extension/update-flow.ts
|
|
55765
|
-
var
|
|
55766
|
-
var
|
|
56031
|
+
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
56032
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
55767
56033
|
var import_node_os20 = __toESM(require("os"), 1);
|
|
55768
56034
|
var import_node_crypto16 = __toESM(require("crypto"), 1);
|
|
55769
56035
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
@@ -55780,11 +56046,11 @@ async function updateFromChannel(args, deps) {
|
|
|
55780
56046
|
channelRef.extId,
|
|
55781
56047
|
channelRef.ownerPrincipalId
|
|
55782
56048
|
);
|
|
55783
|
-
const liveDir =
|
|
56049
|
+
const liveDir = import_node_path48.default.join(deps.extensionsRoot, localExtId);
|
|
55784
56050
|
const prevDir = `${liveDir}.prev`;
|
|
55785
56051
|
let existingVersion;
|
|
55786
56052
|
try {
|
|
55787
|
-
const raw = await
|
|
56053
|
+
const raw = await import_promises8.default.readFile(import_node_path48.default.join(liveDir, "manifest.json"), "utf8");
|
|
55788
56054
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
55789
56055
|
if (!parsed2.success) {
|
|
55790
56056
|
throw new UpdateError(
|
|
@@ -55817,7 +56083,7 @@ async function updateFromChannel(args, deps) {
|
|
|
55817
56083
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
55818
56084
|
}
|
|
55819
56085
|
for (const name of Object.keys(zip.files)) {
|
|
55820
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
56086
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path48.default.isAbsolute(name)) {
|
|
55821
56087
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
55822
56088
|
}
|
|
55823
56089
|
}
|
|
@@ -55849,31 +56115,31 @@ async function updateFromChannel(args, deps) {
|
|
|
55849
56115
|
);
|
|
55850
56116
|
}
|
|
55851
56117
|
await deps.runtime.close(localExtId);
|
|
55852
|
-
await
|
|
55853
|
-
await
|
|
55854
|
-
const stage = await
|
|
55855
|
-
|
|
56118
|
+
await import_promises8.default.rm(prevDir, { recursive: true, force: true });
|
|
56119
|
+
await import_promises8.default.rename(liveDir, prevDir);
|
|
56120
|
+
const stage = await import_promises8.default.mkdtemp(
|
|
56121
|
+
import_node_path48.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
55856
56122
|
);
|
|
55857
56123
|
try {
|
|
55858
56124
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
55859
|
-
const dest =
|
|
56125
|
+
const dest = import_node_path48.default.join(stage, name);
|
|
55860
56126
|
if (entry.dir) {
|
|
55861
|
-
await
|
|
56127
|
+
await import_promises8.default.mkdir(dest, { recursive: true });
|
|
55862
56128
|
continue;
|
|
55863
56129
|
}
|
|
55864
|
-
await
|
|
56130
|
+
await import_promises8.default.mkdir(import_node_path48.default.dirname(dest), { recursive: true });
|
|
55865
56131
|
if (name === "manifest.json") {
|
|
55866
56132
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
55867
|
-
await
|
|
56133
|
+
await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
55868
56134
|
} else {
|
|
55869
|
-
await
|
|
56135
|
+
await import_promises8.default.writeFile(dest, await entry.async("nodebuffer"));
|
|
55870
56136
|
}
|
|
55871
56137
|
}
|
|
55872
|
-
await
|
|
56138
|
+
await import_promises8.default.rename(stage, liveDir);
|
|
55873
56139
|
} catch (e) {
|
|
55874
|
-
await
|
|
56140
|
+
await import_promises8.default.rm(stage, { recursive: true, force: true }).catch(() => {
|
|
55875
56141
|
});
|
|
55876
|
-
await
|
|
56142
|
+
await import_promises8.default.rename(prevDir, liveDir).catch(() => {
|
|
55877
56143
|
});
|
|
55878
56144
|
await deps.runtime.open(localExtId).catch(() => {
|
|
55879
56145
|
});
|
|
@@ -55895,7 +56161,7 @@ async function updateFromChannel(args, deps) {
|
|
|
55895
56161
|
reason: e.message
|
|
55896
56162
|
};
|
|
55897
56163
|
}
|
|
55898
|
-
await
|
|
56164
|
+
await import_promises8.default.rm(prevDir, { recursive: true, force: true });
|
|
55899
56165
|
return {
|
|
55900
56166
|
kind: "updated",
|
|
55901
56167
|
extId: localExtId,
|
|
@@ -55903,9 +56169,9 @@ async function updateFromChannel(args, deps) {
|
|
|
55903
56169
|
};
|
|
55904
56170
|
}
|
|
55905
56171
|
async function rollback(deps, localExtId, liveDir, prevDir) {
|
|
55906
|
-
await
|
|
56172
|
+
await import_promises8.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
|
|
55907
56173
|
});
|
|
55908
|
-
await
|
|
56174
|
+
await import_promises8.default.rename(prevDir, liveDir).catch(() => {
|
|
55909
56175
|
});
|
|
55910
56176
|
await deps.runtime.open(localExtId).catch(() => {
|
|
55911
56177
|
});
|
|
@@ -55954,18 +56220,18 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
55954
56220
|
);
|
|
55955
56221
|
}
|
|
55956
56222
|
}
|
|
55957
|
-
const manifestPath =
|
|
56223
|
+
const manifestPath = import_node_path49.default.join(root, extId, "manifest.json");
|
|
55958
56224
|
const manifest = await readManifest(root, extId);
|
|
55959
56225
|
const next = { ...manifest, version: newVersion };
|
|
55960
56226
|
const tmp = `${manifestPath}.tmp`;
|
|
55961
|
-
await
|
|
55962
|
-
await
|
|
56227
|
+
await import_promises9.default.writeFile(tmp, JSON.stringify(next, null, 2));
|
|
56228
|
+
await import_promises9.default.rename(tmp, manifestPath);
|
|
55963
56229
|
}
|
|
55964
56230
|
async function readManifest(root, extId) {
|
|
55965
|
-
const file =
|
|
56231
|
+
const file = import_node_path49.default.join(root, extId, "manifest.json");
|
|
55966
56232
|
let raw;
|
|
55967
56233
|
try {
|
|
55968
|
-
raw = await
|
|
56234
|
+
raw = await import_promises9.default.readFile(file, "utf8");
|
|
55969
56235
|
} catch (e) {
|
|
55970
56236
|
if (e.code === "ENOENT") {
|
|
55971
56237
|
throw new ClawdError(ERROR_CODES.INVALID_PARAM, `extension ${extId} not installed`);
|
|
@@ -56053,7 +56319,7 @@ function buildExtensionHandlers(deps) {
|
|
|
56053
56319
|
};
|
|
56054
56320
|
async function buildSnapshotMeta(extId) {
|
|
56055
56321
|
const manifest = await readManifest(deps.root, extId);
|
|
56056
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
56322
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path49.default.join(deps.root, extId));
|
|
56057
56323
|
return { manifest, contentHash: sha256, buffer };
|
|
56058
56324
|
}
|
|
56059
56325
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -56236,7 +56502,7 @@ function buildExtensionHandlers(deps) {
|
|
|
56236
56502
|
// src/app-builder/project-store.ts
|
|
56237
56503
|
var import_node_fs42 = require("fs");
|
|
56238
56504
|
var import_node_child_process11 = require("child_process");
|
|
56239
|
-
var
|
|
56505
|
+
var import_node_path50 = require("path");
|
|
56240
56506
|
init_protocol();
|
|
56241
56507
|
var PROJECTS_DIR = "projects";
|
|
56242
56508
|
var META_FILE = ".clawd-project.json";
|
|
@@ -56250,14 +56516,14 @@ var ProjectStore = class {
|
|
|
56250
56516
|
root;
|
|
56251
56517
|
/** projects/<name>/.clawd-project.json 路径 */
|
|
56252
56518
|
metaPath(name) {
|
|
56253
|
-
return (0,
|
|
56519
|
+
return (0, import_node_path50.join)(this.projectsRoot(), name, META_FILE);
|
|
56254
56520
|
}
|
|
56255
56521
|
/** projects/<name>/ 目录路径(cwd 用) */
|
|
56256
56522
|
projectDir(name) {
|
|
56257
|
-
return (0,
|
|
56523
|
+
return (0, import_node_path50.join)(this.projectsRoot(), name);
|
|
56258
56524
|
}
|
|
56259
56525
|
projectsRoot() {
|
|
56260
|
-
return (0,
|
|
56526
|
+
return (0, import_node_path50.join)(this.root, PROJECTS_DIR);
|
|
56261
56527
|
}
|
|
56262
56528
|
async list() {
|
|
56263
56529
|
let entries;
|
|
@@ -56560,7 +56826,7 @@ var PublishJobRegistry = class {
|
|
|
56560
56826
|
// src/app-builder/publish-job-runner.ts
|
|
56561
56827
|
var import_node_child_process13 = require("child_process");
|
|
56562
56828
|
var import_node_fs43 = require("fs");
|
|
56563
|
-
var
|
|
56829
|
+
var import_node_path51 = require("path");
|
|
56564
56830
|
|
|
56565
56831
|
// src/app-builder/publish-stage-parser.ts
|
|
56566
56832
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -56592,7 +56858,7 @@ async function startPublishJob(deps, args) {
|
|
|
56592
56858
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
56593
56859
|
}
|
|
56594
56860
|
const projDir = projectDir(args.name);
|
|
56595
|
-
const logPath = (0,
|
|
56861
|
+
const logPath = (0, import_node_path51.join)(projDir, ".publish.log");
|
|
56596
56862
|
let logStream = null;
|
|
56597
56863
|
try {
|
|
56598
56864
|
logStream = (0, import_node_fs43.createWriteStream)(logPath, { flags: "w" });
|
|
@@ -56852,7 +57118,7 @@ async function recoverInterruptedJobs(deps) {
|
|
|
56852
57118
|
|
|
56853
57119
|
// src/handlers/app-builder.ts
|
|
56854
57120
|
init_protocol();
|
|
56855
|
-
var
|
|
57121
|
+
var import_node_path52 = require("path");
|
|
56856
57122
|
var import_node_fs44 = require("fs");
|
|
56857
57123
|
var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
|
|
56858
57124
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
@@ -57010,8 +57276,8 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57010
57276
|
const project = await userStore.create(f.name, reservedPorts);
|
|
57011
57277
|
try {
|
|
57012
57278
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
|
|
57013
|
-
const templateSrcDir = (0,
|
|
57014
|
-
const scaffoldScript = (0,
|
|
57279
|
+
const templateSrcDir = (0, import_node_path52.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
|
|
57280
|
+
const scaffoldScript = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
|
|
57015
57281
|
const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
|
|
57016
57282
|
deps.logger?.info("app-builder.scaffold.done", {
|
|
57017
57283
|
name: project.name,
|
|
@@ -57232,7 +57498,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57232
57498
|
await userStore.clearPublishJob(args.name);
|
|
57233
57499
|
}
|
|
57234
57500
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
|
|
57235
|
-
const scriptPath = (0,
|
|
57501
|
+
const scriptPath = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "publish.sh");
|
|
57236
57502
|
deps.logger?.info("app-builder.publish.start", {
|
|
57237
57503
|
name: args.name,
|
|
57238
57504
|
sessionId: boundSession.sessionId,
|
|
@@ -57407,12 +57673,12 @@ function buildVisitorHandlers(deps) {
|
|
|
57407
57673
|
}
|
|
57408
57674
|
|
|
57409
57675
|
// src/extension/registry.ts
|
|
57410
|
-
var
|
|
57411
|
-
var
|
|
57676
|
+
var import_promises10 = __toESM(require("fs/promises"), 1);
|
|
57677
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
57412
57678
|
async function loadAll(root) {
|
|
57413
57679
|
let entries;
|
|
57414
57680
|
try {
|
|
57415
|
-
entries = await
|
|
57681
|
+
entries = await import_promises10.default.readdir(root, { withFileTypes: true });
|
|
57416
57682
|
} catch (e) {
|
|
57417
57683
|
if (e.code === "ENOENT") return [];
|
|
57418
57684
|
throw e;
|
|
@@ -57421,16 +57687,16 @@ async function loadAll(root) {
|
|
|
57421
57687
|
for (const ent of entries) {
|
|
57422
57688
|
if (!ent.isDirectory()) continue;
|
|
57423
57689
|
if (ent.name.startsWith(".")) continue;
|
|
57424
|
-
records.push(await loadOne(
|
|
57690
|
+
records.push(await loadOne(import_node_path53.default.join(root, ent.name), ent.name));
|
|
57425
57691
|
}
|
|
57426
57692
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
57427
57693
|
return records;
|
|
57428
57694
|
}
|
|
57429
57695
|
async function loadOne(dir, dirName) {
|
|
57430
|
-
const manifestPath =
|
|
57696
|
+
const manifestPath = import_node_path53.default.join(dir, "manifest.json");
|
|
57431
57697
|
let raw;
|
|
57432
57698
|
try {
|
|
57433
|
-
raw = await
|
|
57699
|
+
raw = await import_promises10.default.readFile(manifestPath, "utf8");
|
|
57434
57700
|
} catch {
|
|
57435
57701
|
return {
|
|
57436
57702
|
extId: dirName,
|
|
@@ -57471,8 +57737,8 @@ async function loadOne(dir, dirName) {
|
|
|
57471
57737
|
}
|
|
57472
57738
|
|
|
57473
57739
|
// src/extension/uninstall.ts
|
|
57474
|
-
var
|
|
57475
|
-
var
|
|
57740
|
+
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
57741
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
57476
57742
|
var UninstallError = class extends Error {
|
|
57477
57743
|
constructor(code, message) {
|
|
57478
57744
|
super(message);
|
|
@@ -57481,14 +57747,14 @@ var UninstallError = class extends Error {
|
|
|
57481
57747
|
code;
|
|
57482
57748
|
};
|
|
57483
57749
|
async function uninstall(deps) {
|
|
57484
|
-
const dir =
|
|
57750
|
+
const dir = import_node_path54.default.join(deps.root, deps.extId);
|
|
57485
57751
|
try {
|
|
57486
|
-
await
|
|
57752
|
+
await import_promises11.default.access(dir);
|
|
57487
57753
|
} catch {
|
|
57488
57754
|
throw new UninstallError("NOT_FOUND", `extension ${deps.extId} not installed`);
|
|
57489
57755
|
}
|
|
57490
57756
|
await deps.runtime.close(deps.extId);
|
|
57491
|
-
await
|
|
57757
|
+
await import_promises11.default.rm(dir, { recursive: true, force: true });
|
|
57492
57758
|
}
|
|
57493
57759
|
|
|
57494
57760
|
// src/handlers/index.ts
|
|
@@ -58201,8 +58467,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
|
|
|
58201
58467
|
|
|
58202
58468
|
// src/extension/runtime.ts
|
|
58203
58469
|
var import_node_child_process16 = require("child_process");
|
|
58204
|
-
var
|
|
58205
|
-
var
|
|
58470
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
58471
|
+
var import_promises12 = require("timers/promises");
|
|
58206
58472
|
|
|
58207
58473
|
// src/extension/port-allocator.ts
|
|
58208
58474
|
var import_node_net2 = __toESM(require("net"), 1);
|
|
@@ -58302,7 +58568,7 @@ var Runtime = class {
|
|
|
58302
58568
|
/\$CLAWOS_EXT_PORT/g,
|
|
58303
58569
|
String(port)
|
|
58304
58570
|
);
|
|
58305
|
-
const dir =
|
|
58571
|
+
const dir = import_node_path55.default.join(this.root, extId);
|
|
58306
58572
|
const env = {
|
|
58307
58573
|
...process.env,
|
|
58308
58574
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -58378,7 +58644,7 @@ ${handle.stderrTail}`
|
|
|
58378
58644
|
if (res.ok) return;
|
|
58379
58645
|
} catch {
|
|
58380
58646
|
}
|
|
58381
|
-
await (0,
|
|
58647
|
+
await (0, import_promises12.setTimeout)(this.healthzIntervalMs);
|
|
58382
58648
|
}
|
|
58383
58649
|
throw new RuntimeError(
|
|
58384
58650
|
"HEALTHZ_FAILED",
|
|
@@ -58403,7 +58669,7 @@ ${handle.stderrTail}`
|
|
|
58403
58669
|
};
|
|
58404
58670
|
killGroup("SIGTERM");
|
|
58405
58671
|
const exited = new Promise((resolve6) => child.once("exit", () => resolve6()));
|
|
58406
|
-
const timed = (0,
|
|
58672
|
+
const timed = (0, import_promises12.setTimeout)(5e3).then(() => "timeout");
|
|
58407
58673
|
const winner = await Promise.race([exited.then(() => "exited"), timed]);
|
|
58408
58674
|
if (winner === "timeout" && child.exitCode === null) {
|
|
58409
58675
|
killGroup("SIGKILL");
|
|
@@ -58413,8 +58679,8 @@ ${handle.stderrTail}`
|
|
|
58413
58679
|
};
|
|
58414
58680
|
|
|
58415
58681
|
// src/extension/published-channels.ts
|
|
58416
|
-
var
|
|
58417
|
-
var
|
|
58682
|
+
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
58683
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
58418
58684
|
init_zod();
|
|
58419
58685
|
var PublishedChannelsError = class extends Error {
|
|
58420
58686
|
constructor(code, message) {
|
|
@@ -58444,7 +58710,7 @@ var PublishedChannelStore = class {
|
|
|
58444
58710
|
this.channels.clear();
|
|
58445
58711
|
let raw;
|
|
58446
58712
|
try {
|
|
58447
|
-
raw = await
|
|
58713
|
+
raw = await import_promises13.default.readFile(this.filePath, "utf8");
|
|
58448
58714
|
} catch (e) {
|
|
58449
58715
|
if (e.code === "ENOENT") {
|
|
58450
58716
|
this.loaded = true;
|
|
@@ -58513,15 +58779,15 @@ var PublishedChannelStore = class {
|
|
|
58513
58779
|
)
|
|
58514
58780
|
};
|
|
58515
58781
|
const tmp = `${this.filePath}.tmp`;
|
|
58516
|
-
await
|
|
58517
|
-
await
|
|
58518
|
-
await
|
|
58782
|
+
await import_promises13.default.mkdir(import_node_path56.default.dirname(this.filePath), { recursive: true });
|
|
58783
|
+
await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
58784
|
+
await import_promises13.default.rename(tmp, this.filePath);
|
|
58519
58785
|
}
|
|
58520
58786
|
};
|
|
58521
58787
|
|
|
58522
58788
|
// src/extension/bundle-cache.ts
|
|
58523
|
-
var
|
|
58524
|
-
var
|
|
58789
|
+
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
58790
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
58525
58791
|
var BundleCache = class {
|
|
58526
58792
|
constructor(rootDir) {
|
|
58527
58793
|
this.rootDir = rootDir;
|
|
@@ -58529,17 +58795,17 @@ var BundleCache = class {
|
|
|
58529
58795
|
rootDir;
|
|
58530
58796
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
58531
58797
|
async write(snapshotHash, buffer) {
|
|
58532
|
-
await
|
|
58533
|
-
const file =
|
|
58798
|
+
await import_promises14.default.mkdir(this.rootDir, { recursive: true });
|
|
58799
|
+
const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58534
58800
|
const tmp = `${file}.tmp`;
|
|
58535
|
-
await
|
|
58536
|
-
await
|
|
58801
|
+
await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
|
|
58802
|
+
await import_promises14.default.rename(tmp, file);
|
|
58537
58803
|
}
|
|
58538
58804
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
58539
58805
|
async read(snapshotHash) {
|
|
58540
|
-
const file =
|
|
58806
|
+
const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58541
58807
|
try {
|
|
58542
|
-
return await
|
|
58808
|
+
return await import_promises14.default.readFile(file);
|
|
58543
58809
|
} catch (e) {
|
|
58544
58810
|
if (e.code === "ENOENT") return null;
|
|
58545
58811
|
throw e;
|
|
@@ -58547,8 +58813,8 @@ var BundleCache = class {
|
|
|
58547
58813
|
}
|
|
58548
58814
|
/** Idempotent — missing file is not an error. */
|
|
58549
58815
|
async delete(snapshotHash) {
|
|
58550
|
-
const file =
|
|
58551
|
-
await
|
|
58816
|
+
const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58817
|
+
await import_promises14.default.rm(file, { force: true });
|
|
58552
58818
|
}
|
|
58553
58819
|
};
|
|
58554
58820
|
|
|
@@ -58570,24 +58836,24 @@ async function startDaemon(config) {
|
|
|
58570
58836
|
sampling: logShippingCfg.sampling,
|
|
58571
58837
|
homeDir: import_node_os22.default.homedir()
|
|
58572
58838
|
});
|
|
58573
|
-
const logDir =
|
|
58839
|
+
const logDir = import_node_path58.default.join(config.dataDir, "log");
|
|
58574
58840
|
import_node_fs45.default.mkdirSync(logDir, { recursive: true });
|
|
58575
58841
|
const logger = createLogger({
|
|
58576
58842
|
level: config.logLevel,
|
|
58577
|
-
file:
|
|
58843
|
+
file: import_node_path58.default.join(logDir, "clawd.log"),
|
|
58578
58844
|
logClient
|
|
58579
58845
|
});
|
|
58580
58846
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
58581
58847
|
const screenIdleProbeLogger = createFileOnlyLogger({
|
|
58582
|
-
file:
|
|
58848
|
+
file: import_node_path58.default.join(logDir, "screen-idle-probe.log"),
|
|
58583
58849
|
level: "debug"
|
|
58584
58850
|
});
|
|
58585
58851
|
logger.info("screen-idle probe logger enabled", {
|
|
58586
|
-
file:
|
|
58852
|
+
file: import_node_path58.default.join(logDir, "screen-idle-probe.log")
|
|
58587
58853
|
});
|
|
58588
58854
|
const CAP_TARGETS = [
|
|
58589
|
-
|
|
58590
|
-
|
|
58855
|
+
import_node_path58.default.join(logDir, "clawd.log"),
|
|
58856
|
+
import_node_path58.default.join(logDir, "screen-idle-probe.log")
|
|
58591
58857
|
];
|
|
58592
58858
|
const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
|
|
58593
58859
|
const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
|
|
@@ -58741,8 +59007,8 @@ async function startDaemon(config) {
|
|
|
58741
59007
|
const agents = new AgentsScanner();
|
|
58742
59008
|
const history = new ClaudeHistoryReader();
|
|
58743
59009
|
let transport = null;
|
|
58744
|
-
const personaStore = new PersonaStore(
|
|
58745
|
-
const usersRoot =
|
|
59010
|
+
const personaStore = new PersonaStore(import_node_path58.default.join(config.dataDir, "personas"));
|
|
59011
|
+
const usersRoot = import_node_path58.default.join(config.dataDir, "users");
|
|
58746
59012
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
58747
59013
|
if (defaultsRoot) {
|
|
58748
59014
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -58761,18 +59027,33 @@ async function startDaemon(config) {
|
|
|
58761
59027
|
migrateAgentsMirror({ store: personaStore, logger });
|
|
58762
59028
|
migrateCodexSandbox({ store: personaStore, logger });
|
|
58763
59029
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
58764
|
-
const
|
|
58765
|
-
|
|
59030
|
+
const dispatchStore = createDispatchStore({
|
|
59031
|
+
filePath: import_node_path58.default.join(config.dataDir, "dispatch.json"),
|
|
59032
|
+
now: () => Date.now(),
|
|
59033
|
+
onFlushError: (err) => logger.error("dispatch store flush failed", {
|
|
59034
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
59035
|
+
})
|
|
59036
|
+
});
|
|
59037
|
+
await dispatchStore.load();
|
|
59038
|
+
dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
|
|
59039
|
+
let deliverPendingRef;
|
|
59040
|
+
const personaDispatchManager = new PersonaDispatchManager({
|
|
59041
|
+
genId: () => v4_default(),
|
|
59042
|
+
store: dispatchStore,
|
|
59043
|
+
now: () => Date.now(),
|
|
59044
|
+
onCompleted: (sid) => deliverPendingRef?.(sid)
|
|
59045
|
+
});
|
|
59046
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path58.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
|
|
58766
59047
|
const mcpConfigs = [];
|
|
58767
59048
|
const dispatchServerCandidates = [
|
|
58768
|
-
|
|
59049
|
+
import_node_path58.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
58769
59050
|
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
58770
|
-
|
|
59051
|
+
import_node_path58.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
58771
59052
|
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
58772
59053
|
];
|
|
58773
59054
|
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58774
59055
|
if (dispatchServerScriptPath) {
|
|
58775
|
-
const dispatchLogPath =
|
|
59056
|
+
const dispatchLogPath = import_node_path58.default.join(logDir, "dispatch-mcp-server.log");
|
|
58776
59057
|
const dispatchCfgPath = writeDispatchMcpConfig({
|
|
58777
59058
|
dataDir: config.dataDir,
|
|
58778
59059
|
serverScriptPath: dispatchServerScriptPath,
|
|
@@ -58790,12 +59071,12 @@ async function startDaemon(config) {
|
|
|
58790
59071
|
});
|
|
58791
59072
|
}
|
|
58792
59073
|
const ticketServerCandidates = [
|
|
58793
|
-
|
|
58794
|
-
|
|
59074
|
+
import_node_path58.default.join(here, "ticket", "mcp-server.cjs"),
|
|
59075
|
+
import_node_path58.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
58795
59076
|
];
|
|
58796
59077
|
const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58797
59078
|
if (ticketServerScriptPath) {
|
|
58798
|
-
const ticketLogPath =
|
|
59079
|
+
const ticketLogPath = import_node_path58.default.join(logDir, "ticket-mcp-server.log");
|
|
58799
59080
|
const ticketCfgPath = writeTicketMcpConfig({
|
|
58800
59081
|
dataDir: config.dataDir,
|
|
58801
59082
|
serverScriptPath: ticketServerScriptPath,
|
|
@@ -58815,12 +59096,12 @@ async function startDaemon(config) {
|
|
|
58815
59096
|
});
|
|
58816
59097
|
}
|
|
58817
59098
|
const shiftServerCandidates = [
|
|
58818
|
-
|
|
58819
|
-
|
|
59099
|
+
import_node_path58.default.join(here, "shift", "mcp-server.cjs"),
|
|
59100
|
+
import_node_path58.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
|
|
58820
59101
|
];
|
|
58821
59102
|
const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58822
59103
|
if (shiftServerScriptPath) {
|
|
58823
|
-
const shiftLogPath =
|
|
59104
|
+
const shiftLogPath = import_node_path58.default.join(logDir, "shift-mcp-server.log");
|
|
58824
59105
|
const shiftCfgPath = await writeShiftMcpConfig({
|
|
58825
59106
|
dataDir: config.dataDir,
|
|
58826
59107
|
serverScriptPath: shiftServerScriptPath,
|
|
@@ -58839,12 +59120,12 @@ async function startDaemon(config) {
|
|
|
58839
59120
|
);
|
|
58840
59121
|
}
|
|
58841
59122
|
const inboxServerCandidates = [
|
|
58842
|
-
|
|
58843
|
-
|
|
59123
|
+
import_node_path58.default.join(here, "inbox", "mcp-server.cjs"),
|
|
59124
|
+
import_node_path58.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
|
|
58844
59125
|
];
|
|
58845
59126
|
const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58846
59127
|
if (inboxServerScriptPath) {
|
|
58847
|
-
const inboxLogPath =
|
|
59128
|
+
const inboxLogPath = import_node_path58.default.join(logDir, "inbox-mcp-server.log");
|
|
58848
59129
|
const inboxCfgPath = await writeInboxMcpConfig({
|
|
58849
59130
|
dataDir: config.dataDir,
|
|
58850
59131
|
serverScriptPath: inboxServerScriptPath,
|
|
@@ -58863,8 +59144,8 @@ async function startDaemon(config) {
|
|
|
58863
59144
|
);
|
|
58864
59145
|
}
|
|
58865
59146
|
const peerOpsServerCandidates = [
|
|
58866
|
-
|
|
58867
|
-
|
|
59147
|
+
import_node_path58.default.join(here, "peer-ops", "mcp-server.cjs"),
|
|
59148
|
+
import_node_path58.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
|
|
58868
59149
|
];
|
|
58869
59150
|
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58870
59151
|
if (peerOpsServerScriptPath) {
|
|
@@ -58884,7 +59165,7 @@ async function startDaemon(config) {
|
|
|
58884
59165
|
);
|
|
58885
59166
|
}
|
|
58886
59167
|
const shiftStore = createShiftStore({
|
|
58887
|
-
filePath:
|
|
59168
|
+
filePath: import_node_path58.default.join(config.dataDir, "shift.json"),
|
|
58888
59169
|
ownerIdProvider: () => ownerPrincipalId,
|
|
58889
59170
|
now: () => Date.now()
|
|
58890
59171
|
});
|
|
@@ -58906,7 +59187,7 @@ async function startDaemon(config) {
|
|
|
58906
59187
|
getAdapter,
|
|
58907
59188
|
historyReader: history,
|
|
58908
59189
|
dataDir: config.dataDir,
|
|
58909
|
-
personaRoot:
|
|
59190
|
+
personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
|
|
58910
59191
|
usersRoot,
|
|
58911
59192
|
personaStore,
|
|
58912
59193
|
ownerDisplayName,
|
|
@@ -58922,6 +59203,8 @@ async function startDaemon(config) {
|
|
|
58922
59203
|
// Persona dispatch (Task 8): manager.createDispatchedSession 用 personaDispatchManager
|
|
58923
59204
|
// registerBSession;reducer 通过闭包反查 dispatchId 注 CLAWD_DISPATCH_ID env。
|
|
58924
59205
|
personaDispatchManager,
|
|
59206
|
+
// Dispatch 结果投递:deliverPending 查台账 + turn-end sweep(spec 2026-07-20 §5)。
|
|
59207
|
+
dispatchStore,
|
|
58925
59208
|
// daemon 级 MCP server 登记表(dispatch / ticket / shift / inbox / ...,上方各 writer
|
|
58926
59209
|
// 块写盘成功即登记);reducer 透传到 SpawnContext.mcpConfigs,cc spawn 逐项 --mcp-config。
|
|
58927
59210
|
mcpConfigs,
|
|
@@ -58944,7 +59227,7 @@ async function startDaemon(config) {
|
|
|
58944
59227
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
58945
59228
|
attachmentGroup: {
|
|
58946
59229
|
onFileEdit: (input) => {
|
|
58947
|
-
const absPath =
|
|
59230
|
+
const absPath = import_node_path58.default.isAbsolute(input.relPath) ? input.relPath : import_node_path58.default.join(input.cwd, input.relPath);
|
|
58948
59231
|
let size = 0;
|
|
58949
59232
|
try {
|
|
58950
59233
|
size = import_node_fs45.default.statSync(absPath).size;
|
|
@@ -59010,6 +59293,7 @@ async function startDaemon(config) {
|
|
|
59010
59293
|
}
|
|
59011
59294
|
});
|
|
59012
59295
|
manager.attachObserver(observer);
|
|
59296
|
+
deliverPendingRef = (sid) => manager.deliverPending(sid);
|
|
59013
59297
|
const claudeAdapter = config.mode === "tui" ? new ClaudeTuiAdapter({
|
|
59014
59298
|
logger,
|
|
59015
59299
|
historyReader: new ClaudeHistoryReader(),
|
|
@@ -59176,11 +59460,11 @@ async function startDaemon(config) {
|
|
|
59176
59460
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
59177
59461
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
59178
59462
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
59179
|
-
personaRoot:
|
|
59463
|
+
personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
|
|
59180
59464
|
usersRoot
|
|
59181
59465
|
},
|
|
59182
59466
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
59183
|
-
personaRoot:
|
|
59467
|
+
personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
|
|
59184
59468
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
59185
59469
|
usersRoot,
|
|
59186
59470
|
// capability:list / delete handler 依赖
|
|
@@ -59291,11 +59575,11 @@ async function startDaemon(config) {
|
|
|
59291
59575
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
59292
59576
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
59293
59577
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
59294
|
-
appBuilderPersonaRoot:
|
|
59578
|
+
appBuilderPersonaRoot: import_node_path58.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
59295
59579
|
// 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
|
|
59296
|
-
deployKitRoot:
|
|
59580
|
+
deployKitRoot: import_node_path58.default.join(config.dataDir, "deploy-kit"),
|
|
59297
59581
|
// scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
|
|
59298
|
-
resolvePersonaRoot: (personaId) =>
|
|
59582
|
+
resolvePersonaRoot: (personaId) => import_node_path58.default.join(config.dataDir, "personas", personaId),
|
|
59299
59583
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
59300
59584
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
59301
59585
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -59325,6 +59609,7 @@ async function startDaemon(config) {
|
|
|
59325
59609
|
let handlers = makeHandlers();
|
|
59326
59610
|
const dispatchHandlers = buildPersonaDispatchHandlers({
|
|
59327
59611
|
personaDispatchManager,
|
|
59612
|
+
store: dispatchStore,
|
|
59328
59613
|
logger,
|
|
59329
59614
|
spawnB: async (args) => {
|
|
59330
59615
|
logger.info("dispatch.spawnB.start", {
|
|
@@ -59338,7 +59623,7 @@ async function startDaemon(config) {
|
|
|
59338
59623
|
}
|
|
59339
59624
|
let sourceJsonlPath = "(no transcript yet \u2014 operate from the task description alone)";
|
|
59340
59625
|
if (sourceFile && sourceFile.toolSessionId) {
|
|
59341
|
-
sourceJsonlPath =
|
|
59626
|
+
sourceJsonlPath = import_node_path58.default.join(
|
|
59342
59627
|
import_node_os22.default.homedir(),
|
|
59343
59628
|
".claude",
|
|
59344
59629
|
"projects",
|
|
@@ -59656,8 +59941,8 @@ async function startDaemon(config) {
|
|
|
59656
59941
|
const lines = [
|
|
59657
59942
|
`Tunnel: ${r.url}`,
|
|
59658
59943
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
59659
|
-
`Frpc config: ${
|
|
59660
|
-
`Frpc log: ${
|
|
59944
|
+
`Frpc config: ${import_node_path58.default.join(config.dataDir, "frpc.toml")}`,
|
|
59945
|
+
`Frpc log: ${import_node_path58.default.join(logDir, "frpc.log")}`
|
|
59661
59946
|
];
|
|
59662
59947
|
const width = Math.max(...lines.map((l) => l.length));
|
|
59663
59948
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -59670,7 +59955,7 @@ ${bar}
|
|
|
59670
59955
|
|
|
59671
59956
|
`);
|
|
59672
59957
|
try {
|
|
59673
|
-
const connectPath =
|
|
59958
|
+
const connectPath = import_node_path58.default.join(config.dataDir, "connect.txt");
|
|
59674
59959
|
import_node_fs45.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
59675
59960
|
} catch {
|
|
59676
59961
|
}
|
|
@@ -59743,7 +60028,7 @@ ${bar}
|
|
|
59743
60028
|
};
|
|
59744
60029
|
}
|
|
59745
60030
|
function migrateDropPersonsDir(dataDir) {
|
|
59746
|
-
const dir =
|
|
60031
|
+
const dir = import_node_path58.default.join(dataDir, "persons");
|
|
59747
60032
|
try {
|
|
59748
60033
|
import_node_fs45.default.rmSync(dir, { recursive: true, force: true });
|
|
59749
60034
|
} catch {
|