@clawos-dev/clawd 0.2.246 → 0.2.248
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +845 -535
- package/dist/dispatch/mcp-server.cjs +90 -18443
- package/dist/share-ui/assets/{guest-DCUpe97P.js → guest-DeJiT1im.js} +125 -125
- package/dist/share-ui/guest.html +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -67,6 +67,8 @@ var init_methods = __esm({
|
|
|
67
67
|
"session:subscribe",
|
|
68
68
|
"session:unsubscribe",
|
|
69
69
|
"session:pin",
|
|
70
|
+
// 清共享未读标记(SessionFile.unreadAt → null)+ 广播 session:info;幂等
|
|
71
|
+
"session:markRead",
|
|
70
72
|
"session:reorderPins",
|
|
71
73
|
// mirror peer sessions (2026-05-26): owner-only RPC,写/删本机 mirror SessionFile —
|
|
72
74
|
// mirror 是「**我**在朋友 daemon 上自己创建的 session」的本机持久化副本(不是朋友的会话),
|
|
@@ -749,8 +751,8 @@ var init_parseUtil = __esm({
|
|
|
749
751
|
init_errors2();
|
|
750
752
|
init_en();
|
|
751
753
|
makeIssue = (params) => {
|
|
752
|
-
const { data, path:
|
|
753
|
-
const fullPath = [...
|
|
754
|
+
const { data, path: path71, errorMaps, issueData } = params;
|
|
755
|
+
const fullPath = [...path71, ...issueData.path || []];
|
|
754
756
|
const fullIssue = {
|
|
755
757
|
...issueData,
|
|
756
758
|
path: fullPath
|
|
@@ -1061,11 +1063,11 @@ var init_types = __esm({
|
|
|
1061
1063
|
init_parseUtil();
|
|
1062
1064
|
init_util();
|
|
1063
1065
|
ParseInputLazyPath = class {
|
|
1064
|
-
constructor(parent, value,
|
|
1066
|
+
constructor(parent, value, path71, key) {
|
|
1065
1067
|
this._cachedPath = [];
|
|
1066
1068
|
this.parent = parent;
|
|
1067
1069
|
this.data = value;
|
|
1068
|
-
this._path =
|
|
1070
|
+
this._path = path71;
|
|
1069
1071
|
this._key = key;
|
|
1070
1072
|
}
|
|
1071
1073
|
get path() {
|
|
@@ -4781,6 +4783,11 @@ var init_schemas = __esm({
|
|
|
4781
4783
|
// pinned 行手动拖拽顺序;越小越靠前。session:reorderPins 整体重写所有 pinned 的此字段。
|
|
4782
4784
|
// 缺失时 view-state 排序回退到 pinnedAt desc(旧数据兼容)
|
|
4783
4785
|
pinSortOrder: external_exports.number().int().nullable().optional(),
|
|
4786
|
+
// daemon 权威的共享未读标记(spec 2026-07-20-shared-session-unread):
|
|
4787
|
+
// session wire status 从 running 跃迁为非 running 时 daemon 置为当时 ISO 时间戳;
|
|
4788
|
+
// session:markRead RPC 或新 turn 开始(→ running)时清为 null。
|
|
4789
|
+
// 所有客户端(desktop / mobile)共享同一份,任一端标读全端清。
|
|
4790
|
+
unreadAt: external_exports.string().min(1).nullable().optional(),
|
|
4784
4791
|
// 用户在 NewSessionDialog 或 Edit modal 选择的 icon 标识;UI 端做 enum 兜底
|
|
4785
4792
|
iconKey: external_exports.string().optional(),
|
|
4786
4793
|
// 由 session:fork 派生的 session 在 create 时记录源 session 的 sessionId(稳定 key,
|
|
@@ -6180,7 +6187,7 @@ var init_feishu_auth = __esm({
|
|
|
6180
6187
|
});
|
|
6181
6188
|
|
|
6182
6189
|
// ../protocol/src/dispatch.ts
|
|
6183
|
-
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema;
|
|
6190
|
+
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema, DISPATCH_STATUSES, DispatchStatusSchema, DispatchRecordSchema, DispatchListArgsSchema, DispatchListResultSchema;
|
|
6184
6191
|
var init_dispatch = __esm({
|
|
6185
6192
|
"../protocol/src/dispatch.ts"() {
|
|
6186
6193
|
"use strict";
|
|
@@ -6212,6 +6219,32 @@ var init_dispatch = __esm({
|
|
|
6212
6219
|
dispatchId: external_exports.string().min(1),
|
|
6213
6220
|
outcome: DispatchOutcomeSchema
|
|
6214
6221
|
});
|
|
6222
|
+
DISPATCH_STATUSES = ["running", "completed", "failed"];
|
|
6223
|
+
DispatchStatusSchema = external_exports.enum(DISPATCH_STATUSES);
|
|
6224
|
+
DispatchRecordSchema = external_exports.object({
|
|
6225
|
+
dispatchId: external_exports.string().min(1),
|
|
6226
|
+
sourceSessionId: external_exports.string().min(1),
|
|
6227
|
+
sourcePersonaId: external_exports.string().min(1).optional(),
|
|
6228
|
+
targetPersonaId: external_exports.string().min(1),
|
|
6229
|
+
/** B 的 sessionId;registerBSession 后回填 */
|
|
6230
|
+
workerSessionId: external_exports.string().min(1).optional(),
|
|
6231
|
+
/** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
|
|
6232
|
+
taskText: external_exports.string(),
|
|
6233
|
+
status: DispatchStatusSchema,
|
|
6234
|
+
outcome: DispatchOutcomeSchema.optional(),
|
|
6235
|
+
/** 上层消费者语义(如司礼监的口谕/验收状态),daemon 不解释 */
|
|
6236
|
+
meta: external_exports.record(external_exports.unknown()).optional(),
|
|
6237
|
+
createdAt: external_exports.string().min(1),
|
|
6238
|
+
completedAt: external_exports.string().min(1).optional(),
|
|
6239
|
+
/** 结果注入 source session 成功时戳,兼当投递 dedup 标记 */
|
|
6240
|
+
deliveredAt: external_exports.string().min(1).optional()
|
|
6241
|
+
});
|
|
6242
|
+
DispatchListArgsSchema = external_exports.object({
|
|
6243
|
+
sourceSessionId: external_exports.string().min(1).optional()
|
|
6244
|
+
});
|
|
6245
|
+
DispatchListResultSchema = external_exports.object({
|
|
6246
|
+
records: external_exports.array(DispatchRecordSchema)
|
|
6247
|
+
});
|
|
6215
6248
|
}
|
|
6216
6249
|
});
|
|
6217
6250
|
|
|
@@ -6564,8 +6597,8 @@ var require_req = __commonJS({
|
|
|
6564
6597
|
if (req.originalUrl) {
|
|
6565
6598
|
_req.url = req.originalUrl;
|
|
6566
6599
|
} else {
|
|
6567
|
-
const
|
|
6568
|
-
_req.url = typeof
|
|
6600
|
+
const path71 = req.path;
|
|
6601
|
+
_req.url = typeof path71 === "string" ? path71 : req.url ? req.url.path || req.url : void 0;
|
|
6569
6602
|
}
|
|
6570
6603
|
if (req.query) {
|
|
6571
6604
|
_req.query = req.query;
|
|
@@ -6730,14 +6763,14 @@ var require_redact = __commonJS({
|
|
|
6730
6763
|
}
|
|
6731
6764
|
return obj;
|
|
6732
6765
|
}
|
|
6733
|
-
function parsePath(
|
|
6766
|
+
function parsePath(path71) {
|
|
6734
6767
|
const parts = [];
|
|
6735
6768
|
let current = "";
|
|
6736
6769
|
let inBrackets = false;
|
|
6737
6770
|
let inQuotes = false;
|
|
6738
6771
|
let quoteChar = "";
|
|
6739
|
-
for (let i = 0; i <
|
|
6740
|
-
const char =
|
|
6772
|
+
for (let i = 0; i < path71.length; i++) {
|
|
6773
|
+
const char = path71[i];
|
|
6741
6774
|
if (!inBrackets && char === ".") {
|
|
6742
6775
|
if (current) {
|
|
6743
6776
|
parts.push(current);
|
|
@@ -6868,10 +6901,10 @@ var require_redact = __commonJS({
|
|
|
6868
6901
|
return current;
|
|
6869
6902
|
}
|
|
6870
6903
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
6871
|
-
for (const
|
|
6872
|
-
const parts = parsePath(
|
|
6904
|
+
for (const path71 of paths) {
|
|
6905
|
+
const parts = parsePath(path71);
|
|
6873
6906
|
if (parts.includes("*")) {
|
|
6874
|
-
redactWildcardPath(obj, parts, censor,
|
|
6907
|
+
redactWildcardPath(obj, parts, censor, path71, remove);
|
|
6875
6908
|
} else {
|
|
6876
6909
|
if (remove) {
|
|
6877
6910
|
removeKey(obj, parts);
|
|
@@ -6956,8 +6989,8 @@ var require_redact = __commonJS({
|
|
|
6956
6989
|
}
|
|
6957
6990
|
} else {
|
|
6958
6991
|
if (afterWildcard.includes("*")) {
|
|
6959
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6960
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
6992
|
+
const wrappedCensor = typeof censor === "function" ? (value, path71) => {
|
|
6993
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path71];
|
|
6961
6994
|
return censor(value, fullPath);
|
|
6962
6995
|
} : censor;
|
|
6963
6996
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6992,8 +7025,8 @@ var require_redact = __commonJS({
|
|
|
6992
7025
|
return null;
|
|
6993
7026
|
}
|
|
6994
7027
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6995
|
-
for (const
|
|
6996
|
-
const parts = parsePath(
|
|
7028
|
+
for (const path71 of pathsToClone) {
|
|
7029
|
+
const parts = parsePath(path71);
|
|
6997
7030
|
let current = pathStructure;
|
|
6998
7031
|
for (let i = 0; i < parts.length; i++) {
|
|
6999
7032
|
const part = parts[i];
|
|
@@ -7045,24 +7078,24 @@ var require_redact = __commonJS({
|
|
|
7045
7078
|
}
|
|
7046
7079
|
return cloneSelectively(obj, pathStructure);
|
|
7047
7080
|
}
|
|
7048
|
-
function validatePath(
|
|
7049
|
-
if (typeof
|
|
7081
|
+
function validatePath(path71) {
|
|
7082
|
+
if (typeof path71 !== "string") {
|
|
7050
7083
|
throw new Error("Paths must be (non-empty) strings");
|
|
7051
7084
|
}
|
|
7052
|
-
if (
|
|
7085
|
+
if (path71 === "") {
|
|
7053
7086
|
throw new Error("Invalid redaction path ()");
|
|
7054
7087
|
}
|
|
7055
|
-
if (
|
|
7056
|
-
throw new Error(`Invalid redaction path (${
|
|
7088
|
+
if (path71.includes("..")) {
|
|
7089
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7057
7090
|
}
|
|
7058
|
-
if (
|
|
7059
|
-
throw new Error(`Invalid redaction path (${
|
|
7091
|
+
if (path71.includes(",")) {
|
|
7092
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7060
7093
|
}
|
|
7061
7094
|
let bracketCount = 0;
|
|
7062
7095
|
let inQuotes = false;
|
|
7063
7096
|
let quoteChar = "";
|
|
7064
|
-
for (let i = 0; i <
|
|
7065
|
-
const char =
|
|
7097
|
+
for (let i = 0; i < path71.length; i++) {
|
|
7098
|
+
const char = path71[i];
|
|
7066
7099
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
7067
7100
|
if (!inQuotes) {
|
|
7068
7101
|
inQuotes = true;
|
|
@@ -7076,20 +7109,20 @@ var require_redact = __commonJS({
|
|
|
7076
7109
|
} else if (char === "]" && !inQuotes) {
|
|
7077
7110
|
bracketCount--;
|
|
7078
7111
|
if (bracketCount < 0) {
|
|
7079
|
-
throw new Error(`Invalid redaction path (${
|
|
7112
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7080
7113
|
}
|
|
7081
7114
|
}
|
|
7082
7115
|
}
|
|
7083
7116
|
if (bracketCount !== 0) {
|
|
7084
|
-
throw new Error(`Invalid redaction path (${
|
|
7117
|
+
throw new Error(`Invalid redaction path (${path71})`);
|
|
7085
7118
|
}
|
|
7086
7119
|
}
|
|
7087
7120
|
function validatePaths(paths) {
|
|
7088
7121
|
if (!Array.isArray(paths)) {
|
|
7089
7122
|
throw new TypeError("paths must be an array");
|
|
7090
7123
|
}
|
|
7091
|
-
for (const
|
|
7092
|
-
validatePath(
|
|
7124
|
+
for (const path71 of paths) {
|
|
7125
|
+
validatePath(path71);
|
|
7093
7126
|
}
|
|
7094
7127
|
}
|
|
7095
7128
|
function slowRedact(options = {}) {
|
|
@@ -7257,8 +7290,8 @@ var require_redaction = __commonJS({
|
|
|
7257
7290
|
if (shape[k2] === null) {
|
|
7258
7291
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
7259
7292
|
} else {
|
|
7260
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
7261
|
-
return censor(value, [k2, ...
|
|
7293
|
+
const wrappedCensor = typeof censor === "function" ? (value, path71) => {
|
|
7294
|
+
return censor(value, [k2, ...path71]);
|
|
7262
7295
|
} : censor;
|
|
7263
7296
|
o[k2] = Redact({
|
|
7264
7297
|
paths: shape[k2],
|
|
@@ -7476,10 +7509,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
7476
7509
|
var require_sonic_boom = __commonJS({
|
|
7477
7510
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
7478
7511
|
"use strict";
|
|
7479
|
-
var
|
|
7512
|
+
var fs65 = require("fs");
|
|
7480
7513
|
var EventEmitter3 = require("events");
|
|
7481
7514
|
var inherits = require("util").inherits;
|
|
7482
|
-
var
|
|
7515
|
+
var path71 = require("path");
|
|
7483
7516
|
var sleep2 = require_atomic_sleep();
|
|
7484
7517
|
var assert = require("assert");
|
|
7485
7518
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -7533,20 +7566,20 @@ var require_sonic_boom = __commonJS({
|
|
|
7533
7566
|
const mode = sonic.mode;
|
|
7534
7567
|
if (sonic.sync) {
|
|
7535
7568
|
try {
|
|
7536
|
-
if (sonic.mkdir)
|
|
7537
|
-
const fd =
|
|
7569
|
+
if (sonic.mkdir) fs65.mkdirSync(path71.dirname(file), { recursive: true });
|
|
7570
|
+
const fd = fs65.openSync(file, flags, mode);
|
|
7538
7571
|
fileOpened(null, fd);
|
|
7539
7572
|
} catch (err) {
|
|
7540
7573
|
fileOpened(err);
|
|
7541
7574
|
throw err;
|
|
7542
7575
|
}
|
|
7543
7576
|
} else if (sonic.mkdir) {
|
|
7544
|
-
|
|
7577
|
+
fs65.mkdir(path71.dirname(file), { recursive: true }, (err) => {
|
|
7545
7578
|
if (err) return fileOpened(err);
|
|
7546
|
-
|
|
7579
|
+
fs65.open(file, flags, mode, fileOpened);
|
|
7547
7580
|
});
|
|
7548
7581
|
} else {
|
|
7549
|
-
|
|
7582
|
+
fs65.open(file, flags, mode, fileOpened);
|
|
7550
7583
|
}
|
|
7551
7584
|
}
|
|
7552
7585
|
function SonicBoom(opts) {
|
|
@@ -7587,8 +7620,8 @@ var require_sonic_boom = __commonJS({
|
|
|
7587
7620
|
this.flush = flushBuffer;
|
|
7588
7621
|
this.flushSync = flushBufferSync;
|
|
7589
7622
|
this._actualWrite = actualWriteBuffer;
|
|
7590
|
-
fsWriteSync = () =>
|
|
7591
|
-
fsWrite = () =>
|
|
7623
|
+
fsWriteSync = () => fs65.writeSync(this.fd, this._writingBuf);
|
|
7624
|
+
fsWrite = () => fs65.write(this.fd, this._writingBuf, this.release);
|
|
7592
7625
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
7593
7626
|
this._writingBuf = "";
|
|
7594
7627
|
this.write = write;
|
|
@@ -7597,15 +7630,15 @@ var require_sonic_boom = __commonJS({
|
|
|
7597
7630
|
this._actualWrite = actualWrite;
|
|
7598
7631
|
fsWriteSync = () => {
|
|
7599
7632
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7600
|
-
return
|
|
7633
|
+
return fs65.writeSync(this.fd, this._writingBuf);
|
|
7601
7634
|
}
|
|
7602
|
-
return
|
|
7635
|
+
return fs65.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7603
7636
|
};
|
|
7604
7637
|
fsWrite = () => {
|
|
7605
7638
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7606
|
-
return
|
|
7639
|
+
return fs65.write(this.fd, this._writingBuf, this.release);
|
|
7607
7640
|
}
|
|
7608
|
-
return
|
|
7641
|
+
return fs65.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
7609
7642
|
};
|
|
7610
7643
|
} else {
|
|
7611
7644
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -7662,7 +7695,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7662
7695
|
}
|
|
7663
7696
|
}
|
|
7664
7697
|
if (this._fsync) {
|
|
7665
|
-
|
|
7698
|
+
fs65.fsyncSync(this.fd);
|
|
7666
7699
|
}
|
|
7667
7700
|
const len = this._len;
|
|
7668
7701
|
if (this._reopening) {
|
|
@@ -7776,7 +7809,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7776
7809
|
const onDrain = () => {
|
|
7777
7810
|
if (!this._fsync) {
|
|
7778
7811
|
try {
|
|
7779
|
-
|
|
7812
|
+
fs65.fsync(this.fd, (err) => {
|
|
7780
7813
|
this._flushPending = false;
|
|
7781
7814
|
cb(err);
|
|
7782
7815
|
});
|
|
@@ -7878,7 +7911,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7878
7911
|
const fd = this.fd;
|
|
7879
7912
|
this.once("ready", () => {
|
|
7880
7913
|
if (fd !== this.fd) {
|
|
7881
|
-
|
|
7914
|
+
fs65.close(fd, (err) => {
|
|
7882
7915
|
if (err) {
|
|
7883
7916
|
return this.emit("error", err);
|
|
7884
7917
|
}
|
|
@@ -7927,7 +7960,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7927
7960
|
buf = this._bufs[0];
|
|
7928
7961
|
}
|
|
7929
7962
|
try {
|
|
7930
|
-
const n = Buffer.isBuffer(buf) ?
|
|
7963
|
+
const n = Buffer.isBuffer(buf) ? fs65.writeSync(this.fd, buf) : fs65.writeSync(this.fd, buf, "utf8");
|
|
7931
7964
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
7932
7965
|
buf = releasedBufObj.writingBuf;
|
|
7933
7966
|
this._len = releasedBufObj.len;
|
|
@@ -7943,7 +7976,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7943
7976
|
}
|
|
7944
7977
|
}
|
|
7945
7978
|
try {
|
|
7946
|
-
|
|
7979
|
+
fs65.fsyncSync(this.fd);
|
|
7947
7980
|
} catch {
|
|
7948
7981
|
}
|
|
7949
7982
|
}
|
|
@@ -7964,7 +7997,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7964
7997
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
7965
7998
|
}
|
|
7966
7999
|
try {
|
|
7967
|
-
const n =
|
|
8000
|
+
const n = fs65.writeSync(this.fd, buf);
|
|
7968
8001
|
buf = buf.subarray(n);
|
|
7969
8002
|
this._len = Math.max(this._len - n, 0);
|
|
7970
8003
|
if (buf.length <= 0) {
|
|
@@ -7992,13 +8025,13 @@ var require_sonic_boom = __commonJS({
|
|
|
7992
8025
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
7993
8026
|
if (this.sync) {
|
|
7994
8027
|
try {
|
|
7995
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
8028
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs65.writeSync(this.fd, this._writingBuf) : fs65.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7996
8029
|
release(null, written);
|
|
7997
8030
|
} catch (err) {
|
|
7998
8031
|
release(err);
|
|
7999
8032
|
}
|
|
8000
8033
|
} else {
|
|
8001
|
-
|
|
8034
|
+
fs65.write(this.fd, this._writingBuf, release);
|
|
8002
8035
|
}
|
|
8003
8036
|
}
|
|
8004
8037
|
function actualWriteBuffer() {
|
|
@@ -8007,7 +8040,7 @@ var require_sonic_boom = __commonJS({
|
|
|
8007
8040
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
8008
8041
|
if (this.sync) {
|
|
8009
8042
|
try {
|
|
8010
|
-
const written =
|
|
8043
|
+
const written = fs65.writeSync(this.fd, this._writingBuf);
|
|
8011
8044
|
release(null, written);
|
|
8012
8045
|
} catch (err) {
|
|
8013
8046
|
release(err);
|
|
@@ -8016,7 +8049,7 @@ var require_sonic_boom = __commonJS({
|
|
|
8016
8049
|
if (kCopyBuffer) {
|
|
8017
8050
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
8018
8051
|
}
|
|
8019
|
-
|
|
8052
|
+
fs65.write(this.fd, this._writingBuf, release);
|
|
8020
8053
|
}
|
|
8021
8054
|
}
|
|
8022
8055
|
function actualClose(sonic) {
|
|
@@ -8032,12 +8065,12 @@ var require_sonic_boom = __commonJS({
|
|
|
8032
8065
|
sonic._lens = [];
|
|
8033
8066
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
8034
8067
|
try {
|
|
8035
|
-
|
|
8068
|
+
fs65.fsync(sonic.fd, closeWrapped);
|
|
8036
8069
|
} catch {
|
|
8037
8070
|
}
|
|
8038
8071
|
function closeWrapped() {
|
|
8039
8072
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
8040
|
-
|
|
8073
|
+
fs65.close(sonic.fd, done);
|
|
8041
8074
|
} else {
|
|
8042
8075
|
done();
|
|
8043
8076
|
}
|
|
@@ -11172,11 +11205,11 @@ var init_lib = __esm({
|
|
|
11172
11205
|
}
|
|
11173
11206
|
}
|
|
11174
11207
|
},
|
|
11175
|
-
addToPath: function addToPath(
|
|
11176
|
-
var last =
|
|
11208
|
+
addToPath: function addToPath(path71, added, removed, oldPosInc, options) {
|
|
11209
|
+
var last = path71.lastComponent;
|
|
11177
11210
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
11178
11211
|
return {
|
|
11179
|
-
oldPos:
|
|
11212
|
+
oldPos: path71.oldPos + oldPosInc,
|
|
11180
11213
|
lastComponent: {
|
|
11181
11214
|
count: last.count + 1,
|
|
11182
11215
|
added,
|
|
@@ -11186,7 +11219,7 @@ var init_lib = __esm({
|
|
|
11186
11219
|
};
|
|
11187
11220
|
} else {
|
|
11188
11221
|
return {
|
|
11189
|
-
oldPos:
|
|
11222
|
+
oldPos: path71.oldPos + oldPosInc,
|
|
11190
11223
|
lastComponent: {
|
|
11191
11224
|
count: 1,
|
|
11192
11225
|
added,
|
|
@@ -11695,10 +11728,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
11695
11728
|
const memories = raw.map((m2) => {
|
|
11696
11729
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11697
11730
|
const rec3 = m2;
|
|
11698
|
-
const
|
|
11731
|
+
const path71 = typeof rec3.path === "string" ? rec3.path : null;
|
|
11699
11732
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
11700
|
-
if (!
|
|
11701
|
-
const entry = { path:
|
|
11733
|
+
if (!path71 || content == null) return null;
|
|
11734
|
+
const entry = { path: path71, content };
|
|
11702
11735
|
if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
|
|
11703
11736
|
return entry;
|
|
11704
11737
|
}).filter((m2) => m2 !== null);
|
|
@@ -12501,10 +12534,10 @@ function parseAttachment(obj) {
|
|
|
12501
12534
|
const memories = raw.map((m2) => {
|
|
12502
12535
|
if (!m2 || typeof m2 !== "object") return null;
|
|
12503
12536
|
const rec3 = m2;
|
|
12504
|
-
const
|
|
12537
|
+
const path71 = typeof rec3.path === "string" ? rec3.path : null;
|
|
12505
12538
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
12506
|
-
if (!
|
|
12507
|
-
const out = { path:
|
|
12539
|
+
if (!path71 || content == null) return null;
|
|
12540
|
+
const out = { path: path71, content };
|
|
12508
12541
|
if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
|
|
12509
12542
|
return out;
|
|
12510
12543
|
}).filter((m2) => m2 !== null);
|
|
@@ -33473,8 +33506,8 @@ var require_utils = __commonJS({
|
|
|
33473
33506
|
var result = transform[inputType][outputType](input);
|
|
33474
33507
|
return result;
|
|
33475
33508
|
};
|
|
33476
|
-
exports2.resolve = function(
|
|
33477
|
-
var parts =
|
|
33509
|
+
exports2.resolve = function(path71) {
|
|
33510
|
+
var parts = path71.split("/");
|
|
33478
33511
|
var result = [];
|
|
33479
33512
|
for (var index = 0; index < parts.length; index++) {
|
|
33480
33513
|
var part = parts[index];
|
|
@@ -39327,18 +39360,18 @@ var require_object = __commonJS({
|
|
|
39327
39360
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
39328
39361
|
this.files[name] = object;
|
|
39329
39362
|
};
|
|
39330
|
-
var parentFolder = function(
|
|
39331
|
-
if (
|
|
39332
|
-
|
|
39363
|
+
var parentFolder = function(path71) {
|
|
39364
|
+
if (path71.slice(-1) === "/") {
|
|
39365
|
+
path71 = path71.substring(0, path71.length - 1);
|
|
39333
39366
|
}
|
|
39334
|
-
var lastSlash =
|
|
39335
|
-
return lastSlash > 0 ?
|
|
39367
|
+
var lastSlash = path71.lastIndexOf("/");
|
|
39368
|
+
return lastSlash > 0 ? path71.substring(0, lastSlash) : "";
|
|
39336
39369
|
};
|
|
39337
|
-
var forceTrailingSlash = function(
|
|
39338
|
-
if (
|
|
39339
|
-
|
|
39370
|
+
var forceTrailingSlash = function(path71) {
|
|
39371
|
+
if (path71.slice(-1) !== "/") {
|
|
39372
|
+
path71 += "/";
|
|
39340
39373
|
}
|
|
39341
|
-
return
|
|
39374
|
+
return path71;
|
|
39342
39375
|
};
|
|
39343
39376
|
var folderAdd = function(name, createFolders) {
|
|
39344
39377
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -40340,7 +40373,7 @@ var require_lib3 = __commonJS({
|
|
|
40340
40373
|
// src/run-case/recorder.ts
|
|
40341
40374
|
function startRunCaseRecorder(opts) {
|
|
40342
40375
|
const now = opts.now ?? Date.now;
|
|
40343
|
-
const dir =
|
|
40376
|
+
const dir = import_node_path59.default.dirname(opts.recordPath);
|
|
40344
40377
|
let stream = null;
|
|
40345
40378
|
let closing = false;
|
|
40346
40379
|
let closedSettled = false;
|
|
@@ -40380,12 +40413,12 @@ function startRunCaseRecorder(opts) {
|
|
|
40380
40413
|
};
|
|
40381
40414
|
return { tap, close, closed };
|
|
40382
40415
|
}
|
|
40383
|
-
var import_node_fs46,
|
|
40416
|
+
var import_node_fs46, import_node_path59;
|
|
40384
40417
|
var init_recorder = __esm({
|
|
40385
40418
|
"src/run-case/recorder.ts"() {
|
|
40386
40419
|
"use strict";
|
|
40387
40420
|
import_node_fs46 = __toESM(require("fs"), 1);
|
|
40388
|
-
|
|
40421
|
+
import_node_path59 = __toESM(require("path"), 1);
|
|
40389
40422
|
}
|
|
40390
40423
|
});
|
|
40391
40424
|
|
|
@@ -40428,7 +40461,7 @@ var init_wire = __esm({
|
|
|
40428
40461
|
// src/run-case/controller.ts
|
|
40429
40462
|
async function runController(opts) {
|
|
40430
40463
|
const now = opts.now ?? Date.now;
|
|
40431
|
-
const cwd = opts.cwd ?? (0, import_node_fs47.mkdtempSync)(
|
|
40464
|
+
const cwd = opts.cwd ?? (0, import_node_fs47.mkdtempSync)(import_node_path60.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
|
|
40432
40465
|
const ownsCwd = opts.cwd === void 0;
|
|
40433
40466
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
40434
40467
|
const spawnCtx = { cwd };
|
|
@@ -40595,13 +40628,13 @@ async function runController(opts) {
|
|
|
40595
40628
|
}
|
|
40596
40629
|
return exitCode ?? 0;
|
|
40597
40630
|
}
|
|
40598
|
-
var import_node_fs47, import_node_os23,
|
|
40631
|
+
var import_node_fs47, import_node_os23, import_node_path60;
|
|
40599
40632
|
var init_controller = __esm({
|
|
40600
40633
|
"src/run-case/controller.ts"() {
|
|
40601
40634
|
"use strict";
|
|
40602
40635
|
import_node_fs47 = require("fs");
|
|
40603
40636
|
import_node_os23 = __toESM(require("os"), 1);
|
|
40604
|
-
|
|
40637
|
+
import_node_path60 = __toESM(require("path"), 1);
|
|
40605
40638
|
init_claude();
|
|
40606
40639
|
init_stdout_splitter();
|
|
40607
40640
|
init_permission_stdio();
|
|
@@ -40863,7 +40896,7 @@ Env (advanced):
|
|
|
40863
40896
|
`;
|
|
40864
40897
|
|
|
40865
40898
|
// src/index.ts
|
|
40866
|
-
var
|
|
40899
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
40867
40900
|
var import_node_fs45 = __toESM(require("fs"), 1);
|
|
40868
40901
|
var import_node_os22 = __toESM(require("os"), 1);
|
|
40869
40902
|
|
|
@@ -41728,6 +41761,28 @@ function dispatchShiftEnd(info, settle, killImpl) {
|
|
|
41728
41761
|
throw new Error(`dispatchShiftEnd: unhandled kind ${JSON.stringify(_exhaustive)}`);
|
|
41729
41762
|
}
|
|
41730
41763
|
|
|
41764
|
+
// src/dispatch/delivery.ts
|
|
41765
|
+
function selectPendingForDelivery(records, sourceSessionId) {
|
|
41766
|
+
return records.filter(
|
|
41767
|
+
(r) => r.sourceSessionId === sourceSessionId && (r.status === "completed" || r.status === "failed") && !r.deliveredAt
|
|
41768
|
+
).slice().sort((a, b2) => a.createdAt < b2.createdAt ? -1 : a.createdAt > b2.createdAt ? 1 : 0);
|
|
41769
|
+
}
|
|
41770
|
+
function formatDeliveryText(records) {
|
|
41771
|
+
const blocks = records.map((r) => {
|
|
41772
|
+
const head = `[dispatch ${r.dispatchId} \u2192 ${r.targetPersonaId}]`;
|
|
41773
|
+
if (r.outcome?.kind === "success") {
|
|
41774
|
+
const files = r.outcome.filePaths && r.outcome.filePaths.length > 0 ? `
|
|
41775
|
+
Related files:
|
|
41776
|
+
${r.outcome.filePaths.map((p2) => `- ${p2}`).join("\n")}` : "";
|
|
41777
|
+
return `${head} \u5B8C\u6210\uFF1A
|
|
41778
|
+
${r.outcome.text}${files}`;
|
|
41779
|
+
}
|
|
41780
|
+
const reason = r.outcome?.kind === "failure" ? r.outcome.reason : "unknown failure";
|
|
41781
|
+
return `${head} \u5931\u8D25\uFF1A${reason}`;
|
|
41782
|
+
});
|
|
41783
|
+
return ["\u4F60\u4E4B\u524D\u59D4\u6D3E\u51FA\u53BB\u7684\u4EFB\u52A1\u6709\u4E86\u7ED3\u679C\uFF1A", "", blocks.join("\n\n")].join("\n");
|
|
41784
|
+
}
|
|
41785
|
+
|
|
41731
41786
|
// src/session/runner.ts
|
|
41732
41787
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
41733
41788
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
@@ -41855,7 +41910,7 @@ var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A perso
|
|
|
41855
41910
|
- \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
|
|
41856
41911
|
- \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
|
|
41857
41912
|
|
|
41858
|
-
tool \u4F1A\
|
|
41913
|
+
tool \u4F1A**\u7ACB\u5373\u8FD4\u56DE** dispatchId\uFF08\u5F02\u6B65\u59D4\u6D3E\uFF09\uFF0C\u5BF9\u65B9\u4EBA\u683C\u5728\u540E\u53F0\u5E72\u6D3B\u3002\u4F60\u544A\u8BC9\u7528\u6237"\u4EFB\u52A1\u5DF2\u4EA4\u529E"\u5373\u53EF\u7ED3\u675F\u672C\u8F6E\u2014\u2014**\u4E0D\u8981\u7B49\u5F85\u3001\u4E0D\u8981\u8F6E\u8BE2**\u3002\u5BF9\u65B9\u5E72\u5B8C\u540E\uFF0C\u7ED3\u679C\u4F1A\u4F5C\u4E3A\u4E00\u6761\u65B0\u6D88\u606F\u81EA\u52A8\u6CE8\u5165\u56DE\u4F60\u7684 session\uFF0C\u4F60\u5C4A\u65F6\u518D\u7EFC\u5408\u8F6C\u8FBE\u7ED9\u7528\u6237\u3002\u60F3\u67E5\u8FDB\u5C55\u65F6\uFF08\u7528\u6237\u95EE\u8D77\uFF09\u8C03 \`mcp__clawd-dispatch__personaDispatchList\`\u3002
|
|
41859
41914
|
|
|
41860
41915
|
- **\u4E0D\u8981**\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF08\u4F60\u4E0D\u662F\u90A3\u4E2A persona\uFF09
|
|
41861
41916
|
- **\u4E0D\u8981** in-place \u6A21\u4EFF\u5BF9\u65B9\u4EBA\u683C \u2014\u2014 dispatch \u662F\u771F\u5207\u5230\u53E6\u4E00\u4E2A\u72EC\u7ACB session
|
|
@@ -41868,7 +41923,7 @@ tool \u4F1A\u963B\u585E\u6302\u8D77\u7B49\u5BF9\u65B9\u4EBA\u683C\u5E72\u5B8C\uF
|
|
|
41868
41923
|
|
|
41869
41924
|
- \`targetDeviceId = <token \u7B2C\u4E8C\u6BB5\u7684 deviceId\uFF0C\u539F\u6837\u586B>\`
|
|
41870
41925
|
|
|
41871
|
-
deviceId \u76F4\u63A5\u53D6\u81EA token\uFF0C\u4E0D\u8981\u6539\u5199\u6216\u731C\u6D4B\u3002\u5BF9\u65B9\u4E0D\u53EF\u8FBE / \u76EE\u6807 persona \u672A\u516C\u5F00\u4F1A\
|
|
41926
|
+
deviceId \u76F4\u63A5\u53D6\u81EA token\uFF0C\u4E0D\u8981\u6539\u5199\u6216\u731C\u6D4B\u3002\u5BF9\u65B9\u4E0D\u53EF\u8FBE / \u76EE\u6807 persona \u672A\u516C\u5F00\u4F1A\u5728\u7ED3\u679C\u56DE\u6D41\u65F6\u62A5\u5931\u8D25\uFF0C\u7167\u5E38\u8F6C\u8FF0\u7ED9\u7528\u6237\u5373\u53EF\u3002\u5176\u4F59\u884C\u4E3A\uFF08\u79D2\u56DE dispatchId\u3001\u7ED3\u679C\u81EA\u52A8\u6CE8\u5165\u3001\u5931\u8D25\u4E0D\u91CD\u8BD5\uFF09\u4E0E\u672C\u5730\u59D4\u6D3E\u4E00\u81F4\u3002
|
|
41872
41927
|
|
|
41873
41928
|
## \u88AB dispatch \u63A5\u5230\u4EFB\u52A1
|
|
41874
41929
|
|
|
@@ -41881,6 +41936,25 @@ deviceId \u76F4\u63A5\u53D6\u81EA token\uFF0C\u4E0D\u8981\u6539\u5199\u6216\u731
|
|
|
41881
41936
|
- \u5931\u8D25\uFF1A\`{ isFailure: true, reason: "..." }\`
|
|
41882
41937
|
- \u62A5\u544A\u5B8C\u540E\u4F60\u7684 session \u5C31\u7ED3\u675F\u4E86\uFF0C\u4E0D\u8981\u7EE7\u7EED\u8F93\u51FA`;
|
|
41883
41938
|
|
|
41939
|
+
// src/session/reducer-types.ts
|
|
41940
|
+
function compressStatus(status) {
|
|
41941
|
+
switch (status) {
|
|
41942
|
+
case "spawning":
|
|
41943
|
+
case "running":
|
|
41944
|
+
return "running";
|
|
41945
|
+
case "running-idle":
|
|
41946
|
+
return "running-idle";
|
|
41947
|
+
case "stopping":
|
|
41948
|
+
case "stopped":
|
|
41949
|
+
return "stopped";
|
|
41950
|
+
case "error":
|
|
41951
|
+
return "error";
|
|
41952
|
+
case "idle":
|
|
41953
|
+
default:
|
|
41954
|
+
return "idle";
|
|
41955
|
+
}
|
|
41956
|
+
}
|
|
41957
|
+
|
|
41884
41958
|
// src/session/reducer.ts
|
|
41885
41959
|
function cloneState(s) {
|
|
41886
41960
|
return {
|
|
@@ -42190,7 +42264,7 @@ var RUNTIME_PATCH_KEYS = [
|
|
|
42190
42264
|
"effort",
|
|
42191
42265
|
"cwd"
|
|
42192
42266
|
];
|
|
42193
|
-
var MARKER_PATCH_KEYS = ["pinnedAt", "pinSortOrder"];
|
|
42267
|
+
var MARKER_PATCH_KEYS = ["pinnedAt", "pinSortOrder", "unreadAt"];
|
|
42194
42268
|
function isMarkerOnlyPatch(patch) {
|
|
42195
42269
|
const keys = Object.keys(patch).filter(
|
|
42196
42270
|
(k2) => patch[k2] !== void 0
|
|
@@ -42435,6 +42509,24 @@ function assertNever(x) {
|
|
|
42435
42509
|
throw new Error(`unexpected command: ${JSON.stringify(x)}`);
|
|
42436
42510
|
}
|
|
42437
42511
|
function reduceSession(state, input, deps) {
|
|
42512
|
+
const result = reduceSessionInner(state, input, deps);
|
|
42513
|
+
const prevWire = compressStatus(state.status);
|
|
42514
|
+
const nextWire = compressStatus(result.state.status);
|
|
42515
|
+
if (prevWire === nextWire) return result;
|
|
42516
|
+
let file;
|
|
42517
|
+
if (prevWire === "running") {
|
|
42518
|
+
file = { ...result.state.file, unreadAt: nowIso(deps) };
|
|
42519
|
+
} else if (nextWire === "running" && result.state.file.unreadAt != null) {
|
|
42520
|
+
file = { ...result.state.file, unreadAt: null };
|
|
42521
|
+
} else {
|
|
42522
|
+
return result;
|
|
42523
|
+
}
|
|
42524
|
+
return {
|
|
42525
|
+
state: { ...result.state, file },
|
|
42526
|
+
effects: [...result.effects, { kind: "persist-file", file }, sessionInfoFrame(file)]
|
|
42527
|
+
};
|
|
42528
|
+
}
|
|
42529
|
+
function reduceSessionInner(state, input, deps) {
|
|
42438
42530
|
switch (input.kind) {
|
|
42439
42531
|
case "stdout-line": {
|
|
42440
42532
|
const events = deps.parseLine(input.line);
|
|
@@ -43216,53 +43308,13 @@ function probePtyDataThrottled(tsid, len, tail) {
|
|
|
43216
43308
|
function compressFrameForWire(frame) {
|
|
43217
43309
|
if (frame.type !== "session:status") return frame;
|
|
43218
43310
|
const raw = frame;
|
|
43219
|
-
const
|
|
43220
|
-
let compressed;
|
|
43221
|
-
switch (status) {
|
|
43222
|
-
case "spawning":
|
|
43223
|
-
case "running":
|
|
43224
|
-
compressed = "running";
|
|
43225
|
-
break;
|
|
43226
|
-
case "running-idle":
|
|
43227
|
-
compressed = "running-idle";
|
|
43228
|
-
break;
|
|
43229
|
-
case "stopping":
|
|
43230
|
-
case "stopped":
|
|
43231
|
-
compressed = "stopped";
|
|
43232
|
-
break;
|
|
43233
|
-
case "error":
|
|
43234
|
-
compressed = "error";
|
|
43235
|
-
break;
|
|
43236
|
-
case "idle":
|
|
43237
|
-
compressed = "idle";
|
|
43238
|
-
break;
|
|
43239
|
-
default:
|
|
43240
|
-
compressed = "idle";
|
|
43241
|
-
break;
|
|
43242
|
-
}
|
|
43311
|
+
const compressed = compressStatus(raw.status);
|
|
43243
43312
|
return {
|
|
43244
43313
|
type: "session:status",
|
|
43245
43314
|
sessionId: raw.sessionId,
|
|
43246
43315
|
status: compressed
|
|
43247
43316
|
};
|
|
43248
43317
|
}
|
|
43249
|
-
function compressStatus(status) {
|
|
43250
|
-
switch (status) {
|
|
43251
|
-
case "spawning":
|
|
43252
|
-
case "running":
|
|
43253
|
-
return "running";
|
|
43254
|
-
case "running-idle":
|
|
43255
|
-
return "running-idle";
|
|
43256
|
-
case "stopping":
|
|
43257
|
-
case "stopped":
|
|
43258
|
-
return "stopped";
|
|
43259
|
-
case "error":
|
|
43260
|
-
return "error";
|
|
43261
|
-
case "idle":
|
|
43262
|
-
default:
|
|
43263
|
-
return "idle";
|
|
43264
|
-
}
|
|
43265
|
-
}
|
|
43266
43318
|
function nowIso2(deps) {
|
|
43267
43319
|
return new Date((deps.now ?? Date.now)()).toISOString();
|
|
43268
43320
|
}
|
|
@@ -43721,6 +43773,13 @@ var SessionManager = class {
|
|
|
43721
43773
|
}
|
|
43722
43774
|
}
|
|
43723
43775
|
}
|
|
43776
|
+
if (compressed.type === "session:status" && this.deps.dispatchStore) {
|
|
43777
|
+
const s = compressed;
|
|
43778
|
+
if (s.sessionId && s.status !== "running") {
|
|
43779
|
+
const sid = s.sessionId;
|
|
43780
|
+
setTimeout(() => this.deliverPending(sid), 0);
|
|
43781
|
+
}
|
|
43782
|
+
}
|
|
43724
43783
|
if (this.currentCollector) {
|
|
43725
43784
|
this.currentCollector.push({ frame: compressed, target });
|
|
43726
43785
|
return;
|
|
@@ -43808,6 +43867,29 @@ var SessionManager = class {
|
|
|
43808
43867
|
this.writeOwned(updated);
|
|
43809
43868
|
return { response: updated, broadcast: [] };
|
|
43810
43869
|
}
|
|
43870
|
+
// 清共享未读(spec 2026-07-20-shared-session-unread)。幂等:已读直接 no-op 不广播。
|
|
43871
|
+
// 与 pin 的差异:no-runner 路径也要广播 session:info——跨端实时清红点是本 RPC 的核心
|
|
43872
|
+
// 语义,不能等下次 session:list。
|
|
43873
|
+
markRead(args) {
|
|
43874
|
+
const existing = this.getFile(args.sessionId);
|
|
43875
|
+
if (existing.unreadAt == null) return { response: existing, broadcast: [] };
|
|
43876
|
+
const runner = this.runners.get(args.sessionId);
|
|
43877
|
+
if (runner) {
|
|
43878
|
+
const { value, broadcast } = this.withCollector(() => {
|
|
43879
|
+
runner.input({ kind: "command", command: { kind: "update", patch: { unreadAt: null } } });
|
|
43880
|
+
return runner.getState().file;
|
|
43881
|
+
});
|
|
43882
|
+
return { response: value, broadcast };
|
|
43883
|
+
}
|
|
43884
|
+
const updated = { ...existing, unreadAt: null };
|
|
43885
|
+
this.writeOwned(updated);
|
|
43886
|
+
return {
|
|
43887
|
+
response: updated,
|
|
43888
|
+
broadcast: [
|
|
43889
|
+
{ frame: { type: "session:info", ...updated }, target: "all" }
|
|
43890
|
+
]
|
|
43891
|
+
};
|
|
43892
|
+
}
|
|
43811
43893
|
// sidebar 拖拽完成 → 整体重写 pinned root 的 pinSortOrder(按 orderedIds 下标 0,1,2...)
|
|
43812
43894
|
// orderedIds 必须正好覆盖所有当前 pinned root(既不能漏,也不能含 unpinned id)
|
|
43813
43895
|
reorderPins(args) {
|
|
@@ -44024,6 +44106,67 @@ var SessionManager = class {
|
|
|
44024
44106
|
});
|
|
44025
44107
|
return { response: { ok: true }, broadcast };
|
|
44026
44108
|
}
|
|
44109
|
+
/**
|
|
44110
|
+
* Dispatch 结果投递(spec 2026-07-20 §5):查台账里该 source session 名下已完成
|
|
44111
|
+
* 且未投递的行,合并成一段 plain text 结果包注入回 source session。
|
|
44112
|
+
*
|
|
44113
|
+
* 触发点两个:complete 钩子(PersonaDispatchManager.onCompleted)+ source turn-end
|
|
44114
|
+
* 兜底 sweep(routeFromRunner 的 session:status 钩子)。幂等:投递成功盖 deliveredAt,
|
|
44115
|
+
* 再次调用查无未投递行直接返回。
|
|
44116
|
+
*
|
|
44117
|
+
* 判定口径:source 当前 running(含 reducer spawning,压缩后同 running)→ 不打扰,
|
|
44118
|
+
* 结果躺台账等下次 sweep。send 抛错(session 已删等)→ 记 log 不盖 deliveredAt,
|
|
44119
|
+
* 下次 sweep 自然重试。注入直接走 runner.input(无 collector),frames 经
|
|
44120
|
+
* routeFromRunner 正常广播上 wire。
|
|
44121
|
+
*/
|
|
44122
|
+
deliverPending(sourceSessionId) {
|
|
44123
|
+
const store = this.deps.dispatchStore;
|
|
44124
|
+
if (!store) return;
|
|
44125
|
+
const pending = selectPendingForDelivery(store.list({ sourceSessionId }), sourceSessionId);
|
|
44126
|
+
if (pending.length === 0) return;
|
|
44127
|
+
const state = this.tryGetState(sourceSessionId);
|
|
44128
|
+
if (state && compressStatus(state.status) === "running") return;
|
|
44129
|
+
if (!this.deps.ownerPrincipalId) {
|
|
44130
|
+
this.deps.logger?.warn("dispatch.deliver.no-owner-principal", { sourceSessionId });
|
|
44131
|
+
return;
|
|
44132
|
+
}
|
|
44133
|
+
const sender = principalToSender(
|
|
44134
|
+
makeOwnerPrincipal(
|
|
44135
|
+
this.deps.ownerPrincipalId,
|
|
44136
|
+
this.deps.ownerDisplayName ?? "Owner",
|
|
44137
|
+
this.deps.ownerFeishuUnionId
|
|
44138
|
+
)
|
|
44139
|
+
);
|
|
44140
|
+
try {
|
|
44141
|
+
const file = this.findOwnedSession(sourceSessionId);
|
|
44142
|
+
if (!file) {
|
|
44143
|
+
this.deps.logger?.info("dispatch.deliver.source-gone", { sourceSessionId });
|
|
44144
|
+
return;
|
|
44145
|
+
}
|
|
44146
|
+
const runner = this.ensureRunnerForScope(file, this.scopeForFile(file));
|
|
44147
|
+
runner.input({
|
|
44148
|
+
kind: "command",
|
|
44149
|
+
command: {
|
|
44150
|
+
kind: "send",
|
|
44151
|
+
text: formatDeliveryText(pending),
|
|
44152
|
+
senderPrincipal: sender
|
|
44153
|
+
}
|
|
44154
|
+
});
|
|
44155
|
+
} catch (err) {
|
|
44156
|
+
this.deps.logger?.warn("dispatch.deliver.send-failed", {
|
|
44157
|
+
sourceSessionId,
|
|
44158
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
44159
|
+
});
|
|
44160
|
+
return;
|
|
44161
|
+
}
|
|
44162
|
+
const nowIso3 = new Date(this.deps.now?.() ?? Date.now()).toISOString();
|
|
44163
|
+
for (const r of pending) store.update(r.dispatchId, { deliveredAt: nowIso3 });
|
|
44164
|
+
this.deps.logger?.info("dispatch.deliver.ok", {
|
|
44165
|
+
sourceSessionId,
|
|
44166
|
+
count: pending.length,
|
|
44167
|
+
dispatchIds: pending.map((r) => r.dispatchId)
|
|
44168
|
+
});
|
|
44169
|
+
}
|
|
44027
44170
|
/**
|
|
44028
44171
|
* 只读拿 SessionState;session 不存在返 null(不 throw)。
|
|
44029
44172
|
* handlers/session.ts:currentTurnSender 用(loopback HTTP RPC 绝对不能因不存在的 sid 崩)。
|
|
@@ -46630,8 +46773,8 @@ function turnStartInput(text) {
|
|
|
46630
46773
|
const items = [];
|
|
46631
46774
|
let leftover = text;
|
|
46632
46775
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
46633
|
-
const [marker, name,
|
|
46634
|
-
items.push({ type: "skill", name, path:
|
|
46776
|
+
const [marker, name, path71] = m2;
|
|
46777
|
+
items.push({ type: "skill", name, path: path71 });
|
|
46635
46778
|
leftover = leftover.replace(marker, "");
|
|
46636
46779
|
}
|
|
46637
46780
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -48130,35 +48273,60 @@ var PersonaDispatchManager = class {
|
|
|
48130
48273
|
dispatchId,
|
|
48131
48274
|
sourceSessionId: args.sourceSessionId,
|
|
48132
48275
|
targetPersona: args.targetPersona,
|
|
48133
|
-
waiters: []
|
|
48134
|
-
|
|
48276
|
+
waiters: []
|
|
48277
|
+
});
|
|
48278
|
+
this.deps.store.add({
|
|
48279
|
+
dispatchId,
|
|
48280
|
+
sourceSessionId: args.sourceSessionId,
|
|
48281
|
+
...args.sourcePersonaId ? { sourcePersonaId: args.sourcePersonaId } : {},
|
|
48282
|
+
targetPersonaId: args.targetPersona,
|
|
48283
|
+
taskText: args.taskText
|
|
48135
48284
|
});
|
|
48136
48285
|
return { dispatchId };
|
|
48137
48286
|
}
|
|
48138
48287
|
get(dispatchId) {
|
|
48139
48288
|
return this.map.get(dispatchId);
|
|
48140
48289
|
}
|
|
48141
|
-
|
|
48290
|
+
complete(dispatchId, outcome) {
|
|
48142
48291
|
const state = this.map.get(dispatchId);
|
|
48143
|
-
|
|
48144
|
-
|
|
48292
|
+
const status = outcome.kind === "success" ? "completed" : "failed";
|
|
48293
|
+
const updated = this.deps.store.update(dispatchId, {
|
|
48294
|
+
status,
|
|
48295
|
+
outcome,
|
|
48296
|
+
completedAt: new Date(this.deps.now()).toISOString()
|
|
48297
|
+
});
|
|
48298
|
+
if (state) {
|
|
48299
|
+
const waiters = state.waiters;
|
|
48300
|
+
state.waiters = [];
|
|
48301
|
+
for (const w2 of waiters) w2.resolve(outcome);
|
|
48302
|
+
this.map.delete(dispatchId);
|
|
48303
|
+
}
|
|
48304
|
+
const sourceSessionId = updated?.sourceSessionId ?? state?.sourceSessionId;
|
|
48305
|
+
if (sourceSessionId) this.deps.onCompleted?.(sourceSessionId);
|
|
48306
|
+
}
|
|
48307
|
+
/**
|
|
48308
|
+
* mesh B 角色 hold 专用(跨设备 dispatch 的 peer 侧):guest B-role handler 用它
|
|
48309
|
+
* 挂住 /rpc HTTP 响应直到 complete,把 outcome 回传给 A 侧 daemon 的 forwardToPeer
|
|
48310
|
+
* (A 侧后台 await,A 的 tool call 不受影响照样秒回)。
|
|
48311
|
+
* 本地 dispatch 链路**不用**这个——本地 outcome 只走台账 + deliverPending。
|
|
48312
|
+
*/
|
|
48313
|
+
async waitForOutcome(dispatchId) {
|
|
48314
|
+
const state = this.map.get(dispatchId);
|
|
48315
|
+
if (!state) {
|
|
48316
|
+
const rec3 = this.deps.store.get(dispatchId);
|
|
48317
|
+
if (rec3?.outcome) return rec3.outcome;
|
|
48318
|
+
throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
48319
|
+
}
|
|
48145
48320
|
const d = defer();
|
|
48146
48321
|
state.waiters.push(d);
|
|
48147
48322
|
return d.promise;
|
|
48148
48323
|
}
|
|
48149
|
-
complete(dispatchId, outcome) {
|
|
48150
|
-
const state = this.map.get(dispatchId);
|
|
48151
|
-
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
48152
|
-
state.outcome = outcome;
|
|
48153
|
-
const waiters = state.waiters;
|
|
48154
|
-
state.waiters = [];
|
|
48155
|
-
for (const w2 of waiters) w2.resolve(outcome);
|
|
48156
|
-
}
|
|
48157
48324
|
/** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
|
|
48158
48325
|
registerBSession(dispatchId, bSessionId) {
|
|
48159
48326
|
const state = this.map.get(dispatchId);
|
|
48160
48327
|
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
48161
48328
|
state.bSessionId = bSessionId;
|
|
48329
|
+
this.deps.store.update(dispatchId, { workerSessionId: bSessionId });
|
|
48162
48330
|
}
|
|
48163
48331
|
/** reducer buildSpawnContext 调,按 B 的 sessionId 反查 dispatchId(用于注 CLAWD_DISPATCH_ID env) */
|
|
48164
48332
|
lookupDispatchByBSessionId(bSessionId) {
|
|
@@ -48169,11 +48337,112 @@ var PersonaDispatchManager = class {
|
|
|
48169
48337
|
}
|
|
48170
48338
|
};
|
|
48171
48339
|
|
|
48340
|
+
// src/dispatch/store.ts
|
|
48341
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
48342
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
48343
|
+
|
|
48344
|
+
// src/shift/constants.ts
|
|
48345
|
+
var MAX_RUNS_PER_SHIFT = 30;
|
|
48346
|
+
var DEFAULT_TIMEOUT_MS = 30 * 6e4;
|
|
48347
|
+
var CONSECUTIVE_ERROR_THRESHOLD = 5;
|
|
48348
|
+
var TICK_INTERVAL_MS = 1e4;
|
|
48349
|
+
var STORE_FLUSH_DEBOUNCE_MS = 500;
|
|
48350
|
+
var CLOCK_JUMP_THRESHOLD_MS = 5 * 6e4;
|
|
48351
|
+
|
|
48352
|
+
// src/dispatch/store.ts
|
|
48353
|
+
var TASK_TEXT_MAX = 500;
|
|
48354
|
+
function createDispatchStore(deps) {
|
|
48355
|
+
let records = [];
|
|
48356
|
+
let flushTimer = null;
|
|
48357
|
+
async function load() {
|
|
48358
|
+
let raw;
|
|
48359
|
+
try {
|
|
48360
|
+
raw = await import_promises.default.readFile(deps.filePath, "utf8");
|
|
48361
|
+
} catch (e) {
|
|
48362
|
+
if (e.code === "ENOENT") {
|
|
48363
|
+
records = [];
|
|
48364
|
+
return;
|
|
48365
|
+
}
|
|
48366
|
+
throw e;
|
|
48367
|
+
}
|
|
48368
|
+
const parsed = JSON.parse(raw);
|
|
48369
|
+
if (parsed.version !== 1) {
|
|
48370
|
+
throw new Error(`dispatch.json: unsupported version ${parsed.version}`);
|
|
48371
|
+
}
|
|
48372
|
+
records = parsed.records ?? [];
|
|
48373
|
+
}
|
|
48374
|
+
async function flushNow() {
|
|
48375
|
+
if (flushTimer) {
|
|
48376
|
+
clearTimeout(flushTimer);
|
|
48377
|
+
flushTimer = null;
|
|
48378
|
+
}
|
|
48379
|
+
const content = { version: 1, records };
|
|
48380
|
+
await import_promises.default.mkdir(import_node_path16.default.dirname(deps.filePath), { recursive: true });
|
|
48381
|
+
const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
|
|
48382
|
+
await import_promises.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
|
|
48383
|
+
await import_promises.default.rename(tmp, deps.filePath);
|
|
48384
|
+
}
|
|
48385
|
+
function scheduleFlush() {
|
|
48386
|
+
if (flushTimer) return;
|
|
48387
|
+
flushTimer = setTimeout(() => {
|
|
48388
|
+
flushTimer = null;
|
|
48389
|
+
flushNow().catch((err) => {
|
|
48390
|
+
deps.onFlushError?.(err);
|
|
48391
|
+
});
|
|
48392
|
+
}, STORE_FLUSH_DEBOUNCE_MS);
|
|
48393
|
+
}
|
|
48394
|
+
function get(dispatchId) {
|
|
48395
|
+
return records.find((r) => r.dispatchId === dispatchId);
|
|
48396
|
+
}
|
|
48397
|
+
function add(input) {
|
|
48398
|
+
const rec3 = {
|
|
48399
|
+
dispatchId: input.dispatchId,
|
|
48400
|
+
sourceSessionId: input.sourceSessionId,
|
|
48401
|
+
...input.sourcePersonaId ? { sourcePersonaId: input.sourcePersonaId } : {},
|
|
48402
|
+
targetPersonaId: input.targetPersonaId,
|
|
48403
|
+
taskText: input.taskText.slice(0, TASK_TEXT_MAX),
|
|
48404
|
+
status: "running",
|
|
48405
|
+
...input.meta ? { meta: input.meta } : {},
|
|
48406
|
+
createdAt: new Date(deps.now()).toISOString()
|
|
48407
|
+
};
|
|
48408
|
+
records.push(rec3);
|
|
48409
|
+
scheduleFlush();
|
|
48410
|
+
return rec3;
|
|
48411
|
+
}
|
|
48412
|
+
function update(dispatchId, patch) {
|
|
48413
|
+
const idx = records.findIndex((r) => r.dispatchId === dispatchId);
|
|
48414
|
+
if (idx < 0) return void 0;
|
|
48415
|
+
const merged = { ...records[idx], ...patch };
|
|
48416
|
+
records[idx] = merged;
|
|
48417
|
+
scheduleFlush();
|
|
48418
|
+
return merged;
|
|
48419
|
+
}
|
|
48420
|
+
function list(filter) {
|
|
48421
|
+
return records.filter((r) => !filter?.sourceSessionId || r.sourceSessionId === filter.sourceSessionId).slice().sort((a, b2) => a.createdAt < b2.createdAt ? 1 : a.createdAt > b2.createdAt ? -1 : 0);
|
|
48422
|
+
}
|
|
48423
|
+
function markInterruptedAsFailed(nowIso3) {
|
|
48424
|
+
let touched = false;
|
|
48425
|
+
for (const r of records) {
|
|
48426
|
+
if (r.status === "running") {
|
|
48427
|
+
r.status = "failed";
|
|
48428
|
+
r.outcome = {
|
|
48429
|
+
kind: "failure",
|
|
48430
|
+
reason: "daemon restarted while dispatch in flight"
|
|
48431
|
+
};
|
|
48432
|
+
r.completedAt = nowIso3;
|
|
48433
|
+
touched = true;
|
|
48434
|
+
}
|
|
48435
|
+
}
|
|
48436
|
+
if (touched) scheduleFlush();
|
|
48437
|
+
}
|
|
48438
|
+
return { load, flushNow, add, update, list, get, markInterruptedAsFailed };
|
|
48439
|
+
}
|
|
48440
|
+
|
|
48172
48441
|
// src/dispatch/mcp-config.ts
|
|
48173
48442
|
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
48174
|
-
var
|
|
48443
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
48175
48444
|
function dispatchMcpConfigPath(dataDir) {
|
|
48176
|
-
return
|
|
48445
|
+
return import_node_path17.default.join(dataDir, "dispatch.mcp.json");
|
|
48177
48446
|
}
|
|
48178
48447
|
function writeDispatchMcpConfig(args) {
|
|
48179
48448
|
const cfgPath = dispatchMcpConfigPath(args.dataDir);
|
|
@@ -48195,9 +48464,9 @@ function writeDispatchMcpConfig(args) {
|
|
|
48195
48464
|
|
|
48196
48465
|
// src/ticket/mcp-config.ts
|
|
48197
48466
|
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
48198
|
-
var
|
|
48467
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
48199
48468
|
function ticketMcpConfigPath(dataDir) {
|
|
48200
|
-
return
|
|
48469
|
+
return import_node_path18.default.join(dataDir, "ticket.mcp.json");
|
|
48201
48470
|
}
|
|
48202
48471
|
function writeTicketMcpConfig(args) {
|
|
48203
48472
|
const cfgPath = ticketMcpConfigPath(args.dataDir);
|
|
@@ -48224,9 +48493,9 @@ function writeTicketMcpConfig(args) {
|
|
|
48224
48493
|
|
|
48225
48494
|
// src/shift/mcp-config.ts
|
|
48226
48495
|
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
48227
|
-
var
|
|
48496
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
48228
48497
|
function shiftMcpConfigPath(dataDir) {
|
|
48229
|
-
return
|
|
48498
|
+
return import_node_path19.default.join(dataDir, "shift.mcp.json");
|
|
48230
48499
|
}
|
|
48231
48500
|
async function writeShiftMcpConfig(args) {
|
|
48232
48501
|
const cfgPath = shiftMcpConfigPath(args.dataDir);
|
|
@@ -48248,9 +48517,9 @@ async function writeShiftMcpConfig(args) {
|
|
|
48248
48517
|
|
|
48249
48518
|
// src/inbox/mcp-config.ts
|
|
48250
48519
|
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
48251
|
-
var
|
|
48520
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
48252
48521
|
function inboxMcpConfigPath(dataDir) {
|
|
48253
|
-
return
|
|
48522
|
+
return import_node_path20.default.join(dataDir, "inbox.mcp.json");
|
|
48254
48523
|
}
|
|
48255
48524
|
async function writeInboxMcpConfig(args) {
|
|
48256
48525
|
const cfgPath = inboxMcpConfigPath(args.dataDir);
|
|
@@ -48272,9 +48541,9 @@ async function writeInboxMcpConfig(args) {
|
|
|
48272
48541
|
|
|
48273
48542
|
// src/peer-ops/mcp-config.ts
|
|
48274
48543
|
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
48275
|
-
var
|
|
48544
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
48276
48545
|
function peerOpsMcpConfigPath(dataDir) {
|
|
48277
|
-
return
|
|
48546
|
+
return import_node_path21.default.join(dataDir, "peer-ops.mcp.json");
|
|
48278
48547
|
}
|
|
48279
48548
|
function writePeerOpsMcpConfig(args) {
|
|
48280
48549
|
const cfgPath = peerOpsMcpConfigPath(args.dataDir);
|
|
@@ -48293,18 +48562,10 @@ function writePeerOpsMcpConfig(args) {
|
|
|
48293
48562
|
}
|
|
48294
48563
|
|
|
48295
48564
|
// src/shift/store.ts
|
|
48296
|
-
var
|
|
48297
|
-
var
|
|
48565
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
48566
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
48298
48567
|
var import_node_crypto6 = require("crypto");
|
|
48299
48568
|
|
|
48300
|
-
// src/shift/constants.ts
|
|
48301
|
-
var MAX_RUNS_PER_SHIFT = 30;
|
|
48302
|
-
var DEFAULT_TIMEOUT_MS = 30 * 6e4;
|
|
48303
|
-
var CONSECUTIVE_ERROR_THRESHOLD = 5;
|
|
48304
|
-
var TICK_INTERVAL_MS = 1e4;
|
|
48305
|
-
var STORE_FLUSH_DEBOUNCE_MS = 500;
|
|
48306
|
-
var CLOCK_JUMP_THRESHOLD_MS = 5 * 6e4;
|
|
48307
|
-
|
|
48308
48569
|
// src/shift/schedule.ts
|
|
48309
48570
|
var import_cron_parser = __toESM(require_dist(), 1);
|
|
48310
48571
|
function computeNextRunAtMs(schedule, fromMs) {
|
|
@@ -48349,7 +48610,7 @@ function createShiftStore(deps) {
|
|
|
48349
48610
|
async function load() {
|
|
48350
48611
|
let raw;
|
|
48351
48612
|
try {
|
|
48352
|
-
raw = await
|
|
48613
|
+
raw = await import_promises2.default.readFile(deps.filePath, "utf8");
|
|
48353
48614
|
} catch (e) {
|
|
48354
48615
|
if (e.code === "ENOENT") {
|
|
48355
48616
|
shifts = [];
|
|
@@ -48377,10 +48638,10 @@ function createShiftStore(deps) {
|
|
|
48377
48638
|
flushTimer = null;
|
|
48378
48639
|
}
|
|
48379
48640
|
const content = { version: 1, shifts };
|
|
48380
|
-
await
|
|
48641
|
+
await import_promises2.default.mkdir(import_node_path22.default.dirname(deps.filePath), { recursive: true });
|
|
48381
48642
|
const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
|
|
48382
|
-
await
|
|
48383
|
-
await
|
|
48643
|
+
await import_promises2.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
|
|
48644
|
+
await import_promises2.default.rename(tmp, deps.filePath);
|
|
48384
48645
|
}
|
|
48385
48646
|
function scheduleFlush() {
|
|
48386
48647
|
if (flushTimer) return;
|
|
@@ -48815,18 +49076,33 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48815
49076
|
if (!deps.forwardToPeer) {
|
|
48816
49077
|
throw new Error("cross-device dispatch not wired (forwardToPeer missing)");
|
|
48817
49078
|
}
|
|
49079
|
+
if (!sourceSessionId) {
|
|
49080
|
+
throw new Error(
|
|
49081
|
+
"personaDispatch:run requires sessionId (caller must pass x-clawd-session-id header)"
|
|
49082
|
+
);
|
|
49083
|
+
}
|
|
49084
|
+
const { dispatchId: dispatchId2 } = mgr.start({
|
|
49085
|
+
sourceSessionId,
|
|
49086
|
+
targetPersona: args.targetPersona,
|
|
49087
|
+
taskText: args.prompt
|
|
49088
|
+
});
|
|
48818
49089
|
logger?.info("dispatch.run.forward", {
|
|
49090
|
+
dispatchId: dispatchId2,
|
|
48819
49091
|
targetDeviceId: args.targetDeviceId,
|
|
48820
49092
|
targetPersona: args.targetPersona
|
|
48821
49093
|
});
|
|
48822
|
-
|
|
49094
|
+
void deps.forwardToPeer({
|
|
48823
49095
|
targetDeviceId: args.targetDeviceId,
|
|
48824
49096
|
targetPersona: args.targetPersona,
|
|
48825
49097
|
prompt: args.prompt,
|
|
48826
49098
|
...args.model ? { model: args.model } : {}
|
|
49099
|
+
}).then((outcome) => mgr.complete(dispatchId2, outcome)).catch((err) => {
|
|
49100
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
49101
|
+
logger?.warn("dispatch.forward.failed", { dispatchId: dispatchId2, reason });
|
|
49102
|
+
mgr.complete(dispatchId2, { kind: "failure", reason });
|
|
48827
49103
|
});
|
|
48828
49104
|
return {
|
|
48829
|
-
response: { type: "personaDispatch:run:ok",
|
|
49105
|
+
response: { type: "personaDispatch:run:ok", dispatchId: dispatchId2 }
|
|
48830
49106
|
};
|
|
48831
49107
|
}
|
|
48832
49108
|
if (ctx?.principal.kind === "guest") {
|
|
@@ -48839,7 +49115,8 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48839
49115
|
}
|
|
48840
49116
|
const { dispatchId: dispatchId2 } = mgr.start({
|
|
48841
49117
|
sourceSessionId: ctx.principal.id,
|
|
48842
|
-
targetPersona: args.targetPersona
|
|
49118
|
+
targetPersona: args.targetPersona,
|
|
49119
|
+
taskText: args.prompt
|
|
48843
49120
|
});
|
|
48844
49121
|
logger?.info("dispatch.run.received.guest", {
|
|
48845
49122
|
dispatchId: dispatchId2,
|
|
@@ -48865,9 +49142,9 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48865
49142
|
reason: `failed to spawn B: ${reason}`
|
|
48866
49143
|
});
|
|
48867
49144
|
});
|
|
48868
|
-
const
|
|
49145
|
+
const outcome = await mgr.waitForOutcome(dispatchId2);
|
|
48869
49146
|
return {
|
|
48870
|
-
response: { type: "personaDispatch:run:ok", outcome
|
|
49147
|
+
response: { type: "personaDispatch:run:ok", outcome }
|
|
48871
49148
|
};
|
|
48872
49149
|
}
|
|
48873
49150
|
if (!sourceSessionId) {
|
|
@@ -48877,7 +49154,8 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48877
49154
|
}
|
|
48878
49155
|
const { dispatchId } = mgr.start({
|
|
48879
49156
|
sourceSessionId,
|
|
48880
|
-
targetPersona: args.targetPersona
|
|
49157
|
+
targetPersona: args.targetPersona,
|
|
49158
|
+
taskText: args.prompt
|
|
48881
49159
|
});
|
|
48882
49160
|
logger?.info("dispatch.run.received", {
|
|
48883
49161
|
dispatchId,
|
|
@@ -48901,14 +49179,8 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48901
49179
|
reason: `failed to spawn B: ${reason}`
|
|
48902
49180
|
});
|
|
48903
49181
|
});
|
|
48904
|
-
logger?.info("dispatch.run.waiting", { dispatchId });
|
|
48905
|
-
const outcome = await mgr.wait(dispatchId);
|
|
48906
|
-
logger?.info("dispatch.run.resolved", {
|
|
48907
|
-
dispatchId,
|
|
48908
|
-
outcomeKind: outcome.kind
|
|
48909
|
-
});
|
|
48910
49182
|
return {
|
|
48911
|
-
response: { type: "personaDispatch:run:ok",
|
|
49183
|
+
response: { type: "personaDispatch:run:ok", dispatchId }
|
|
48912
49184
|
};
|
|
48913
49185
|
};
|
|
48914
49186
|
const complete = async (frame) => {
|
|
@@ -48923,9 +49195,20 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48923
49195
|
response: { type: "personaDispatch:complete:ok" }
|
|
48924
49196
|
};
|
|
48925
49197
|
};
|
|
49198
|
+
const list = async (frame) => {
|
|
49199
|
+
const { type: _t, requestId: _r, ...rest } = frame;
|
|
49200
|
+
const args = DispatchListArgsSchema.parse(rest);
|
|
49201
|
+
const records = deps.store.list(
|
|
49202
|
+
args.sourceSessionId ? { sourceSessionId: args.sourceSessionId } : void 0
|
|
49203
|
+
);
|
|
49204
|
+
return {
|
|
49205
|
+
response: { type: "personaDispatch:list:ok", records }
|
|
49206
|
+
};
|
|
49207
|
+
};
|
|
48926
49208
|
return {
|
|
48927
49209
|
"personaDispatch:run": run,
|
|
48928
|
-
"personaDispatch:complete": complete
|
|
49210
|
+
"personaDispatch:complete": complete,
|
|
49211
|
+
"personaDispatch:list": list
|
|
48929
49212
|
};
|
|
48930
49213
|
}
|
|
48931
49214
|
|
|
@@ -49231,13 +49514,13 @@ function mapSkillsListResponse(res) {
|
|
|
49231
49514
|
const r = s ?? {};
|
|
49232
49515
|
const name = str3(r.name);
|
|
49233
49516
|
if (!name) continue;
|
|
49234
|
-
const
|
|
49517
|
+
const path71 = str3(r.path);
|
|
49235
49518
|
const description = str3(r.description);
|
|
49236
49519
|
const isPlugin = name.includes(":");
|
|
49237
49520
|
out.push({
|
|
49238
49521
|
name,
|
|
49239
49522
|
source: isPlugin ? "plugin" : "project",
|
|
49240
|
-
...
|
|
49523
|
+
...path71 ? { path: path71 } : {},
|
|
49241
49524
|
...description ? { description } : {},
|
|
49242
49525
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
49243
49526
|
});
|
|
@@ -49278,14 +49561,14 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
49278
49561
|
// src/workspace/browser.ts
|
|
49279
49562
|
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
49280
49563
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
49281
|
-
var
|
|
49564
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
49282
49565
|
init_protocol();
|
|
49283
49566
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
49284
49567
|
function resolveInsideCwd(cwd, subpath) {
|
|
49285
|
-
const absCwd =
|
|
49286
|
-
const joined =
|
|
49287
|
-
const rel =
|
|
49288
|
-
if (rel.startsWith("..") ||
|
|
49568
|
+
const absCwd = import_node_path23.default.resolve(cwd);
|
|
49569
|
+
const joined = import_node_path23.default.resolve(absCwd, subpath ?? ".");
|
|
49570
|
+
const rel = import_node_path23.default.relative(absCwd, joined);
|
|
49571
|
+
if (rel.startsWith("..") || import_node_path23.default.isAbsolute(rel)) {
|
|
49289
49572
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
49290
49573
|
}
|
|
49291
49574
|
return joined;
|
|
@@ -49316,7 +49599,7 @@ var WorkspaceBrowser = class {
|
|
|
49316
49599
|
mtime: ""
|
|
49317
49600
|
};
|
|
49318
49601
|
try {
|
|
49319
|
-
const st = import_node_fs24.default.statSync(
|
|
49602
|
+
const st = import_node_fs24.default.statSync(import_node_path23.default.join(full, d.name));
|
|
49320
49603
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
49321
49604
|
if (d.isFile()) entry.size = st.size;
|
|
49322
49605
|
} catch {
|
|
@@ -49363,7 +49646,7 @@ var WorkspaceBrowser = class {
|
|
|
49363
49646
|
// src/skills/agents-scanner.ts
|
|
49364
49647
|
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
49365
49648
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
49366
|
-
var
|
|
49649
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
49367
49650
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
49368
49651
|
function isDirLikeSync2(p2) {
|
|
49369
49652
|
try {
|
|
@@ -49401,10 +49684,10 @@ function scanAgentsDir(dir, source, seen, out) {
|
|
|
49401
49684
|
}
|
|
49402
49685
|
for (const ent of entries) {
|
|
49403
49686
|
if (!ent.name.endsWith(".md")) continue;
|
|
49404
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
49687
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path24.default.join(dir, ent.name)))) {
|
|
49405
49688
|
continue;
|
|
49406
49689
|
}
|
|
49407
|
-
const filePath =
|
|
49690
|
+
const filePath = import_node_path24.default.join(dir, ent.name);
|
|
49408
49691
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
49409
49692
|
if (seen.has(baseName)) continue;
|
|
49410
49693
|
seen.add(baseName);
|
|
@@ -49427,7 +49710,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
49427
49710
|
return;
|
|
49428
49711
|
}
|
|
49429
49712
|
for (const ent of entries) {
|
|
49430
|
-
const childPath =
|
|
49713
|
+
const childPath = import_node_path24.default.join(dir, ent.name);
|
|
49431
49714
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
49432
49715
|
walk2(childPath, [...namespaces, ent.name]);
|
|
49433
49716
|
continue;
|
|
@@ -49452,9 +49735,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
49452
49735
|
walk2(root, []);
|
|
49453
49736
|
}
|
|
49454
49737
|
function readInstalledPlugins2(home) {
|
|
49455
|
-
const pluginsDir =
|
|
49456
|
-
const v2 =
|
|
49457
|
-
const v1 =
|
|
49738
|
+
const pluginsDir = import_node_path24.default.join(home, ".claude", "plugins");
|
|
49739
|
+
const v2 = import_node_path24.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
49740
|
+
const v1 = import_node_path24.default.join(pluginsDir, "installed_plugins.json");
|
|
49458
49741
|
let raw = null;
|
|
49459
49742
|
for (const candidate of [v2, v1]) {
|
|
49460
49743
|
try {
|
|
@@ -49483,19 +49766,19 @@ function readInstalledPlugins2(home) {
|
|
|
49483
49766
|
return out;
|
|
49484
49767
|
}
|
|
49485
49768
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
49486
|
-
let cur =
|
|
49487
|
-
const fsRoot =
|
|
49769
|
+
let cur = import_node_path24.default.resolve(startCwd);
|
|
49770
|
+
const fsRoot = import_node_path24.default.parse(cur).root;
|
|
49488
49771
|
while (true) {
|
|
49489
|
-
scanAgentsDir(
|
|
49772
|
+
scanAgentsDir(import_node_path24.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
49490
49773
|
let hasGit = false;
|
|
49491
49774
|
try {
|
|
49492
|
-
hasGit = import_node_fs25.default.existsSync(
|
|
49775
|
+
hasGit = import_node_fs25.default.existsSync(import_node_path24.default.join(cur, ".git"));
|
|
49493
49776
|
} catch {
|
|
49494
49777
|
}
|
|
49495
49778
|
if (hasGit) return;
|
|
49496
49779
|
if (cur === home) return;
|
|
49497
49780
|
if (cur === fsRoot) return;
|
|
49498
|
-
const parent =
|
|
49781
|
+
const parent = import_node_path24.default.dirname(cur);
|
|
49499
49782
|
if (parent === cur) return;
|
|
49500
49783
|
cur = parent;
|
|
49501
49784
|
}
|
|
@@ -49530,7 +49813,7 @@ var AgentsScanner = class {
|
|
|
49530
49813
|
}
|
|
49531
49814
|
const fsBlock = [];
|
|
49532
49815
|
scanAgentsDir(
|
|
49533
|
-
|
|
49816
|
+
import_node_path24.default.join(this.home, ".claude", "agents"),
|
|
49534
49817
|
"global",
|
|
49535
49818
|
seen,
|
|
49536
49819
|
fsBlock
|
|
@@ -49544,7 +49827,7 @@ var AgentsScanner = class {
|
|
|
49544
49827
|
...this.extraPluginRoots
|
|
49545
49828
|
];
|
|
49546
49829
|
for (const { name, root } of plugins) {
|
|
49547
|
-
const agentsRoot =
|
|
49830
|
+
const agentsRoot = import_node_path24.default.join(root, "agents");
|
|
49548
49831
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
49549
49832
|
}
|
|
49550
49833
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -49554,13 +49837,13 @@ var AgentsScanner = class {
|
|
|
49554
49837
|
// src/observer/session-observer.ts
|
|
49555
49838
|
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
49556
49839
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
49557
|
-
var
|
|
49840
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
49558
49841
|
init_claude_history();
|
|
49559
49842
|
|
|
49560
49843
|
// src/observer/subagent-meta-observer.ts
|
|
49561
49844
|
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
49562
49845
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
49563
|
-
var
|
|
49846
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
49564
49847
|
init_claude_history();
|
|
49565
49848
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
49566
49849
|
var SubagentMetaObserver = class {
|
|
@@ -49573,7 +49856,7 @@ var SubagentMetaObserver = class {
|
|
|
49573
49856
|
watches = /* @__PURE__ */ new Map();
|
|
49574
49857
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
49575
49858
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
49576
|
-
return
|
|
49859
|
+
return import_node_path25.default.join(
|
|
49577
49860
|
this.home,
|
|
49578
49861
|
".claude",
|
|
49579
49862
|
"projects",
|
|
@@ -49629,7 +49912,7 @@ var SubagentMetaObserver = class {
|
|
|
49629
49912
|
if (!m2) return;
|
|
49630
49913
|
const agentId = m2[1];
|
|
49631
49914
|
if (w2.emitted.has(agentId)) return;
|
|
49632
|
-
const file =
|
|
49915
|
+
const file = import_node_path25.default.join(w2.dirPath, name);
|
|
49633
49916
|
let raw;
|
|
49634
49917
|
try {
|
|
49635
49918
|
raw = import_node_fs26.default.readFileSync(file, "utf8");
|
|
@@ -49689,7 +49972,7 @@ var SessionObserver = class {
|
|
|
49689
49972
|
metaObserver;
|
|
49690
49973
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
49691
49974
|
if (override) return override;
|
|
49692
|
-
return
|
|
49975
|
+
return import_node_path26.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
49693
49976
|
}
|
|
49694
49977
|
start(args) {
|
|
49695
49978
|
this.stop(args.sessionId);
|
|
@@ -49715,10 +49998,10 @@ var SessionObserver = class {
|
|
|
49715
49998
|
lastDeriveMs: 0
|
|
49716
49999
|
};
|
|
49717
50000
|
try {
|
|
49718
|
-
import_node_fs27.default.mkdirSync(
|
|
50001
|
+
import_node_fs27.default.mkdirSync(import_node_path26.default.dirname(filePath), { recursive: true });
|
|
49719
50002
|
} catch {
|
|
49720
50003
|
}
|
|
49721
|
-
w2.watcher = import_node_fs27.default.watch(
|
|
50004
|
+
w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
49722
50005
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
49723
50006
|
this.poll(w2);
|
|
49724
50007
|
});
|
|
@@ -49815,7 +50098,7 @@ var SessionObserver = class {
|
|
|
49815
50098
|
const now = Date.now();
|
|
49816
50099
|
if (now - w2.lastRelocateScanMs < 1e3) return;
|
|
49817
50100
|
w2.lastRelocateScanMs = now;
|
|
49818
|
-
const projectsRoot =
|
|
50101
|
+
const projectsRoot = import_node_path26.default.join(this.home, ".claude", "projects");
|
|
49819
50102
|
const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
|
|
49820
50103
|
if (!found || found === w2.filePath) return;
|
|
49821
50104
|
try {
|
|
@@ -49824,7 +50107,7 @@ var SessionObserver = class {
|
|
|
49824
50107
|
}
|
|
49825
50108
|
w2.filePath = found;
|
|
49826
50109
|
try {
|
|
49827
|
-
w2.watcher = import_node_fs27.default.watch(
|
|
50110
|
+
w2.watcher = import_node_fs27.default.watch(import_node_path26.default.dirname(found), { persistent: false }, (_event, changedName) => {
|
|
49828
50111
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
49829
50112
|
this.poll(w2);
|
|
49830
50113
|
});
|
|
@@ -50408,13 +50691,13 @@ var EXPOSED_RPC_METHODS = [
|
|
|
50408
50691
|
// dataclaw-builder:persona 建页时取建页人身份(含 union_id)写进生成 app 的配置。
|
|
50409
50692
|
// 路由到 handlers['auth:getIdentity'],只返 identity、绝不带 ttcToken(见 handlers/feishu-auth.ts)。
|
|
50410
50693
|
"auth.getIdentity",
|
|
50411
|
-
// Persona dispatch
|
|
50412
|
-
// B
|
|
50413
|
-
// protocol/src/dispatch.ts。
|
|
50694
|
+
// Persona dispatch(异步,spec 2026-07-20):A 端 dispatch MCP server 调 run(秒回 dispatchId);
|
|
50695
|
+
// B 端调 complete(带 outcome → 台账 + 投递);发起方调 list 查台账。详见 protocol/src/dispatch.ts。
|
|
50414
50696
|
"personaDispatch.run",
|
|
50415
50697
|
// 跨设备 exec(spec 2026-07-16):A 侧本地 cc 经 /api/rpc 调,带 peerDeviceId → daemon forward。
|
|
50416
50698
|
"peerExec.run",
|
|
50417
50699
|
"personaDispatch.complete",
|
|
50700
|
+
"personaDispatch.list",
|
|
50418
50701
|
// clawd-shift v1 (spec 2026-06-24-clawd-shift):cc 子进程内的 shift MCP server 调
|
|
50419
50702
|
// 这 5 个 method 管理 owner 的 shift(fire-and-forget 排班)。鉴权靠 body.personaId
|
|
50420
50703
|
// (mcp-server 从 process.env.CLAWD_PERSONA_ID 读,源 = SessionFile.ownerPersonaId)。
|
|
@@ -50679,14 +50962,14 @@ async function authenticate(token, deps) {
|
|
|
50679
50962
|
}
|
|
50680
50963
|
|
|
50681
50964
|
// src/permission/capability-store.ts
|
|
50682
|
-
var
|
|
50683
|
-
var
|
|
50965
|
+
var fs32 = __toESM(require("fs"), 1);
|
|
50966
|
+
var path31 = __toESM(require("path"), 1);
|
|
50684
50967
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
50685
50968
|
var FILE_VERSION = 1;
|
|
50686
50969
|
var CapabilityStore = class {
|
|
50687
50970
|
constructor(dataDir) {
|
|
50688
50971
|
this.dataDir = dataDir;
|
|
50689
|
-
|
|
50972
|
+
fs32.mkdirSync(dataDir, { recursive: true });
|
|
50690
50973
|
this.cache = this.readFromDisk();
|
|
50691
50974
|
}
|
|
50692
50975
|
dataDir;
|
|
@@ -50710,13 +50993,13 @@ var CapabilityStore = class {
|
|
|
50710
50993
|
this.flush();
|
|
50711
50994
|
}
|
|
50712
50995
|
filePath() {
|
|
50713
|
-
return
|
|
50996
|
+
return path31.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
50714
50997
|
}
|
|
50715
50998
|
readFromDisk() {
|
|
50716
50999
|
const file = this.filePath();
|
|
50717
51000
|
let raw;
|
|
50718
51001
|
try {
|
|
50719
|
-
raw =
|
|
51002
|
+
raw = fs32.readFileSync(file, "utf8");
|
|
50720
51003
|
} catch (err) {
|
|
50721
51004
|
if (err?.code === "ENOENT") return [];
|
|
50722
51005
|
return [];
|
|
@@ -50744,10 +51027,10 @@ var CapabilityStore = class {
|
|
|
50744
51027
|
}
|
|
50745
51028
|
atomicWrite(file, content) {
|
|
50746
51029
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
50747
|
-
|
|
50748
|
-
|
|
51030
|
+
fs32.writeFileSync(tmp, content, { mode: 384 });
|
|
51031
|
+
fs32.renameSync(tmp, file);
|
|
50749
51032
|
try {
|
|
50750
|
-
|
|
51033
|
+
fs32.chmodSync(file, 384);
|
|
50751
51034
|
} catch {
|
|
50752
51035
|
}
|
|
50753
51036
|
}
|
|
@@ -50840,14 +51123,14 @@ var CapabilityManager = class {
|
|
|
50840
51123
|
};
|
|
50841
51124
|
|
|
50842
51125
|
// src/permission/cleanup.ts
|
|
50843
|
-
var
|
|
51126
|
+
var fs33 = __toESM(require("fs"), 1);
|
|
50844
51127
|
function cleanupGuestSessionsForCapability(cap, factory) {
|
|
50845
51128
|
const removed = [];
|
|
50846
51129
|
for (const g2 of cap.grants) {
|
|
50847
51130
|
if (g2.resource.type !== "persona") continue;
|
|
50848
51131
|
const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
|
|
50849
51132
|
try {
|
|
50850
|
-
|
|
51133
|
+
fs33.rmSync(dir, { recursive: true, force: true });
|
|
50851
51134
|
removed.push(dir);
|
|
50852
51135
|
} catch {
|
|
50853
51136
|
}
|
|
@@ -50856,13 +51139,13 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
50856
51139
|
}
|
|
50857
51140
|
|
|
50858
51141
|
// src/inbox/inbox-store.ts
|
|
50859
|
-
var
|
|
50860
|
-
var
|
|
51142
|
+
var fs34 = __toESM(require("fs"), 1);
|
|
51143
|
+
var path32 = __toESM(require("path"), 1);
|
|
50861
51144
|
var INBOX_SUBDIR = "inbox";
|
|
50862
51145
|
var InboxStore = class {
|
|
50863
51146
|
constructor(dataDir) {
|
|
50864
51147
|
this.dataDir = dataDir;
|
|
50865
|
-
|
|
51148
|
+
fs34.mkdirSync(this.dirPath(), { recursive: true });
|
|
50866
51149
|
}
|
|
50867
51150
|
dataDir;
|
|
50868
51151
|
/**
|
|
@@ -50874,7 +51157,7 @@ var InboxStore = class {
|
|
|
50874
51157
|
const file = this.filePath(peerDeviceId);
|
|
50875
51158
|
let raw;
|
|
50876
51159
|
try {
|
|
50877
|
-
raw =
|
|
51160
|
+
raw = fs34.readFileSync(file, "utf8");
|
|
50878
51161
|
} catch (err) {
|
|
50879
51162
|
if (err?.code === "ENOENT") return [];
|
|
50880
51163
|
return [];
|
|
@@ -50890,7 +51173,7 @@ var InboxStore = class {
|
|
|
50890
51173
|
const dir = this.dirPath();
|
|
50891
51174
|
let entries;
|
|
50892
51175
|
try {
|
|
50893
|
-
entries =
|
|
51176
|
+
entries = fs34.readdirSync(dir);
|
|
50894
51177
|
} catch (err) {
|
|
50895
51178
|
if (err?.code === "ENOENT") return [];
|
|
50896
51179
|
return [];
|
|
@@ -50906,9 +51189,9 @@ var InboxStore = class {
|
|
|
50906
51189
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
50907
51190
|
const file = this.filePath(message.peerDeviceId);
|
|
50908
51191
|
const line = JSON.stringify(message) + "\n";
|
|
50909
|
-
|
|
51192
|
+
fs34.appendFileSync(file, line, { mode: 384 });
|
|
50910
51193
|
try {
|
|
50911
|
-
|
|
51194
|
+
fs34.chmodSync(file, 384);
|
|
50912
51195
|
} catch {
|
|
50913
51196
|
}
|
|
50914
51197
|
}
|
|
@@ -50938,7 +51221,7 @@ var InboxStore = class {
|
|
|
50938
51221
|
removeByPeerDeviceId(peerDeviceId) {
|
|
50939
51222
|
const file = this.filePath(peerDeviceId);
|
|
50940
51223
|
try {
|
|
50941
|
-
|
|
51224
|
+
fs34.unlinkSync(file);
|
|
50942
51225
|
} catch (err) {
|
|
50943
51226
|
if (err?.code === "ENOENT") return;
|
|
50944
51227
|
}
|
|
@@ -50947,18 +51230,18 @@ var InboxStore = class {
|
|
|
50947
51230
|
const file = this.filePath(peerDeviceId);
|
|
50948
51231
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
50949
51232
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
50950
|
-
|
|
50951
|
-
|
|
51233
|
+
fs34.writeFileSync(tmp, content, { mode: 384 });
|
|
51234
|
+
fs34.renameSync(tmp, file);
|
|
50952
51235
|
try {
|
|
50953
|
-
|
|
51236
|
+
fs34.chmodSync(file, 384);
|
|
50954
51237
|
} catch {
|
|
50955
51238
|
}
|
|
50956
51239
|
}
|
|
50957
51240
|
dirPath() {
|
|
50958
|
-
return
|
|
51241
|
+
return path32.join(this.dataDir, INBOX_SUBDIR);
|
|
50959
51242
|
}
|
|
50960
51243
|
filePath(peerDeviceId) {
|
|
50961
|
-
return
|
|
51244
|
+
return path32.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
50962
51245
|
}
|
|
50963
51246
|
};
|
|
50964
51247
|
function parseAllLines(raw) {
|
|
@@ -51046,8 +51329,8 @@ var InboxManager = class {
|
|
|
51046
51329
|
};
|
|
51047
51330
|
|
|
51048
51331
|
// src/state/contact-store.ts
|
|
51049
|
-
var
|
|
51050
|
-
var
|
|
51332
|
+
var fs35 = __toESM(require("fs"), 1);
|
|
51333
|
+
var path33 = __toESM(require("path"), 1);
|
|
51051
51334
|
var FILE_NAME = "contacts.json";
|
|
51052
51335
|
var ContactStore = class {
|
|
51053
51336
|
constructor(dataDir) {
|
|
@@ -51057,10 +51340,10 @@ var ContactStore = class {
|
|
|
51057
51340
|
contacts = /* @__PURE__ */ new Map();
|
|
51058
51341
|
load() {
|
|
51059
51342
|
this.contacts.clear();
|
|
51060
|
-
const file =
|
|
51343
|
+
const file = path33.join(this.dataDir, FILE_NAME);
|
|
51061
51344
|
let raw;
|
|
51062
51345
|
try {
|
|
51063
|
-
raw =
|
|
51346
|
+
raw = fs35.readFileSync(file, "utf8");
|
|
51064
51347
|
} catch (err) {
|
|
51065
51348
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
51066
51349
|
return;
|
|
@@ -51129,20 +51412,20 @@ var ContactStore = class {
|
|
|
51129
51412
|
return true;
|
|
51130
51413
|
}
|
|
51131
51414
|
flush() {
|
|
51132
|
-
const file =
|
|
51415
|
+
const file = path33.join(this.dataDir, FILE_NAME);
|
|
51133
51416
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
51134
51417
|
const content = JSON.stringify(
|
|
51135
51418
|
{ contacts: Array.from(this.contacts.values()) },
|
|
51136
51419
|
null,
|
|
51137
51420
|
2
|
|
51138
51421
|
);
|
|
51139
|
-
|
|
51140
|
-
|
|
51141
|
-
|
|
51422
|
+
fs35.mkdirSync(this.dataDir, { recursive: true });
|
|
51423
|
+
fs35.writeFileSync(tmp, content, { mode: 384 });
|
|
51424
|
+
fs35.renameSync(tmp, file);
|
|
51142
51425
|
}
|
|
51143
51426
|
renameBak(file) {
|
|
51144
51427
|
try {
|
|
51145
|
-
|
|
51428
|
+
fs35.renameSync(file, `${file}.bak`);
|
|
51146
51429
|
} catch {
|
|
51147
51430
|
}
|
|
51148
51431
|
}
|
|
@@ -51295,61 +51578,61 @@ async function autoReverseContact(args) {
|
|
|
51295
51578
|
}
|
|
51296
51579
|
|
|
51297
51580
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
51298
|
-
var
|
|
51299
|
-
var
|
|
51581
|
+
var fs36 = __toESM(require("fs"), 1);
|
|
51582
|
+
var path34 = __toESM(require("path"), 1);
|
|
51300
51583
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
51301
51584
|
function migrateFlattenSessions(opts) {
|
|
51302
51585
|
const dataDir = opts.dataDir;
|
|
51303
51586
|
const now = opts.now ?? Date.now;
|
|
51304
|
-
const sessionsDir =
|
|
51305
|
-
const flagPath =
|
|
51587
|
+
const sessionsDir = path34.join(dataDir, "sessions");
|
|
51588
|
+
const flagPath = path34.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
51306
51589
|
if (existsSync3(flagPath)) {
|
|
51307
51590
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
51308
51591
|
}
|
|
51309
51592
|
let movedBare = 0;
|
|
51310
51593
|
let movedVmOwner = 0;
|
|
51311
51594
|
let archivedListener = 0;
|
|
51312
|
-
const defaultDir =
|
|
51595
|
+
const defaultDir = path34.join(sessionsDir, "default");
|
|
51313
51596
|
if (existsSync3(defaultDir)) {
|
|
51314
51597
|
for (const entry of readdirSafe(defaultDir)) {
|
|
51315
51598
|
if (!entry.endsWith(".json")) continue;
|
|
51316
|
-
const src =
|
|
51317
|
-
const dst =
|
|
51318
|
-
|
|
51599
|
+
const src = path34.join(defaultDir, entry);
|
|
51600
|
+
const dst = path34.join(sessionsDir, entry);
|
|
51601
|
+
fs36.renameSync(src, dst);
|
|
51319
51602
|
movedBare += 1;
|
|
51320
51603
|
}
|
|
51321
51604
|
rmdirIfEmpty(defaultDir);
|
|
51322
51605
|
}
|
|
51323
51606
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
51324
|
-
const personaDir =
|
|
51607
|
+
const personaDir = path34.join(sessionsDir, pid);
|
|
51325
51608
|
if (!isDir(personaDir)) continue;
|
|
51326
51609
|
if (pid === "default") continue;
|
|
51327
|
-
const ownerSrc =
|
|
51610
|
+
const ownerSrc = path34.join(personaDir, "owner");
|
|
51328
51611
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
51329
|
-
const ownerDst =
|
|
51330
|
-
|
|
51612
|
+
const ownerDst = path34.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
51613
|
+
fs36.mkdirSync(ownerDst, { recursive: true });
|
|
51331
51614
|
for (const file of readdirSafe(ownerSrc)) {
|
|
51332
51615
|
if (!file.endsWith(".json")) continue;
|
|
51333
|
-
|
|
51616
|
+
fs36.renameSync(path34.join(ownerSrc, file), path34.join(ownerDst, file));
|
|
51334
51617
|
movedVmOwner += 1;
|
|
51335
51618
|
}
|
|
51336
51619
|
rmdirIfEmpty(ownerSrc);
|
|
51337
51620
|
}
|
|
51338
|
-
const listenerSrc =
|
|
51621
|
+
const listenerSrc = path34.join(personaDir, "listener");
|
|
51339
51622
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
51340
|
-
const archiveDst =
|
|
51341
|
-
|
|
51623
|
+
const archiveDst = path34.join(dataDir, ".legacy", `listener-${pid}`);
|
|
51624
|
+
fs36.mkdirSync(archiveDst, { recursive: true });
|
|
51342
51625
|
for (const file of readdirSafe(listenerSrc)) {
|
|
51343
51626
|
if (!file.endsWith(".json")) continue;
|
|
51344
|
-
|
|
51627
|
+
fs36.renameSync(path34.join(listenerSrc, file), path34.join(archiveDst, file));
|
|
51345
51628
|
archivedListener += 1;
|
|
51346
51629
|
}
|
|
51347
51630
|
rmdirIfEmpty(listenerSrc);
|
|
51348
51631
|
}
|
|
51349
51632
|
rmdirIfEmpty(personaDir);
|
|
51350
51633
|
}
|
|
51351
|
-
|
|
51352
|
-
|
|
51634
|
+
fs36.mkdirSync(sessionsDir, { recursive: true });
|
|
51635
|
+
fs36.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
51353
51636
|
return {
|
|
51354
51637
|
skipped: false,
|
|
51355
51638
|
flagWritten: true,
|
|
@@ -51360,7 +51643,7 @@ function migrateFlattenSessions(opts) {
|
|
|
51360
51643
|
}
|
|
51361
51644
|
function existsSync3(p2) {
|
|
51362
51645
|
try {
|
|
51363
|
-
|
|
51646
|
+
fs36.statSync(p2);
|
|
51364
51647
|
return true;
|
|
51365
51648
|
} catch {
|
|
51366
51649
|
return false;
|
|
@@ -51368,31 +51651,31 @@ function existsSync3(p2) {
|
|
|
51368
51651
|
}
|
|
51369
51652
|
function isDir(p2) {
|
|
51370
51653
|
try {
|
|
51371
|
-
return
|
|
51654
|
+
return fs36.statSync(p2).isDirectory();
|
|
51372
51655
|
} catch {
|
|
51373
51656
|
return false;
|
|
51374
51657
|
}
|
|
51375
51658
|
}
|
|
51376
51659
|
function readdirSafe(p2) {
|
|
51377
51660
|
try {
|
|
51378
|
-
return
|
|
51661
|
+
return fs36.readdirSync(p2);
|
|
51379
51662
|
} catch {
|
|
51380
51663
|
return [];
|
|
51381
51664
|
}
|
|
51382
51665
|
}
|
|
51383
51666
|
function rmdirIfEmpty(p2) {
|
|
51384
51667
|
try {
|
|
51385
|
-
|
|
51668
|
+
fs36.rmdirSync(p2);
|
|
51386
51669
|
} catch {
|
|
51387
51670
|
}
|
|
51388
51671
|
}
|
|
51389
51672
|
|
|
51390
51673
|
// src/transport/http-router.ts
|
|
51391
51674
|
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
51392
|
-
var
|
|
51675
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
51393
51676
|
|
|
51394
51677
|
// src/attachment/mime.ts
|
|
51395
|
-
var
|
|
51678
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
51396
51679
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
51397
51680
|
var EXT_TO_NATIVE_MIME = {
|
|
51398
51681
|
// 图片
|
|
@@ -51499,7 +51782,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
51499
51782
|
".mk"
|
|
51500
51783
|
]);
|
|
51501
51784
|
function lookupMime(filePathOrName) {
|
|
51502
|
-
const ext =
|
|
51785
|
+
const ext = import_node_path27.default.extname(filePathOrName).toLowerCase();
|
|
51503
51786
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
51504
51787
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
51505
51788
|
return "application/octet-stream";
|
|
@@ -51569,9 +51852,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
51569
51852
|
|
|
51570
51853
|
// src/attachment/upload.ts
|
|
51571
51854
|
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
51572
|
-
var
|
|
51855
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
51573
51856
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
51574
|
-
var
|
|
51857
|
+
var import_promises3 = require("stream/promises");
|
|
51575
51858
|
var UploadError = class extends Error {
|
|
51576
51859
|
constructor(code, message) {
|
|
51577
51860
|
super(message);
|
|
@@ -51581,14 +51864,14 @@ var UploadError = class extends Error {
|
|
|
51581
51864
|
code;
|
|
51582
51865
|
};
|
|
51583
51866
|
function assertValidFileName(fileName) {
|
|
51584
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
51867
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path28.default.basename(fileName)) {
|
|
51585
51868
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
51586
51869
|
}
|
|
51587
51870
|
}
|
|
51588
51871
|
var HASH_PREFIX_LEN = 16;
|
|
51589
51872
|
async function writeUploadedAttachment(args) {
|
|
51590
51873
|
assertValidFileName(args.fileName);
|
|
51591
|
-
const attachmentsRoot =
|
|
51874
|
+
const attachmentsRoot = import_node_path28.default.join(args.sessionDir, ".attachments");
|
|
51592
51875
|
try {
|
|
51593
51876
|
import_node_fs28.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
51594
51877
|
} catch (err) {
|
|
@@ -51596,12 +51879,12 @@ async function writeUploadedAttachment(args) {
|
|
|
51596
51879
|
}
|
|
51597
51880
|
const hasher = import_node_crypto8.default.createHash("sha256");
|
|
51598
51881
|
let actualSize = 0;
|
|
51599
|
-
const tmpPath =
|
|
51882
|
+
const tmpPath = import_node_path28.default.join(
|
|
51600
51883
|
attachmentsRoot,
|
|
51601
51884
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
|
|
51602
51885
|
);
|
|
51603
51886
|
try {
|
|
51604
|
-
await (0,
|
|
51887
|
+
await (0, import_promises3.pipeline)(
|
|
51605
51888
|
args.body,
|
|
51606
51889
|
async function* (source) {
|
|
51607
51890
|
for await (const chunk of source) {
|
|
@@ -51631,7 +51914,7 @@ async function writeUploadedAttachment(args) {
|
|
|
51631
51914
|
);
|
|
51632
51915
|
}
|
|
51633
51916
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
51634
|
-
const hashDir =
|
|
51917
|
+
const hashDir = import_node_path28.default.join(attachmentsRoot, attachmentId);
|
|
51635
51918
|
let finalFileName;
|
|
51636
51919
|
let hashDirExists = false;
|
|
51637
51920
|
try {
|
|
@@ -51649,7 +51932,7 @@ async function writeUploadedAttachment(args) {
|
|
|
51649
51932
|
try {
|
|
51650
51933
|
import_node_fs28.default.mkdirSync(hashDir, { recursive: true });
|
|
51651
51934
|
finalFileName = args.fileName;
|
|
51652
|
-
import_node_fs28.default.renameSync(tmpPath,
|
|
51935
|
+
import_node_fs28.default.renameSync(tmpPath, import_node_path28.default.join(hashDir, finalFileName));
|
|
51653
51936
|
} catch (err) {
|
|
51654
51937
|
try {
|
|
51655
51938
|
import_node_fs28.default.unlinkSync(tmpPath);
|
|
@@ -51658,8 +51941,8 @@ async function writeUploadedAttachment(args) {
|
|
|
51658
51941
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
51659
51942
|
}
|
|
51660
51943
|
}
|
|
51661
|
-
const absPath =
|
|
51662
|
-
const relPath =
|
|
51944
|
+
const absPath = import_node_path28.default.join(hashDir, finalFileName);
|
|
51945
|
+
const relPath = import_node_path28.default.relative(args.sessionDir, absPath);
|
|
51663
51946
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
51664
51947
|
relPath: absPath,
|
|
51665
51948
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -51672,8 +51955,8 @@ async function writeUploadedAttachment(args) {
|
|
|
51672
51955
|
}
|
|
51673
51956
|
|
|
51674
51957
|
// src/extension/import.ts
|
|
51675
|
-
var
|
|
51676
|
-
var
|
|
51958
|
+
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
51959
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
51677
51960
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
51678
51961
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
51679
51962
|
var ImportError = class extends Error {
|
|
@@ -51691,7 +51974,7 @@ async function importZip(buf, root) {
|
|
|
51691
51974
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
51692
51975
|
}
|
|
51693
51976
|
for (const name of Object.keys(zip.files)) {
|
|
51694
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
51977
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path29.default.isAbsolute(name)) {
|
|
51695
51978
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
51696
51979
|
}
|
|
51697
51980
|
}
|
|
@@ -51724,33 +52007,33 @@ async function importZip(buf, root) {
|
|
|
51724
52007
|
);
|
|
51725
52008
|
}
|
|
51726
52009
|
}
|
|
51727
|
-
const destDir =
|
|
52010
|
+
const destDir = import_node_path29.default.join(root, manifest.id);
|
|
51728
52011
|
let destExists = false;
|
|
51729
52012
|
try {
|
|
51730
|
-
await
|
|
52013
|
+
await import_promises4.default.access(destDir);
|
|
51731
52014
|
destExists = true;
|
|
51732
52015
|
} catch {
|
|
51733
52016
|
}
|
|
51734
52017
|
if (destExists) {
|
|
51735
52018
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
51736
52019
|
}
|
|
51737
|
-
const stage = await
|
|
52020
|
+
const stage = await import_promises4.default.mkdtemp(import_node_path29.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
51738
52021
|
try {
|
|
51739
52022
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
51740
|
-
const dest =
|
|
52023
|
+
const dest = import_node_path29.default.join(stage, name);
|
|
51741
52024
|
if (entry.dir) {
|
|
51742
|
-
await
|
|
52025
|
+
await import_promises4.default.mkdir(dest, { recursive: true });
|
|
51743
52026
|
continue;
|
|
51744
52027
|
}
|
|
51745
|
-
await
|
|
52028
|
+
await import_promises4.default.mkdir(import_node_path29.default.dirname(dest), { recursive: true });
|
|
51746
52029
|
const content = await entry.async("nodebuffer");
|
|
51747
|
-
await
|
|
52030
|
+
await import_promises4.default.writeFile(dest, content);
|
|
51748
52031
|
}
|
|
51749
|
-
await
|
|
51750
|
-
await
|
|
52032
|
+
await import_promises4.default.mkdir(root, { recursive: true });
|
|
52033
|
+
await import_promises4.default.rename(stage, destDir);
|
|
51751
52034
|
return { extId: manifest.id };
|
|
51752
52035
|
} catch (e) {
|
|
51753
|
-
await
|
|
52036
|
+
await import_promises4.default.rm(stage, { recursive: true, force: true }).catch(() => {
|
|
51754
52037
|
});
|
|
51755
52038
|
throw e;
|
|
51756
52039
|
}
|
|
@@ -51773,7 +52056,7 @@ var SHARE_UI_ASSET_MIME = {
|
|
|
51773
52056
|
".wasm": "application/wasm"
|
|
51774
52057
|
};
|
|
51775
52058
|
function shareUiAssetMime(filePath) {
|
|
51776
|
-
const ext =
|
|
52059
|
+
const ext = import_node_path30.default.extname(filePath).toLowerCase();
|
|
51777
52060
|
return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
|
|
51778
52061
|
}
|
|
51779
52062
|
var DISPATCH_HEARTBEAT_MS = 25e3;
|
|
@@ -51860,7 +52143,7 @@ function isValidUploadFileName(fileName) {
|
|
|
51860
52143
|
if (fileName === "." || fileName === "..") return false;
|
|
51861
52144
|
if (fileName.startsWith(".")) return false;
|
|
51862
52145
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
51863
|
-
return fileName ===
|
|
52146
|
+
return fileName === import_node_path30.default.basename(fileName);
|
|
51864
52147
|
}
|
|
51865
52148
|
function createHttpRouter(deps) {
|
|
51866
52149
|
return async (req, res) => {
|
|
@@ -52156,7 +52439,7 @@ function createHttpRouter(deps) {
|
|
|
52156
52439
|
sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
|
|
52157
52440
|
return true;
|
|
52158
52441
|
}
|
|
52159
|
-
sendHtml(res, 200, loader.renderViewerHtml(
|
|
52442
|
+
sendHtml(res, 200, loader.renderViewerHtml(import_node_path30.default.basename(r.absPath)));
|
|
52160
52443
|
return true;
|
|
52161
52444
|
}
|
|
52162
52445
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
@@ -52277,7 +52560,7 @@ function createHttpRouter(deps) {
|
|
|
52277
52560
|
return true;
|
|
52278
52561
|
}
|
|
52279
52562
|
let absPath;
|
|
52280
|
-
if (
|
|
52563
|
+
if (import_node_path30.default.isAbsolute(pathParam)) {
|
|
52281
52564
|
absPath = pathParam;
|
|
52282
52565
|
} else if (deps.sessionStore) {
|
|
52283
52566
|
const file = deps.sessionStore.read(sid);
|
|
@@ -52285,7 +52568,7 @@ function createHttpRouter(deps) {
|
|
|
52285
52568
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
52286
52569
|
return true;
|
|
52287
52570
|
}
|
|
52288
|
-
absPath =
|
|
52571
|
+
absPath = import_node_path30.default.join(file.cwd, pathParam);
|
|
52289
52572
|
} else {
|
|
52290
52573
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
52291
52574
|
return true;
|
|
@@ -52387,7 +52670,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52387
52670
|
return;
|
|
52388
52671
|
}
|
|
52389
52672
|
const mime = lookupMime(absPath);
|
|
52390
|
-
const basename =
|
|
52673
|
+
const basename = import_node_path30.default.basename(absPath);
|
|
52391
52674
|
res.writeHead(200, {
|
|
52392
52675
|
"Content-Type": mime,
|
|
52393
52676
|
"Content-Length": String(stat.size),
|
|
@@ -52405,7 +52688,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52405
52688
|
|
|
52406
52689
|
// src/attachment/gc.ts
|
|
52407
52690
|
var import_node_fs30 = __toESM(require("fs"), 1);
|
|
52408
|
-
var
|
|
52691
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
52409
52692
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
52410
52693
|
function runAttachmentGc(args) {
|
|
52411
52694
|
const now = (args.now ?? Date.now)();
|
|
@@ -52414,17 +52697,17 @@ function runAttachmentGc(args) {
|
|
|
52414
52697
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52415
52698
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
52416
52699
|
if (entry.stale) continue;
|
|
52417
|
-
if (
|
|
52700
|
+
if (import_node_path31.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
52418
52701
|
}
|
|
52419
52702
|
}
|
|
52420
52703
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52421
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
52704
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path31.default.join(
|
|
52422
52705
|
args.dataDir,
|
|
52423
52706
|
"sessions",
|
|
52424
52707
|
...scopeSubPath(scope).map(safeFileName),
|
|
52425
52708
|
safeFileName(sessionId)
|
|
52426
52709
|
);
|
|
52427
|
-
const attRoot =
|
|
52710
|
+
const attRoot = import_node_path31.default.join(sessionDir, ".attachments");
|
|
52428
52711
|
let hashDirs;
|
|
52429
52712
|
try {
|
|
52430
52713
|
hashDirs = import_node_fs30.default.readdirSync(attRoot);
|
|
@@ -52434,7 +52717,7 @@ function runAttachmentGc(args) {
|
|
|
52434
52717
|
continue;
|
|
52435
52718
|
}
|
|
52436
52719
|
for (const hashDir of hashDirs) {
|
|
52437
|
-
const hashDirAbs =
|
|
52720
|
+
const hashDirAbs = import_node_path31.default.join(attRoot, hashDir);
|
|
52438
52721
|
let files;
|
|
52439
52722
|
try {
|
|
52440
52723
|
files = import_node_fs30.default.readdirSync(hashDirAbs);
|
|
@@ -52442,7 +52725,7 @@ function runAttachmentGc(args) {
|
|
|
52442
52725
|
continue;
|
|
52443
52726
|
}
|
|
52444
52727
|
for (const name of files) {
|
|
52445
|
-
const file =
|
|
52728
|
+
const file = import_node_path31.default.join(hashDirAbs, name);
|
|
52446
52729
|
let stat;
|
|
52447
52730
|
try {
|
|
52448
52731
|
stat = import_node_fs30.default.statSync(file);
|
|
@@ -52473,7 +52756,7 @@ function runAttachmentGc(args) {
|
|
|
52473
52756
|
|
|
52474
52757
|
// src/attachment/group.ts
|
|
52475
52758
|
var import_node_fs31 = __toESM(require("fs"), 1);
|
|
52476
|
-
var
|
|
52759
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
52477
52760
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
52478
52761
|
init_protocol();
|
|
52479
52762
|
var GroupFileStore = class {
|
|
@@ -52485,11 +52768,11 @@ var GroupFileStore = class {
|
|
|
52485
52768
|
this.logger = opts.logger;
|
|
52486
52769
|
}
|
|
52487
52770
|
rootForScope(scope) {
|
|
52488
|
-
return
|
|
52771
|
+
return import_node_path32.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
52489
52772
|
}
|
|
52490
52773
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
52491
52774
|
filePath(scope, sessionId) {
|
|
52492
|
-
return
|
|
52775
|
+
return import_node_path32.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
52493
52776
|
}
|
|
52494
52777
|
cacheKey(scope, sessionId) {
|
|
52495
52778
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -52524,7 +52807,7 @@ var GroupFileStore = class {
|
|
|
52524
52807
|
}
|
|
52525
52808
|
writeFile(scope, sessionId, entries) {
|
|
52526
52809
|
const file = this.filePath(scope, sessionId);
|
|
52527
|
-
import_node_fs31.default.mkdirSync(
|
|
52810
|
+
import_node_fs31.default.mkdirSync(import_node_path32.default.dirname(file), { recursive: true });
|
|
52528
52811
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
52529
52812
|
import_node_fs31.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
52530
52813
|
import_node_fs31.default.renameSync(tmp, file);
|
|
@@ -52614,9 +52897,9 @@ var GroupFileStore = class {
|
|
|
52614
52897
|
|
|
52615
52898
|
// src/discovery/state-file.ts
|
|
52616
52899
|
var import_node_fs32 = __toESM(require("fs"), 1);
|
|
52617
|
-
var
|
|
52900
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
52618
52901
|
function defaultStateFilePath(dataDir) {
|
|
52619
|
-
return
|
|
52902
|
+
return import_node_path33.default.join(dataDir, "state.json");
|
|
52620
52903
|
}
|
|
52621
52904
|
function isPidAlive(pid) {
|
|
52622
52905
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -52652,7 +52935,7 @@ var StateFileManager = class {
|
|
|
52652
52935
|
return { status: "stale", existing };
|
|
52653
52936
|
}
|
|
52654
52937
|
write(state) {
|
|
52655
|
-
import_node_fs32.default.mkdirSync(
|
|
52938
|
+
import_node_fs32.default.mkdirSync(import_node_path33.default.dirname(this.file), { recursive: true });
|
|
52656
52939
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
52657
52940
|
import_node_fs32.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
52658
52941
|
import_node_fs32.default.renameSync(tmp, this.file);
|
|
@@ -52680,13 +52963,13 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
|
|
|
52680
52963
|
|
|
52681
52964
|
// src/tunnel/tunnel-manager.ts
|
|
52682
52965
|
var import_node_fs36 = __toESM(require("fs"), 1);
|
|
52683
|
-
var
|
|
52966
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
52684
52967
|
var import_node_crypto10 = __toESM(require("crypto"), 1);
|
|
52685
52968
|
var import_node_child_process9 = require("child_process");
|
|
52686
52969
|
|
|
52687
52970
|
// src/tunnel/tunnel-store.ts
|
|
52688
52971
|
var import_node_fs33 = __toESM(require("fs"), 1);
|
|
52689
|
-
var
|
|
52972
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
52690
52973
|
var TunnelStore = class {
|
|
52691
52974
|
constructor(filePath) {
|
|
52692
52975
|
this.filePath = filePath;
|
|
@@ -52705,7 +52988,7 @@ var TunnelStore = class {
|
|
|
52705
52988
|
}
|
|
52706
52989
|
}
|
|
52707
52990
|
async set(v2) {
|
|
52708
|
-
const dir =
|
|
52991
|
+
const dir = import_node_path34.default.dirname(this.filePath);
|
|
52709
52992
|
await import_node_fs33.default.promises.mkdir(dir, { recursive: true });
|
|
52710
52993
|
const data = JSON.stringify(v2, null, 2);
|
|
52711
52994
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
@@ -52817,10 +53100,10 @@ function escape(v2) {
|
|
|
52817
53100
|
// src/tunnel/frpc-binary.ts
|
|
52818
53101
|
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
52819
53102
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
52820
|
-
var
|
|
53103
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
52821
53104
|
var import_node_child_process7 = require("child_process");
|
|
52822
53105
|
var import_node_stream3 = require("stream");
|
|
52823
|
-
var
|
|
53106
|
+
var import_promises5 = require("stream/promises");
|
|
52824
53107
|
var FRPC_VERSION = "0.68.0";
|
|
52825
53108
|
var UnsupportedPlatformError = class extends Error {
|
|
52826
53109
|
constructor(platform, arch) {
|
|
@@ -52856,13 +53139,13 @@ async function ensureFrpcBinary(opts) {
|
|
|
52856
53139
|
}
|
|
52857
53140
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
52858
53141
|
const platform = opts.platform ?? detectPlatform();
|
|
52859
|
-
const binDir =
|
|
53142
|
+
const binDir = import_node_path35.default.join(opts.dataDir, "bin");
|
|
52860
53143
|
import_node_fs34.default.mkdirSync(binDir, { recursive: true });
|
|
52861
53144
|
cleanupStaleArtifacts(binDir);
|
|
52862
|
-
const stableBin =
|
|
53145
|
+
const stableBin = import_node_path35.default.join(binDir, "frpc");
|
|
52863
53146
|
if (import_node_fs34.default.existsSync(stableBin)) return stableBin;
|
|
52864
53147
|
const partialBin = `${stableBin}.partial`;
|
|
52865
|
-
const tarballPath =
|
|
53148
|
+
const tarballPath = import_node_path35.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
52866
53149
|
try {
|
|
52867
53150
|
const url = frpcDownloadUrl(version2, platform);
|
|
52868
53151
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -52888,7 +53171,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
52888
53171
|
}
|
|
52889
53172
|
for (const name of entries) {
|
|
52890
53173
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
52891
|
-
const full =
|
|
53174
|
+
const full = import_node_path35.default.join(binDir, name);
|
|
52892
53175
|
try {
|
|
52893
53176
|
import_node_fs34.default.rmSync(full, { recursive: true, force: true });
|
|
52894
53177
|
} catch {
|
|
@@ -52911,10 +53194,10 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
52911
53194
|
}
|
|
52912
53195
|
const out = import_node_fs34.default.createWriteStream(dest);
|
|
52913
53196
|
const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
|
|
52914
|
-
await (0,
|
|
53197
|
+
await (0, import_promises5.pipeline)(nodeStream, out);
|
|
52915
53198
|
}
|
|
52916
53199
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
52917
|
-
const work =
|
|
53200
|
+
const work = import_node_path35.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
52918
53201
|
import_node_fs34.default.mkdirSync(work, { recursive: true });
|
|
52919
53202
|
try {
|
|
52920
53203
|
await new Promise((resolve6, reject) => {
|
|
@@ -52923,7 +53206,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
52923
53206
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
52924
53207
|
});
|
|
52925
53208
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
52926
|
-
const src =
|
|
53209
|
+
const src = import_node_path35.default.join(work, dirName, "frpc");
|
|
52927
53210
|
if (!import_node_fs34.default.existsSync(src)) {
|
|
52928
53211
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
52929
53212
|
}
|
|
@@ -52935,10 +53218,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
52935
53218
|
|
|
52936
53219
|
// src/tunnel/frpc-process.ts
|
|
52937
53220
|
var import_node_fs35 = __toESM(require("fs"), 1);
|
|
52938
|
-
var
|
|
53221
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
52939
53222
|
var import_node_child_process8 = require("child_process");
|
|
52940
53223
|
function frpcPidFilePath(dataDir) {
|
|
52941
|
-
return
|
|
53224
|
+
return import_node_path36.default.join(dataDir, "frpc.pid");
|
|
52942
53225
|
}
|
|
52943
53226
|
function writeFrpcPid(dataDir, pid) {
|
|
52944
53227
|
try {
|
|
@@ -52980,7 +53263,7 @@ function defaultSleep(ms) {
|
|
|
52980
53263
|
}
|
|
52981
53264
|
async function killStaleFrpc(deps) {
|
|
52982
53265
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
52983
|
-
const tomlPath =
|
|
53266
|
+
const tomlPath = import_node_path36.default.join(deps.dataDir, "frpc.toml");
|
|
52984
53267
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
52985
53268
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
52986
53269
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -53052,7 +53335,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
53052
53335
|
var TunnelManager = class {
|
|
53053
53336
|
constructor(deps) {
|
|
53054
53337
|
this.deps = deps;
|
|
53055
|
-
this.store = deps.store ?? new TunnelStore(
|
|
53338
|
+
this.store = deps.store ?? new TunnelStore(import_node_path37.default.join(deps.dataDir, "tunnel.json"));
|
|
53056
53339
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
53057
53340
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
53058
53341
|
}
|
|
@@ -53179,7 +53462,7 @@ var TunnelManager = class {
|
|
|
53179
53462
|
dataDir: this.deps.dataDir,
|
|
53180
53463
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
53181
53464
|
});
|
|
53182
|
-
const tomlPath =
|
|
53465
|
+
const tomlPath = import_node_path37.default.join(this.deps.dataDir, "frpc.toml");
|
|
53183
53466
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
|
|
53184
53467
|
const toml = buildFrpcToml({
|
|
53185
53468
|
serverAddr: t.frpsHost,
|
|
@@ -53194,9 +53477,9 @@ var TunnelManager = class {
|
|
|
53194
53477
|
const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
|
|
53195
53478
|
stdio: ["ignore", "pipe", "pipe"]
|
|
53196
53479
|
});
|
|
53197
|
-
const logDir =
|
|
53480
|
+
const logDir = import_node_path37.default.join(this.deps.dataDir, "log");
|
|
53198
53481
|
import_node_fs36.default.mkdirSync(logDir, { recursive: true });
|
|
53199
|
-
const logFilePath =
|
|
53482
|
+
const logFilePath = import_node_path37.default.join(logDir, "frpc.log");
|
|
53200
53483
|
const logStream = import_node_fs36.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
53201
53484
|
logStream.on("error", () => {
|
|
53202
53485
|
});
|
|
@@ -53280,15 +53563,15 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
53280
53563
|
|
|
53281
53564
|
// src/tunnel/device-key.ts
|
|
53282
53565
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
53283
|
-
var
|
|
53566
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
53284
53567
|
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
53285
53568
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
53286
53569
|
function deriveStableDeviceKey(opts = {}) {
|
|
53287
53570
|
const hostname = opts.hostname ?? import_node_os14.default.hostname();
|
|
53288
53571
|
const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
|
|
53289
53572
|
const home = opts.home ?? import_node_os14.default.homedir();
|
|
53290
|
-
const defaultDataDir =
|
|
53291
|
-
const normalizedDataDir = opts.dataDir ?
|
|
53573
|
+
const defaultDataDir = import_node_path38.default.resolve(import_node_path38.default.join(home, ".clawd"));
|
|
53574
|
+
const normalizedDataDir = opts.dataDir ? import_node_path38.default.resolve(opts.dataDir) : null;
|
|
53292
53575
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
53293
53576
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
53294
53577
|
return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
@@ -53296,11 +53579,11 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
53296
53579
|
|
|
53297
53580
|
// src/auth-store.ts
|
|
53298
53581
|
var import_node_fs37 = __toESM(require("fs"), 1);
|
|
53299
|
-
var
|
|
53582
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
53300
53583
|
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
53301
53584
|
var AUTH_FILE_NAME = "auth.json";
|
|
53302
53585
|
function authFilePath(dataDir) {
|
|
53303
|
-
return
|
|
53586
|
+
return import_node_path39.default.join(dataDir, AUTH_FILE_NAME);
|
|
53304
53587
|
}
|
|
53305
53588
|
function loadOrCreateAuthFile(opts) {
|
|
53306
53589
|
const file = authFilePath(opts.dataDir);
|
|
@@ -53356,7 +53639,7 @@ function readAuthFile(file) {
|
|
|
53356
53639
|
}
|
|
53357
53640
|
}
|
|
53358
53641
|
function writeAuthFile(file, content) {
|
|
53359
|
-
import_node_fs37.default.mkdirSync(
|
|
53642
|
+
import_node_fs37.default.mkdirSync(import_node_path39.default.dirname(file), { recursive: true });
|
|
53360
53643
|
import_node_fs37.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
53361
53644
|
try {
|
|
53362
53645
|
import_node_fs37.default.chmodSync(file, 384);
|
|
@@ -53367,11 +53650,11 @@ function writeAuthFile(file, content) {
|
|
|
53367
53650
|
// src/owner-profile.ts
|
|
53368
53651
|
var import_node_fs38 = __toESM(require("fs"), 1);
|
|
53369
53652
|
var import_node_os15 = __toESM(require("os"), 1);
|
|
53370
|
-
var
|
|
53653
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
53371
53654
|
var PROFILE_FILENAME = "profile.json";
|
|
53372
53655
|
function loadOwnerDisplayName(dataDir) {
|
|
53373
53656
|
const fallback = import_node_os15.default.userInfo().username;
|
|
53374
|
-
const profilePath =
|
|
53657
|
+
const profilePath = import_node_path40.default.join(dataDir, PROFILE_FILENAME);
|
|
53375
53658
|
let raw;
|
|
53376
53659
|
try {
|
|
53377
53660
|
raw = import_node_fs38.default.readFileSync(profilePath, "utf8");
|
|
@@ -53398,12 +53681,12 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
53398
53681
|
|
|
53399
53682
|
// src/feishu-auth/owner-identity-store.ts
|
|
53400
53683
|
var import_node_fs39 = __toESM(require("fs"), 1);
|
|
53401
|
-
var
|
|
53684
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
53402
53685
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
53403
53686
|
var OwnerIdentityStore = class {
|
|
53404
53687
|
file;
|
|
53405
53688
|
constructor(dataDir) {
|
|
53406
|
-
this.file =
|
|
53689
|
+
this.file = import_node_path41.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
53407
53690
|
}
|
|
53408
53691
|
read() {
|
|
53409
53692
|
let raw;
|
|
@@ -53436,7 +53719,7 @@ var OwnerIdentityStore = class {
|
|
|
53436
53719
|
};
|
|
53437
53720
|
}
|
|
53438
53721
|
write(record) {
|
|
53439
|
-
import_node_fs39.default.mkdirSync(
|
|
53722
|
+
import_node_fs39.default.mkdirSync(import_node_path41.default.dirname(this.file), { recursive: true });
|
|
53440
53723
|
import_node_fs39.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
53441
53724
|
try {
|
|
53442
53725
|
import_node_fs39.default.chmodSync(this.file, 384);
|
|
@@ -53582,9 +53865,9 @@ var CentralClientError = class extends Error {
|
|
|
53582
53865
|
code;
|
|
53583
53866
|
cause;
|
|
53584
53867
|
};
|
|
53585
|
-
async function centralRequest(opts,
|
|
53868
|
+
async function centralRequest(opts, path71, init) {
|
|
53586
53869
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
53587
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
53870
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path71}`;
|
|
53588
53871
|
const ctrl = new AbortController();
|
|
53589
53872
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
53590
53873
|
let res;
|
|
@@ -53778,8 +54061,8 @@ function verifyConnectToken(args) {
|
|
|
53778
54061
|
}
|
|
53779
54062
|
|
|
53780
54063
|
// src/feishu-auth/server-key.ts
|
|
53781
|
-
var
|
|
53782
|
-
var
|
|
54064
|
+
var fs50 = __toESM(require("fs"), 1);
|
|
54065
|
+
var path50 = __toESM(require("path"), 1);
|
|
53783
54066
|
var FILE_NAME2 = "server-signing-key.json";
|
|
53784
54067
|
var ServerKeyStore = class {
|
|
53785
54068
|
constructor(dataDir) {
|
|
@@ -53787,12 +54070,12 @@ var ServerKeyStore = class {
|
|
|
53787
54070
|
}
|
|
53788
54071
|
dataDir;
|
|
53789
54072
|
filePath() {
|
|
53790
|
-
return
|
|
54073
|
+
return path50.join(this.dataDir, FILE_NAME2);
|
|
53791
54074
|
}
|
|
53792
54075
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
53793
54076
|
read() {
|
|
53794
54077
|
try {
|
|
53795
|
-
const raw =
|
|
54078
|
+
const raw = fs50.readFileSync(this.filePath(), "utf8");
|
|
53796
54079
|
const parsed = JSON.parse(raw);
|
|
53797
54080
|
if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
|
|
53798
54081
|
return parsed.publicKeyPem;
|
|
@@ -53807,12 +54090,12 @@ var ServerKeyStore = class {
|
|
|
53807
54090
|
publicKeyPem,
|
|
53808
54091
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
53809
54092
|
};
|
|
53810
|
-
|
|
53811
|
-
|
|
54093
|
+
fs50.mkdirSync(this.dataDir, { recursive: true });
|
|
54094
|
+
fs50.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
|
|
53812
54095
|
}
|
|
53813
54096
|
clear() {
|
|
53814
54097
|
try {
|
|
53815
|
-
|
|
54098
|
+
fs50.unlinkSync(this.filePath());
|
|
53816
54099
|
} catch {
|
|
53817
54100
|
}
|
|
53818
54101
|
}
|
|
@@ -53827,7 +54110,7 @@ init_protocol();
|
|
|
53827
54110
|
// src/session/fork.ts
|
|
53828
54111
|
var import_node_fs40 = __toESM(require("fs"), 1);
|
|
53829
54112
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
53830
|
-
var
|
|
54113
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
53831
54114
|
init_claude_history();
|
|
53832
54115
|
function readJsonlEntries(file) {
|
|
53833
54116
|
const raw = import_node_fs40.default.readFileSync(file, "utf8");
|
|
@@ -53843,19 +54126,19 @@ function readJsonlEntries(file) {
|
|
|
53843
54126
|
return out;
|
|
53844
54127
|
}
|
|
53845
54128
|
function forkSession(input) {
|
|
53846
|
-
const baseDir = input.baseDir ??
|
|
53847
|
-
let projectDir =
|
|
53848
|
-
let sourceFile =
|
|
54129
|
+
const baseDir = input.baseDir ?? import_node_path42.default.join(import_node_os16.default.homedir(), ".claude");
|
|
54130
|
+
let projectDir = import_node_path42.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
54131
|
+
let sourceFile = import_node_path42.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
53849
54132
|
if (!import_node_fs40.default.existsSync(sourceFile)) {
|
|
53850
54133
|
const found = findTranscriptByToolSessionId(
|
|
53851
|
-
|
|
54134
|
+
import_node_path42.default.join(baseDir, "projects"),
|
|
53852
54135
|
input.toolSessionId
|
|
53853
54136
|
);
|
|
53854
54137
|
if (!found) {
|
|
53855
54138
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
53856
54139
|
}
|
|
53857
54140
|
sourceFile = found;
|
|
53858
|
-
projectDir =
|
|
54141
|
+
projectDir = import_node_path42.default.dirname(found);
|
|
53859
54142
|
}
|
|
53860
54143
|
const entries = readJsonlEntries(sourceFile);
|
|
53861
54144
|
const mainEntries = entries.filter((e) => e.isSidechain !== true);
|
|
@@ -53884,7 +54167,7 @@ function forkSession(input) {
|
|
|
53884
54167
|
}
|
|
53885
54168
|
forkedLines.push(JSON.stringify(forked));
|
|
53886
54169
|
}
|
|
53887
|
-
const forkedFilePath =
|
|
54170
|
+
const forkedFilePath = import_node_path42.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
53888
54171
|
import_node_fs40.default.mkdirSync(projectDir, { recursive: true });
|
|
53889
54172
|
import_node_fs40.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
53890
54173
|
return { forkedToolSessionId, forkedFilePath };
|
|
@@ -54136,6 +54419,12 @@ function buildSessionHandlers(deps) {
|
|
|
54136
54419
|
const { response, broadcast } = manager.pin(args);
|
|
54137
54420
|
return { response: { type: "session:info", ...response }, broadcast };
|
|
54138
54421
|
};
|
|
54422
|
+
const markRead = async (frame, _client, ctx) => {
|
|
54423
|
+
const args = SessionIdArgs.parse(frame);
|
|
54424
|
+
ensureSessionAccess(ctx, args.sessionId, "send");
|
|
54425
|
+
const { response, broadcast } = manager.markRead(args);
|
|
54426
|
+
return { response: { type: "session:info", ...response }, broadcast };
|
|
54427
|
+
};
|
|
54139
54428
|
const reorderPins = async (frame) => {
|
|
54140
54429
|
const args = SessionReorderPinsArgs.parse(frame);
|
|
54141
54430
|
const { response, broadcast } = manager.reorderPins(args);
|
|
@@ -54251,6 +54540,7 @@ function buildSessionHandlers(deps) {
|
|
|
54251
54540
|
"session:subscribe": subscribe,
|
|
54252
54541
|
"session:unsubscribe": unsubscribe,
|
|
54253
54542
|
"session:pin": pin,
|
|
54543
|
+
"session:markRead": markRead,
|
|
54254
54544
|
"session:reorderPins": reorderPins,
|
|
54255
54545
|
"session:answerQuestion": answerQuestion,
|
|
54256
54546
|
"session:cancelQuestion": cancelQuestion,
|
|
@@ -54277,7 +54567,7 @@ function buildPermissionHandlers(deps) {
|
|
|
54277
54567
|
}
|
|
54278
54568
|
|
|
54279
54569
|
// src/handlers/history.ts
|
|
54280
|
-
var
|
|
54570
|
+
var path53 = __toESM(require("path"), 1);
|
|
54281
54571
|
init_protocol();
|
|
54282
54572
|
|
|
54283
54573
|
// src/session/recent-dirs.ts
|
|
@@ -54295,7 +54585,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
54295
54585
|
}
|
|
54296
54586
|
|
|
54297
54587
|
// src/permission/persona-paths.ts
|
|
54298
|
-
var
|
|
54588
|
+
var path52 = __toESM(require("path"), 1);
|
|
54299
54589
|
function getAllowedPersonaIds(grants, action) {
|
|
54300
54590
|
const ids = /* @__PURE__ */ new Set();
|
|
54301
54591
|
for (const g2 of grants) {
|
|
@@ -54308,42 +54598,42 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
54308
54598
|
return ids;
|
|
54309
54599
|
}
|
|
54310
54600
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
54311
|
-
const target =
|
|
54601
|
+
const target = path52.resolve(absPath);
|
|
54312
54602
|
if (userWorkDir) {
|
|
54313
|
-
const u =
|
|
54314
|
-
const usep = u.endsWith(
|
|
54603
|
+
const u = path52.resolve(userWorkDir);
|
|
54604
|
+
const usep = u.endsWith(path52.sep) ? "" : path52.sep;
|
|
54315
54605
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
54316
54606
|
}
|
|
54317
|
-
const root =
|
|
54318
|
-
const sep3 = root.endsWith(
|
|
54607
|
+
const root = path52.resolve(personaRoot);
|
|
54608
|
+
const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
|
|
54319
54609
|
if (!target.startsWith(root + sep3)) return false;
|
|
54320
|
-
const rel =
|
|
54610
|
+
const rel = path52.relative(root, target);
|
|
54321
54611
|
if (!rel || rel.startsWith("..")) return false;
|
|
54322
|
-
const personaId = rel.split(
|
|
54612
|
+
const personaId = rel.split(path52.sep)[0];
|
|
54323
54613
|
if (!personaId) return false;
|
|
54324
54614
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
54325
54615
|
if (allowed === "*") return true;
|
|
54326
54616
|
return allowed.has(personaId);
|
|
54327
54617
|
}
|
|
54328
54618
|
function personaIdFromPath(absPath, personaRoot) {
|
|
54329
|
-
const root =
|
|
54330
|
-
const target =
|
|
54331
|
-
const sep3 = root.endsWith(
|
|
54619
|
+
const root = path52.resolve(personaRoot);
|
|
54620
|
+
const target = path52.resolve(absPath);
|
|
54621
|
+
const sep3 = root.endsWith(path52.sep) ? "" : path52.sep;
|
|
54332
54622
|
if (!target.startsWith(root + sep3)) return null;
|
|
54333
|
-
const rel =
|
|
54623
|
+
const rel = path52.relative(root, target);
|
|
54334
54624
|
if (!rel || rel.startsWith("..")) return null;
|
|
54335
|
-
const id = rel.split(
|
|
54625
|
+
const id = rel.split(path52.sep)[0];
|
|
54336
54626
|
return id || null;
|
|
54337
54627
|
}
|
|
54338
54628
|
function isPathWithin(dir, absPath) {
|
|
54339
|
-
const d =
|
|
54340
|
-
const t =
|
|
54341
|
-
const sep3 = d.endsWith(
|
|
54629
|
+
const d = path52.resolve(dir);
|
|
54630
|
+
const t = path52.resolve(absPath);
|
|
54631
|
+
const sep3 = d.endsWith(path52.sep) ? "" : path52.sep;
|
|
54342
54632
|
return t === d || t.startsWith(d + sep3);
|
|
54343
54633
|
}
|
|
54344
54634
|
function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
|
|
54345
54635
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
54346
|
-
return personaIdFromPath(
|
|
54636
|
+
return personaIdFromPath(path52.resolve(absPath), personaRoot) === personaId;
|
|
54347
54637
|
}
|
|
54348
54638
|
|
|
54349
54639
|
// src/handlers/history.ts
|
|
@@ -54395,7 +54685,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54395
54685
|
if (!pid) return false;
|
|
54396
54686
|
return isGuestPathAllowed(
|
|
54397
54687
|
ctx.grants,
|
|
54398
|
-
|
|
54688
|
+
path53.join(personaRoot, pid),
|
|
54399
54689
|
personaRoot,
|
|
54400
54690
|
"read",
|
|
54401
54691
|
userWorkDir
|
|
@@ -54407,7 +54697,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54407
54697
|
};
|
|
54408
54698
|
const list = async (frame, _client, ctx) => {
|
|
54409
54699
|
const args = HistoryListArgs.parse(frame);
|
|
54410
|
-
assertGuestPath(ctx,
|
|
54700
|
+
assertGuestPath(ctx, path53.resolve(args.projectPath), personaRoot, "history:list");
|
|
54411
54701
|
const sessions = await history.listSessions(args);
|
|
54412
54702
|
return { response: { type: "history:list", sessions } };
|
|
54413
54703
|
};
|
|
@@ -54440,13 +54730,13 @@ function buildHistoryHandlers(deps) {
|
|
|
54440
54730
|
};
|
|
54441
54731
|
const subagents = async (frame, _client, ctx) => {
|
|
54442
54732
|
const args = HistorySubagentsArgs.parse(frame);
|
|
54443
|
-
assertGuestPath(ctx,
|
|
54733
|
+
assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
54444
54734
|
const subs = await history.listSubagents(args);
|
|
54445
54735
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
54446
54736
|
};
|
|
54447
54737
|
const subagentRead = async (frame, _client, ctx) => {
|
|
54448
54738
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
54449
|
-
assertGuestPath(ctx,
|
|
54739
|
+
assertGuestPath(ctx, path53.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
54450
54740
|
const res = await history.readSubagent(args);
|
|
54451
54741
|
return { response: { type: "history:subagent-read", ...res } };
|
|
54452
54742
|
};
|
|
@@ -54455,7 +54745,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54455
54745
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
54456
54746
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
54457
54747
|
const filtered = dirs.filter(
|
|
54458
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
54748
|
+
(d) => isGuestPathAllowed(ctx.grants, path53.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
54459
54749
|
);
|
|
54460
54750
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
54461
54751
|
}
|
|
@@ -54472,7 +54762,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54472
54762
|
}
|
|
54473
54763
|
|
|
54474
54764
|
// src/handlers/workspace.ts
|
|
54475
|
-
var
|
|
54765
|
+
var path54 = __toESM(require("path"), 1);
|
|
54476
54766
|
var os16 = __toESM(require("os"), 1);
|
|
54477
54767
|
init_protocol();
|
|
54478
54768
|
init_protocol();
|
|
@@ -54514,22 +54804,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54514
54804
|
const args = WorkspaceListArgs.parse(frame);
|
|
54515
54805
|
const isGuest = ctx?.principal.kind === "guest";
|
|
54516
54806
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
|
|
54517
|
-
const resolvedCwd =
|
|
54518
|
-
const target = args.path ?
|
|
54807
|
+
const resolvedCwd = path54.resolve(args.cwd ?? fallbackCwd);
|
|
54808
|
+
const target = args.path ? path54.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
54519
54809
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
54520
54810
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
54521
54811
|
return { response: { type: "workspace:list", ...res } };
|
|
54522
54812
|
};
|
|
54523
54813
|
const read = async (frame, _client, ctx) => {
|
|
54524
54814
|
const args = WorkspaceReadArgs.parse(frame);
|
|
54525
|
-
const target =
|
|
54815
|
+
const target = path54.isAbsolute(args.path) ? path54.resolve(args.path) : path54.resolve(args.cwd, args.path);
|
|
54526
54816
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
54527
54817
|
const res = workspace.read(args);
|
|
54528
54818
|
return { response: { type: "workspace:read", ...res } };
|
|
54529
54819
|
};
|
|
54530
54820
|
const skillsList = async (frame, _client, ctx) => {
|
|
54531
54821
|
const args = SkillsListArgs.parse(frame);
|
|
54532
|
-
const cwdAbs =
|
|
54822
|
+
const cwdAbs = path54.resolve(args.cwd);
|
|
54533
54823
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
54534
54824
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
54535
54825
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -54541,7 +54831,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54541
54831
|
};
|
|
54542
54832
|
const agentsList = async (frame, _client, ctx) => {
|
|
54543
54833
|
const args = AgentsListArgs.parse(frame);
|
|
54544
|
-
const cwdAbs =
|
|
54834
|
+
const cwdAbs = path54.resolve(args.cwd);
|
|
54545
54835
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
54546
54836
|
if (args.tool === "codex") {
|
|
54547
54837
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -54563,18 +54853,18 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54563
54853
|
}
|
|
54564
54854
|
|
|
54565
54855
|
// src/handlers/git.ts
|
|
54566
|
-
var
|
|
54856
|
+
var path56 = __toESM(require("path"), 1);
|
|
54567
54857
|
init_protocol();
|
|
54568
54858
|
init_protocol();
|
|
54569
54859
|
|
|
54570
54860
|
// src/workspace/git.ts
|
|
54571
54861
|
var import_node_child_process10 = require("child_process");
|
|
54572
54862
|
var import_node_fs41 = __toESM(require("fs"), 1);
|
|
54573
|
-
var
|
|
54863
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
54574
54864
|
var import_node_util = require("util");
|
|
54575
54865
|
var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
|
|
54576
54866
|
function normalizePath(p2) {
|
|
54577
|
-
const resolved =
|
|
54867
|
+
const resolved = import_node_path43.default.resolve(p2);
|
|
54578
54868
|
try {
|
|
54579
54869
|
return import_node_fs41.default.realpathSync(resolved);
|
|
54580
54870
|
} catch {
|
|
@@ -54650,7 +54940,7 @@ async function listGitBranches(cwd) {
|
|
|
54650
54940
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
54651
54941
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
54652
54942
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
54653
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
54943
|
+
if (!isGuestPathAllowed(ctx.grants, path56.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
54654
54944
|
throw new ClawdError(
|
|
54655
54945
|
ERROR_CODES.UNAUTHORIZED,
|
|
54656
54946
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -55336,7 +55626,7 @@ function buildPersonaHandlers(deps) {
|
|
|
55336
55626
|
}
|
|
55337
55627
|
|
|
55338
55628
|
// src/handlers/attachment.ts
|
|
55339
|
-
var
|
|
55629
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
55340
55630
|
init_protocol();
|
|
55341
55631
|
init_protocol();
|
|
55342
55632
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -55416,12 +55706,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
55416
55706
|
`session ${args.sessionId} scope unresolved`
|
|
55417
55707
|
);
|
|
55418
55708
|
}
|
|
55419
|
-
const cwdAbs =
|
|
55420
|
-
const candidateAbs =
|
|
55709
|
+
const cwdAbs = import_node_path44.default.resolve(sessionFile.cwd);
|
|
55710
|
+
const candidateAbs = import_node_path44.default.isAbsolute(args.relPath) ? import_node_path44.default.resolve(args.relPath) : import_node_path44.default.resolve(cwdAbs, args.relPath);
|
|
55421
55711
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
|
|
55422
55712
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
55423
55713
|
const entry = entries.find((e) => {
|
|
55424
|
-
const storedAbs =
|
|
55714
|
+
const storedAbs = import_node_path44.default.isAbsolute(e.relPath) ? import_node_path44.default.resolve(e.relPath) : import_node_path44.default.resolve(cwdAbs, e.relPath);
|
|
55425
55715
|
return storedAbs === candidateAbs && !e.stale;
|
|
55426
55716
|
});
|
|
55427
55717
|
if (!entry) {
|
|
@@ -55446,7 +55736,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
55446
55736
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
55447
55737
|
const f = deps.sessionStore.read(sessionId);
|
|
55448
55738
|
if (!f) return;
|
|
55449
|
-
assertGuestAttachmentPath(ctx,
|
|
55739
|
+
assertGuestAttachmentPath(ctx, import_node_path44.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
55450
55740
|
}
|
|
55451
55741
|
const groupAdd = async (frame, _client, ctx) => {
|
|
55452
55742
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -55461,8 +55751,8 @@ function buildAttachmentHandlers(deps) {
|
|
|
55461
55751
|
if (!scope) {
|
|
55462
55752
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
|
|
55463
55753
|
}
|
|
55464
|
-
const cwdAbs =
|
|
55465
|
-
const candidateAbs =
|
|
55754
|
+
const cwdAbs = import_node_path44.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
|
|
55755
|
+
const candidateAbs = import_node_path44.default.isAbsolute(args.relPath) ? import_node_path44.default.resolve(args.relPath) : import_node_path44.default.resolve(cwdAbs, args.relPath);
|
|
55466
55756
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
|
|
55467
55757
|
const from = ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
55468
55758
|
const size = 0;
|
|
@@ -55520,21 +55810,21 @@ function buildAttachmentHandlers(deps) {
|
|
|
55520
55810
|
}
|
|
55521
55811
|
|
|
55522
55812
|
// src/handlers/extension.ts
|
|
55523
|
-
var
|
|
55524
|
-
var
|
|
55813
|
+
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
55814
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
55525
55815
|
init_protocol();
|
|
55526
55816
|
|
|
55527
55817
|
// src/extension/bundle-zip.ts
|
|
55528
|
-
var
|
|
55529
|
-
var
|
|
55818
|
+
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
55819
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
55530
55820
|
var import_node_crypto14 = __toESM(require("crypto"), 1);
|
|
55531
55821
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
55532
55822
|
async function bundleExtensionDir(dir) {
|
|
55533
55823
|
const entries = await listFilesSorted(dir);
|
|
55534
55824
|
const zip = new import_jszip2.default();
|
|
55535
55825
|
for (const rel of entries) {
|
|
55536
|
-
const abs =
|
|
55537
|
-
const content = await
|
|
55826
|
+
const abs = import_node_path45.default.join(dir, rel);
|
|
55827
|
+
const content = await import_promises6.default.readFile(abs);
|
|
55538
55828
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
55539
55829
|
}
|
|
55540
55830
|
const buffer = await zip.generateAsync({
|
|
@@ -55554,8 +55844,8 @@ async function listFilesSorted(rootDir) {
|
|
|
55554
55844
|
return out;
|
|
55555
55845
|
}
|
|
55556
55846
|
async function walk(absRoot, relPrefix, out) {
|
|
55557
|
-
const dirAbs =
|
|
55558
|
-
const entries = await
|
|
55847
|
+
const dirAbs = import_node_path45.default.join(absRoot, relPrefix);
|
|
55848
|
+
const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
|
|
55559
55849
|
for (const e of entries) {
|
|
55560
55850
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
55561
55851
|
const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
|
|
@@ -55607,26 +55897,26 @@ function computePublishCheck(args) {
|
|
|
55607
55897
|
}
|
|
55608
55898
|
|
|
55609
55899
|
// src/extension/install-flow.ts
|
|
55610
|
-
var
|
|
55611
|
-
var
|
|
55900
|
+
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
55901
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
55612
55902
|
var import_node_os19 = __toESM(require("os"), 1);
|
|
55613
55903
|
var import_node_crypto15 = __toESM(require("crypto"), 1);
|
|
55614
55904
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
55615
55905
|
|
|
55616
55906
|
// src/extension/paths.ts
|
|
55617
55907
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
55618
|
-
var
|
|
55908
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
55619
55909
|
function clawdHomeRoot(override) {
|
|
55620
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
55910
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path46.default.join(import_node_os18.default.homedir(), ".clawd");
|
|
55621
55911
|
}
|
|
55622
55912
|
function extensionsRoot(override) {
|
|
55623
|
-
return
|
|
55913
|
+
return import_node_path46.default.join(clawdHomeRoot(override), "extensions");
|
|
55624
55914
|
}
|
|
55625
55915
|
function publishedChannelsFile(override) {
|
|
55626
|
-
return
|
|
55916
|
+
return import_node_path46.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
55627
55917
|
}
|
|
55628
55918
|
function bundleCacheRoot(override) {
|
|
55629
|
-
return
|
|
55919
|
+
return import_node_path46.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
55630
55920
|
}
|
|
55631
55921
|
|
|
55632
55922
|
// src/extension/install-flow.ts
|
|
@@ -55653,7 +55943,7 @@ async function installFromChannel(args, deps) {
|
|
|
55653
55943
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
55654
55944
|
}
|
|
55655
55945
|
for (const name of Object.keys(zip.files)) {
|
|
55656
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
55946
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path47.default.isAbsolute(name)) {
|
|
55657
55947
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
55658
55948
|
}
|
|
55659
55949
|
}
|
|
@@ -55685,10 +55975,10 @@ async function installFromChannel(args, deps) {
|
|
|
55685
55975
|
);
|
|
55686
55976
|
}
|
|
55687
55977
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
55688
|
-
const destDir =
|
|
55978
|
+
const destDir = import_node_path47.default.join(deps.extensionsRoot, localExtId);
|
|
55689
55979
|
let destExists = false;
|
|
55690
55980
|
try {
|
|
55691
|
-
await
|
|
55981
|
+
await import_promises7.default.access(destDir);
|
|
55692
55982
|
destExists = true;
|
|
55693
55983
|
} catch {
|
|
55694
55984
|
}
|
|
@@ -55698,28 +55988,28 @@ async function installFromChannel(args, deps) {
|
|
|
55698
55988
|
`extension ${localExtId} already installed locally (from owner ${channelRef.ownerPrincipalId})`
|
|
55699
55989
|
);
|
|
55700
55990
|
}
|
|
55701
|
-
const stage = await
|
|
55702
|
-
|
|
55991
|
+
const stage = await import_promises7.default.mkdtemp(
|
|
55992
|
+
import_node_path47.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
55703
55993
|
);
|
|
55704
55994
|
try {
|
|
55705
55995
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
55706
|
-
const dest =
|
|
55996
|
+
const dest = import_node_path47.default.join(stage, name);
|
|
55707
55997
|
if (entry.dir) {
|
|
55708
|
-
await
|
|
55998
|
+
await import_promises7.default.mkdir(dest, { recursive: true });
|
|
55709
55999
|
continue;
|
|
55710
56000
|
}
|
|
55711
|
-
await
|
|
56001
|
+
await import_promises7.default.mkdir(import_node_path47.default.dirname(dest), { recursive: true });
|
|
55712
56002
|
if (name === "manifest.json") {
|
|
55713
56003
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
55714
|
-
await
|
|
56004
|
+
await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
55715
56005
|
} else {
|
|
55716
|
-
await
|
|
56006
|
+
await import_promises7.default.writeFile(dest, await entry.async("nodebuffer"));
|
|
55717
56007
|
}
|
|
55718
56008
|
}
|
|
55719
|
-
await
|
|
55720
|
-
await
|
|
56009
|
+
await import_promises7.default.mkdir(deps.extensionsRoot, { recursive: true });
|
|
56010
|
+
await import_promises7.default.rename(stage, destDir);
|
|
55721
56011
|
} catch (e) {
|
|
55722
|
-
await
|
|
56012
|
+
await import_promises7.default.rm(stage, { recursive: true, force: true }).catch(() => {
|
|
55723
56013
|
});
|
|
55724
56014
|
throw e;
|
|
55725
56015
|
}
|
|
@@ -55728,8 +56018,8 @@ async function installFromChannel(args, deps) {
|
|
|
55728
56018
|
}
|
|
55729
56019
|
|
|
55730
56020
|
// src/extension/update-flow.ts
|
|
55731
|
-
var
|
|
55732
|
-
var
|
|
56021
|
+
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
56022
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
55733
56023
|
var import_node_os20 = __toESM(require("os"), 1);
|
|
55734
56024
|
var import_node_crypto16 = __toESM(require("crypto"), 1);
|
|
55735
56025
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
@@ -55746,11 +56036,11 @@ async function updateFromChannel(args, deps) {
|
|
|
55746
56036
|
channelRef.extId,
|
|
55747
56037
|
channelRef.ownerPrincipalId
|
|
55748
56038
|
);
|
|
55749
|
-
const liveDir =
|
|
56039
|
+
const liveDir = import_node_path48.default.join(deps.extensionsRoot, localExtId);
|
|
55750
56040
|
const prevDir = `${liveDir}.prev`;
|
|
55751
56041
|
let existingVersion;
|
|
55752
56042
|
try {
|
|
55753
|
-
const raw = await
|
|
56043
|
+
const raw = await import_promises8.default.readFile(import_node_path48.default.join(liveDir, "manifest.json"), "utf8");
|
|
55754
56044
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
55755
56045
|
if (!parsed2.success) {
|
|
55756
56046
|
throw new UpdateError(
|
|
@@ -55783,7 +56073,7 @@ async function updateFromChannel(args, deps) {
|
|
|
55783
56073
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
55784
56074
|
}
|
|
55785
56075
|
for (const name of Object.keys(zip.files)) {
|
|
55786
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
56076
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path48.default.isAbsolute(name)) {
|
|
55787
56077
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
55788
56078
|
}
|
|
55789
56079
|
}
|
|
@@ -55815,31 +56105,31 @@ async function updateFromChannel(args, deps) {
|
|
|
55815
56105
|
);
|
|
55816
56106
|
}
|
|
55817
56107
|
await deps.runtime.close(localExtId);
|
|
55818
|
-
await
|
|
55819
|
-
await
|
|
55820
|
-
const stage = await
|
|
55821
|
-
|
|
56108
|
+
await import_promises8.default.rm(prevDir, { recursive: true, force: true });
|
|
56109
|
+
await import_promises8.default.rename(liveDir, prevDir);
|
|
56110
|
+
const stage = await import_promises8.default.mkdtemp(
|
|
56111
|
+
import_node_path48.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
55822
56112
|
);
|
|
55823
56113
|
try {
|
|
55824
56114
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
55825
|
-
const dest =
|
|
56115
|
+
const dest = import_node_path48.default.join(stage, name);
|
|
55826
56116
|
if (entry.dir) {
|
|
55827
|
-
await
|
|
56117
|
+
await import_promises8.default.mkdir(dest, { recursive: true });
|
|
55828
56118
|
continue;
|
|
55829
56119
|
}
|
|
55830
|
-
await
|
|
56120
|
+
await import_promises8.default.mkdir(import_node_path48.default.dirname(dest), { recursive: true });
|
|
55831
56121
|
if (name === "manifest.json") {
|
|
55832
56122
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
55833
|
-
await
|
|
56123
|
+
await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
55834
56124
|
} else {
|
|
55835
|
-
await
|
|
56125
|
+
await import_promises8.default.writeFile(dest, await entry.async("nodebuffer"));
|
|
55836
56126
|
}
|
|
55837
56127
|
}
|
|
55838
|
-
await
|
|
56128
|
+
await import_promises8.default.rename(stage, liveDir);
|
|
55839
56129
|
} catch (e) {
|
|
55840
|
-
await
|
|
56130
|
+
await import_promises8.default.rm(stage, { recursive: true, force: true }).catch(() => {
|
|
55841
56131
|
});
|
|
55842
|
-
await
|
|
56132
|
+
await import_promises8.default.rename(prevDir, liveDir).catch(() => {
|
|
55843
56133
|
});
|
|
55844
56134
|
await deps.runtime.open(localExtId).catch(() => {
|
|
55845
56135
|
});
|
|
@@ -55861,7 +56151,7 @@ async function updateFromChannel(args, deps) {
|
|
|
55861
56151
|
reason: e.message
|
|
55862
56152
|
};
|
|
55863
56153
|
}
|
|
55864
|
-
await
|
|
56154
|
+
await import_promises8.default.rm(prevDir, { recursive: true, force: true });
|
|
55865
56155
|
return {
|
|
55866
56156
|
kind: "updated",
|
|
55867
56157
|
extId: localExtId,
|
|
@@ -55869,9 +56159,9 @@ async function updateFromChannel(args, deps) {
|
|
|
55869
56159
|
};
|
|
55870
56160
|
}
|
|
55871
56161
|
async function rollback(deps, localExtId, liveDir, prevDir) {
|
|
55872
|
-
await
|
|
56162
|
+
await import_promises8.default.rm(liveDir, { recursive: true, force: true }).catch(() => {
|
|
55873
56163
|
});
|
|
55874
|
-
await
|
|
56164
|
+
await import_promises8.default.rename(prevDir, liveDir).catch(() => {
|
|
55875
56165
|
});
|
|
55876
56166
|
await deps.runtime.open(localExtId).catch(() => {
|
|
55877
56167
|
});
|
|
@@ -55920,18 +56210,18 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
55920
56210
|
);
|
|
55921
56211
|
}
|
|
55922
56212
|
}
|
|
55923
|
-
const manifestPath =
|
|
56213
|
+
const manifestPath = import_node_path49.default.join(root, extId, "manifest.json");
|
|
55924
56214
|
const manifest = await readManifest(root, extId);
|
|
55925
56215
|
const next = { ...manifest, version: newVersion };
|
|
55926
56216
|
const tmp = `${manifestPath}.tmp`;
|
|
55927
|
-
await
|
|
55928
|
-
await
|
|
56217
|
+
await import_promises9.default.writeFile(tmp, JSON.stringify(next, null, 2));
|
|
56218
|
+
await import_promises9.default.rename(tmp, manifestPath);
|
|
55929
56219
|
}
|
|
55930
56220
|
async function readManifest(root, extId) {
|
|
55931
|
-
const file =
|
|
56221
|
+
const file = import_node_path49.default.join(root, extId, "manifest.json");
|
|
55932
56222
|
let raw;
|
|
55933
56223
|
try {
|
|
55934
|
-
raw = await
|
|
56224
|
+
raw = await import_promises9.default.readFile(file, "utf8");
|
|
55935
56225
|
} catch (e) {
|
|
55936
56226
|
if (e.code === "ENOENT") {
|
|
55937
56227
|
throw new ClawdError(ERROR_CODES.INVALID_PARAM, `extension ${extId} not installed`);
|
|
@@ -56019,7 +56309,7 @@ function buildExtensionHandlers(deps) {
|
|
|
56019
56309
|
};
|
|
56020
56310
|
async function buildSnapshotMeta(extId) {
|
|
56021
56311
|
const manifest = await readManifest(deps.root, extId);
|
|
56022
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
56312
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path49.default.join(deps.root, extId));
|
|
56023
56313
|
return { manifest, contentHash: sha256, buffer };
|
|
56024
56314
|
}
|
|
56025
56315
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -56202,7 +56492,7 @@ function buildExtensionHandlers(deps) {
|
|
|
56202
56492
|
// src/app-builder/project-store.ts
|
|
56203
56493
|
var import_node_fs42 = require("fs");
|
|
56204
56494
|
var import_node_child_process11 = require("child_process");
|
|
56205
|
-
var
|
|
56495
|
+
var import_node_path50 = require("path");
|
|
56206
56496
|
init_protocol();
|
|
56207
56497
|
var PROJECTS_DIR = "projects";
|
|
56208
56498
|
var META_FILE = ".clawd-project.json";
|
|
@@ -56216,14 +56506,14 @@ var ProjectStore = class {
|
|
|
56216
56506
|
root;
|
|
56217
56507
|
/** projects/<name>/.clawd-project.json 路径 */
|
|
56218
56508
|
metaPath(name) {
|
|
56219
|
-
return (0,
|
|
56509
|
+
return (0, import_node_path50.join)(this.projectsRoot(), name, META_FILE);
|
|
56220
56510
|
}
|
|
56221
56511
|
/** projects/<name>/ 目录路径(cwd 用) */
|
|
56222
56512
|
projectDir(name) {
|
|
56223
|
-
return (0,
|
|
56513
|
+
return (0, import_node_path50.join)(this.projectsRoot(), name);
|
|
56224
56514
|
}
|
|
56225
56515
|
projectsRoot() {
|
|
56226
|
-
return (0,
|
|
56516
|
+
return (0, import_node_path50.join)(this.root, PROJECTS_DIR);
|
|
56227
56517
|
}
|
|
56228
56518
|
async list() {
|
|
56229
56519
|
let entries;
|
|
@@ -56526,7 +56816,7 @@ var PublishJobRegistry = class {
|
|
|
56526
56816
|
// src/app-builder/publish-job-runner.ts
|
|
56527
56817
|
var import_node_child_process13 = require("child_process");
|
|
56528
56818
|
var import_node_fs43 = require("fs");
|
|
56529
|
-
var
|
|
56819
|
+
var import_node_path51 = require("path");
|
|
56530
56820
|
|
|
56531
56821
|
// src/app-builder/publish-stage-parser.ts
|
|
56532
56822
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -56558,7 +56848,7 @@ async function startPublishJob(deps, args) {
|
|
|
56558
56848
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
56559
56849
|
}
|
|
56560
56850
|
const projDir = projectDir(args.name);
|
|
56561
|
-
const logPath = (0,
|
|
56851
|
+
const logPath = (0, import_node_path51.join)(projDir, ".publish.log");
|
|
56562
56852
|
let logStream = null;
|
|
56563
56853
|
try {
|
|
56564
56854
|
logStream = (0, import_node_fs43.createWriteStream)(logPath, { flags: "w" });
|
|
@@ -56818,7 +57108,7 @@ async function recoverInterruptedJobs(deps) {
|
|
|
56818
57108
|
|
|
56819
57109
|
// src/handlers/app-builder.ts
|
|
56820
57110
|
init_protocol();
|
|
56821
|
-
var
|
|
57111
|
+
var import_node_path52 = require("path");
|
|
56822
57112
|
var import_node_fs44 = require("fs");
|
|
56823
57113
|
var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
|
|
56824
57114
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
@@ -56976,8 +57266,8 @@ function buildAppBuilderHandlers(deps) {
|
|
|
56976
57266
|
const project = await userStore.create(f.name, reservedPorts);
|
|
56977
57267
|
try {
|
|
56978
57268
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
|
|
56979
|
-
const templateSrcDir = (0,
|
|
56980
|
-
const scaffoldScript = (0,
|
|
57269
|
+
const templateSrcDir = (0, import_node_path52.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
|
|
57270
|
+
const scaffoldScript = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
|
|
56981
57271
|
const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
|
|
56982
57272
|
deps.logger?.info("app-builder.scaffold.done", {
|
|
56983
57273
|
name: project.name,
|
|
@@ -57198,7 +57488,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57198
57488
|
await userStore.clearPublishJob(args.name);
|
|
57199
57489
|
}
|
|
57200
57490
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
|
|
57201
|
-
const scriptPath = (0,
|
|
57491
|
+
const scriptPath = (0, import_node_path52.join)(deps.deployKitRoot, "scripts", "publish.sh");
|
|
57202
57492
|
deps.logger?.info("app-builder.publish.start", {
|
|
57203
57493
|
name: args.name,
|
|
57204
57494
|
sessionId: boundSession.sessionId,
|
|
@@ -57373,12 +57663,12 @@ function buildVisitorHandlers(deps) {
|
|
|
57373
57663
|
}
|
|
57374
57664
|
|
|
57375
57665
|
// src/extension/registry.ts
|
|
57376
|
-
var
|
|
57377
|
-
var
|
|
57666
|
+
var import_promises10 = __toESM(require("fs/promises"), 1);
|
|
57667
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
57378
57668
|
async function loadAll(root) {
|
|
57379
57669
|
let entries;
|
|
57380
57670
|
try {
|
|
57381
|
-
entries = await
|
|
57671
|
+
entries = await import_promises10.default.readdir(root, { withFileTypes: true });
|
|
57382
57672
|
} catch (e) {
|
|
57383
57673
|
if (e.code === "ENOENT") return [];
|
|
57384
57674
|
throw e;
|
|
@@ -57387,16 +57677,16 @@ async function loadAll(root) {
|
|
|
57387
57677
|
for (const ent of entries) {
|
|
57388
57678
|
if (!ent.isDirectory()) continue;
|
|
57389
57679
|
if (ent.name.startsWith(".")) continue;
|
|
57390
|
-
records.push(await loadOne(
|
|
57680
|
+
records.push(await loadOne(import_node_path53.default.join(root, ent.name), ent.name));
|
|
57391
57681
|
}
|
|
57392
57682
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
57393
57683
|
return records;
|
|
57394
57684
|
}
|
|
57395
57685
|
async function loadOne(dir, dirName) {
|
|
57396
|
-
const manifestPath =
|
|
57686
|
+
const manifestPath = import_node_path53.default.join(dir, "manifest.json");
|
|
57397
57687
|
let raw;
|
|
57398
57688
|
try {
|
|
57399
|
-
raw = await
|
|
57689
|
+
raw = await import_promises10.default.readFile(manifestPath, "utf8");
|
|
57400
57690
|
} catch {
|
|
57401
57691
|
return {
|
|
57402
57692
|
extId: dirName,
|
|
@@ -57437,8 +57727,8 @@ async function loadOne(dir, dirName) {
|
|
|
57437
57727
|
}
|
|
57438
57728
|
|
|
57439
57729
|
// src/extension/uninstall.ts
|
|
57440
|
-
var
|
|
57441
|
-
var
|
|
57730
|
+
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
57731
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
57442
57732
|
var UninstallError = class extends Error {
|
|
57443
57733
|
constructor(code, message) {
|
|
57444
57734
|
super(message);
|
|
@@ -57447,14 +57737,14 @@ var UninstallError = class extends Error {
|
|
|
57447
57737
|
code;
|
|
57448
57738
|
};
|
|
57449
57739
|
async function uninstall(deps) {
|
|
57450
|
-
const dir =
|
|
57740
|
+
const dir = import_node_path54.default.join(deps.root, deps.extId);
|
|
57451
57741
|
try {
|
|
57452
|
-
await
|
|
57742
|
+
await import_promises11.default.access(dir);
|
|
57453
57743
|
} catch {
|
|
57454
57744
|
throw new UninstallError("NOT_FOUND", `extension ${deps.extId} not installed`);
|
|
57455
57745
|
}
|
|
57456
57746
|
await deps.runtime.close(deps.extId);
|
|
57457
|
-
await
|
|
57747
|
+
await import_promises11.default.rm(dir, { recursive: true, force: true });
|
|
57458
57748
|
}
|
|
57459
57749
|
|
|
57460
57750
|
// src/handlers/index.ts
|
|
@@ -58007,6 +58297,7 @@ var METHOD_GRANT_MAP = {
|
|
|
58007
58297
|
"session:subscribe": CAPABILITY_SCOPED,
|
|
58008
58298
|
"session:unsubscribe": CAPABILITY_SCOPED,
|
|
58009
58299
|
"session:pin": CAPABILITY_SCOPED,
|
|
58300
|
+
"session:markRead": CAPABILITY_SCOPED,
|
|
58010
58301
|
"session:reorderPins": ADMIN_ANY,
|
|
58011
58302
|
// owner 全局操作,无 personaId 维度
|
|
58012
58303
|
// mirror peer sessions (2026-05-26):owner-only — guest 不应能写/删本机 mirror SessionFile
|
|
@@ -58166,8 +58457,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
|
|
|
58166
58457
|
|
|
58167
58458
|
// src/extension/runtime.ts
|
|
58168
58459
|
var import_node_child_process16 = require("child_process");
|
|
58169
|
-
var
|
|
58170
|
-
var
|
|
58460
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
58461
|
+
var import_promises12 = require("timers/promises");
|
|
58171
58462
|
|
|
58172
58463
|
// src/extension/port-allocator.ts
|
|
58173
58464
|
var import_node_net2 = __toESM(require("net"), 1);
|
|
@@ -58267,7 +58558,7 @@ var Runtime = class {
|
|
|
58267
58558
|
/\$CLAWOS_EXT_PORT/g,
|
|
58268
58559
|
String(port)
|
|
58269
58560
|
);
|
|
58270
|
-
const dir =
|
|
58561
|
+
const dir = import_node_path55.default.join(this.root, extId);
|
|
58271
58562
|
const env = {
|
|
58272
58563
|
...process.env,
|
|
58273
58564
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -58343,7 +58634,7 @@ ${handle.stderrTail}`
|
|
|
58343
58634
|
if (res.ok) return;
|
|
58344
58635
|
} catch {
|
|
58345
58636
|
}
|
|
58346
|
-
await (0,
|
|
58637
|
+
await (0, import_promises12.setTimeout)(this.healthzIntervalMs);
|
|
58347
58638
|
}
|
|
58348
58639
|
throw new RuntimeError(
|
|
58349
58640
|
"HEALTHZ_FAILED",
|
|
@@ -58368,7 +58659,7 @@ ${handle.stderrTail}`
|
|
|
58368
58659
|
};
|
|
58369
58660
|
killGroup("SIGTERM");
|
|
58370
58661
|
const exited = new Promise((resolve6) => child.once("exit", () => resolve6()));
|
|
58371
|
-
const timed = (0,
|
|
58662
|
+
const timed = (0, import_promises12.setTimeout)(5e3).then(() => "timeout");
|
|
58372
58663
|
const winner = await Promise.race([exited.then(() => "exited"), timed]);
|
|
58373
58664
|
if (winner === "timeout" && child.exitCode === null) {
|
|
58374
58665
|
killGroup("SIGKILL");
|
|
@@ -58378,8 +58669,8 @@ ${handle.stderrTail}`
|
|
|
58378
58669
|
};
|
|
58379
58670
|
|
|
58380
58671
|
// src/extension/published-channels.ts
|
|
58381
|
-
var
|
|
58382
|
-
var
|
|
58672
|
+
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
58673
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
58383
58674
|
init_zod();
|
|
58384
58675
|
var PublishedChannelsError = class extends Error {
|
|
58385
58676
|
constructor(code, message) {
|
|
@@ -58409,7 +58700,7 @@ var PublishedChannelStore = class {
|
|
|
58409
58700
|
this.channels.clear();
|
|
58410
58701
|
let raw;
|
|
58411
58702
|
try {
|
|
58412
|
-
raw = await
|
|
58703
|
+
raw = await import_promises13.default.readFile(this.filePath, "utf8");
|
|
58413
58704
|
} catch (e) {
|
|
58414
58705
|
if (e.code === "ENOENT") {
|
|
58415
58706
|
this.loaded = true;
|
|
@@ -58478,15 +58769,15 @@ var PublishedChannelStore = class {
|
|
|
58478
58769
|
)
|
|
58479
58770
|
};
|
|
58480
58771
|
const tmp = `${this.filePath}.tmp`;
|
|
58481
|
-
await
|
|
58482
|
-
await
|
|
58483
|
-
await
|
|
58772
|
+
await import_promises13.default.mkdir(import_node_path56.default.dirname(this.filePath), { recursive: true });
|
|
58773
|
+
await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
58774
|
+
await import_promises13.default.rename(tmp, this.filePath);
|
|
58484
58775
|
}
|
|
58485
58776
|
};
|
|
58486
58777
|
|
|
58487
58778
|
// src/extension/bundle-cache.ts
|
|
58488
|
-
var
|
|
58489
|
-
var
|
|
58779
|
+
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
58780
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
58490
58781
|
var BundleCache = class {
|
|
58491
58782
|
constructor(rootDir) {
|
|
58492
58783
|
this.rootDir = rootDir;
|
|
@@ -58494,17 +58785,17 @@ var BundleCache = class {
|
|
|
58494
58785
|
rootDir;
|
|
58495
58786
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
58496
58787
|
async write(snapshotHash, buffer) {
|
|
58497
|
-
await
|
|
58498
|
-
const file =
|
|
58788
|
+
await import_promises14.default.mkdir(this.rootDir, { recursive: true });
|
|
58789
|
+
const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58499
58790
|
const tmp = `${file}.tmp`;
|
|
58500
|
-
await
|
|
58501
|
-
await
|
|
58791
|
+
await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
|
|
58792
|
+
await import_promises14.default.rename(tmp, file);
|
|
58502
58793
|
}
|
|
58503
58794
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
58504
58795
|
async read(snapshotHash) {
|
|
58505
|
-
const file =
|
|
58796
|
+
const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58506
58797
|
try {
|
|
58507
|
-
return await
|
|
58798
|
+
return await import_promises14.default.readFile(file);
|
|
58508
58799
|
} catch (e) {
|
|
58509
58800
|
if (e.code === "ENOENT") return null;
|
|
58510
58801
|
throw e;
|
|
@@ -58512,8 +58803,8 @@ var BundleCache = class {
|
|
|
58512
58803
|
}
|
|
58513
58804
|
/** Idempotent — missing file is not an error. */
|
|
58514
58805
|
async delete(snapshotHash) {
|
|
58515
|
-
const file =
|
|
58516
|
-
await
|
|
58806
|
+
const file = import_node_path57.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58807
|
+
await import_promises14.default.rm(file, { force: true });
|
|
58517
58808
|
}
|
|
58518
58809
|
};
|
|
58519
58810
|
|
|
@@ -58535,24 +58826,24 @@ async function startDaemon(config) {
|
|
|
58535
58826
|
sampling: logShippingCfg.sampling,
|
|
58536
58827
|
homeDir: import_node_os22.default.homedir()
|
|
58537
58828
|
});
|
|
58538
|
-
const logDir =
|
|
58829
|
+
const logDir = import_node_path58.default.join(config.dataDir, "log");
|
|
58539
58830
|
import_node_fs45.default.mkdirSync(logDir, { recursive: true });
|
|
58540
58831
|
const logger = createLogger({
|
|
58541
58832
|
level: config.logLevel,
|
|
58542
|
-
file:
|
|
58833
|
+
file: import_node_path58.default.join(logDir, "clawd.log"),
|
|
58543
58834
|
logClient
|
|
58544
58835
|
});
|
|
58545
58836
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
58546
58837
|
const screenIdleProbeLogger = createFileOnlyLogger({
|
|
58547
|
-
file:
|
|
58838
|
+
file: import_node_path58.default.join(logDir, "screen-idle-probe.log"),
|
|
58548
58839
|
level: "debug"
|
|
58549
58840
|
});
|
|
58550
58841
|
logger.info("screen-idle probe logger enabled", {
|
|
58551
|
-
file:
|
|
58842
|
+
file: import_node_path58.default.join(logDir, "screen-idle-probe.log")
|
|
58552
58843
|
});
|
|
58553
58844
|
const CAP_TARGETS = [
|
|
58554
|
-
|
|
58555
|
-
|
|
58845
|
+
import_node_path58.default.join(logDir, "clawd.log"),
|
|
58846
|
+
import_node_path58.default.join(logDir, "screen-idle-probe.log")
|
|
58556
58847
|
];
|
|
58557
58848
|
const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
|
|
58558
58849
|
const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
|
|
@@ -58706,8 +58997,8 @@ async function startDaemon(config) {
|
|
|
58706
58997
|
const agents = new AgentsScanner();
|
|
58707
58998
|
const history = new ClaudeHistoryReader();
|
|
58708
58999
|
let transport = null;
|
|
58709
|
-
const personaStore = new PersonaStore(
|
|
58710
|
-
const usersRoot =
|
|
59000
|
+
const personaStore = new PersonaStore(import_node_path58.default.join(config.dataDir, "personas"));
|
|
59001
|
+
const usersRoot = import_node_path58.default.join(config.dataDir, "users");
|
|
58711
59002
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
58712
59003
|
if (defaultsRoot) {
|
|
58713
59004
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -58726,18 +59017,33 @@ async function startDaemon(config) {
|
|
|
58726
59017
|
migrateAgentsMirror({ store: personaStore, logger });
|
|
58727
59018
|
migrateCodexSandbox({ store: personaStore, logger });
|
|
58728
59019
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
58729
|
-
const
|
|
58730
|
-
|
|
59020
|
+
const dispatchStore = createDispatchStore({
|
|
59021
|
+
filePath: import_node_path58.default.join(config.dataDir, "dispatch.json"),
|
|
59022
|
+
now: () => Date.now(),
|
|
59023
|
+
onFlushError: (err) => logger.error("dispatch store flush failed", {
|
|
59024
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
59025
|
+
})
|
|
59026
|
+
});
|
|
59027
|
+
await dispatchStore.load();
|
|
59028
|
+
dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
|
|
59029
|
+
let deliverPendingRef;
|
|
59030
|
+
const personaDispatchManager = new PersonaDispatchManager({
|
|
59031
|
+
genId: () => v4_default(),
|
|
59032
|
+
store: dispatchStore,
|
|
59033
|
+
now: () => Date.now(),
|
|
59034
|
+
onCompleted: (sid) => deliverPendingRef?.(sid)
|
|
59035
|
+
});
|
|
59036
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path58.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
|
|
58731
59037
|
const mcpConfigs = [];
|
|
58732
59038
|
const dispatchServerCandidates = [
|
|
58733
|
-
|
|
59039
|
+
import_node_path58.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
58734
59040
|
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
58735
|
-
|
|
59041
|
+
import_node_path58.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
58736
59042
|
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
58737
59043
|
];
|
|
58738
59044
|
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58739
59045
|
if (dispatchServerScriptPath) {
|
|
58740
|
-
const dispatchLogPath =
|
|
59046
|
+
const dispatchLogPath = import_node_path58.default.join(logDir, "dispatch-mcp-server.log");
|
|
58741
59047
|
const dispatchCfgPath = writeDispatchMcpConfig({
|
|
58742
59048
|
dataDir: config.dataDir,
|
|
58743
59049
|
serverScriptPath: dispatchServerScriptPath,
|
|
@@ -58755,12 +59061,12 @@ async function startDaemon(config) {
|
|
|
58755
59061
|
});
|
|
58756
59062
|
}
|
|
58757
59063
|
const ticketServerCandidates = [
|
|
58758
|
-
|
|
58759
|
-
|
|
59064
|
+
import_node_path58.default.join(here, "ticket", "mcp-server.cjs"),
|
|
59065
|
+
import_node_path58.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
58760
59066
|
];
|
|
58761
59067
|
const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58762
59068
|
if (ticketServerScriptPath) {
|
|
58763
|
-
const ticketLogPath =
|
|
59069
|
+
const ticketLogPath = import_node_path58.default.join(logDir, "ticket-mcp-server.log");
|
|
58764
59070
|
const ticketCfgPath = writeTicketMcpConfig({
|
|
58765
59071
|
dataDir: config.dataDir,
|
|
58766
59072
|
serverScriptPath: ticketServerScriptPath,
|
|
@@ -58780,12 +59086,12 @@ async function startDaemon(config) {
|
|
|
58780
59086
|
});
|
|
58781
59087
|
}
|
|
58782
59088
|
const shiftServerCandidates = [
|
|
58783
|
-
|
|
58784
|
-
|
|
59089
|
+
import_node_path58.default.join(here, "shift", "mcp-server.cjs"),
|
|
59090
|
+
import_node_path58.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
|
|
58785
59091
|
];
|
|
58786
59092
|
const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58787
59093
|
if (shiftServerScriptPath) {
|
|
58788
|
-
const shiftLogPath =
|
|
59094
|
+
const shiftLogPath = import_node_path58.default.join(logDir, "shift-mcp-server.log");
|
|
58789
59095
|
const shiftCfgPath = await writeShiftMcpConfig({
|
|
58790
59096
|
dataDir: config.dataDir,
|
|
58791
59097
|
serverScriptPath: shiftServerScriptPath,
|
|
@@ -58804,12 +59110,12 @@ async function startDaemon(config) {
|
|
|
58804
59110
|
);
|
|
58805
59111
|
}
|
|
58806
59112
|
const inboxServerCandidates = [
|
|
58807
|
-
|
|
58808
|
-
|
|
59113
|
+
import_node_path58.default.join(here, "inbox", "mcp-server.cjs"),
|
|
59114
|
+
import_node_path58.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
|
|
58809
59115
|
];
|
|
58810
59116
|
const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58811
59117
|
if (inboxServerScriptPath) {
|
|
58812
|
-
const inboxLogPath =
|
|
59118
|
+
const inboxLogPath = import_node_path58.default.join(logDir, "inbox-mcp-server.log");
|
|
58813
59119
|
const inboxCfgPath = await writeInboxMcpConfig({
|
|
58814
59120
|
dataDir: config.dataDir,
|
|
58815
59121
|
serverScriptPath: inboxServerScriptPath,
|
|
@@ -58828,8 +59134,8 @@ async function startDaemon(config) {
|
|
|
58828
59134
|
);
|
|
58829
59135
|
}
|
|
58830
59136
|
const peerOpsServerCandidates = [
|
|
58831
|
-
|
|
58832
|
-
|
|
59137
|
+
import_node_path58.default.join(here, "peer-ops", "mcp-server.cjs"),
|
|
59138
|
+
import_node_path58.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
|
|
58833
59139
|
];
|
|
58834
59140
|
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs45.default.existsSync(p2));
|
|
58835
59141
|
if (peerOpsServerScriptPath) {
|
|
@@ -58849,7 +59155,7 @@ async function startDaemon(config) {
|
|
|
58849
59155
|
);
|
|
58850
59156
|
}
|
|
58851
59157
|
const shiftStore = createShiftStore({
|
|
58852
|
-
filePath:
|
|
59158
|
+
filePath: import_node_path58.default.join(config.dataDir, "shift.json"),
|
|
58853
59159
|
ownerIdProvider: () => ownerPrincipalId,
|
|
58854
59160
|
now: () => Date.now()
|
|
58855
59161
|
});
|
|
@@ -58871,7 +59177,7 @@ async function startDaemon(config) {
|
|
|
58871
59177
|
getAdapter,
|
|
58872
59178
|
historyReader: history,
|
|
58873
59179
|
dataDir: config.dataDir,
|
|
58874
|
-
personaRoot:
|
|
59180
|
+
personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
|
|
58875
59181
|
usersRoot,
|
|
58876
59182
|
personaStore,
|
|
58877
59183
|
ownerDisplayName,
|
|
@@ -58887,6 +59193,8 @@ async function startDaemon(config) {
|
|
|
58887
59193
|
// Persona dispatch (Task 8): manager.createDispatchedSession 用 personaDispatchManager
|
|
58888
59194
|
// registerBSession;reducer 通过闭包反查 dispatchId 注 CLAWD_DISPATCH_ID env。
|
|
58889
59195
|
personaDispatchManager,
|
|
59196
|
+
// Dispatch 结果投递:deliverPending 查台账 + turn-end sweep(spec 2026-07-20 §5)。
|
|
59197
|
+
dispatchStore,
|
|
58890
59198
|
// daemon 级 MCP server 登记表(dispatch / ticket / shift / inbox / ...,上方各 writer
|
|
58891
59199
|
// 块写盘成功即登记);reducer 透传到 SpawnContext.mcpConfigs,cc spawn 逐项 --mcp-config。
|
|
58892
59200
|
mcpConfigs,
|
|
@@ -58909,7 +59217,7 @@ async function startDaemon(config) {
|
|
|
58909
59217
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
58910
59218
|
attachmentGroup: {
|
|
58911
59219
|
onFileEdit: (input) => {
|
|
58912
|
-
const absPath =
|
|
59220
|
+
const absPath = import_node_path58.default.isAbsolute(input.relPath) ? input.relPath : import_node_path58.default.join(input.cwd, input.relPath);
|
|
58913
59221
|
let size = 0;
|
|
58914
59222
|
try {
|
|
58915
59223
|
size = import_node_fs45.default.statSync(absPath).size;
|
|
@@ -58975,6 +59283,7 @@ async function startDaemon(config) {
|
|
|
58975
59283
|
}
|
|
58976
59284
|
});
|
|
58977
59285
|
manager.attachObserver(observer);
|
|
59286
|
+
deliverPendingRef = (sid) => manager.deliverPending(sid);
|
|
58978
59287
|
const claudeAdapter = config.mode === "tui" ? new ClaudeTuiAdapter({
|
|
58979
59288
|
logger,
|
|
58980
59289
|
historyReader: new ClaudeHistoryReader(),
|
|
@@ -59141,11 +59450,11 @@ async function startDaemon(config) {
|
|
|
59141
59450
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
59142
59451
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
59143
59452
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
59144
|
-
personaRoot:
|
|
59453
|
+
personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
|
|
59145
59454
|
usersRoot
|
|
59146
59455
|
},
|
|
59147
59456
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
59148
|
-
personaRoot:
|
|
59457
|
+
personaRoot: import_node_path58.default.join(config.dataDir, "personas"),
|
|
59149
59458
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
59150
59459
|
usersRoot,
|
|
59151
59460
|
// capability:list / delete handler 依赖
|
|
@@ -59256,11 +59565,11 @@ async function startDaemon(config) {
|
|
|
59256
59565
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
59257
59566
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
59258
59567
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
59259
|
-
appBuilderPersonaRoot:
|
|
59568
|
+
appBuilderPersonaRoot: import_node_path58.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
59260
59569
|
// 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
|
|
59261
|
-
deployKitRoot:
|
|
59570
|
+
deployKitRoot: import_node_path58.default.join(config.dataDir, "deploy-kit"),
|
|
59262
59571
|
// scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
|
|
59263
|
-
resolvePersonaRoot: (personaId) =>
|
|
59572
|
+
resolvePersonaRoot: (personaId) => import_node_path58.default.join(config.dataDir, "personas", personaId),
|
|
59264
59573
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
59265
59574
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
59266
59575
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -59290,6 +59599,7 @@ async function startDaemon(config) {
|
|
|
59290
59599
|
let handlers = makeHandlers();
|
|
59291
59600
|
const dispatchHandlers = buildPersonaDispatchHandlers({
|
|
59292
59601
|
personaDispatchManager,
|
|
59602
|
+
store: dispatchStore,
|
|
59293
59603
|
logger,
|
|
59294
59604
|
spawnB: async (args) => {
|
|
59295
59605
|
logger.info("dispatch.spawnB.start", {
|
|
@@ -59303,7 +59613,7 @@ async function startDaemon(config) {
|
|
|
59303
59613
|
}
|
|
59304
59614
|
let sourceJsonlPath = "(no transcript yet \u2014 operate from the task description alone)";
|
|
59305
59615
|
if (sourceFile && sourceFile.toolSessionId) {
|
|
59306
|
-
sourceJsonlPath =
|
|
59616
|
+
sourceJsonlPath = import_node_path58.default.join(
|
|
59307
59617
|
import_node_os22.default.homedir(),
|
|
59308
59618
|
".claude",
|
|
59309
59619
|
"projects",
|
|
@@ -59621,8 +59931,8 @@ async function startDaemon(config) {
|
|
|
59621
59931
|
const lines = [
|
|
59622
59932
|
`Tunnel: ${r.url}`,
|
|
59623
59933
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
59624
|
-
`Frpc config: ${
|
|
59625
|
-
`Frpc log: ${
|
|
59934
|
+
`Frpc config: ${import_node_path58.default.join(config.dataDir, "frpc.toml")}`,
|
|
59935
|
+
`Frpc log: ${import_node_path58.default.join(logDir, "frpc.log")}`
|
|
59626
59936
|
];
|
|
59627
59937
|
const width = Math.max(...lines.map((l) => l.length));
|
|
59628
59938
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -59635,7 +59945,7 @@ ${bar}
|
|
|
59635
59945
|
|
|
59636
59946
|
`);
|
|
59637
59947
|
try {
|
|
59638
|
-
const connectPath =
|
|
59948
|
+
const connectPath = import_node_path58.default.join(config.dataDir, "connect.txt");
|
|
59639
59949
|
import_node_fs45.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
59640
59950
|
} catch {
|
|
59641
59951
|
}
|
|
@@ -59708,7 +60018,7 @@ ${bar}
|
|
|
59708
60018
|
};
|
|
59709
60019
|
}
|
|
59710
60020
|
function migrateDropPersonsDir(dataDir) {
|
|
59711
|
-
const dir =
|
|
60021
|
+
const dir = import_node_path58.default.join(dataDir, "persons");
|
|
59712
60022
|
try {
|
|
59713
60023
|
import_node_fs45.default.rmSync(dir, { recursive: true, force: true });
|
|
59714
60024
|
} catch {
|