@clawos-dev/clawd 0.2.191-beta.383.956b6ae → 0.2.192-beta.386.33a5833
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 +896 -636
- package/dist/dispatch/mcp-server.cjs +34 -19
- package/dist/share-ui/assets/{guest-DG1-7F5a.js → guest-BGhERiEC.js} +119 -119
- package/dist/share-ui/guest.html +1 -1
- package/package.json +1 -1
- package/dist/persona-defaults/persona-bug-fixer/.claude/settings.json +0 -7
- package/dist/persona-defaults/persona-bug-fixer/.mcp.json +0 -15
- package/dist/persona-defaults/persona-bug-fixer/CLAUDE.md +0 -102
- package/dist/persona-defaults/persona-ticket-manager/CLAUDE.md +0 -97
package/dist/cli.cjs
CHANGED
|
@@ -733,8 +733,8 @@ var init_parseUtil = __esm({
|
|
|
733
733
|
init_errors2();
|
|
734
734
|
init_en();
|
|
735
735
|
makeIssue = (params) => {
|
|
736
|
-
const { data, path:
|
|
737
|
-
const fullPath = [...
|
|
736
|
+
const { data, path: path68, errorMaps, issueData } = params;
|
|
737
|
+
const fullPath = [...path68, ...issueData.path || []];
|
|
738
738
|
const fullIssue = {
|
|
739
739
|
...issueData,
|
|
740
740
|
path: fullPath
|
|
@@ -1045,11 +1045,11 @@ var init_types = __esm({
|
|
|
1045
1045
|
init_parseUtil();
|
|
1046
1046
|
init_util();
|
|
1047
1047
|
ParseInputLazyPath = class {
|
|
1048
|
-
constructor(parent, value,
|
|
1048
|
+
constructor(parent, value, path68, key) {
|
|
1049
1049
|
this._cachedPath = [];
|
|
1050
1050
|
this.parent = parent;
|
|
1051
1051
|
this.data = value;
|
|
1052
|
-
this._path =
|
|
1052
|
+
this._path = path68;
|
|
1053
1053
|
this._key = key;
|
|
1054
1054
|
}
|
|
1055
1055
|
get path() {
|
|
@@ -5996,7 +5996,7 @@ var init_feishu_auth = __esm({
|
|
|
5996
5996
|
});
|
|
5997
5997
|
|
|
5998
5998
|
// ../protocol/src/dispatch.ts
|
|
5999
|
-
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema;
|
|
5999
|
+
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchRunResponseSchema, DispatchCompleteArgsSchema;
|
|
6000
6000
|
var init_dispatch = __esm({
|
|
6001
6001
|
"../protocol/src/dispatch.ts"() {
|
|
6002
6002
|
"use strict";
|
|
@@ -6017,10 +6017,21 @@ var init_dispatch = __esm({
|
|
|
6017
6017
|
prompt: external_exports.string(),
|
|
6018
6018
|
// 跨设备 dispatch:非空 = A 角色,转发到该 contact deviceId 的 peer daemon;
|
|
6019
6019
|
// 省略 = 本地 dispatch / B 角色本地执行。A 转发给 B 时 body 不带此字段。
|
|
6020
|
-
targetDeviceId: external_exports.string().min(1).optional()
|
|
6020
|
+
targetDeviceId: external_exports.string().min(1).optional(),
|
|
6021
|
+
// 精确寻址已知 B session(复用其上下文):
|
|
6022
|
+
// - 本地(targetDeviceId 缺省):daemon 校验目标为本机 session 且
|
|
6023
|
+
// dispatchedFromSessionId 匹配 A 的 sessionId(防越权)
|
|
6024
|
+
// - 跨设备(targetDeviceId 非空):peer daemon 在其本地按同规则校验
|
|
6025
|
+
// creatorPrincipalId === A.deviceId
|
|
6026
|
+
// - 省略 = 新建 B session
|
|
6027
|
+
targetSessionId: external_exports.string().min(1).optional()
|
|
6028
|
+
});
|
|
6029
|
+
DispatchRunResponseSchema = external_exports.object({
|
|
6030
|
+
type: external_exports.literal("personaDispatch:run:ok"),
|
|
6031
|
+
outcome: DispatchOutcomeSchema,
|
|
6032
|
+
dispatchedSessionId: external_exports.string().min(1).optional()
|
|
6021
6033
|
});
|
|
6022
6034
|
DispatchCompleteArgsSchema = external_exports.object({
|
|
6023
|
-
dispatchId: external_exports.string().min(1),
|
|
6024
6035
|
outcome: DispatchOutcomeSchema
|
|
6025
6036
|
});
|
|
6026
6037
|
}
|
|
@@ -6373,8 +6384,8 @@ var require_req = __commonJS({
|
|
|
6373
6384
|
if (req.originalUrl) {
|
|
6374
6385
|
_req.url = req.originalUrl;
|
|
6375
6386
|
} else {
|
|
6376
|
-
const
|
|
6377
|
-
_req.url = typeof
|
|
6387
|
+
const path68 = req.path;
|
|
6388
|
+
_req.url = typeof path68 === "string" ? path68 : req.url ? req.url.path || req.url : void 0;
|
|
6378
6389
|
}
|
|
6379
6390
|
if (req.query) {
|
|
6380
6391
|
_req.query = req.query;
|
|
@@ -6539,14 +6550,14 @@ var require_redact = __commonJS({
|
|
|
6539
6550
|
}
|
|
6540
6551
|
return obj;
|
|
6541
6552
|
}
|
|
6542
|
-
function parsePath(
|
|
6553
|
+
function parsePath(path68) {
|
|
6543
6554
|
const parts = [];
|
|
6544
6555
|
let current = "";
|
|
6545
6556
|
let inBrackets = false;
|
|
6546
6557
|
let inQuotes = false;
|
|
6547
6558
|
let quoteChar = "";
|
|
6548
|
-
for (let i = 0; i <
|
|
6549
|
-
const char =
|
|
6559
|
+
for (let i = 0; i < path68.length; i++) {
|
|
6560
|
+
const char = path68[i];
|
|
6550
6561
|
if (!inBrackets && char === ".") {
|
|
6551
6562
|
if (current) {
|
|
6552
6563
|
parts.push(current);
|
|
@@ -6677,10 +6688,10 @@ var require_redact = __commonJS({
|
|
|
6677
6688
|
return current;
|
|
6678
6689
|
}
|
|
6679
6690
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
6680
|
-
for (const
|
|
6681
|
-
const parts = parsePath(
|
|
6691
|
+
for (const path68 of paths) {
|
|
6692
|
+
const parts = parsePath(path68);
|
|
6682
6693
|
if (parts.includes("*")) {
|
|
6683
|
-
redactWildcardPath(obj, parts, censor,
|
|
6694
|
+
redactWildcardPath(obj, parts, censor, path68, remove);
|
|
6684
6695
|
} else {
|
|
6685
6696
|
if (remove) {
|
|
6686
6697
|
removeKey(obj, parts);
|
|
@@ -6765,8 +6776,8 @@ var require_redact = __commonJS({
|
|
|
6765
6776
|
}
|
|
6766
6777
|
} else {
|
|
6767
6778
|
if (afterWildcard.includes("*")) {
|
|
6768
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
6769
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
6779
|
+
const wrappedCensor = typeof censor === "function" ? (value, path68) => {
|
|
6780
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path68];
|
|
6770
6781
|
return censor(value, fullPath);
|
|
6771
6782
|
} : censor;
|
|
6772
6783
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -6801,8 +6812,8 @@ var require_redact = __commonJS({
|
|
|
6801
6812
|
return null;
|
|
6802
6813
|
}
|
|
6803
6814
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
6804
|
-
for (const
|
|
6805
|
-
const parts = parsePath(
|
|
6815
|
+
for (const path68 of pathsToClone) {
|
|
6816
|
+
const parts = parsePath(path68);
|
|
6806
6817
|
let current = pathStructure;
|
|
6807
6818
|
for (let i = 0; i < parts.length; i++) {
|
|
6808
6819
|
const part = parts[i];
|
|
@@ -6854,24 +6865,24 @@ var require_redact = __commonJS({
|
|
|
6854
6865
|
}
|
|
6855
6866
|
return cloneSelectively(obj, pathStructure);
|
|
6856
6867
|
}
|
|
6857
|
-
function validatePath(
|
|
6858
|
-
if (typeof
|
|
6868
|
+
function validatePath(path68) {
|
|
6869
|
+
if (typeof path68 !== "string") {
|
|
6859
6870
|
throw new Error("Paths must be (non-empty) strings");
|
|
6860
6871
|
}
|
|
6861
|
-
if (
|
|
6872
|
+
if (path68 === "") {
|
|
6862
6873
|
throw new Error("Invalid redaction path ()");
|
|
6863
6874
|
}
|
|
6864
|
-
if (
|
|
6865
|
-
throw new Error(`Invalid redaction path (${
|
|
6875
|
+
if (path68.includes("..")) {
|
|
6876
|
+
throw new Error(`Invalid redaction path (${path68})`);
|
|
6866
6877
|
}
|
|
6867
|
-
if (
|
|
6868
|
-
throw new Error(`Invalid redaction path (${
|
|
6878
|
+
if (path68.includes(",")) {
|
|
6879
|
+
throw new Error(`Invalid redaction path (${path68})`);
|
|
6869
6880
|
}
|
|
6870
6881
|
let bracketCount = 0;
|
|
6871
6882
|
let inQuotes = false;
|
|
6872
6883
|
let quoteChar = "";
|
|
6873
|
-
for (let i = 0; i <
|
|
6874
|
-
const char =
|
|
6884
|
+
for (let i = 0; i < path68.length; i++) {
|
|
6885
|
+
const char = path68[i];
|
|
6875
6886
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
6876
6887
|
if (!inQuotes) {
|
|
6877
6888
|
inQuotes = true;
|
|
@@ -6885,20 +6896,20 @@ var require_redact = __commonJS({
|
|
|
6885
6896
|
} else if (char === "]" && !inQuotes) {
|
|
6886
6897
|
bracketCount--;
|
|
6887
6898
|
if (bracketCount < 0) {
|
|
6888
|
-
throw new Error(`Invalid redaction path (${
|
|
6899
|
+
throw new Error(`Invalid redaction path (${path68})`);
|
|
6889
6900
|
}
|
|
6890
6901
|
}
|
|
6891
6902
|
}
|
|
6892
6903
|
if (bracketCount !== 0) {
|
|
6893
|
-
throw new Error(`Invalid redaction path (${
|
|
6904
|
+
throw new Error(`Invalid redaction path (${path68})`);
|
|
6894
6905
|
}
|
|
6895
6906
|
}
|
|
6896
6907
|
function validatePaths(paths) {
|
|
6897
6908
|
if (!Array.isArray(paths)) {
|
|
6898
6909
|
throw new TypeError("paths must be an array");
|
|
6899
6910
|
}
|
|
6900
|
-
for (const
|
|
6901
|
-
validatePath(
|
|
6911
|
+
for (const path68 of paths) {
|
|
6912
|
+
validatePath(path68);
|
|
6902
6913
|
}
|
|
6903
6914
|
}
|
|
6904
6915
|
function slowRedact(options = {}) {
|
|
@@ -7066,8 +7077,8 @@ var require_redaction = __commonJS({
|
|
|
7066
7077
|
if (shape[k2] === null) {
|
|
7067
7078
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
7068
7079
|
} else {
|
|
7069
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
7070
|
-
return censor(value, [k2, ...
|
|
7080
|
+
const wrappedCensor = typeof censor === "function" ? (value, path68) => {
|
|
7081
|
+
return censor(value, [k2, ...path68]);
|
|
7071
7082
|
} : censor;
|
|
7072
7083
|
o[k2] = Redact({
|
|
7073
7084
|
paths: shape[k2],
|
|
@@ -7288,7 +7299,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7288
7299
|
var fs61 = require("fs");
|
|
7289
7300
|
var EventEmitter3 = require("events");
|
|
7290
7301
|
var inherits = require("util").inherits;
|
|
7291
|
-
var
|
|
7302
|
+
var path68 = require("path");
|
|
7292
7303
|
var sleep2 = require_atomic_sleep();
|
|
7293
7304
|
var assert = require("assert");
|
|
7294
7305
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -7342,7 +7353,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7342
7353
|
const mode = sonic.mode;
|
|
7343
7354
|
if (sonic.sync) {
|
|
7344
7355
|
try {
|
|
7345
|
-
if (sonic.mkdir) fs61.mkdirSync(
|
|
7356
|
+
if (sonic.mkdir) fs61.mkdirSync(path68.dirname(file), { recursive: true });
|
|
7346
7357
|
const fd = fs61.openSync(file, flags, mode);
|
|
7347
7358
|
fileOpened(null, fd);
|
|
7348
7359
|
} catch (err) {
|
|
@@ -7350,7 +7361,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7350
7361
|
throw err;
|
|
7351
7362
|
}
|
|
7352
7363
|
} else if (sonic.mkdir) {
|
|
7353
|
-
fs61.mkdir(
|
|
7364
|
+
fs61.mkdir(path68.dirname(file), { recursive: true }, (err) => {
|
|
7354
7365
|
if (err) return fileOpened(err);
|
|
7355
7366
|
fs61.open(file, flags, mode, fileOpened);
|
|
7356
7367
|
});
|
|
@@ -10210,7 +10221,7 @@ var require_multistream = __commonJS({
|
|
|
10210
10221
|
var require_pino = __commonJS({
|
|
10211
10222
|
"../node_modules/.pnpm/pino@9.14.0/node_modules/pino/pino.js"(exports2, module2) {
|
|
10212
10223
|
"use strict";
|
|
10213
|
-
var
|
|
10224
|
+
var os23 = require("os");
|
|
10214
10225
|
var stdSerializers = require_pino_std_serializers();
|
|
10215
10226
|
var caller = require_caller();
|
|
10216
10227
|
var redaction = require_redaction();
|
|
@@ -10257,7 +10268,7 @@ var require_pino = __commonJS({
|
|
|
10257
10268
|
} = symbols;
|
|
10258
10269
|
var { epochTime, nullTime } = time;
|
|
10259
10270
|
var { pid } = process;
|
|
10260
|
-
var hostname =
|
|
10271
|
+
var hostname = os23.hostname();
|
|
10261
10272
|
var defaultErrorSerializer = stdSerializers.err;
|
|
10262
10273
|
var defaultOptions = {
|
|
10263
10274
|
level: "info",
|
|
@@ -10981,11 +10992,11 @@ var init_lib = __esm({
|
|
|
10981
10992
|
}
|
|
10982
10993
|
}
|
|
10983
10994
|
},
|
|
10984
|
-
addToPath: function addToPath(
|
|
10985
|
-
var last =
|
|
10995
|
+
addToPath: function addToPath(path68, added, removed, oldPosInc, options) {
|
|
10996
|
+
var last = path68.lastComponent;
|
|
10986
10997
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
10987
10998
|
return {
|
|
10988
|
-
oldPos:
|
|
10999
|
+
oldPos: path68.oldPos + oldPosInc,
|
|
10989
11000
|
lastComponent: {
|
|
10990
11001
|
count: last.count + 1,
|
|
10991
11002
|
added,
|
|
@@ -10995,7 +11006,7 @@ var init_lib = __esm({
|
|
|
10995
11006
|
};
|
|
10996
11007
|
} else {
|
|
10997
11008
|
return {
|
|
10998
|
-
oldPos:
|
|
11009
|
+
oldPos: path68.oldPos + oldPosInc,
|
|
10999
11010
|
lastComponent: {
|
|
11000
11011
|
count: 1,
|
|
11001
11012
|
added,
|
|
@@ -11053,7 +11064,7 @@ var init_lib = __esm({
|
|
|
11053
11064
|
tokenize: function tokenize(value) {
|
|
11054
11065
|
return Array.from(value);
|
|
11055
11066
|
},
|
|
11056
|
-
join: function
|
|
11067
|
+
join: function join3(chars) {
|
|
11057
11068
|
return chars.join("");
|
|
11058
11069
|
},
|
|
11059
11070
|
postProcess: function postProcess(changeObjects) {
|
|
@@ -11235,13 +11246,33 @@ var init_tool_result_extra = __esm({
|
|
|
11235
11246
|
function cwdToHashDir(cwd) {
|
|
11236
11247
|
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
11237
11248
|
}
|
|
11249
|
+
function newestSubagentMtimeMs(projectsRoot, cwd, toolSessionId) {
|
|
11250
|
+
const dir = import_node_path4.default.join(projectsRoot, cwdToHashDir(cwd), toolSessionId, "subagents");
|
|
11251
|
+
let entries;
|
|
11252
|
+
try {
|
|
11253
|
+
entries = import_node_fs4.default.readdirSync(dir, { withFileTypes: true });
|
|
11254
|
+
} catch {
|
|
11255
|
+
return null;
|
|
11256
|
+
}
|
|
11257
|
+
let newest = null;
|
|
11258
|
+
for (const e of entries) {
|
|
11259
|
+
if (!e.isFile()) continue;
|
|
11260
|
+
if (!e.name.startsWith("agent-") || !e.name.endsWith(".jsonl")) continue;
|
|
11261
|
+
try {
|
|
11262
|
+
const m2 = import_node_fs4.default.statSync(import_node_path4.default.join(dir, e.name)).mtimeMs;
|
|
11263
|
+
if (newest === null || m2 > newest) newest = m2;
|
|
11264
|
+
} catch {
|
|
11265
|
+
}
|
|
11266
|
+
}
|
|
11267
|
+
return newest;
|
|
11268
|
+
}
|
|
11238
11269
|
function hashDirToCwd(hash) {
|
|
11239
11270
|
const body = hash.startsWith("-") ? hash.slice(1) : hash;
|
|
11240
11271
|
return "/" + body.replace(/-/g, "/");
|
|
11241
11272
|
}
|
|
11242
11273
|
function safeStatMtime(p2) {
|
|
11243
11274
|
try {
|
|
11244
|
-
return
|
|
11275
|
+
return import_node_fs4.default.statSync(p2).mtimeMs;
|
|
11245
11276
|
} catch {
|
|
11246
11277
|
return 0;
|
|
11247
11278
|
}
|
|
@@ -11249,7 +11280,7 @@ function safeStatMtime(p2) {
|
|
|
11249
11280
|
function readJsonlLines(file) {
|
|
11250
11281
|
let raw;
|
|
11251
11282
|
try {
|
|
11252
|
-
raw =
|
|
11283
|
+
raw = import_node_fs4.default.readFileSync(file, "utf8");
|
|
11253
11284
|
} catch (err) {
|
|
11254
11285
|
if (err.code === "ENOENT") return [];
|
|
11255
11286
|
throw err;
|
|
@@ -11441,10 +11472,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
11441
11472
|
const memories = raw.map((m2) => {
|
|
11442
11473
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11443
11474
|
const rec3 = m2;
|
|
11444
|
-
const
|
|
11475
|
+
const path68 = typeof rec3.path === "string" ? rec3.path : null;
|
|
11445
11476
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
11446
|
-
if (!
|
|
11447
|
-
const entry = { path:
|
|
11477
|
+
if (!path68 || content == null) return null;
|
|
11478
|
+
const entry = { path: path68, content };
|
|
11448
11479
|
if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
|
|
11449
11480
|
return entry;
|
|
11450
11481
|
}).filter((m2) => m2 !== null);
|
|
@@ -11480,8 +11511,8 @@ function attachmentDeferredToolsText(a) {
|
|
|
11480
11511
|
function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
|
|
11481
11512
|
if (backupFileName === null) return null;
|
|
11482
11513
|
try {
|
|
11483
|
-
return
|
|
11484
|
-
|
|
11514
|
+
return import_node_fs4.default.readFileSync(
|
|
11515
|
+
import_node_path4.default.join(fileHistoryRoot, toolSessionId, backupFileName),
|
|
11485
11516
|
"utf8"
|
|
11486
11517
|
);
|
|
11487
11518
|
} catch {
|
|
@@ -11490,19 +11521,19 @@ function readBackupContent(fileHistoryRoot, toolSessionId, backupFileName) {
|
|
|
11490
11521
|
}
|
|
11491
11522
|
function readCurrentContent(filePath) {
|
|
11492
11523
|
try {
|
|
11493
|
-
return
|
|
11524
|
+
return import_node_fs4.default.readFileSync(filePath, "utf8");
|
|
11494
11525
|
} catch (err) {
|
|
11495
11526
|
if (err.code === "ENOENT") return null;
|
|
11496
11527
|
return null;
|
|
11497
11528
|
}
|
|
11498
11529
|
}
|
|
11499
|
-
var
|
|
11530
|
+
var import_node_fs4, import_node_os3, import_node_path4, TASK_NOTIFICATION_RE, TASK_ID_RE, TOOL_USE_ID_RE, SLASH_COMMAND_RE, LOCAL_COMMAND_RE, SYSTEM_REMINDER_RE, OPENSPEC_BLOCK_RE, SKILL_HINT_RE, ATTACHMENT_SILENT_SUBTYPES, ClaudeHistoryReader;
|
|
11500
11531
|
var init_claude_history = __esm({
|
|
11501
11532
|
"src/tools/claude-history.ts"() {
|
|
11502
11533
|
"use strict";
|
|
11503
|
-
|
|
11504
|
-
|
|
11505
|
-
|
|
11534
|
+
import_node_fs4 = __toESM(require("fs"), 1);
|
|
11535
|
+
import_node_os3 = __toESM(require("os"), 1);
|
|
11536
|
+
import_node_path4 = __toESM(require("path"), 1);
|
|
11506
11537
|
init_lib();
|
|
11507
11538
|
init_tool_result_extra();
|
|
11508
11539
|
TASK_NOTIFICATION_RE = /<task-notification\b[\s\S]*?<\/task-notification>/i;
|
|
@@ -11526,14 +11557,14 @@ var init_claude_history = __esm({
|
|
|
11526
11557
|
// 每次 user 提交前 trackEdit 拷一份,作为 rewind 回退目标
|
|
11527
11558
|
fileHistoryRoot;
|
|
11528
11559
|
constructor(opts = {}) {
|
|
11529
|
-
const base = opts.baseDir ??
|
|
11530
|
-
this.projectsRoot =
|
|
11531
|
-
this.fileHistoryRoot =
|
|
11560
|
+
const base = opts.baseDir ?? import_node_path4.default.join(import_node_os3.default.homedir(), ".claude");
|
|
11561
|
+
this.projectsRoot = import_node_path4.default.join(base, "projects");
|
|
11562
|
+
this.fileHistoryRoot = import_node_path4.default.join(base, "file-history");
|
|
11532
11563
|
}
|
|
11533
11564
|
async listProjects() {
|
|
11534
11565
|
let entries;
|
|
11535
11566
|
try {
|
|
11536
|
-
entries =
|
|
11567
|
+
entries = import_node_fs4.default.readdirSync(this.projectsRoot, { withFileTypes: true });
|
|
11537
11568
|
} catch (err) {
|
|
11538
11569
|
if (err.code === "ENOENT") return [];
|
|
11539
11570
|
throw err;
|
|
@@ -11541,9 +11572,9 @@ var init_claude_history = __esm({
|
|
|
11541
11572
|
const out = [];
|
|
11542
11573
|
for (const ent of entries) {
|
|
11543
11574
|
if (!ent.isDirectory()) continue;
|
|
11544
|
-
const dir =
|
|
11545
|
-
const files =
|
|
11546
|
-
const updatedAtMs = files.reduce((m2, f) => Math.max(m2, safeStatMtime(
|
|
11575
|
+
const dir = import_node_path4.default.join(this.projectsRoot, ent.name);
|
|
11576
|
+
const files = import_node_fs4.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
11577
|
+
const updatedAtMs = files.reduce((m2, f) => Math.max(m2, safeStatMtime(import_node_path4.default.join(dir, f))), 0);
|
|
11547
11578
|
out.push({
|
|
11548
11579
|
projectPath: hashDirToCwd(ent.name),
|
|
11549
11580
|
hashDir: ent.name,
|
|
@@ -11555,17 +11586,17 @@ var init_claude_history = __esm({
|
|
|
11555
11586
|
return out;
|
|
11556
11587
|
}
|
|
11557
11588
|
async listSessions(args) {
|
|
11558
|
-
const dir =
|
|
11589
|
+
const dir = import_node_path4.default.join(this.projectsRoot, cwdToHashDir(args.projectPath));
|
|
11559
11590
|
let files;
|
|
11560
11591
|
try {
|
|
11561
|
-
files =
|
|
11592
|
+
files = import_node_fs4.default.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
11562
11593
|
} catch (err) {
|
|
11563
11594
|
if (err.code === "ENOENT") return [];
|
|
11564
11595
|
throw err;
|
|
11565
11596
|
}
|
|
11566
11597
|
const out = [];
|
|
11567
11598
|
for (const f of files) {
|
|
11568
|
-
const full =
|
|
11599
|
+
const full = import_node_path4.default.join(dir, f);
|
|
11569
11600
|
const toolSessionId = f.slice(0, -".jsonl".length);
|
|
11570
11601
|
const lines = readJsonlLines(full);
|
|
11571
11602
|
let summary = "";
|
|
@@ -11620,7 +11651,7 @@ var init_claude_history = __esm({
|
|
|
11620
11651
|
return out;
|
|
11621
11652
|
}
|
|
11622
11653
|
async read(args) {
|
|
11623
|
-
const file =
|
|
11654
|
+
const file = import_node_path4.default.join(
|
|
11624
11655
|
this.projectsRoot,
|
|
11625
11656
|
cwdToHashDir(args.cwd),
|
|
11626
11657
|
`${args.toolSessionId}.jsonl`
|
|
@@ -11657,7 +11688,7 @@ var init_claude_history = __esm({
|
|
|
11657
11688
|
// 独立目录路径:<projectsRoot>/<cwdHash>/<toolSessionId>/subagents/*.jsonl
|
|
11658
11689
|
// 返回 null 表示目录不存在(调用方回退旧实现);返回空数组表示目录存在但无 jsonl
|
|
11659
11690
|
listSubagentsFromDirectory(cwd, toolSessionId) {
|
|
11660
|
-
const dir =
|
|
11691
|
+
const dir = import_node_path4.default.join(
|
|
11661
11692
|
this.projectsRoot,
|
|
11662
11693
|
cwdToHashDir(cwd),
|
|
11663
11694
|
toolSessionId,
|
|
@@ -11665,7 +11696,7 @@ var init_claude_history = __esm({
|
|
|
11665
11696
|
);
|
|
11666
11697
|
let entries;
|
|
11667
11698
|
try {
|
|
11668
|
-
entries =
|
|
11699
|
+
entries = import_node_fs4.default.readdirSync(dir, { withFileTypes: true });
|
|
11669
11700
|
} catch (err) {
|
|
11670
11701
|
if (err.code === "ENOENT") return null;
|
|
11671
11702
|
return null;
|
|
@@ -11675,7 +11706,7 @@ var init_claude_history = __esm({
|
|
|
11675
11706
|
if (!e.isFile()) continue;
|
|
11676
11707
|
if (!e.name.startsWith("agent-") || !e.name.endsWith(".jsonl")) continue;
|
|
11677
11708
|
const subagentId = e.name.slice("agent-".length, -".jsonl".length);
|
|
11678
|
-
const filePath =
|
|
11709
|
+
const filePath = import_node_path4.default.join(dir, e.name);
|
|
11679
11710
|
const lines = readJsonlLines(filePath);
|
|
11680
11711
|
let firstText = "";
|
|
11681
11712
|
let messageCount = 0;
|
|
@@ -11692,7 +11723,7 @@ var init_claude_history = __esm({
|
|
|
11692
11723
|
return out;
|
|
11693
11724
|
}
|
|
11694
11725
|
listSubagentsFromMainJsonl(cwd, toolSessionId) {
|
|
11695
|
-
const file =
|
|
11726
|
+
const file = import_node_path4.default.join(
|
|
11696
11727
|
this.projectsRoot,
|
|
11697
11728
|
cwdToHashDir(cwd),
|
|
11698
11729
|
`${toolSessionId}.jsonl`
|
|
@@ -11727,7 +11758,7 @@ var init_claude_history = __esm({
|
|
|
11727
11758
|
}
|
|
11728
11759
|
// 独立文件路径:agent-<subagentId>.jsonl;文件不存在返回 null 让调用方回退旧实现
|
|
11729
11760
|
readSubagentFromFile(cwd, toolSessionId, subagentId) {
|
|
11730
|
-
const file =
|
|
11761
|
+
const file = import_node_path4.default.join(
|
|
11731
11762
|
this.projectsRoot,
|
|
11732
11763
|
cwdToHashDir(cwd),
|
|
11733
11764
|
toolSessionId,
|
|
@@ -11736,7 +11767,7 @@ var init_claude_history = __esm({
|
|
|
11736
11767
|
);
|
|
11737
11768
|
let exists = false;
|
|
11738
11769
|
try {
|
|
11739
|
-
exists =
|
|
11770
|
+
exists = import_node_fs4.default.statSync(file).isFile();
|
|
11740
11771
|
} catch {
|
|
11741
11772
|
return null;
|
|
11742
11773
|
}
|
|
@@ -11755,7 +11786,7 @@ var init_claude_history = __esm({
|
|
|
11755
11786
|
* "那一刻每个 tracked 文件对应的 backup 文件名"
|
|
11756
11787
|
*/
|
|
11757
11788
|
readFileHistorySnapshots(args) {
|
|
11758
|
-
const file =
|
|
11789
|
+
const file = import_node_path4.default.join(
|
|
11759
11790
|
this.projectsRoot,
|
|
11760
11791
|
cwdToHashDir(args.cwd),
|
|
11761
11792
|
`${args.toolSessionId}.jsonl`
|
|
@@ -11800,7 +11831,7 @@ var init_claude_history = __esm({
|
|
|
11800
11831
|
for (const [anchorId, target] of snapshots) {
|
|
11801
11832
|
let hasAny = false;
|
|
11802
11833
|
for (const [rawPath, backup] of Object.entries(target)) {
|
|
11803
|
-
const absPath =
|
|
11834
|
+
const absPath = import_node_path4.default.isAbsolute(rawPath) ? rawPath : import_node_path4.default.join(args.cwd, rawPath);
|
|
11804
11835
|
const backupContent = readBackupContent(
|
|
11805
11836
|
this.fileHistoryRoot,
|
|
11806
11837
|
args.toolSessionId,
|
|
@@ -11840,7 +11871,7 @@ var init_claude_history = __esm({
|
|
|
11840
11871
|
let totalInsertions = 0;
|
|
11841
11872
|
let totalDeletions = 0;
|
|
11842
11873
|
for (const [rawPath, backup] of Object.entries(target)) {
|
|
11843
|
-
const absPath =
|
|
11874
|
+
const absPath = import_node_path4.default.isAbsolute(rawPath) ? rawPath : import_node_path4.default.join(args.cwd, rawPath);
|
|
11844
11875
|
const backupContent = readBackupContent(
|
|
11845
11876
|
this.fileHistoryRoot,
|
|
11846
11877
|
args.toolSessionId,
|
|
@@ -11887,7 +11918,7 @@ var init_claude_history = __esm({
|
|
|
11887
11918
|
};
|
|
11888
11919
|
}
|
|
11889
11920
|
readSubagentFromMainJsonl(cwd, toolSessionId, subagentId) {
|
|
11890
|
-
const file =
|
|
11921
|
+
const file = import_node_path4.default.join(
|
|
11891
11922
|
this.projectsRoot,
|
|
11892
11923
|
cwdToHashDir(cwd),
|
|
11893
11924
|
`${toolSessionId}.jsonl`
|
|
@@ -12256,10 +12287,10 @@ function parseAttachment(obj) {
|
|
|
12256
12287
|
const memories = raw.map((m2) => {
|
|
12257
12288
|
if (!m2 || typeof m2 !== "object") return null;
|
|
12258
12289
|
const rec3 = m2;
|
|
12259
|
-
const
|
|
12290
|
+
const path68 = typeof rec3.path === "string" ? rec3.path : null;
|
|
12260
12291
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
12261
|
-
if (!
|
|
12262
|
-
const out = { path:
|
|
12292
|
+
if (!path68 || content == null) return null;
|
|
12293
|
+
const out = { path: path68, content };
|
|
12263
12294
|
if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
|
|
12264
12295
|
return out;
|
|
12265
12296
|
}).filter((m2) => m2 !== null);
|
|
@@ -12391,8 +12422,9 @@ var init_claude = __esm({
|
|
|
12391
12422
|
};
|
|
12392
12423
|
CLAUDE_MODELS = [
|
|
12393
12424
|
{ id: "", label: "Default", description: "CLI default model", contextWindowSize: 2e5, default: true },
|
|
12394
|
-
{ id: "sonnet", label: "Sonnet", description: "Fast, balanced", contextWindowSize: 2e5 },
|
|
12395
12425
|
{ id: "opus", label: "Opus", description: "Most capable", contextWindowSize: 1e6 },
|
|
12426
|
+
{ id: "fable", label: "Fable", contextWindowSize: 2e5 },
|
|
12427
|
+
{ id: "sonnet", label: "Sonnet", description: "Fast, balanced", contextWindowSize: 2e5 },
|
|
12396
12428
|
{ id: "haiku", label: "Haiku", description: "Fastest, lightest", contextWindowSize: 2e5 }
|
|
12397
12429
|
];
|
|
12398
12430
|
CLAUDE_PERMISSION_MODES = [
|
|
@@ -33223,8 +33255,8 @@ var require_utils = __commonJS({
|
|
|
33223
33255
|
var result = transform[inputType][outputType](input);
|
|
33224
33256
|
return result;
|
|
33225
33257
|
};
|
|
33226
|
-
exports2.resolve = function(
|
|
33227
|
-
var parts =
|
|
33258
|
+
exports2.resolve = function(path68) {
|
|
33259
|
+
var parts = path68.split("/");
|
|
33228
33260
|
var result = [];
|
|
33229
33261
|
for (var index = 0; index < parts.length; index++) {
|
|
33230
33262
|
var part = parts[index];
|
|
@@ -39077,18 +39109,18 @@ var require_object = __commonJS({
|
|
|
39077
39109
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
39078
39110
|
this.files[name] = object;
|
|
39079
39111
|
};
|
|
39080
|
-
var parentFolder = function(
|
|
39081
|
-
if (
|
|
39082
|
-
|
|
39112
|
+
var parentFolder = function(path68) {
|
|
39113
|
+
if (path68.slice(-1) === "/") {
|
|
39114
|
+
path68 = path68.substring(0, path68.length - 1);
|
|
39083
39115
|
}
|
|
39084
|
-
var lastSlash =
|
|
39085
|
-
return lastSlash > 0 ?
|
|
39116
|
+
var lastSlash = path68.lastIndexOf("/");
|
|
39117
|
+
return lastSlash > 0 ? path68.substring(0, lastSlash) : "";
|
|
39086
39118
|
};
|
|
39087
|
-
var forceTrailingSlash = function(
|
|
39088
|
-
if (
|
|
39089
|
-
|
|
39119
|
+
var forceTrailingSlash = function(path68) {
|
|
39120
|
+
if (path68.slice(-1) !== "/") {
|
|
39121
|
+
path68 += "/";
|
|
39090
39122
|
}
|
|
39091
|
-
return
|
|
39123
|
+
return path68;
|
|
39092
39124
|
};
|
|
39093
39125
|
var folderAdd = function(name, createFolders) {
|
|
39094
39126
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -40090,7 +40122,7 @@ var require_lib3 = __commonJS({
|
|
|
40090
40122
|
// src/run-case/recorder.ts
|
|
40091
40123
|
function startRunCaseRecorder(opts) {
|
|
40092
40124
|
const now = opts.now ?? Date.now;
|
|
40093
|
-
const dir =
|
|
40125
|
+
const dir = import_node_path56.default.dirname(opts.recordPath);
|
|
40094
40126
|
let stream = null;
|
|
40095
40127
|
let closing = false;
|
|
40096
40128
|
let closedSettled = false;
|
|
@@ -40130,12 +40162,12 @@ function startRunCaseRecorder(opts) {
|
|
|
40130
40162
|
};
|
|
40131
40163
|
return { tap, close, closed };
|
|
40132
40164
|
}
|
|
40133
|
-
var import_node_fs43,
|
|
40165
|
+
var import_node_fs43, import_node_path56;
|
|
40134
40166
|
var init_recorder = __esm({
|
|
40135
40167
|
"src/run-case/recorder.ts"() {
|
|
40136
40168
|
"use strict";
|
|
40137
40169
|
import_node_fs43 = __toESM(require("fs"), 1);
|
|
40138
|
-
|
|
40170
|
+
import_node_path56 = __toESM(require("path"), 1);
|
|
40139
40171
|
}
|
|
40140
40172
|
});
|
|
40141
40173
|
|
|
@@ -40178,7 +40210,7 @@ var init_wire = __esm({
|
|
|
40178
40210
|
// src/run-case/controller.ts
|
|
40179
40211
|
async function runController(opts) {
|
|
40180
40212
|
const now = opts.now ?? Date.now;
|
|
40181
|
-
const cwd = opts.cwd ?? (0, import_node_fs44.mkdtempSync)(
|
|
40213
|
+
const cwd = opts.cwd ?? (0, import_node_fs44.mkdtempSync)(import_node_path57.default.join(import_node_os22.default.tmpdir(), "clawd-runcase-"));
|
|
40182
40214
|
const ownsCwd = opts.cwd === void 0;
|
|
40183
40215
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
40184
40216
|
const spawnCtx = { cwd };
|
|
@@ -40345,13 +40377,13 @@ async function runController(opts) {
|
|
|
40345
40377
|
}
|
|
40346
40378
|
return exitCode ?? 0;
|
|
40347
40379
|
}
|
|
40348
|
-
var import_node_fs44,
|
|
40380
|
+
var import_node_fs44, import_node_os22, import_node_path57;
|
|
40349
40381
|
var init_controller = __esm({
|
|
40350
40382
|
"src/run-case/controller.ts"() {
|
|
40351
40383
|
"use strict";
|
|
40352
40384
|
import_node_fs44 = require("fs");
|
|
40353
|
-
|
|
40354
|
-
|
|
40385
|
+
import_node_os22 = __toESM(require("os"), 1);
|
|
40386
|
+
import_node_path57 = __toESM(require("path"), 1);
|
|
40355
40387
|
init_claude();
|
|
40356
40388
|
init_stdout_splitter();
|
|
40357
40389
|
init_permission_stdio();
|
|
@@ -40613,9 +40645,9 @@ Env (advanced):
|
|
|
40613
40645
|
`;
|
|
40614
40646
|
|
|
40615
40647
|
// src/index.ts
|
|
40616
|
-
var
|
|
40648
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
40617
40649
|
var import_node_fs42 = __toESM(require("fs"), 1);
|
|
40618
|
-
var
|
|
40650
|
+
var import_node_os21 = __toESM(require("os"), 1);
|
|
40619
40651
|
|
|
40620
40652
|
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
40621
40653
|
var byteToHex = [];
|
|
@@ -41232,9 +41264,9 @@ var SessionStoreFactory = class {
|
|
|
41232
41264
|
};
|
|
41233
41265
|
|
|
41234
41266
|
// src/session/manager.ts
|
|
41235
|
-
var
|
|
41236
|
-
var
|
|
41237
|
-
var
|
|
41267
|
+
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
41268
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
41269
|
+
var import_node_os5 = __toESM(require("os"), 1);
|
|
41238
41270
|
init_protocol();
|
|
41239
41271
|
|
|
41240
41272
|
// src/tools/guest-settings.ts
|
|
@@ -41332,6 +41364,10 @@ function escapeAttr(v2) {
|
|
|
41332
41364
|
return v2.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
41333
41365
|
}
|
|
41334
41366
|
|
|
41367
|
+
// src/session/runner.ts
|
|
41368
|
+
var import_node_os4 = __toESM(require("os"), 1);
|
|
41369
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
41370
|
+
|
|
41335
41371
|
// src/session/reducer.ts
|
|
41336
41372
|
init_runtime();
|
|
41337
41373
|
|
|
@@ -41418,7 +41454,7 @@ var ATTACHMENT_SHARING_HINT = `## \u628A\u4EA7\u51FA\u6587\u4EF6\u5206\u4EAB\u7E
|
|
|
41418
41454
|
// src/dispatch/system-prompt.ts
|
|
41419
41455
|
var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A persona\uFF08dispatch\uFF09
|
|
41420
41456
|
|
|
41421
|
-
\u5F53\u7528\u6237\u6D88\u606F\u91CC\u542B \`@persona/<id>\`\uFF08\u5982 \`@persona/persona-
|
|
41457
|
+
\u5F53\u7528\u6237\u6D88\u606F\u91CC\u542B \`@persona/<id>\`\uFF08\u5982 \`@persona/persona-app-builder\`\uFF09\u65F6\uFF0C**\u4F60\u5FC5\u987B**\u7ACB\u5373\u8C03 MCP tool \`mcp__clawd-dispatch__personaDispatch\` \u59D4\u6D3E\uFF0C\u4E0D\u8981\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF1A
|
|
41422
41458
|
|
|
41423
41459
|
- \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
|
|
41424
41460
|
- \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
|
|
@@ -41470,7 +41506,7 @@ function cloneState(s) {
|
|
|
41470
41506
|
pendingSend: s.pendingSend.slice()
|
|
41471
41507
|
};
|
|
41472
41508
|
}
|
|
41473
|
-
var IDLE_KILL_DELAY_MS =
|
|
41509
|
+
var IDLE_KILL_DELAY_MS = 6e5;
|
|
41474
41510
|
function tryFlushPending(state, deps) {
|
|
41475
41511
|
if (!state.readyForSend || state.pendingSend.length === 0) return [];
|
|
41476
41512
|
const text = state.pendingSend.shift();
|
|
@@ -41527,8 +41563,6 @@ function buildSpawnContext(state, deps) {
|
|
|
41527
41563
|
env.CLAWD_SESSION_ID = file.sessionId;
|
|
41528
41564
|
const daemonUrl = deps.getDaemonUrl?.() ?? null;
|
|
41529
41565
|
if (daemonUrl) env.CLAWD_DAEMON_URL = daemonUrl;
|
|
41530
|
-
const dispatchId = deps.lookupDispatchByBSessionId?.(file.sessionId);
|
|
41531
|
-
if (dispatchId) env.CLAWD_DISPATCH_ID = dispatchId;
|
|
41532
41566
|
const personaId = file.ownerPersonaId;
|
|
41533
41567
|
if (personaId) env.CLAWD_PERSONA_ID = personaId;
|
|
41534
41568
|
const dispatchMcpConfigPath2 = deps.getDispatchMcpConfigPath?.() ?? null;
|
|
@@ -42141,6 +42175,18 @@ function reduceSession(state, input, deps) {
|
|
|
42141
42175
|
if (state.status !== "running-idle") {
|
|
42142
42176
|
return { state, effects: [] };
|
|
42143
42177
|
}
|
|
42178
|
+
if (input.subagentActive) {
|
|
42179
|
+
return {
|
|
42180
|
+
state,
|
|
42181
|
+
effects: [
|
|
42182
|
+
{
|
|
42183
|
+
kind: "schedule-idle-kill",
|
|
42184
|
+
sessionId: state.file.sessionId,
|
|
42185
|
+
ms: IDLE_KILL_DELAY_MS
|
|
42186
|
+
}
|
|
42187
|
+
]
|
|
42188
|
+
};
|
|
42189
|
+
}
|
|
42144
42190
|
const next = cloneState(state);
|
|
42145
42191
|
next.status = "stopping";
|
|
42146
42192
|
return {
|
|
@@ -42197,10 +42243,11 @@ function reduceSession(state, input, deps) {
|
|
|
42197
42243
|
// src/session/runner.ts
|
|
42198
42244
|
init_stdout_splitter();
|
|
42199
42245
|
init_permission_stdio();
|
|
42246
|
+
init_claude_history();
|
|
42200
42247
|
|
|
42201
42248
|
// src/ipc-recorder.ts
|
|
42202
|
-
var
|
|
42203
|
-
var
|
|
42249
|
+
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
42250
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
42204
42251
|
function tsForFilename(ms) {
|
|
42205
42252
|
return new Date(ms).toISOString().replace(/[:.]/g, "-");
|
|
42206
42253
|
}
|
|
@@ -42211,8 +42258,8 @@ function startRecorder(opts) {
|
|
|
42211
42258
|
return null;
|
|
42212
42259
|
}
|
|
42213
42260
|
const now = opts.now ?? Date.now;
|
|
42214
|
-
const dir =
|
|
42215
|
-
const filePath =
|
|
42261
|
+
const dir = import_node_path5.default.join(opts.dataDir, "ipc-recordings", opts.sessionId);
|
|
42262
|
+
const filePath = import_node_path5.default.join(dir, `${tsForFilename(now())}.jsonl`);
|
|
42216
42263
|
let stream = null;
|
|
42217
42264
|
let closedResolve;
|
|
42218
42265
|
const closed = new Promise((resolve6) => {
|
|
@@ -42221,8 +42268,8 @@ function startRecorder(opts) {
|
|
|
42221
42268
|
let exited = false;
|
|
42222
42269
|
const ensureStream = () => {
|
|
42223
42270
|
if (stream) return stream;
|
|
42224
|
-
|
|
42225
|
-
stream =
|
|
42271
|
+
import_node_fs5.default.mkdirSync(dir, { recursive: true });
|
|
42272
|
+
stream = import_node_fs5.default.createWriteStream(filePath, { flags: "a" });
|
|
42226
42273
|
stream.on("close", () => closedResolve());
|
|
42227
42274
|
return stream;
|
|
42228
42275
|
};
|
|
@@ -42267,6 +42314,7 @@ function encodeAllowWithInputControlResponse(requestId, updatedInput) {
|
|
|
42267
42314
|
return JSON.stringify(payload) + "\n";
|
|
42268
42315
|
}
|
|
42269
42316
|
var DEFAULT_WAIT_STOP_TIMEOUT_MS = 3e3;
|
|
42317
|
+
var SUBAGENT_ACTIVE_WINDOW_MS = 3e5;
|
|
42270
42318
|
var SessionRunner = class {
|
|
42271
42319
|
constructor(initial, hooks) {
|
|
42272
42320
|
this.hooks = hooks;
|
|
@@ -42320,14 +42368,14 @@ var SessionRunner = class {
|
|
|
42320
42368
|
// 单栏 refactor (spec 2026-06-02 §5.1): cc 子进程 env 注入 CLAWD_DAEMON_URL,让 assistant
|
|
42321
42369
|
// curl daemon HTTP RPC adapter (/api/rpc/<method>) 触发管理操作。null = HTTP adapter 未启。
|
|
42322
42370
|
getDaemonUrl: this.hooks.getDaemonUrl,
|
|
42323
|
-
// Persona dispatch:透传 dispatch.mcp.json
|
|
42324
|
-
//
|
|
42371
|
+
// Persona dispatch:透传 dispatch.mcp.json 路径闭包,让 cc spawn 加 --mcp-config flag
|
|
42372
|
+
// 使两侧 cc 都能看到 personaDispatch / personaDispatchComplete tool(按 session 身份分工用哪个)。
|
|
42373
|
+
// dispatchId 不注 cc env——complete handler 用 sessionId 反查 in-flight dispatchId 配对。
|
|
42325
42374
|
getDispatchMcpConfigPath: this.hooks.getDispatchMcpConfigPath,
|
|
42326
42375
|
getShiftMcpConfigPath: this.hooks.getShiftMcpConfigPath,
|
|
42327
42376
|
getInboxMcpConfigPath: this.hooks.getInboxMcpConfigPath,
|
|
42328
42377
|
// Ticket MCP:透传 ticket.mcp.json 路径闭包(reducer 内做 persona-ticket-manager gating)
|
|
42329
42378
|
getTicketMcpConfigPath: this.hooks.getTicketMcpConfigPath,
|
|
42330
|
-
lookupDispatchByBSessionId: this.hooks.lookupDispatchByBSessionId,
|
|
42331
42379
|
// ReadyGate v2:透传 mode 让 reducer send / ready-detected 分支决定走暂存队列还是直写
|
|
42332
42380
|
mode: this.hooks.mode,
|
|
42333
42381
|
// [RG-DBG] 注入 logger 让 reducer rgDbg 走 pino 进 clawd.log;定位完跟 rgDbg 一起删
|
|
@@ -42579,7 +42627,7 @@ var SessionRunner = class {
|
|
|
42579
42627
|
if (existing) clearTimeout(existing);
|
|
42580
42628
|
const timer = setTimeout(() => {
|
|
42581
42629
|
this.idleKillTimers.delete(effect.sessionId);
|
|
42582
|
-
this.input({ kind: "idle-kill-fired" });
|
|
42630
|
+
this.input({ kind: "idle-kill-fired", subagentActive: this.isSubagentActive() });
|
|
42583
42631
|
}, effect.ms);
|
|
42584
42632
|
timer.unref?.();
|
|
42585
42633
|
this.idleKillTimers.set(effect.sessionId, timer);
|
|
@@ -42595,6 +42643,18 @@ var SessionRunner = class {
|
|
|
42595
42643
|
}
|
|
42596
42644
|
}
|
|
42597
42645
|
}
|
|
42646
|
+
// idle-kill 到点判定:本 session 的 subagents/ 里是否还有 agent-*.jsonl 在近期写盘。
|
|
42647
|
+
// 新鲜(近 SUBAGENT_ACTIVE_WINDOW_MS 内有写)= 后台 subagent 还在干活 → 不该杀。
|
|
42648
|
+
// 没有 toolSessionId(SDK 模式 CC 内生 id)/ 无目录 / 无 agent 文件 → false(照常回收)。
|
|
42649
|
+
isSubagentActive() {
|
|
42650
|
+
const toolSessionId = this.state.file.toolSessionId;
|
|
42651
|
+
if (!toolSessionId) return false;
|
|
42652
|
+
const projectsRoot = import_node_path6.default.join(this.hooks.home ?? import_node_os4.default.homedir(), ".claude", "projects");
|
|
42653
|
+
const mtime = newestSubagentMtimeMs(projectsRoot, this.state.file.cwd, toolSessionId);
|
|
42654
|
+
if (mtime === null) return false;
|
|
42655
|
+
const now = (this.hooks.now ?? Date.now)();
|
|
42656
|
+
return now - mtime < SUBAGENT_ACTIVE_WINDOW_MS;
|
|
42657
|
+
}
|
|
42598
42658
|
// 清空所有 idle-kill timer(runner dispose / proc 永久退出时调用)。
|
|
42599
42659
|
// 不喂 idle-kill-fired —— dispose 路径不再翻 reducer 状态
|
|
42600
42660
|
clearIdleKillTimers() {
|
|
@@ -42677,15 +42737,15 @@ function extractEditPath(input) {
|
|
|
42677
42737
|
}
|
|
42678
42738
|
|
|
42679
42739
|
// src/debug/pty-probe.ts
|
|
42680
|
-
var
|
|
42681
|
-
var
|
|
42740
|
+
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
42741
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
42682
42742
|
var PROBE_DIR = "/tmp/clawd-probe";
|
|
42683
|
-
var EVENTS_FILE =
|
|
42743
|
+
var EVENTS_FILE = import_node_path7.default.join(PROBE_DIR, "events.jsonl");
|
|
42684
42744
|
var inited = false;
|
|
42685
42745
|
function ensureDir() {
|
|
42686
42746
|
if (inited) return true;
|
|
42687
42747
|
try {
|
|
42688
|
-
|
|
42748
|
+
import_node_fs6.default.mkdirSync(PROBE_DIR, { recursive: true });
|
|
42689
42749
|
inited = true;
|
|
42690
42750
|
return true;
|
|
42691
42751
|
} catch {
|
|
@@ -42696,15 +42756,15 @@ function probeEvent(event, data = {}) {
|
|
|
42696
42756
|
try {
|
|
42697
42757
|
if (!ensureDir()) return;
|
|
42698
42758
|
const line = JSON.stringify({ ts: Date.now(), event, ...data }) + "\n";
|
|
42699
|
-
|
|
42759
|
+
import_node_fs6.default.appendFileSync(EVENTS_FILE, line);
|
|
42700
42760
|
} catch {
|
|
42701
42761
|
}
|
|
42702
42762
|
}
|
|
42703
42763
|
function probeDumpReplay(sessionId, payload) {
|
|
42704
42764
|
try {
|
|
42705
42765
|
if (!ensureDir()) return "";
|
|
42706
|
-
const file =
|
|
42707
|
-
|
|
42766
|
+
const file = import_node_path7.default.join(PROBE_DIR, `replay-${sessionId}-${Date.now()}.ans`);
|
|
42767
|
+
import_node_fs6.default.writeFileSync(file, payload, "utf8");
|
|
42708
42768
|
return file;
|
|
42709
42769
|
} catch {
|
|
42710
42770
|
return "";
|
|
@@ -42799,9 +42859,22 @@ You may read this file with your Read tool to understand context. You do not hav
|
|
|
42799
42859
|
|
|
42800
42860
|
When done, call the MCP tool \`mcp__clawd-dispatch__personaDispatchComplete\` with your result:
|
|
42801
42861
|
- Success: { text: "...", filePaths?: ["abs/path", ...] }
|
|
42802
|
-
- Failure: { isFailure: true, reason: "..." }
|
|
42862
|
+
- Failure: { isFailure: true, reason: "..." }`;
|
|
42863
|
+
}
|
|
42864
|
+
function buildDispatchContinuationPack(args) {
|
|
42865
|
+
return `[Dispatched from owner \u2014 follow-up query]
|
|
42803
42866
|
|
|
42804
|
-
|
|
42867
|
+
Although you reported back on the previous task, the owner has a follow-up question. Continue from where you left off.
|
|
42868
|
+
|
|
42869
|
+
Owner's new message:
|
|
42870
|
+
${args.prompt}
|
|
42871
|
+
|
|
42872
|
+
Source conversation (jsonl, same path as before, may contain new messages):
|
|
42873
|
+
${args.sourceJsonlPath}
|
|
42874
|
+
|
|
42875
|
+
When done, call \`mcp__clawd-dispatch__personaDispatchComplete\` again with your result:
|
|
42876
|
+
- Success: { text: "...", filePaths?: ["abs/path", ...] }
|
|
42877
|
+
- Failure: { isFailure: true, reason: "..." }`;
|
|
42805
42878
|
}
|
|
42806
42879
|
function derivePersonaSpawnCwd(file, personaRoot) {
|
|
42807
42880
|
const personaId = file.ownerPersonaId;
|
|
@@ -42811,7 +42884,7 @@ function derivePersonaSpawnCwd(file, personaRoot) {
|
|
|
42811
42884
|
`derivePersonaSpawnCwd: personaRoot missing for owner session ${file.sessionId} (ownerPersonaId=${personaId})`
|
|
42812
42885
|
);
|
|
42813
42886
|
}
|
|
42814
|
-
return
|
|
42887
|
+
return import_node_path8.default.join(personaRoot, safeFileName(personaId));
|
|
42815
42888
|
}
|
|
42816
42889
|
function makeInitialState(file, subSessionMeta) {
|
|
42817
42890
|
return {
|
|
@@ -42936,10 +43009,10 @@ var SessionManager = class {
|
|
|
42936
43009
|
// <dataDir>/sessions/ 列子目录 (排除 'default').
|
|
42937
43010
|
listPersonaIdsOnDisk() {
|
|
42938
43011
|
if (!this.deps.dataDir) return [];
|
|
42939
|
-
const root = this.deps.storeFactory ?
|
|
43012
|
+
const root = this.deps.storeFactory ? import_node_path8.default.join(this.deps.dataDir, "personas") : import_node_path8.default.join(this.deps.dataDir, "sessions");
|
|
42940
43013
|
let entries;
|
|
42941
43014
|
try {
|
|
42942
|
-
entries =
|
|
43015
|
+
entries = import_node_fs7.default.readdirSync(root, { withFileTypes: true });
|
|
42943
43016
|
} catch (err) {
|
|
42944
43017
|
const code = err?.code;
|
|
42945
43018
|
if (code === "ENOENT") return [];
|
|
@@ -42952,7 +43025,7 @@ var SessionManager = class {
|
|
|
42952
43025
|
// 只在 storeFactory 注入 (新布局) 下生效, 老布局无 guest 目录.
|
|
42953
43026
|
listGuestCapIdsForPersona(personaId) {
|
|
42954
43027
|
if (!this.deps.dataDir || !this.deps.storeFactory) return [];
|
|
42955
|
-
const root =
|
|
43028
|
+
const root = import_node_path8.default.join(
|
|
42956
43029
|
this.deps.dataDir,
|
|
42957
43030
|
"personas",
|
|
42958
43031
|
personaId,
|
|
@@ -42962,7 +43035,7 @@ var SessionManager = class {
|
|
|
42962
43035
|
);
|
|
42963
43036
|
let entries;
|
|
42964
43037
|
try {
|
|
42965
|
-
entries =
|
|
43038
|
+
entries = import_node_fs7.default.readdirSync(root, { withFileTypes: true });
|
|
42966
43039
|
} catch (err) {
|
|
42967
43040
|
const code = err?.code;
|
|
42968
43041
|
if (code === "ENOENT") return [];
|
|
@@ -43081,7 +43154,7 @@ var SessionManager = class {
|
|
|
43081
43154
|
callerDisplayName
|
|
43082
43155
|
);
|
|
43083
43156
|
if (subSessionMeta?.userWorkDir) {
|
|
43084
|
-
|
|
43157
|
+
import_node_fs7.default.mkdirSync(subSessionMeta.userWorkDir, { recursive: true });
|
|
43085
43158
|
}
|
|
43086
43159
|
if (scope.kind === "persona" && scope.mode === "guest") {
|
|
43087
43160
|
if (!this.deps.personaRoot || !subSessionMeta?.userWorkDir) {
|
|
@@ -43092,8 +43165,8 @@ var SessionManager = class {
|
|
|
43092
43165
|
const base = this.deps.personaStore?.readSandboxSettings(scope.personaId) ?? null;
|
|
43093
43166
|
const settings = composeGuestSandbox(base, subSessionMeta.userWorkDir, file.cwd);
|
|
43094
43167
|
subSessionMeta.extraSettings = JSON.stringify(settings);
|
|
43095
|
-
const home =
|
|
43096
|
-
const expand = (p2) => p2 === "~" ? home : p2.startsWith("~/") ?
|
|
43168
|
+
const home = import_node_os5.default.homedir();
|
|
43169
|
+
const expand = (p2) => p2 === "~" ? home : p2.startsWith("~/") ? import_node_path8.default.join(home, p2.slice(2)) : p2;
|
|
43097
43170
|
const codexCfg = this.deps.personaStore?.readCodexSandboxSettings(scope.personaId) ?? null;
|
|
43098
43171
|
subSessionMeta.codexSandbox = {
|
|
43099
43172
|
writableRoots: [subSessionMeta.userWorkDir, ...(codexCfg?.writableRoots ?? []).map(expand)],
|
|
@@ -43122,13 +43195,13 @@ var SessionManager = class {
|
|
|
43122
43195
|
// 单栏 refactor (spec 2026-06-02 §5.1): 透传 daemon HTTP RPC base URL 闭包,
|
|
43123
43196
|
// reducer 把它注入 cc 子进程 env CLAWD_DAEMON_URL.
|
|
43124
43197
|
getDaemonUrl: this.deps.getDaemonUrl,
|
|
43125
|
-
// Persona dispatch
|
|
43126
|
-
//
|
|
43198
|
+
// Persona dispatch: dispatch.mcp.json 路径闭包透传给 reducer,让 cc spawn 加
|
|
43199
|
+
// --mcp-config flag 挂 dispatch MCP server(两侧 cc 都挂,按 session 身份分工调 tool)。
|
|
43200
|
+
// dispatchId 不再走 cc env——complete handler 用 sessionId 反查 in-flight dispatchId 配对。
|
|
43127
43201
|
getDispatchMcpConfigPath: this.deps.dispatchMcpConfigPath ? () => this.deps.dispatchMcpConfigPath ?? null : void 0,
|
|
43128
43202
|
getTicketMcpConfigPath: this.deps.ticketMcpConfigPath ? () => this.deps.ticketMcpConfigPath ?? null : void 0,
|
|
43129
43203
|
getShiftMcpConfigPath: this.deps.shiftMcpConfigPath ? () => this.deps.shiftMcpConfigPath ?? null : void 0,
|
|
43130
43204
|
getInboxMcpConfigPath: this.deps.inboxMcpConfigPath ? () => this.deps.inboxMcpConfigPath ?? null : void 0,
|
|
43131
|
-
lookupDispatchByBSessionId: this.deps.personaDispatchManager ? (bSid) => this.deps.personaDispatchManager?.lookupDispatchByBSessionId(bSid) : void 0,
|
|
43132
43205
|
// file-sharing (spec §6 PR 3):闭包 scope + sessionId,runner 只暴露 tool/relPath/cwd
|
|
43133
43206
|
onFileEdit: attachmentGroup ? (input) => attachmentGroup.onFileEdit({
|
|
43134
43207
|
scope,
|
|
@@ -43246,7 +43319,7 @@ var SessionManager = class {
|
|
|
43246
43319
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, "cwd required when ownerPersonaId is absent");
|
|
43247
43320
|
}
|
|
43248
43321
|
try {
|
|
43249
|
-
const stat =
|
|
43322
|
+
const stat = import_node_fs7.default.statSync(cwd);
|
|
43250
43323
|
if (!stat.isDirectory()) throw new Error("not dir");
|
|
43251
43324
|
} catch {
|
|
43252
43325
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `cwd not a directory: ${cwd}`);
|
|
@@ -43777,7 +43850,7 @@ var SessionManager = class {
|
|
|
43777
43850
|
*/
|
|
43778
43851
|
createForScope(args) {
|
|
43779
43852
|
try {
|
|
43780
|
-
const stat =
|
|
43853
|
+
const stat = import_node_fs7.default.statSync(args.cwd);
|
|
43781
43854
|
if (!stat.isDirectory()) throw new Error("not dir");
|
|
43782
43855
|
} catch {
|
|
43783
43856
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `cwd not a directory: ${args.cwd}`);
|
|
@@ -43968,10 +44041,11 @@ var SessionManager = class {
|
|
|
43968
44041
|
* Persona dispatch: 启动 B session 并投递任务包当第一条 user message。
|
|
43969
44042
|
*
|
|
43970
44043
|
* - 复用 persona-owner 创建路径(cwd=personaDir、scope=persona-owner、不沙箱)
|
|
43971
|
-
* - SessionFile 上写 dispatchedFromSessionId 关联回 A(UI 折叠用;mirror 一侧 strip
|
|
43972
|
-
*
|
|
43973
|
-
*
|
|
43974
|
-
*
|
|
44044
|
+
* - SessionFile 上写 dispatchedFromSessionId 关联回 A(UI 折叠用;mirror 一侧 strip;
|
|
44045
|
+
* targetSessionId 复用路径也按此字段校验寻址来源)
|
|
44046
|
+
* - 跟 PersonaDispatchManager 登记 dispatchId → B sessionId(complete handler 用
|
|
44047
|
+
* findInflightDispatchByBSessionId 反查回 dispatchId 配对回 A 的 waiter)
|
|
44048
|
+
* - 投任务包;包尾教 B 用 personaDispatchComplete tool 回传
|
|
43975
44049
|
*
|
|
43976
44050
|
* cwd 派生与 SessionManager.create 的 owner persona 路径一致(derivePersonaSpawnCwd)。
|
|
43977
44051
|
*/
|
|
@@ -43993,7 +44067,7 @@ var SessionManager = class {
|
|
|
43993
44067
|
personaId: args.targetPersona,
|
|
43994
44068
|
mode: "owner"
|
|
43995
44069
|
};
|
|
43996
|
-
const cwd =
|
|
44070
|
+
const cwd = import_node_path8.default.join(this.deps.personaRoot, safeFileName(args.targetPersona));
|
|
43997
44071
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
43998
44072
|
const file = {
|
|
43999
44073
|
sessionId,
|
|
@@ -44026,8 +44100,7 @@ var SessionManager = class {
|
|
|
44026
44100
|
});
|
|
44027
44101
|
const taskPack = buildDispatchTaskPack({
|
|
44028
44102
|
prompt: args.prompt,
|
|
44029
|
-
sourceJsonlPath: args.sourceJsonlPath
|
|
44030
|
-
dispatchId: args.dispatchId
|
|
44103
|
+
sourceJsonlPath: args.sourceJsonlPath
|
|
44031
44104
|
});
|
|
44032
44105
|
runner.input({ kind: "command", command: { kind: "send", text: taskPack } });
|
|
44033
44106
|
this.deps.logger?.info("dispatch.createDispatchedSession.task-pack-sent", {
|
|
@@ -44036,6 +44109,59 @@ var SessionManager = class {
|
|
|
44036
44109
|
});
|
|
44037
44110
|
return { sessionId };
|
|
44038
44111
|
}
|
|
44112
|
+
/**
|
|
44113
|
+
* targetSessionId 精确寻址已知 B session 复用其上下文。投 continuation pack 给 runner。
|
|
44114
|
+
*
|
|
44115
|
+
* 关键差异 vs createDispatchedSession:
|
|
44116
|
+
* - 不 newSessionId() / 不写 SessionFile —— B session 复用(走 findOwnedSession)
|
|
44117
|
+
* - 权限校验:本地 dispatch → SessionFile.dispatchedFromSessionId === A 的 sessionId;
|
|
44118
|
+
* 跨设备 B 角色 → SessionFile.creatorPrincipalId === A 的 deviceId
|
|
44119
|
+
* - 跟 PersonaDispatchManager 重新登记(新 dispatchId 复用同 bSessionId)
|
|
44120
|
+
* - ensureRunnerForScope: cc 活复用;cc 死时首次 send 触发 spawn,jsonl 已存在自动 --resume
|
|
44121
|
+
*
|
|
44122
|
+
* @param callerIdentity 权限校验依据:
|
|
44123
|
+
* - kind='local': A 的 sessionId(本机 dispatch),校验 dispatchedFromSessionId 匹配
|
|
44124
|
+
* - kind='guest': A 的 deviceId(跨设备转发进来的 A),校验 creatorPrincipalId 匹配
|
|
44125
|
+
*/
|
|
44126
|
+
resumeDispatchedSession(args) {
|
|
44127
|
+
if (!this.deps.personaDispatchManager) {
|
|
44128
|
+
throw new Error("resumeDispatchedSession: personaDispatchManager missing in ManagerDeps");
|
|
44129
|
+
}
|
|
44130
|
+
const file = this.findOwnedSession(args.bSessionId);
|
|
44131
|
+
if (!file) {
|
|
44132
|
+
throw new Error(`resumeDispatchedSession: B session ${args.bSessionId} not found`);
|
|
44133
|
+
}
|
|
44134
|
+
if (args.callerIdentity.kind === "local") {
|
|
44135
|
+
if (file.dispatchedFromSessionId !== args.callerIdentity.sourceSessionId) {
|
|
44136
|
+
throw new Error(
|
|
44137
|
+
`resumeDispatchedSession: session ${args.bSessionId} not dispatched by caller (dispatchedFromSessionId mismatch)`
|
|
44138
|
+
);
|
|
44139
|
+
}
|
|
44140
|
+
} else {
|
|
44141
|
+
if (file.creatorPrincipalId !== args.callerIdentity.sourcePrincipalId) {
|
|
44142
|
+
throw new Error(
|
|
44143
|
+
`resumeDispatchedSession: session ${args.bSessionId} not dispatched by caller device (creatorPrincipalId mismatch)`
|
|
44144
|
+
);
|
|
44145
|
+
}
|
|
44146
|
+
}
|
|
44147
|
+
const scope = this.scopeForFile(file);
|
|
44148
|
+
this.deps.personaDispatchManager.registerBSession(args.dispatchId, args.bSessionId);
|
|
44149
|
+
this.deps.logger?.info("dispatch.resumeDispatchedSession.registered", {
|
|
44150
|
+
dispatchId: args.dispatchId,
|
|
44151
|
+
bSessionId: args.bSessionId
|
|
44152
|
+
});
|
|
44153
|
+
const runner = this.ensureRunnerForScope(file, scope);
|
|
44154
|
+
const pack = buildDispatchContinuationPack({
|
|
44155
|
+
prompt: args.prompt,
|
|
44156
|
+
sourceJsonlPath: args.sourceJsonlPath
|
|
44157
|
+
});
|
|
44158
|
+
runner.input({ kind: "command", command: { kind: "send", text: pack } });
|
|
44159
|
+
this.deps.logger?.info("dispatch.resumeDispatchedSession.continuation-sent", {
|
|
44160
|
+
dispatchId: args.dispatchId,
|
|
44161
|
+
bSessionId: args.bSessionId
|
|
44162
|
+
});
|
|
44163
|
+
return { sessionId: args.bSessionId };
|
|
44164
|
+
}
|
|
44039
44165
|
/**
|
|
44040
44166
|
* shift v1 (spec 2026-06-24-clawd-shift):到点 fire 时由 ShiftScheduler 调,
|
|
44041
44167
|
* 起一个新 cc session 跑 prompt(fire-and-forget,不绑 dispatchId / 不挂 caller)。
|
|
@@ -44058,7 +44184,7 @@ var SessionManager = class {
|
|
|
44058
44184
|
personaId: args.targetPersona,
|
|
44059
44185
|
mode: "owner"
|
|
44060
44186
|
};
|
|
44061
|
-
const cwd =
|
|
44187
|
+
const cwd = import_node_path8.default.join(this.deps.personaRoot, safeFileName(args.targetPersona));
|
|
44062
44188
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
44063
44189
|
const file = {
|
|
44064
44190
|
sessionId,
|
|
@@ -44540,28 +44666,28 @@ var SessionManager = class {
|
|
|
44540
44666
|
};
|
|
44541
44667
|
|
|
44542
44668
|
// src/persona/store.ts
|
|
44543
|
-
var
|
|
44544
|
-
var
|
|
44669
|
+
var fs8 = __toESM(require("fs"), 1);
|
|
44670
|
+
var path11 = __toESM(require("path"), 1);
|
|
44545
44671
|
init_protocol();
|
|
44546
44672
|
var PersonaStore = class {
|
|
44547
44673
|
constructor(root) {
|
|
44548
44674
|
this.root = root;
|
|
44549
|
-
|
|
44675
|
+
fs8.mkdirSync(root, { recursive: true });
|
|
44550
44676
|
}
|
|
44551
44677
|
root;
|
|
44552
44678
|
personaDir(personaId) {
|
|
44553
|
-
return
|
|
44679
|
+
return path11.join(this.root, safeFileName(personaId));
|
|
44554
44680
|
}
|
|
44555
44681
|
metaPath(personaId) {
|
|
44556
|
-
return
|
|
44682
|
+
return path11.join(this.personaDir(personaId), ".clawd", "persona.json");
|
|
44557
44683
|
}
|
|
44558
44684
|
claudeMdPath(personaId) {
|
|
44559
|
-
return
|
|
44685
|
+
return path11.join(this.personaDir(personaId), "CLAUDE.md");
|
|
44560
44686
|
}
|
|
44561
44687
|
// codex 原生读 cwd 的 AGENTS.md。人格双写镜像:claude 读 CLAUDE.md、codex 读 AGENTS.md,
|
|
44562
44688
|
// 两份内容恒一致,persona 切 tool 零迁移。
|
|
44563
44689
|
agentsMdPath(personaId) {
|
|
44564
|
-
return
|
|
44690
|
+
return path11.join(this.personaDir(personaId), "AGENTS.md");
|
|
44565
44691
|
}
|
|
44566
44692
|
/**
|
|
44567
44693
|
* persona 级 sandbox base 落盘路径 —— 故意放 `.clawd/` 而非 `.claude/`,让 CC 的 project
|
|
@@ -44570,11 +44696,11 @@ var PersonaStore = class {
|
|
|
44570
44696
|
* spawn 前 per-guest 动态拼到各自 session 目录的那份(base + 强制底座 + 本 guest userWorkDir carve)。
|
|
44571
44697
|
*/
|
|
44572
44698
|
sandboxSettingsPath(personaId) {
|
|
44573
|
-
return
|
|
44699
|
+
return path11.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
|
|
44574
44700
|
}
|
|
44575
44701
|
write(persona, personality) {
|
|
44576
44702
|
const dir = this.personaDir(persona.personaId);
|
|
44577
|
-
|
|
44703
|
+
fs8.mkdirSync(path11.join(dir, ".clawd"), { recursive: true });
|
|
44578
44704
|
this.atomicWrite(this.claudeMdPath(persona.personaId), personality);
|
|
44579
44705
|
this.atomicWrite(this.agentsMdPath(persona.personaId), personality);
|
|
44580
44706
|
this.writeSandboxSettings(persona.personaId, buildGuestSettingsV1());
|
|
@@ -44593,9 +44719,9 @@ var PersonaStore = class {
|
|
|
44593
44719
|
ensureAgentsMirror(personaId) {
|
|
44594
44720
|
const claudeMd = this.claudeMdPath(personaId);
|
|
44595
44721
|
const agentsMd = this.agentsMdPath(personaId);
|
|
44596
|
-
if (!
|
|
44597
|
-
if (
|
|
44598
|
-
this.atomicWrite(agentsMd,
|
|
44722
|
+
if (!fs8.existsSync(claudeMd)) return false;
|
|
44723
|
+
if (fs8.existsSync(agentsMd)) return false;
|
|
44724
|
+
this.atomicWrite(agentsMd, fs8.readFileSync(claudeMd, "utf8"));
|
|
44599
44725
|
return true;
|
|
44600
44726
|
}
|
|
44601
44727
|
/**
|
|
@@ -44619,22 +44745,22 @@ var PersonaStore = class {
|
|
|
44619
44745
|
return { ...s, permissions: { ...s.permissions ?? {}, deny: [...prev, rule] } };
|
|
44620
44746
|
}
|
|
44621
44747
|
codexSandboxSettingsPath(personaId) {
|
|
44622
|
-
return
|
|
44748
|
+
return path11.join(this.personaDir(personaId), ".clawd", "codex-sandbox.json");
|
|
44623
44749
|
}
|
|
44624
44750
|
/** 读 codex-sandbox.json;不存在/损坏 → null。 */
|
|
44625
44751
|
readCodexSandboxSettings(personaId) {
|
|
44626
44752
|
const p2 = this.codexSandboxSettingsPath(personaId);
|
|
44627
|
-
if (!
|
|
44753
|
+
if (!fs8.existsSync(p2)) return null;
|
|
44628
44754
|
try {
|
|
44629
|
-
return CodexSandboxSettingsSchema.parse(JSON.parse(
|
|
44755
|
+
return CodexSandboxSettingsSchema.parse(JSON.parse(fs8.readFileSync(p2, "utf8")));
|
|
44630
44756
|
} catch {
|
|
44631
44757
|
return null;
|
|
44632
44758
|
}
|
|
44633
44759
|
}
|
|
44634
44760
|
/** 覆盖写 codex-sandbox.json(seed/migrate 用)。 */
|
|
44635
44761
|
writeCodexSandboxSettings(personaId, settings) {
|
|
44636
|
-
const dir =
|
|
44637
|
-
|
|
44762
|
+
const dir = path11.join(this.personaDir(personaId), ".clawd");
|
|
44763
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
44638
44764
|
this.atomicWrite(this.codexSandboxSettingsPath(personaId), JSON.stringify(settings, null, 2));
|
|
44639
44765
|
}
|
|
44640
44766
|
writeMeta(persona) {
|
|
@@ -44642,8 +44768,8 @@ var PersonaStore = class {
|
|
|
44642
44768
|
}
|
|
44643
44769
|
read(personaId) {
|
|
44644
44770
|
const p2 = this.metaPath(personaId);
|
|
44645
|
-
if (!
|
|
44646
|
-
const raw = JSON.parse(
|
|
44771
|
+
if (!fs8.existsSync(p2)) return null;
|
|
44772
|
+
const raw = JSON.parse(fs8.readFileSync(p2, "utf8"));
|
|
44647
44773
|
if (raw && typeof raw === "object" && "tokenMap" in raw) {
|
|
44648
44774
|
delete raw.tokenMap;
|
|
44649
44775
|
this.atomicWrite(p2, JSON.stringify(raw, null, 2));
|
|
@@ -44651,13 +44777,13 @@ var PersonaStore = class {
|
|
|
44651
44777
|
return PersonaFileSchema.parse(raw);
|
|
44652
44778
|
}
|
|
44653
44779
|
has(personaId) {
|
|
44654
|
-
return
|
|
44780
|
+
return fs8.existsSync(this.metaPath(personaId));
|
|
44655
44781
|
}
|
|
44656
44782
|
readPersonality(personaId) {
|
|
44657
44783
|
const claudeMd = this.claudeMdPath(personaId);
|
|
44658
|
-
if (
|
|
44784
|
+
if (fs8.existsSync(claudeMd)) return fs8.readFileSync(claudeMd, "utf8");
|
|
44659
44785
|
const agentsMd = this.agentsMdPath(personaId);
|
|
44660
|
-
if (
|
|
44786
|
+
if (fs8.existsSync(agentsMd)) return fs8.readFileSync(agentsMd, "utf8");
|
|
44661
44787
|
return null;
|
|
44662
44788
|
}
|
|
44663
44789
|
/**
|
|
@@ -44666,23 +44792,23 @@ var PersonaStore = class {
|
|
|
44666
44792
|
*/
|
|
44667
44793
|
readSandboxSettings(personaId) {
|
|
44668
44794
|
const p2 = this.sandboxSettingsPath(personaId);
|
|
44669
|
-
if (!
|
|
44795
|
+
if (!fs8.existsSync(p2)) return null;
|
|
44670
44796
|
try {
|
|
44671
|
-
return JSON.parse(
|
|
44797
|
+
return JSON.parse(fs8.readFileSync(p2, "utf8"));
|
|
44672
44798
|
} catch {
|
|
44673
44799
|
return null;
|
|
44674
44800
|
}
|
|
44675
44801
|
}
|
|
44676
44802
|
/** Persona 私有 skills 目录路径:<personaDir>/.claude/skills */
|
|
44677
44803
|
skillsDir(personaId) {
|
|
44678
|
-
return
|
|
44804
|
+
return path11.join(this.personaDir(personaId), ".claude", "skills");
|
|
44679
44805
|
}
|
|
44680
44806
|
/**
|
|
44681
44807
|
* Claude Code 项目级 settings 路径:`<personaDir>/.claude/settings.json`。
|
|
44682
44808
|
* 这里只读 `enabledPlugins` 字段,由 owner 通过 CC `/plugin` 之类命令维护,daemon 不写。
|
|
44683
44809
|
*/
|
|
44684
44810
|
claudeSettingsPath(personaId) {
|
|
44685
|
-
return
|
|
44811
|
+
return path11.join(this.personaDir(personaId), ".claude", "settings.json");
|
|
44686
44812
|
}
|
|
44687
44813
|
/**
|
|
44688
44814
|
* 读取 persona 的 `.claude/settings.json` 中 `enabledPlugins` map,把 value === true
|
|
@@ -44697,10 +44823,10 @@ var PersonaStore = class {
|
|
|
44697
44823
|
*/
|
|
44698
44824
|
readEnabledPlugins(personaId) {
|
|
44699
44825
|
const p2 = this.claudeSettingsPath(personaId);
|
|
44700
|
-
if (!
|
|
44826
|
+
if (!fs8.existsSync(p2)) return [];
|
|
44701
44827
|
let raw;
|
|
44702
44828
|
try {
|
|
44703
|
-
raw = JSON.parse(
|
|
44829
|
+
raw = JSON.parse(fs8.readFileSync(p2, "utf8"));
|
|
44704
44830
|
} catch {
|
|
44705
44831
|
return [];
|
|
44706
44832
|
}
|
|
@@ -44714,22 +44840,22 @@ var PersonaStore = class {
|
|
|
44714
44840
|
return out;
|
|
44715
44841
|
}
|
|
44716
44842
|
list() {
|
|
44717
|
-
if (!
|
|
44718
|
-
return
|
|
44719
|
-
return
|
|
44843
|
+
if (!fs8.existsSync(this.root)) return [];
|
|
44844
|
+
return fs8.readdirSync(this.root).filter((name) => {
|
|
44845
|
+
return fs8.existsSync(path11.join(this.root, name, ".clawd", "persona.json"));
|
|
44720
44846
|
});
|
|
44721
44847
|
}
|
|
44722
44848
|
remove(personaId) {
|
|
44723
44849
|
const dir = this.personaDir(personaId);
|
|
44724
|
-
if (
|
|
44850
|
+
if (fs8.existsSync(dir)) fs8.rmSync(dir, { recursive: true, force: true });
|
|
44725
44851
|
}
|
|
44726
44852
|
personaDirPath(personaId) {
|
|
44727
44853
|
return this.personaDir(personaId);
|
|
44728
44854
|
}
|
|
44729
44855
|
atomicWrite(file, content) {
|
|
44730
44856
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
44731
|
-
|
|
44732
|
-
|
|
44857
|
+
fs8.writeFileSync(tmp, content, { mode: 384 });
|
|
44858
|
+
fs8.renameSync(tmp, file);
|
|
44733
44859
|
}
|
|
44734
44860
|
};
|
|
44735
44861
|
|
|
@@ -44775,9 +44901,9 @@ var PersonaRegistry = class {
|
|
|
44775
44901
|
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
44776
44902
|
|
|
44777
44903
|
// src/skills/scanner.ts
|
|
44778
|
-
var
|
|
44779
|
-
var
|
|
44780
|
-
var
|
|
44904
|
+
var import_node_fs8 = __toESM(require("fs"), 1);
|
|
44905
|
+
var import_node_os6 = __toESM(require("os"), 1);
|
|
44906
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
44781
44907
|
|
|
44782
44908
|
// src/skills/frontmatter.ts
|
|
44783
44909
|
var STRIP_QUOTES = /^["']|["']$/g;
|
|
@@ -44886,7 +45012,7 @@ function parseDescription(content) {
|
|
|
44886
45012
|
}
|
|
44887
45013
|
function isDirLikeSync(p2) {
|
|
44888
45014
|
try {
|
|
44889
|
-
return
|
|
45015
|
+
return import_node_fs8.default.statSync(p2).isDirectory();
|
|
44890
45016
|
} catch {
|
|
44891
45017
|
return false;
|
|
44892
45018
|
}
|
|
@@ -44894,19 +45020,19 @@ function isDirLikeSync(p2) {
|
|
|
44894
45020
|
function scanSkillDir(dir, source, seen, out, pluginName) {
|
|
44895
45021
|
let entries;
|
|
44896
45022
|
try {
|
|
44897
|
-
entries =
|
|
45023
|
+
entries = import_node_fs8.default.readdirSync(dir, { withFileTypes: true });
|
|
44898
45024
|
} catch {
|
|
44899
45025
|
return;
|
|
44900
45026
|
}
|
|
44901
45027
|
for (const ent of entries) {
|
|
44902
|
-
const entryPath =
|
|
45028
|
+
const entryPath = import_node_path9.default.join(dir, ent.name);
|
|
44903
45029
|
if (!ent.isDirectory() && !(ent.isSymbolicLink() && isDirLikeSync(entryPath))) continue;
|
|
44904
45030
|
let content;
|
|
44905
45031
|
try {
|
|
44906
|
-
content =
|
|
45032
|
+
content = import_node_fs8.default.readFileSync(import_node_path9.default.join(entryPath, "SKILL.md"), "utf8");
|
|
44907
45033
|
} catch {
|
|
44908
45034
|
try {
|
|
44909
|
-
content =
|
|
45035
|
+
content = import_node_fs8.default.readFileSync(import_node_path9.default.join(entryPath, "skill.md"), "utf8");
|
|
44910
45036
|
} catch {
|
|
44911
45037
|
continue;
|
|
44912
45038
|
}
|
|
@@ -44930,26 +45056,26 @@ function listSkillsForDir(dir, source) {
|
|
|
44930
45056
|
function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
44931
45057
|
let entries;
|
|
44932
45058
|
try {
|
|
44933
|
-
entries =
|
|
45059
|
+
entries = import_node_fs8.default.readdirSync(dir, { withFileTypes: true });
|
|
44934
45060
|
} catch {
|
|
44935
45061
|
return;
|
|
44936
45062
|
}
|
|
44937
45063
|
for (const ent of entries) {
|
|
44938
|
-
const entryPath =
|
|
45064
|
+
const entryPath = import_node_path9.default.join(dir, ent.name);
|
|
44939
45065
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync(entryPath)) {
|
|
44940
45066
|
const ns = ent.name;
|
|
44941
45067
|
let subEntries;
|
|
44942
45068
|
try {
|
|
44943
|
-
subEntries =
|
|
45069
|
+
subEntries = import_node_fs8.default.readdirSync(entryPath, { withFileTypes: true });
|
|
44944
45070
|
} catch {
|
|
44945
45071
|
continue;
|
|
44946
45072
|
}
|
|
44947
45073
|
for (const se of subEntries) {
|
|
44948
45074
|
if (!se.name.endsWith(".md")) continue;
|
|
44949
|
-
const sePath =
|
|
45075
|
+
const sePath = import_node_path9.default.join(entryPath, se.name);
|
|
44950
45076
|
let content;
|
|
44951
45077
|
try {
|
|
44952
|
-
content =
|
|
45078
|
+
content = import_node_fs8.default.readFileSync(sePath, "utf8");
|
|
44953
45079
|
} catch {
|
|
44954
45080
|
continue;
|
|
44955
45081
|
}
|
|
@@ -44966,7 +45092,7 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
44966
45092
|
} else if (ent.name.endsWith(".md")) {
|
|
44967
45093
|
let content;
|
|
44968
45094
|
try {
|
|
44969
|
-
content =
|
|
45095
|
+
content = import_node_fs8.default.readFileSync(entryPath, "utf8");
|
|
44970
45096
|
} catch {
|
|
44971
45097
|
continue;
|
|
44972
45098
|
}
|
|
@@ -44982,10 +45108,10 @@ function scanCommandDir(dir, source, seen, out, pluginName) {
|
|
|
44982
45108
|
}
|
|
44983
45109
|
}
|
|
44984
45110
|
function readInstalledPlugins(home) {
|
|
44985
|
-
const file =
|
|
45111
|
+
const file = import_node_path9.default.join(home, ".claude", "plugins", "installed_plugins.json");
|
|
44986
45112
|
let raw;
|
|
44987
45113
|
try {
|
|
44988
|
-
raw =
|
|
45114
|
+
raw = import_node_fs8.default.readFileSync(file, "utf8");
|
|
44989
45115
|
} catch {
|
|
44990
45116
|
return [];
|
|
44991
45117
|
}
|
|
@@ -45010,7 +45136,7 @@ var SkillsScanner = class {
|
|
|
45010
45136
|
home;
|
|
45011
45137
|
extraPluginRoots;
|
|
45012
45138
|
constructor(opts = {}) {
|
|
45013
|
-
this.home = opts.home ??
|
|
45139
|
+
this.home = opts.home ?? import_node_os6.default.homedir();
|
|
45014
45140
|
this.extraPluginRoots = opts.extraPluginRoots ?? [];
|
|
45015
45141
|
}
|
|
45016
45142
|
/**
|
|
@@ -45033,14 +45159,14 @@ var SkillsScanner = class {
|
|
|
45033
45159
|
});
|
|
45034
45160
|
}
|
|
45035
45161
|
const fsBlock = [];
|
|
45036
|
-
scanSkillDir(
|
|
45037
|
-
scanCommandDir(
|
|
45038
|
-
scanSkillDir(
|
|
45039
|
-
scanCommandDir(
|
|
45162
|
+
scanSkillDir(import_node_path9.default.join(this.home, ".claude", "skills"), "global", seen, fsBlock);
|
|
45163
|
+
scanCommandDir(import_node_path9.default.join(this.home, ".claude", "commands"), "global", seen, fsBlock);
|
|
45164
|
+
scanSkillDir(import_node_path9.default.join(args.cwd, ".claude", "skills"), "project", seen, fsBlock);
|
|
45165
|
+
scanCommandDir(import_node_path9.default.join(args.cwd, ".claude", "commands"), "project", seen, fsBlock);
|
|
45040
45166
|
const plugins = [...readInstalledPlugins(this.home), ...this.extraPluginRoots];
|
|
45041
45167
|
for (const { name, root } of plugins) {
|
|
45042
|
-
scanSkillDir(
|
|
45043
|
-
scanCommandDir(
|
|
45168
|
+
scanSkillDir(import_node_path9.default.join(root, "skills"), "plugin", seen, fsBlock, name);
|
|
45169
|
+
scanCommandDir(import_node_path9.default.join(root, "commands"), "plugin", seen, fsBlock, name);
|
|
45044
45170
|
}
|
|
45045
45171
|
fsBlock.sort((a, b2) => a.name < b2.name ? -1 : a.name > b2.name ? 1 : 0);
|
|
45046
45172
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -45146,8 +45272,8 @@ var PersonaManager = class {
|
|
|
45146
45272
|
};
|
|
45147
45273
|
|
|
45148
45274
|
// src/persona/seed.ts
|
|
45149
|
-
var
|
|
45150
|
-
var
|
|
45275
|
+
var fs10 = __toESM(require("fs"), 1);
|
|
45276
|
+
var path13 = __toESM(require("path"), 1);
|
|
45151
45277
|
var import_node_url = require("url");
|
|
45152
45278
|
var import_meta = {};
|
|
45153
45279
|
var DEFAULT_BYPASS_PROFILE = {
|
|
@@ -45178,16 +45304,6 @@ var DEFAULT_PERSONAS = [
|
|
|
45178
45304
|
public: false,
|
|
45179
45305
|
sandboxProfile: DEFAULT_BYPASS_PROFILE
|
|
45180
45306
|
},
|
|
45181
|
-
{
|
|
45182
|
-
// 工单管理员:纯操作员,按指令调 clawd-ticket MCP 增删改查 ticket。MCP 由 daemon 全局
|
|
45183
|
-
// 注入(index.ts ticket-mcp wiring),persona 端不需要单独 .mcp.json。
|
|
45184
|
-
personaId: "persona-ticket-manager",
|
|
45185
|
-
label: "\u5DE5\u5355\u7BA1\u7406\u5458",
|
|
45186
|
-
model: "opus",
|
|
45187
|
-
iconKey: "assist",
|
|
45188
|
-
public: false,
|
|
45189
|
-
sandboxProfile: DEFAULT_BYPASS_PROFILE
|
|
45190
|
-
},
|
|
45191
45307
|
{
|
|
45192
45308
|
personaId: "persona-feishu-assistant",
|
|
45193
45309
|
label: "\u98DE\u4E66\u52A9\u7406",
|
|
@@ -45281,14 +45397,6 @@ var DEFAULT_PERSONAS = [
|
|
|
45281
45397
|
public: false,
|
|
45282
45398
|
sandboxProfile: DEFAULT_BYPASS_PROFILE
|
|
45283
45399
|
},
|
|
45284
|
-
{
|
|
45285
|
-
personaId: "persona-bug-fixer",
|
|
45286
|
-
label: "Bug \u4FEE\u590D\u5E08",
|
|
45287
|
-
model: "opus",
|
|
45288
|
-
iconKey: "debug",
|
|
45289
|
-
public: false,
|
|
45290
|
-
sandboxProfile: DEFAULT_BYPASS_PROFILE
|
|
45291
|
-
},
|
|
45292
45400
|
{
|
|
45293
45401
|
// HTML PPT 制作师:把想法/文字/旧 PPT 转成单文件 HTML 演示稿
|
|
45294
45402
|
// bundle 含 frontend-slides skill(MIT,Zara Zhang),daemon ship 进 .claude/skills/
|
|
@@ -45335,24 +45443,24 @@ function bundleSiblingFromArgv(argv1, sibling) {
|
|
|
45335
45443
|
if (!argv1) return null;
|
|
45336
45444
|
let real = argv1;
|
|
45337
45445
|
try {
|
|
45338
|
-
real =
|
|
45446
|
+
real = fs10.realpathSync(argv1);
|
|
45339
45447
|
} catch {
|
|
45340
45448
|
}
|
|
45341
|
-
return
|
|
45449
|
+
return path13.resolve(path13.dirname(real), sibling);
|
|
45342
45450
|
}
|
|
45343
45451
|
function findDefaultsRoot(logger) {
|
|
45344
45452
|
const candidates = [];
|
|
45345
45453
|
try {
|
|
45346
|
-
const here =
|
|
45347
|
-
candidates.push(
|
|
45348
|
-
candidates.push(
|
|
45454
|
+
const here = path13.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
45455
|
+
candidates.push(path13.resolve(here, "defaults"));
|
|
45456
|
+
candidates.push(path13.resolve(here, "persona-defaults"));
|
|
45349
45457
|
} catch {
|
|
45350
45458
|
}
|
|
45351
45459
|
const fromArgv = bundleSiblingFromArgv(process.argv[1], "persona-defaults");
|
|
45352
45460
|
if (fromArgv) candidates.push(fromArgv);
|
|
45353
45461
|
for (const c of candidates) {
|
|
45354
45462
|
try {
|
|
45355
|
-
if (
|
|
45463
|
+
if (fs10.statSync(c).isDirectory()) {
|
|
45356
45464
|
logger?.info("persona.defaults-root.resolved", { root: c });
|
|
45357
45465
|
return c;
|
|
45358
45466
|
}
|
|
@@ -45369,8 +45477,8 @@ function seedDefaultPersonas(args) {
|
|
|
45369
45477
|
args.logger.info("persona.seed.skip", { personaId: entry.personaId, reason: "exists" });
|
|
45370
45478
|
continue;
|
|
45371
45479
|
}
|
|
45372
|
-
const bundleDir =
|
|
45373
|
-
if (!
|
|
45480
|
+
const bundleDir = path13.join(args.defaultsRoot, entry.personaId);
|
|
45481
|
+
if (!fs10.existsSync(bundleDir)) {
|
|
45374
45482
|
args.logger.warn("persona.seed.skip", {
|
|
45375
45483
|
personaId: entry.personaId,
|
|
45376
45484
|
reason: "bundle-missing",
|
|
@@ -45378,8 +45486,8 @@ function seedDefaultPersonas(args) {
|
|
|
45378
45486
|
});
|
|
45379
45487
|
continue;
|
|
45380
45488
|
}
|
|
45381
|
-
const claudeMdPath =
|
|
45382
|
-
if (!
|
|
45489
|
+
const claudeMdPath = path13.join(bundleDir, "CLAUDE.md");
|
|
45490
|
+
if (!fs10.existsSync(claudeMdPath)) {
|
|
45383
45491
|
args.logger.warn("persona.seed.skip", {
|
|
45384
45492
|
personaId: entry.personaId,
|
|
45385
45493
|
reason: "no-CLAUDE.md",
|
|
@@ -45387,7 +45495,7 @@ function seedDefaultPersonas(args) {
|
|
|
45387
45495
|
});
|
|
45388
45496
|
continue;
|
|
45389
45497
|
}
|
|
45390
|
-
const personality =
|
|
45498
|
+
const personality = fs10.readFileSync(claudeMdPath, "utf8");
|
|
45391
45499
|
const now = Date.now();
|
|
45392
45500
|
const persona = {
|
|
45393
45501
|
personaId: entry.personaId,
|
|
@@ -45413,17 +45521,17 @@ function seedDefaultPersonas(args) {
|
|
|
45413
45521
|
}
|
|
45414
45522
|
}
|
|
45415
45523
|
function skipNodeModulesUnder(srcRoot) {
|
|
45416
|
-
return (src) => !
|
|
45524
|
+
return (src) => !path13.relative(srcRoot, src).split(path13.sep).includes("node_modules");
|
|
45417
45525
|
}
|
|
45418
45526
|
function copyBundleExtras(srcDir, dstDir) {
|
|
45419
|
-
for (const entry of
|
|
45527
|
+
for (const entry of fs10.readdirSync(srcDir, { withFileTypes: true })) {
|
|
45420
45528
|
if (entry.name === "CLAUDE.md" || entry.name === ".clawd") continue;
|
|
45421
|
-
const srcPath =
|
|
45422
|
-
const dstPath =
|
|
45529
|
+
const srcPath = path13.join(srcDir, entry.name);
|
|
45530
|
+
const dstPath = path13.join(dstDir, entry.name);
|
|
45423
45531
|
if (entry.isDirectory()) {
|
|
45424
|
-
|
|
45532
|
+
fs10.cpSync(srcPath, dstPath, { recursive: true, dereference: true, filter: skipNodeModulesUnder(srcPath) });
|
|
45425
45533
|
} else if (entry.isFile()) {
|
|
45426
|
-
|
|
45534
|
+
fs10.copyFileSync(srcPath, dstPath);
|
|
45427
45535
|
}
|
|
45428
45536
|
}
|
|
45429
45537
|
}
|
|
@@ -45431,16 +45539,16 @@ var DAEMON_MANAGED_PATHS = ["extension-kit", "CLAUDE.md", ".mcp.json"];
|
|
|
45431
45539
|
function refreshDaemonManagedDirs(args) {
|
|
45432
45540
|
const entries = args.entries ?? DEFAULT_PERSONAS;
|
|
45433
45541
|
for (const entry of entries) {
|
|
45434
|
-
const bundleDir =
|
|
45435
|
-
if (!
|
|
45542
|
+
const bundleDir = path13.join(args.defaultsRoot, entry.personaId);
|
|
45543
|
+
if (!fs10.existsSync(bundleDir)) continue;
|
|
45436
45544
|
const personaDir = args.store.personaDirPath(entry.personaId);
|
|
45437
|
-
if (!
|
|
45545
|
+
if (!fs10.existsSync(personaDir)) continue;
|
|
45438
45546
|
for (const relPath of DAEMON_MANAGED_PATHS) {
|
|
45439
|
-
const srcPath =
|
|
45440
|
-
if (!
|
|
45441
|
-
const dstPath =
|
|
45547
|
+
const srcPath = path13.join(bundleDir, relPath);
|
|
45548
|
+
if (!fs10.existsSync(srcPath)) continue;
|
|
45549
|
+
const dstPath = path13.join(personaDir, relPath);
|
|
45442
45550
|
try {
|
|
45443
|
-
|
|
45551
|
+
fs10.cpSync(srcPath, dstPath, { recursive: true, force: true, dereference: true, filter: skipNodeModulesUnder(srcPath) });
|
|
45444
45552
|
args.logger.info("persona.refresh.synced", {
|
|
45445
45553
|
personaId: entry.personaId,
|
|
45446
45554
|
path: relPath
|
|
@@ -45500,15 +45608,15 @@ function migrateCodexSandbox(args) {
|
|
|
45500
45608
|
function findDeployKitRoot(logger) {
|
|
45501
45609
|
const candidates = [];
|
|
45502
45610
|
try {
|
|
45503
|
-
const here =
|
|
45504
|
-
candidates.push(
|
|
45611
|
+
const here = path13.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
45612
|
+
candidates.push(path13.resolve(here, "..", "deploy-kit"));
|
|
45505
45613
|
} catch {
|
|
45506
45614
|
}
|
|
45507
45615
|
const fromArgv = bundleSiblingFromArgv(process.argv[1], "deploy-kit");
|
|
45508
45616
|
if (fromArgv) candidates.push(fromArgv);
|
|
45509
45617
|
for (const c of candidates) {
|
|
45510
45618
|
try {
|
|
45511
|
-
if (
|
|
45619
|
+
if (fs10.statSync(c).isDirectory()) {
|
|
45512
45620
|
logger?.info("persona.deploy-kit-root.resolved", { root: c });
|
|
45513
45621
|
return c;
|
|
45514
45622
|
}
|
|
@@ -45519,8 +45627,8 @@ function findDeployKitRoot(logger) {
|
|
|
45519
45627
|
return null;
|
|
45520
45628
|
}
|
|
45521
45629
|
function seedDeployKit(args) {
|
|
45522
|
-
const dst =
|
|
45523
|
-
|
|
45630
|
+
const dst = path13.join(args.dataDir, "deploy-kit");
|
|
45631
|
+
fs10.cpSync(args.deployKitBundleRoot, dst, {
|
|
45524
45632
|
recursive: true,
|
|
45525
45633
|
dereference: true,
|
|
45526
45634
|
force: false,
|
|
@@ -45529,35 +45637,35 @@ function seedDeployKit(args) {
|
|
|
45529
45637
|
args.logger.info("deploy-kit.seed.done", { dst });
|
|
45530
45638
|
}
|
|
45531
45639
|
function refreshDeployKit(args) {
|
|
45532
|
-
const dst =
|
|
45533
|
-
if (!
|
|
45640
|
+
const dst = path13.join(args.dataDir, "deploy-kit");
|
|
45641
|
+
if (!fs10.existsSync(dst)) {
|
|
45534
45642
|
seedDeployKit(args);
|
|
45535
45643
|
return;
|
|
45536
45644
|
}
|
|
45537
45645
|
for (const sub of ["scripts", "contract"]) {
|
|
45538
|
-
const s =
|
|
45539
|
-
if (
|
|
45540
|
-
|
|
45646
|
+
const s = path13.join(args.deployKitBundleRoot, sub);
|
|
45647
|
+
if (fs10.existsSync(s)) {
|
|
45648
|
+
fs10.cpSync(s, path13.join(dst, sub), { recursive: true, force: true, dereference: true });
|
|
45541
45649
|
}
|
|
45542
45650
|
}
|
|
45543
|
-
const secretsSrc =
|
|
45544
|
-
if (
|
|
45545
|
-
|
|
45546
|
-
for (const f of
|
|
45651
|
+
const secretsSrc = path13.join(args.deployKitBundleRoot, ".secrets");
|
|
45652
|
+
if (fs10.existsSync(secretsSrc)) {
|
|
45653
|
+
fs10.mkdirSync(path13.join(dst, ".secrets"), { recursive: true });
|
|
45654
|
+
for (const f of fs10.readdirSync(secretsSrc)) {
|
|
45547
45655
|
if (!f.endsWith(".example")) continue;
|
|
45548
|
-
|
|
45656
|
+
fs10.copyFileSync(path13.join(secretsSrc, f), path13.join(dst, ".secrets", f));
|
|
45549
45657
|
}
|
|
45550
45658
|
}
|
|
45551
45659
|
args.logger.info("deploy-kit.refresh.done", { dst });
|
|
45552
45660
|
}
|
|
45553
45661
|
|
|
45554
45662
|
// src/share-md-viewer/load.ts
|
|
45555
|
-
var
|
|
45556
|
-
var
|
|
45663
|
+
var import_node_fs10 = __toESM(require("fs"), 1);
|
|
45664
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
45557
45665
|
var import_node_url2 = require("url");
|
|
45558
45666
|
|
|
45559
45667
|
// src/share-md-viewer/asset-loader.ts
|
|
45560
|
-
var
|
|
45668
|
+
var import_node_fs9 = __toESM(require("fs"), 1);
|
|
45561
45669
|
function htmlEscape(s) {
|
|
45562
45670
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
45563
45671
|
}
|
|
@@ -45565,12 +45673,12 @@ function createViewerAssetLoader(opts) {
|
|
|
45565
45673
|
let viewerTemplate;
|
|
45566
45674
|
let errorTemplate;
|
|
45567
45675
|
try {
|
|
45568
|
-
viewerTemplate =
|
|
45676
|
+
viewerTemplate = import_node_fs9.default.readFileSync(opts.viewerHtmlPath, "utf8");
|
|
45569
45677
|
} catch (err) {
|
|
45570
45678
|
throw new Error(`viewer asset not found at ${opts.viewerHtmlPath}: ${err.message}`);
|
|
45571
45679
|
}
|
|
45572
45680
|
try {
|
|
45573
|
-
errorTemplate =
|
|
45681
|
+
errorTemplate = import_node_fs9.default.readFileSync(opts.errorHtmlPath, "utf8");
|
|
45574
45682
|
} catch (err) {
|
|
45575
45683
|
throw new Error(`viewer error asset not found at ${opts.errorHtmlPath}: ${err.message}`);
|
|
45576
45684
|
}
|
|
@@ -45589,25 +45697,25 @@ var import_meta2 = {};
|
|
|
45589
45697
|
function tryLoadViewerAssets(logger) {
|
|
45590
45698
|
const candidates = [];
|
|
45591
45699
|
try {
|
|
45592
|
-
const here =
|
|
45700
|
+
const here = import_node_path10.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url));
|
|
45593
45701
|
candidates.push(here);
|
|
45594
|
-
candidates.push(
|
|
45595
|
-
candidates.push(
|
|
45702
|
+
candidates.push(import_node_path10.default.resolve(here, ".."));
|
|
45703
|
+
candidates.push(import_node_path10.default.resolve(here, "..", "..", "dist"));
|
|
45596
45704
|
} catch {
|
|
45597
45705
|
}
|
|
45598
45706
|
if (process.argv[1]) {
|
|
45599
45707
|
let real = process.argv[1];
|
|
45600
45708
|
try {
|
|
45601
|
-
real =
|
|
45709
|
+
real = import_node_fs10.default.realpathSync(process.argv[1]);
|
|
45602
45710
|
} catch {
|
|
45603
45711
|
}
|
|
45604
|
-
candidates.push(
|
|
45712
|
+
candidates.push(import_node_path10.default.dirname(real));
|
|
45605
45713
|
}
|
|
45606
45714
|
for (const root of candidates) {
|
|
45607
|
-
const viewerHtmlPath =
|
|
45608
|
-
const errorHtmlPath =
|
|
45715
|
+
const viewerHtmlPath = import_node_path10.default.join(root, "share-md-viewer.html");
|
|
45716
|
+
const errorHtmlPath = import_node_path10.default.join(root, "share-md-viewer-error.html");
|
|
45609
45717
|
try {
|
|
45610
|
-
if (
|
|
45718
|
+
if (import_node_fs10.default.statSync(viewerHtmlPath).isFile() && import_node_fs10.default.statSync(errorHtmlPath).isFile()) {
|
|
45611
45719
|
logger?.info("share-md-viewer.assets-root.resolved", { root });
|
|
45612
45720
|
return createViewerAssetLoader({ viewerHtmlPath, errorHtmlPath });
|
|
45613
45721
|
}
|
|
@@ -45622,30 +45730,30 @@ function tryLoadViewerAssets(logger) {
|
|
|
45622
45730
|
}
|
|
45623
45731
|
|
|
45624
45732
|
// src/share-ui/load.ts
|
|
45625
|
-
var
|
|
45626
|
-
var
|
|
45733
|
+
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
45734
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
45627
45735
|
var import_node_url3 = require("url");
|
|
45628
45736
|
|
|
45629
45737
|
// src/share-ui/asset-loader.ts
|
|
45630
|
-
var
|
|
45631
|
-
var
|
|
45738
|
+
var import_node_fs11 = __toESM(require("fs"), 1);
|
|
45739
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
45632
45740
|
function createShareUiAssetLoader(opts) {
|
|
45633
45741
|
let indexHtml;
|
|
45634
45742
|
try {
|
|
45635
|
-
indexHtml =
|
|
45743
|
+
indexHtml = import_node_fs11.default.readFileSync(opts.indexHtmlPath, "utf8");
|
|
45636
45744
|
} catch (err) {
|
|
45637
45745
|
throw new Error(`share-ui index.html not found at ${opts.indexHtmlPath}: ${err.message}`);
|
|
45638
45746
|
}
|
|
45639
|
-
const assetsDir =
|
|
45747
|
+
const assetsDir = import_node_path11.default.resolve(opts.assetsDir);
|
|
45640
45748
|
return {
|
|
45641
45749
|
renderIndexHtml() {
|
|
45642
45750
|
return indexHtml;
|
|
45643
45751
|
},
|
|
45644
45752
|
resolveAssetPath(rel) {
|
|
45645
|
-
const resolved =
|
|
45646
|
-
if (resolved !== assetsDir && !resolved.startsWith(assetsDir +
|
|
45753
|
+
const resolved = import_node_path11.default.resolve(assetsDir, rel);
|
|
45754
|
+
if (resolved !== assetsDir && !resolved.startsWith(assetsDir + import_node_path11.default.sep)) return null;
|
|
45647
45755
|
try {
|
|
45648
|
-
if (
|
|
45756
|
+
if (import_node_fs11.default.statSync(resolved).isFile()) return resolved;
|
|
45649
45757
|
} catch {
|
|
45650
45758
|
}
|
|
45651
45759
|
return null;
|
|
@@ -45659,28 +45767,28 @@ function bundleDirFromArgv(argv1) {
|
|
|
45659
45767
|
if (!argv1) return null;
|
|
45660
45768
|
let real = argv1;
|
|
45661
45769
|
try {
|
|
45662
|
-
real =
|
|
45770
|
+
real = import_node_fs12.default.realpathSync(argv1);
|
|
45663
45771
|
} catch {
|
|
45664
45772
|
}
|
|
45665
|
-
return
|
|
45773
|
+
return import_node_path12.default.dirname(real);
|
|
45666
45774
|
}
|
|
45667
45775
|
function tryLoadShareUi(logger) {
|
|
45668
45776
|
const candidates = [];
|
|
45669
45777
|
try {
|
|
45670
|
-
const here =
|
|
45778
|
+
const here = import_node_path12.default.dirname((0, import_node_url3.fileURLToPath)(import_meta3.url));
|
|
45671
45779
|
candidates.push(here);
|
|
45672
|
-
candidates.push(
|
|
45673
|
-
candidates.push(
|
|
45780
|
+
candidates.push(import_node_path12.default.resolve(here, ".."));
|
|
45781
|
+
candidates.push(import_node_path12.default.resolve(here, "..", "..", "dist"));
|
|
45674
45782
|
} catch {
|
|
45675
45783
|
}
|
|
45676
45784
|
const argvDir = bundleDirFromArgv(process.argv[1]);
|
|
45677
45785
|
if (argvDir) candidates.push(argvDir);
|
|
45678
45786
|
for (const root of candidates) {
|
|
45679
|
-
const shareUiDir =
|
|
45680
|
-
const indexHtmlPath =
|
|
45681
|
-
const assetsDir =
|
|
45787
|
+
const shareUiDir = import_node_path12.default.join(root, "share-ui");
|
|
45788
|
+
const indexHtmlPath = import_node_path12.default.join(shareUiDir, "guest.html");
|
|
45789
|
+
const assetsDir = import_node_path12.default.join(shareUiDir, "assets");
|
|
45682
45790
|
try {
|
|
45683
|
-
if (
|
|
45791
|
+
if (import_node_fs12.default.statSync(indexHtmlPath).isFile() && import_node_fs12.default.statSync(assetsDir).isDirectory()) {
|
|
45684
45792
|
logger?.info("share-ui.assets-root.resolved", { root: shareUiDir });
|
|
45685
45793
|
return createShareUiAssetLoader({ indexHtmlPath, assetsDir });
|
|
45686
45794
|
}
|
|
@@ -45762,20 +45870,20 @@ function buildVisitorLogin(deps) {
|
|
|
45762
45870
|
}
|
|
45763
45871
|
|
|
45764
45872
|
// src/visitor/visitor-store.ts
|
|
45765
|
-
var
|
|
45766
|
-
var
|
|
45873
|
+
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
45874
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
45767
45875
|
function createVisitorStore(opts) {
|
|
45768
|
-
const file =
|
|
45876
|
+
const file = import_node_path13.default.join(opts.dir, "visitors.json");
|
|
45769
45877
|
const read = () => {
|
|
45770
45878
|
try {
|
|
45771
|
-
return JSON.parse(
|
|
45879
|
+
return JSON.parse(import_node_fs13.default.readFileSync(file, "utf8"));
|
|
45772
45880
|
} catch {
|
|
45773
45881
|
return [];
|
|
45774
45882
|
}
|
|
45775
45883
|
};
|
|
45776
45884
|
const write = (rows) => {
|
|
45777
|
-
|
|
45778
|
-
|
|
45885
|
+
import_node_fs13.default.mkdirSync(opts.dir, { recursive: true });
|
|
45886
|
+
import_node_fs13.default.writeFileSync(file, JSON.stringify(rows, null, 2));
|
|
45779
45887
|
};
|
|
45780
45888
|
return {
|
|
45781
45889
|
upsert(r) {
|
|
@@ -46057,8 +46165,8 @@ function turnStartInput(text) {
|
|
|
46057
46165
|
const items = [];
|
|
46058
46166
|
let leftover = text;
|
|
46059
46167
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
46060
|
-
const [marker, name,
|
|
46061
|
-
items.push({ type: "skill", name, path:
|
|
46168
|
+
const [marker, name, path68] = m2;
|
|
46169
|
+
items.push({ type: "skill", name, path: path68 });
|
|
46062
46170
|
leftover = leftover.replace(marker, "");
|
|
46063
46171
|
}
|
|
46064
46172
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -46291,8 +46399,8 @@ var CodexAdapter = class {
|
|
|
46291
46399
|
|
|
46292
46400
|
// src/tools/claude-tui.ts
|
|
46293
46401
|
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
46294
|
-
var
|
|
46295
|
-
var
|
|
46402
|
+
var import_node_os7 = __toESM(require("os"), 1);
|
|
46403
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
46296
46404
|
var import_headless = __toESM(require_xterm_headless(), 1);
|
|
46297
46405
|
|
|
46298
46406
|
// ../node_modules/.pnpm/@xterm+addon-serialize@0.14.0/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs
|
|
@@ -47428,8 +47536,8 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
|
|
|
47428
47536
|
}
|
|
47429
47537
|
function jsonlExistsForCtx(ctx) {
|
|
47430
47538
|
if (!ctx.toolSessionId) return false;
|
|
47431
|
-
const home =
|
|
47432
|
-
const file =
|
|
47539
|
+
const home = import_node_os7.default.homedir();
|
|
47540
|
+
const file = import_node_path14.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
|
|
47433
47541
|
try {
|
|
47434
47542
|
return import_node_fs16.default.statSync(file).isFile();
|
|
47435
47543
|
} catch {
|
|
@@ -47460,6 +47568,7 @@ var PersonaDispatchManager = class {
|
|
|
47460
47568
|
dispatchId,
|
|
47461
47569
|
sourceSessionId: args.sourceSessionId,
|
|
47462
47570
|
targetPersona: args.targetPersona,
|
|
47571
|
+
bSessionId: args.bSessionId,
|
|
47463
47572
|
waiters: [],
|
|
47464
47573
|
outcome: null
|
|
47465
47574
|
});
|
|
@@ -47490,10 +47599,22 @@ var PersonaDispatchManager = class {
|
|
|
47490
47599
|
if (!state) throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
47491
47600
|
state.bSessionId = bSessionId;
|
|
47492
47601
|
}
|
|
47493
|
-
/**
|
|
47494
|
-
|
|
47602
|
+
/**
|
|
47603
|
+
* 按 B sessionId 找当前 in-flight(未 resolved)的 dispatchId。complete handler 用这个把
|
|
47604
|
+
* B 的 outcome 配对回 A 的 waiter —— dispatchId 不再走 cc env,全靠
|
|
47605
|
+
* (bSessionId → in-flight dispatchId) 反查。
|
|
47606
|
+
*
|
|
47607
|
+
* 同一 bSessionId 不会同时有多个 in-flight:A 拿不到 outcome 不会发起新 dispatch;
|
|
47608
|
+
* 老板规则下 A 一次只能挂一个 waiter。
|
|
47609
|
+
*
|
|
47610
|
+
* 历史 entry(已 resolved)暂不清 —— 单 daemon lifetime 累积可接受;未来用量大了加
|
|
47611
|
+
* TTL GC(complete 后 N min 删 entry)。
|
|
47612
|
+
*/
|
|
47613
|
+
findInflightDispatchByBSessionId(bSessionId) {
|
|
47495
47614
|
for (const state of this.map.values()) {
|
|
47496
|
-
if (state.bSessionId === bSessionId
|
|
47615
|
+
if (state.bSessionId === bSessionId && state.outcome === null) {
|
|
47616
|
+
return state.dispatchId;
|
|
47617
|
+
}
|
|
47497
47618
|
}
|
|
47498
47619
|
return void 0;
|
|
47499
47620
|
}
|
|
@@ -47501,9 +47622,9 @@ var PersonaDispatchManager = class {
|
|
|
47501
47622
|
|
|
47502
47623
|
// src/dispatch/mcp-config.ts
|
|
47503
47624
|
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
47504
|
-
var
|
|
47625
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
47505
47626
|
function dispatchMcpConfigPath(dataDir) {
|
|
47506
|
-
return
|
|
47627
|
+
return import_node_path15.default.join(dataDir, "dispatch.mcp.json");
|
|
47507
47628
|
}
|
|
47508
47629
|
function writeDispatchMcpConfig(args) {
|
|
47509
47630
|
const cfgPath = dispatchMcpConfigPath(args.dataDir);
|
|
@@ -47525,9 +47646,9 @@ function writeDispatchMcpConfig(args) {
|
|
|
47525
47646
|
|
|
47526
47647
|
// src/ticket/mcp-config.ts
|
|
47527
47648
|
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
47528
|
-
var
|
|
47649
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
47529
47650
|
function ticketMcpConfigPath(dataDir) {
|
|
47530
|
-
return
|
|
47651
|
+
return import_node_path16.default.join(dataDir, "ticket.mcp.json");
|
|
47531
47652
|
}
|
|
47532
47653
|
function writeTicketMcpConfig(args) {
|
|
47533
47654
|
const cfgPath = ticketMcpConfigPath(args.dataDir);
|
|
@@ -47555,9 +47676,9 @@ function writeTicketMcpConfig(args) {
|
|
|
47555
47676
|
|
|
47556
47677
|
// src/shift/mcp-config.ts
|
|
47557
47678
|
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
47558
|
-
var
|
|
47679
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
47559
47680
|
function shiftMcpConfigPath(dataDir) {
|
|
47560
|
-
return
|
|
47681
|
+
return import_node_path17.default.join(dataDir, "shift.mcp.json");
|
|
47561
47682
|
}
|
|
47562
47683
|
async function writeShiftMcpConfig(args) {
|
|
47563
47684
|
const cfgPath = shiftMcpConfigPath(args.dataDir);
|
|
@@ -47579,9 +47700,9 @@ async function writeShiftMcpConfig(args) {
|
|
|
47579
47700
|
|
|
47580
47701
|
// src/inbox/mcp-config.ts
|
|
47581
47702
|
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
47582
|
-
var
|
|
47703
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
47583
47704
|
function inboxMcpConfigPath(dataDir) {
|
|
47584
|
-
return
|
|
47705
|
+
return import_node_path18.default.join(dataDir, "inbox.mcp.json");
|
|
47585
47706
|
}
|
|
47586
47707
|
async function writeInboxMcpConfig(args) {
|
|
47587
47708
|
const cfgPath = inboxMcpConfigPath(args.dataDir);
|
|
@@ -47603,7 +47724,7 @@ async function writeInboxMcpConfig(args) {
|
|
|
47603
47724
|
|
|
47604
47725
|
// src/shift/store.ts
|
|
47605
47726
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
47606
|
-
var
|
|
47727
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
47607
47728
|
var import_node_crypto5 = require("crypto");
|
|
47608
47729
|
|
|
47609
47730
|
// src/shift/constants.ts
|
|
@@ -47672,7 +47793,7 @@ function createShiftStore(deps) {
|
|
|
47672
47793
|
flushTimer = null;
|
|
47673
47794
|
}
|
|
47674
47795
|
const content = { version: 1, shifts };
|
|
47675
|
-
await import_promises.default.mkdir(
|
|
47796
|
+
await import_promises.default.mkdir(import_node_path19.default.dirname(deps.filePath), { recursive: true });
|
|
47676
47797
|
const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
|
|
47677
47798
|
await import_promises.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
|
|
47678
47799
|
await import_promises.default.rename(tmp, deps.filePath);
|
|
@@ -48092,6 +48213,28 @@ function canAccessPersona(grants, personaId, action) {
|
|
|
48092
48213
|
}
|
|
48093
48214
|
|
|
48094
48215
|
// src/handlers/persona-dispatch.ts
|
|
48216
|
+
function assertLocalReuseAllowed(bFile, sourceSessionId) {
|
|
48217
|
+
if (bFile.dispatchedFromSessionId !== sourceSessionId) {
|
|
48218
|
+
throw new ClawdError(
|
|
48219
|
+
ERROR_CODES.UNAUTHORIZED,
|
|
48220
|
+
`targetSessionId not dispatched by caller (dispatchedFromSessionId mismatch)`
|
|
48221
|
+
);
|
|
48222
|
+
}
|
|
48223
|
+
}
|
|
48224
|
+
function assertGuestReuseAllowed(bFile, sourcePrincipalId, targetPersona) {
|
|
48225
|
+
if (bFile.ownerPersonaId !== targetPersona) {
|
|
48226
|
+
throw new ClawdError(
|
|
48227
|
+
ERROR_CODES.UNAUTHORIZED,
|
|
48228
|
+
`targetSessionId does not belong to targetPersona`
|
|
48229
|
+
);
|
|
48230
|
+
}
|
|
48231
|
+
if (bFile.creatorPrincipalId !== sourcePrincipalId) {
|
|
48232
|
+
throw new ClawdError(
|
|
48233
|
+
ERROR_CODES.UNAUTHORIZED,
|
|
48234
|
+
`targetSessionId not dispatched by caller device (creatorPrincipalId mismatch)`
|
|
48235
|
+
);
|
|
48236
|
+
}
|
|
48237
|
+
}
|
|
48095
48238
|
function buildPersonaDispatchHandlers(deps) {
|
|
48096
48239
|
const { personaDispatchManager: mgr, spawnB, logger } = deps;
|
|
48097
48240
|
const run = async (frame, _client, ctx) => {
|
|
@@ -48110,15 +48253,21 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48110
48253
|
}
|
|
48111
48254
|
logger?.info("dispatch.run.forward", {
|
|
48112
48255
|
targetDeviceId: args.targetDeviceId,
|
|
48113
|
-
targetPersona: args.targetPersona
|
|
48256
|
+
targetPersona: args.targetPersona,
|
|
48257
|
+
hasTargetSessionId: Boolean(args.targetSessionId)
|
|
48114
48258
|
});
|
|
48115
|
-
const outcome2 = await deps.forwardToPeer({
|
|
48259
|
+
const { outcome: outcome2, dispatchedSessionId } = await deps.forwardToPeer({
|
|
48116
48260
|
targetDeviceId: args.targetDeviceId,
|
|
48117
48261
|
targetPersona: args.targetPersona,
|
|
48118
|
-
prompt: args.prompt
|
|
48262
|
+
prompt: args.prompt,
|
|
48263
|
+
targetSessionId: args.targetSessionId
|
|
48119
48264
|
});
|
|
48120
48265
|
return {
|
|
48121
|
-
response: {
|
|
48266
|
+
response: {
|
|
48267
|
+
type: "personaDispatch:run:ok",
|
|
48268
|
+
outcome: outcome2,
|
|
48269
|
+
...dispatchedSessionId ? { dispatchedSessionId } : {}
|
|
48270
|
+
}
|
|
48122
48271
|
};
|
|
48123
48272
|
}
|
|
48124
48273
|
if (ctx?.principal.kind === "guest") {
|
|
@@ -48129,34 +48278,65 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48129
48278
|
`persona not dispatchable: ${args.targetPersona}`
|
|
48130
48279
|
);
|
|
48131
48280
|
}
|
|
48281
|
+
const guestSourceId = ctx.principal.id;
|
|
48282
|
+
let bSessionId2;
|
|
48283
|
+
let route2 = "new";
|
|
48284
|
+
if (args.targetSessionId) {
|
|
48285
|
+
if (!deps.findOwnedSession) {
|
|
48286
|
+
throw new Error("targetSessionId reuse not wired (findOwnedSession missing)");
|
|
48287
|
+
}
|
|
48288
|
+
const bFile = deps.findOwnedSession(args.targetSessionId);
|
|
48289
|
+
if (!bFile) {
|
|
48290
|
+
throw new ClawdError(
|
|
48291
|
+
ERROR_CODES.SESSION_NOT_FOUND,
|
|
48292
|
+
`targetSessionId not found: ${args.targetSessionId}`
|
|
48293
|
+
);
|
|
48294
|
+
}
|
|
48295
|
+
assertGuestReuseAllowed(bFile, guestSourceId, args.targetPersona);
|
|
48296
|
+
route2 = "resume";
|
|
48297
|
+
bSessionId2 = args.targetSessionId;
|
|
48298
|
+
}
|
|
48132
48299
|
const { dispatchId: dispatchId2 } = mgr.start({
|
|
48133
|
-
sourceSessionId:
|
|
48134
|
-
targetPersona: args.targetPersona
|
|
48300
|
+
sourceSessionId: guestSourceId,
|
|
48301
|
+
targetPersona: args.targetPersona,
|
|
48302
|
+
bSessionId: bSessionId2
|
|
48135
48303
|
});
|
|
48136
48304
|
logger?.info("dispatch.run.received.guest", {
|
|
48137
48305
|
dispatchId: dispatchId2,
|
|
48138
|
-
sourcePrincipal:
|
|
48306
|
+
sourcePrincipal: guestSourceId,
|
|
48139
48307
|
targetPersona: args.targetPersona,
|
|
48140
|
-
promptLen: args.prompt.length
|
|
48308
|
+
promptLen: args.prompt.length,
|
|
48309
|
+
route: route2
|
|
48141
48310
|
});
|
|
48142
|
-
|
|
48143
|
-
|
|
48144
|
-
|
|
48145
|
-
|
|
48146
|
-
|
|
48147
|
-
|
|
48148
|
-
|
|
48149
|
-
|
|
48311
|
+
let resolvedBSessionId2 = bSessionId2;
|
|
48312
|
+
try {
|
|
48313
|
+
const { bSessionId: minted } = await spawnB({
|
|
48314
|
+
dispatchId: dispatchId2,
|
|
48315
|
+
sourceSessionId: guestSourceId,
|
|
48316
|
+
targetPersona: args.targetPersona,
|
|
48317
|
+
prompt: args.prompt,
|
|
48318
|
+
route: route2,
|
|
48319
|
+
bSessionId: bSessionId2,
|
|
48320
|
+
guestPrincipalId: guestSourceId,
|
|
48321
|
+
guestDisplayName: ctx.principal.displayName
|
|
48322
|
+
});
|
|
48323
|
+
resolvedBSessionId2 = minted;
|
|
48324
|
+
logger?.info("dispatch.spawnB.ok", { dispatchId: dispatchId2, route: route2 });
|
|
48325
|
+
} catch (err) {
|
|
48150
48326
|
const reason = err instanceof Error ? err.message : String(err);
|
|
48151
|
-
logger?.warn("dispatch.spawnB.failed", { dispatchId: dispatchId2, reason });
|
|
48327
|
+
logger?.warn("dispatch.spawnB.failed", { dispatchId: dispatchId2, route: route2, reason });
|
|
48152
48328
|
mgr.complete(dispatchId2, {
|
|
48153
48329
|
kind: "failure",
|
|
48154
48330
|
reason: `failed to spawn B: ${reason}`
|
|
48155
48331
|
});
|
|
48156
|
-
}
|
|
48332
|
+
}
|
|
48157
48333
|
const outcome2 = await mgr.wait(dispatchId2);
|
|
48158
48334
|
return {
|
|
48159
|
-
response: {
|
|
48335
|
+
response: {
|
|
48336
|
+
type: "personaDispatch:run:ok",
|
|
48337
|
+
outcome: outcome2,
|
|
48338
|
+
...resolvedBSessionId2 ? { dispatchedSessionId: resolvedBSessionId2 } : {}
|
|
48339
|
+
}
|
|
48160
48340
|
};
|
|
48161
48341
|
}
|
|
48162
48342
|
if (!sourceSessionId) {
|
|
@@ -48164,31 +48344,61 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48164
48344
|
"personaDispatch:run requires sessionId (caller must pass x-clawd-session-id header)"
|
|
48165
48345
|
);
|
|
48166
48346
|
}
|
|
48347
|
+
let bSessionId;
|
|
48348
|
+
let route = "new";
|
|
48349
|
+
if (args.targetSessionId) {
|
|
48350
|
+
if (!deps.findOwnedSession) {
|
|
48351
|
+
throw new Error("targetSessionId reuse not wired (findOwnedSession missing)");
|
|
48352
|
+
}
|
|
48353
|
+
const bFile = deps.findOwnedSession(args.targetSessionId);
|
|
48354
|
+
if (!bFile) {
|
|
48355
|
+
throw new ClawdError(
|
|
48356
|
+
ERROR_CODES.SESSION_NOT_FOUND,
|
|
48357
|
+
`targetSessionId not found: ${args.targetSessionId}`
|
|
48358
|
+
);
|
|
48359
|
+
}
|
|
48360
|
+
if (bFile.ownerPersonaId !== args.targetPersona) {
|
|
48361
|
+
throw new ClawdError(
|
|
48362
|
+
ERROR_CODES.UNAUTHORIZED,
|
|
48363
|
+
`targetSessionId does not belong to targetPersona`
|
|
48364
|
+
);
|
|
48365
|
+
}
|
|
48366
|
+
assertLocalReuseAllowed(bFile, sourceSessionId);
|
|
48367
|
+
route = "resume";
|
|
48368
|
+
bSessionId = args.targetSessionId;
|
|
48369
|
+
}
|
|
48167
48370
|
const { dispatchId } = mgr.start({
|
|
48168
48371
|
sourceSessionId,
|
|
48169
|
-
targetPersona: args.targetPersona
|
|
48372
|
+
targetPersona: args.targetPersona,
|
|
48373
|
+
bSessionId
|
|
48170
48374
|
});
|
|
48171
48375
|
logger?.info("dispatch.run.received", {
|
|
48172
48376
|
dispatchId,
|
|
48173
48377
|
sourceSessionId,
|
|
48174
48378
|
targetPersona: args.targetPersona,
|
|
48175
|
-
promptLen: args.prompt.length
|
|
48379
|
+
promptLen: args.prompt.length,
|
|
48380
|
+
route
|
|
48176
48381
|
});
|
|
48177
|
-
|
|
48178
|
-
|
|
48179
|
-
|
|
48180
|
-
|
|
48181
|
-
|
|
48182
|
-
|
|
48183
|
-
|
|
48184
|
-
|
|
48382
|
+
let resolvedBSessionId = bSessionId;
|
|
48383
|
+
try {
|
|
48384
|
+
const { bSessionId: minted } = await spawnB({
|
|
48385
|
+
dispatchId,
|
|
48386
|
+
sourceSessionId,
|
|
48387
|
+
targetPersona: args.targetPersona,
|
|
48388
|
+
prompt: args.prompt,
|
|
48389
|
+
route,
|
|
48390
|
+
bSessionId
|
|
48391
|
+
});
|
|
48392
|
+
resolvedBSessionId = minted;
|
|
48393
|
+
logger?.info("dispatch.spawnB.ok", { dispatchId, route });
|
|
48394
|
+
} catch (err) {
|
|
48185
48395
|
const reason = err instanceof Error ? err.message : String(err);
|
|
48186
|
-
logger?.warn("dispatch.spawnB.failed", { dispatchId, reason });
|
|
48396
|
+
logger?.warn("dispatch.spawnB.failed", { dispatchId, route, reason });
|
|
48187
48397
|
mgr.complete(dispatchId, {
|
|
48188
48398
|
kind: "failure",
|
|
48189
48399
|
reason: `failed to spawn B: ${reason}`
|
|
48190
48400
|
});
|
|
48191
|
-
}
|
|
48401
|
+
}
|
|
48192
48402
|
logger?.info("dispatch.run.waiting", { dispatchId });
|
|
48193
48403
|
const outcome = await mgr.wait(dispatchId);
|
|
48194
48404
|
logger?.info("dispatch.run.resolved", {
|
|
@@ -48196,17 +48406,34 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
48196
48406
|
outcomeKind: outcome.kind
|
|
48197
48407
|
});
|
|
48198
48408
|
return {
|
|
48199
|
-
response: {
|
|
48409
|
+
response: {
|
|
48410
|
+
type: "personaDispatch:run:ok",
|
|
48411
|
+
outcome,
|
|
48412
|
+
...resolvedBSessionId ? { dispatchedSessionId: resolvedBSessionId } : {}
|
|
48413
|
+
}
|
|
48200
48414
|
};
|
|
48201
48415
|
};
|
|
48202
48416
|
const complete = async (frame) => {
|
|
48203
48417
|
const { type: _t, requestId: _r, ...rest } = frame;
|
|
48418
|
+
const sessionId = typeof rest.sessionId === "string" ? rest.sessionId : void 0;
|
|
48204
48419
|
const args = DispatchCompleteArgsSchema.parse(rest);
|
|
48420
|
+
if (!sessionId) {
|
|
48421
|
+
throw new Error(
|
|
48422
|
+
"personaDispatch:complete requires sessionId (caller must pass x-clawd-session-id header)"
|
|
48423
|
+
);
|
|
48424
|
+
}
|
|
48425
|
+
const dispatchId = mgr.findInflightDispatchByBSessionId(sessionId);
|
|
48426
|
+
if (!dispatchId) {
|
|
48427
|
+
throw new Error(
|
|
48428
|
+
`no in-flight dispatch for session ${sessionId} (already completed or B was never dispatched)`
|
|
48429
|
+
);
|
|
48430
|
+
}
|
|
48205
48431
|
logger?.info("dispatch.complete.received", {
|
|
48206
|
-
dispatchId
|
|
48432
|
+
dispatchId,
|
|
48433
|
+
sessionId,
|
|
48207
48434
|
outcomeKind: args.outcome.kind
|
|
48208
48435
|
});
|
|
48209
|
-
mgr.complete(
|
|
48436
|
+
mgr.complete(dispatchId, args.outcome);
|
|
48210
48437
|
return {
|
|
48211
48438
|
response: { type: "personaDispatch:complete:ok" }
|
|
48212
48439
|
};
|
|
@@ -48236,25 +48463,37 @@ async function forwardDispatchToPeer(args) {
|
|
|
48236
48463
|
authorization: `Bearer ${args.contact.connectToken}`
|
|
48237
48464
|
},
|
|
48238
48465
|
// 注意:不带 targetDeviceId —— B 端据此判定为本地执行(B 角色)。
|
|
48239
|
-
|
|
48466
|
+
// targetSessionId 透传:peer 那台机会按 creatorPrincipalId === A.deviceId 校验。
|
|
48467
|
+
body: JSON.stringify({
|
|
48468
|
+
targetPersona: args.targetPersona,
|
|
48469
|
+
prompt: args.prompt,
|
|
48470
|
+
...args.targetSessionId ? { targetSessionId: args.targetSessionId } : {}
|
|
48471
|
+
})
|
|
48240
48472
|
});
|
|
48241
48473
|
} catch (err) {
|
|
48242
48474
|
const msg = err instanceof Error ? err.message : String(err);
|
|
48243
|
-
return { kind: "failure", reason: `forward to peer failed: ${msg}` };
|
|
48475
|
+
return { outcome: { kind: "failure", reason: `forward to peer failed: ${msg}` } };
|
|
48244
48476
|
}
|
|
48245
48477
|
let json;
|
|
48246
48478
|
try {
|
|
48247
48479
|
json = await res.json();
|
|
48248
48480
|
} catch {
|
|
48249
48481
|
return {
|
|
48250
|
-
|
|
48251
|
-
|
|
48482
|
+
outcome: {
|
|
48483
|
+
kind: "failure",
|
|
48484
|
+
reason: `peer returned non-JSON response (HTTP ${res.status})`
|
|
48485
|
+
}
|
|
48252
48486
|
};
|
|
48253
48487
|
}
|
|
48254
48488
|
if (json.ok === false) {
|
|
48255
|
-
return {
|
|
48489
|
+
return {
|
|
48490
|
+
outcome: { kind: "failure", reason: `peer rejected: ${json.error}: ${json.message}` }
|
|
48491
|
+
};
|
|
48256
48492
|
}
|
|
48257
|
-
return
|
|
48493
|
+
return {
|
|
48494
|
+
outcome: json.result.outcome,
|
|
48495
|
+
dispatchedSessionId: json.result.dispatchedSessionId
|
|
48496
|
+
};
|
|
48258
48497
|
}
|
|
48259
48498
|
async function forwardInboxPostToPeer(args) {
|
|
48260
48499
|
const f = args.fetchImpl ?? fetch;
|
|
@@ -48476,13 +48715,13 @@ function mapSkillsListResponse(res) {
|
|
|
48476
48715
|
const r = s ?? {};
|
|
48477
48716
|
const name = str3(r.name);
|
|
48478
48717
|
if (!name) continue;
|
|
48479
|
-
const
|
|
48718
|
+
const path68 = str3(r.path);
|
|
48480
48719
|
const description = str3(r.description);
|
|
48481
48720
|
const isPlugin = name.includes(":");
|
|
48482
48721
|
out.push({
|
|
48483
48722
|
name,
|
|
48484
48723
|
source: isPlugin ? "plugin" : "project",
|
|
48485
|
-
...
|
|
48724
|
+
...path68 ? { path: path68 } : {},
|
|
48486
48725
|
...description ? { description } : {},
|
|
48487
48726
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
48488
48727
|
});
|
|
@@ -48522,15 +48761,15 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
48522
48761
|
|
|
48523
48762
|
// src/workspace/browser.ts
|
|
48524
48763
|
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
48525
|
-
var
|
|
48526
|
-
var
|
|
48764
|
+
var import_node_os8 = __toESM(require("os"), 1);
|
|
48765
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
48527
48766
|
init_protocol();
|
|
48528
48767
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
48529
48768
|
function resolveInsideCwd(cwd, subpath) {
|
|
48530
|
-
const absCwd =
|
|
48531
|
-
const joined =
|
|
48532
|
-
const rel =
|
|
48533
|
-
if (rel.startsWith("..") ||
|
|
48769
|
+
const absCwd = import_node_path20.default.resolve(cwd);
|
|
48770
|
+
const joined = import_node_path20.default.resolve(absCwd, subpath ?? ".");
|
|
48771
|
+
const rel = import_node_path20.default.relative(absCwd, joined);
|
|
48772
|
+
if (rel.startsWith("..") || import_node_path20.default.isAbsolute(rel)) {
|
|
48534
48773
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
48535
48774
|
}
|
|
48536
48775
|
return joined;
|
|
@@ -48548,7 +48787,7 @@ function ensureCwd(cwd) {
|
|
|
48548
48787
|
}
|
|
48549
48788
|
var WorkspaceBrowser = class {
|
|
48550
48789
|
list(args) {
|
|
48551
|
-
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd :
|
|
48790
|
+
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os8.default.homedir();
|
|
48552
48791
|
ensureCwd(cwd);
|
|
48553
48792
|
const full = resolveInsideCwd(cwd, args.path);
|
|
48554
48793
|
const dirents = import_node_fs21.default.readdirSync(full, { withFileTypes: true });
|
|
@@ -48561,7 +48800,7 @@ var WorkspaceBrowser = class {
|
|
|
48561
48800
|
mtime: ""
|
|
48562
48801
|
};
|
|
48563
48802
|
try {
|
|
48564
|
-
const st = import_node_fs21.default.statSync(
|
|
48803
|
+
const st = import_node_fs21.default.statSync(import_node_path20.default.join(full, d.name));
|
|
48565
48804
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
48566
48805
|
if (d.isFile()) entry.size = st.size;
|
|
48567
48806
|
} catch {
|
|
@@ -48607,8 +48846,8 @@ var WorkspaceBrowser = class {
|
|
|
48607
48846
|
|
|
48608
48847
|
// src/skills/agents-scanner.ts
|
|
48609
48848
|
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
48610
|
-
var
|
|
48611
|
-
var
|
|
48849
|
+
var import_node_os9 = __toESM(require("os"), 1);
|
|
48850
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
48612
48851
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
48613
48852
|
function isDirLikeSync2(p2) {
|
|
48614
48853
|
try {
|
|
@@ -48646,10 +48885,10 @@ function scanAgentsDir(dir, source, seen, out) {
|
|
|
48646
48885
|
}
|
|
48647
48886
|
for (const ent of entries) {
|
|
48648
48887
|
if (!ent.name.endsWith(".md")) continue;
|
|
48649
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
48888
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path21.default.join(dir, ent.name)))) {
|
|
48650
48889
|
continue;
|
|
48651
48890
|
}
|
|
48652
|
-
const filePath =
|
|
48891
|
+
const filePath = import_node_path21.default.join(dir, ent.name);
|
|
48653
48892
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
48654
48893
|
if (seen.has(baseName)) continue;
|
|
48655
48894
|
seen.add(baseName);
|
|
@@ -48672,7 +48911,7 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
48672
48911
|
return;
|
|
48673
48912
|
}
|
|
48674
48913
|
for (const ent of entries) {
|
|
48675
|
-
const childPath =
|
|
48914
|
+
const childPath = import_node_path21.default.join(dir, ent.name);
|
|
48676
48915
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
48677
48916
|
walk2(childPath, [...namespaces, ent.name]);
|
|
48678
48917
|
continue;
|
|
@@ -48697,9 +48936,9 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
48697
48936
|
walk2(root, []);
|
|
48698
48937
|
}
|
|
48699
48938
|
function readInstalledPlugins2(home) {
|
|
48700
|
-
const pluginsDir =
|
|
48701
|
-
const v2 =
|
|
48702
|
-
const v1 =
|
|
48939
|
+
const pluginsDir = import_node_path21.default.join(home, ".claude", "plugins");
|
|
48940
|
+
const v2 = import_node_path21.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
48941
|
+
const v1 = import_node_path21.default.join(pluginsDir, "installed_plugins.json");
|
|
48703
48942
|
let raw = null;
|
|
48704
48943
|
for (const candidate of [v2, v1]) {
|
|
48705
48944
|
try {
|
|
@@ -48728,19 +48967,19 @@ function readInstalledPlugins2(home) {
|
|
|
48728
48967
|
return out;
|
|
48729
48968
|
}
|
|
48730
48969
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
48731
|
-
let cur =
|
|
48732
|
-
const fsRoot =
|
|
48970
|
+
let cur = import_node_path21.default.resolve(startCwd);
|
|
48971
|
+
const fsRoot = import_node_path21.default.parse(cur).root;
|
|
48733
48972
|
while (true) {
|
|
48734
|
-
scanAgentsDir(
|
|
48973
|
+
scanAgentsDir(import_node_path21.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
48735
48974
|
let hasGit = false;
|
|
48736
48975
|
try {
|
|
48737
|
-
hasGit = import_node_fs22.default.existsSync(
|
|
48976
|
+
hasGit = import_node_fs22.default.existsSync(import_node_path21.default.join(cur, ".git"));
|
|
48738
48977
|
} catch {
|
|
48739
48978
|
}
|
|
48740
48979
|
if (hasGit) return;
|
|
48741
48980
|
if (cur === home) return;
|
|
48742
48981
|
if (cur === fsRoot) return;
|
|
48743
|
-
const parent =
|
|
48982
|
+
const parent = import_node_path21.default.dirname(cur);
|
|
48744
48983
|
if (parent === cur) return;
|
|
48745
48984
|
cur = parent;
|
|
48746
48985
|
}
|
|
@@ -48750,7 +48989,7 @@ var AgentsScanner = class {
|
|
|
48750
48989
|
extraPluginRoots;
|
|
48751
48990
|
policyDir;
|
|
48752
48991
|
constructor(opts = {}) {
|
|
48753
|
-
this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ??
|
|
48992
|
+
this.home = opts.home ?? process.env.CLAUDE_CONFIG_DIR ?? import_node_os9.default.homedir();
|
|
48754
48993
|
this.extraPluginRoots = opts.extraPluginRoots ?? [];
|
|
48755
48994
|
if (opts.policyDir !== void 0) {
|
|
48756
48995
|
this.policyDir = opts.policyDir;
|
|
@@ -48775,7 +49014,7 @@ var AgentsScanner = class {
|
|
|
48775
49014
|
}
|
|
48776
49015
|
const fsBlock = [];
|
|
48777
49016
|
scanAgentsDir(
|
|
48778
|
-
|
|
49017
|
+
import_node_path21.default.join(this.home, ".claude", "agents"),
|
|
48779
49018
|
"global",
|
|
48780
49019
|
seen,
|
|
48781
49020
|
fsBlock
|
|
@@ -48789,7 +49028,7 @@ var AgentsScanner = class {
|
|
|
48789
49028
|
...this.extraPluginRoots
|
|
48790
49029
|
];
|
|
48791
49030
|
for (const { name, root } of plugins) {
|
|
48792
|
-
const agentsRoot =
|
|
49031
|
+
const agentsRoot = import_node_path21.default.join(root, "agents");
|
|
48793
49032
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
48794
49033
|
}
|
|
48795
49034
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -48798,27 +49037,27 @@ var AgentsScanner = class {
|
|
|
48798
49037
|
|
|
48799
49038
|
// src/observer/session-observer.ts
|
|
48800
49039
|
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
48801
|
-
var
|
|
48802
|
-
var
|
|
49040
|
+
var import_node_os11 = __toESM(require("os"), 1);
|
|
49041
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
48803
49042
|
init_claude_history();
|
|
48804
49043
|
|
|
48805
49044
|
// src/observer/subagent-meta-observer.ts
|
|
48806
49045
|
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
48807
|
-
var
|
|
48808
|
-
var
|
|
49046
|
+
var import_node_os10 = __toESM(require("os"), 1);
|
|
49047
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
48809
49048
|
init_claude_history();
|
|
48810
49049
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
48811
49050
|
var SubagentMetaObserver = class {
|
|
48812
49051
|
constructor(opts) {
|
|
48813
49052
|
this.opts = opts;
|
|
48814
|
-
this.home = opts.home ??
|
|
49053
|
+
this.home = opts.home ?? import_node_os10.default.homedir();
|
|
48815
49054
|
}
|
|
48816
49055
|
opts;
|
|
48817
49056
|
home;
|
|
48818
49057
|
watches = /* @__PURE__ */ new Map();
|
|
48819
49058
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
48820
49059
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
48821
|
-
return
|
|
49060
|
+
return import_node_path22.default.join(
|
|
48822
49061
|
this.home,
|
|
48823
49062
|
".claude",
|
|
48824
49063
|
"projects",
|
|
@@ -48874,7 +49113,7 @@ var SubagentMetaObserver = class {
|
|
|
48874
49113
|
if (!m2) return;
|
|
48875
49114
|
const agentId = m2[1];
|
|
48876
49115
|
if (w2.emitted.has(agentId)) return;
|
|
48877
|
-
const file =
|
|
49116
|
+
const file = import_node_path22.default.join(w2.dirPath, name);
|
|
48878
49117
|
let raw;
|
|
48879
49118
|
try {
|
|
48880
49119
|
raw = import_node_fs23.default.readFileSync(file, "utf8");
|
|
@@ -48922,7 +49161,7 @@ var SubagentMetaObserver = class {
|
|
|
48922
49161
|
var SessionObserver = class {
|
|
48923
49162
|
constructor(opts) {
|
|
48924
49163
|
this.opts = opts;
|
|
48925
|
-
this.home = opts.home ??
|
|
49164
|
+
this.home = opts.home ?? import_node_os11.default.homedir();
|
|
48926
49165
|
this.metaObserver = opts.enableSubagentMetaObserver ? new SubagentMetaObserver({ home: this.home, onEvent: opts.onEvent }) : null;
|
|
48927
49166
|
}
|
|
48928
49167
|
opts;
|
|
@@ -48934,7 +49173,7 @@ var SessionObserver = class {
|
|
|
48934
49173
|
metaObserver;
|
|
48935
49174
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
48936
49175
|
if (override) return override;
|
|
48937
|
-
return
|
|
49176
|
+
return import_node_path23.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
48938
49177
|
}
|
|
48939
49178
|
start(args) {
|
|
48940
49179
|
this.stop(args.sessionId);
|
|
@@ -48955,10 +49194,10 @@ var SessionObserver = class {
|
|
|
48955
49194
|
prevIsRejectSentinel: false
|
|
48956
49195
|
};
|
|
48957
49196
|
try {
|
|
48958
|
-
import_node_fs24.default.mkdirSync(
|
|
49197
|
+
import_node_fs24.default.mkdirSync(import_node_path23.default.dirname(filePath), { recursive: true });
|
|
48959
49198
|
} catch {
|
|
48960
49199
|
}
|
|
48961
|
-
w2.watcher = import_node_fs24.default.watch(
|
|
49200
|
+
w2.watcher = import_node_fs24.default.watch(import_node_path23.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
48962
49201
|
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
48963
49202
|
this.poll(w2);
|
|
48964
49203
|
});
|
|
@@ -49840,7 +50079,7 @@ async function authenticate(token, deps) {
|
|
|
49840
50079
|
|
|
49841
50080
|
// src/permission/capability-store.ts
|
|
49842
50081
|
var fs28 = __toESM(require("fs"), 1);
|
|
49843
|
-
var
|
|
50082
|
+
var path28 = __toESM(require("path"), 1);
|
|
49844
50083
|
var CAPABILITIES_FILE_NAME = "capabilities.json";
|
|
49845
50084
|
var FILE_VERSION = 1;
|
|
49846
50085
|
var CapabilityStore = class {
|
|
@@ -49870,7 +50109,7 @@ var CapabilityStore = class {
|
|
|
49870
50109
|
this.flush();
|
|
49871
50110
|
}
|
|
49872
50111
|
filePath() {
|
|
49873
|
-
return
|
|
50112
|
+
return path28.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
49874
50113
|
}
|
|
49875
50114
|
readFromDisk() {
|
|
49876
50115
|
const file = this.filePath();
|
|
@@ -50017,7 +50256,7 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
50017
50256
|
|
|
50018
50257
|
// src/inbox/inbox-store.ts
|
|
50019
50258
|
var fs30 = __toESM(require("fs"), 1);
|
|
50020
|
-
var
|
|
50259
|
+
var path29 = __toESM(require("path"), 1);
|
|
50021
50260
|
var INBOX_SUBDIR = "inbox";
|
|
50022
50261
|
var InboxStore = class {
|
|
50023
50262
|
constructor(dataDir) {
|
|
@@ -50115,10 +50354,10 @@ var InboxStore = class {
|
|
|
50115
50354
|
}
|
|
50116
50355
|
}
|
|
50117
50356
|
dirPath() {
|
|
50118
|
-
return
|
|
50357
|
+
return path29.join(this.dataDir, INBOX_SUBDIR);
|
|
50119
50358
|
}
|
|
50120
50359
|
filePath(peerDeviceId) {
|
|
50121
|
-
return
|
|
50360
|
+
return path29.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
50122
50361
|
}
|
|
50123
50362
|
};
|
|
50124
50363
|
function parseAllLines(raw) {
|
|
@@ -50207,7 +50446,7 @@ var InboxManager = class {
|
|
|
50207
50446
|
|
|
50208
50447
|
// src/state/contact-store.ts
|
|
50209
50448
|
var fs31 = __toESM(require("fs"), 1);
|
|
50210
|
-
var
|
|
50449
|
+
var path30 = __toESM(require("path"), 1);
|
|
50211
50450
|
var FILE_NAME = "contacts.json";
|
|
50212
50451
|
var ContactStore = class {
|
|
50213
50452
|
constructor(dataDir) {
|
|
@@ -50217,7 +50456,7 @@ var ContactStore = class {
|
|
|
50217
50456
|
contacts = /* @__PURE__ */ new Map();
|
|
50218
50457
|
load() {
|
|
50219
50458
|
this.contacts.clear();
|
|
50220
|
-
const file =
|
|
50459
|
+
const file = path30.join(this.dataDir, FILE_NAME);
|
|
50221
50460
|
let raw;
|
|
50222
50461
|
try {
|
|
50223
50462
|
raw = fs31.readFileSync(file, "utf8");
|
|
@@ -50263,7 +50502,7 @@ var ContactStore = class {
|
|
|
50263
50502
|
return existed;
|
|
50264
50503
|
}
|
|
50265
50504
|
flush() {
|
|
50266
|
-
const file =
|
|
50505
|
+
const file = path30.join(this.dataDir, FILE_NAME);
|
|
50267
50506
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
50268
50507
|
const content = JSON.stringify(
|
|
50269
50508
|
{ contacts: Array.from(this.contacts.values()) },
|
|
@@ -50427,52 +50666,52 @@ async function autoReverseContact(args) {
|
|
|
50427
50666
|
|
|
50428
50667
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
50429
50668
|
var fs32 = __toESM(require("fs"), 1);
|
|
50430
|
-
var
|
|
50669
|
+
var path31 = __toESM(require("path"), 1);
|
|
50431
50670
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
50432
50671
|
function migrateFlattenSessions(opts) {
|
|
50433
50672
|
const dataDir = opts.dataDir;
|
|
50434
50673
|
const now = opts.now ?? Date.now;
|
|
50435
|
-
const sessionsDir =
|
|
50436
|
-
const flagPath =
|
|
50674
|
+
const sessionsDir = path31.join(dataDir, "sessions");
|
|
50675
|
+
const flagPath = path31.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
50437
50676
|
if (existsSync3(flagPath)) {
|
|
50438
50677
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
50439
50678
|
}
|
|
50440
50679
|
let movedBare = 0;
|
|
50441
50680
|
let movedVmOwner = 0;
|
|
50442
50681
|
let archivedListener = 0;
|
|
50443
|
-
const defaultDir =
|
|
50682
|
+
const defaultDir = path31.join(sessionsDir, "default");
|
|
50444
50683
|
if (existsSync3(defaultDir)) {
|
|
50445
50684
|
for (const entry of readdirSafe(defaultDir)) {
|
|
50446
50685
|
if (!entry.endsWith(".json")) continue;
|
|
50447
|
-
const src =
|
|
50448
|
-
const dst =
|
|
50686
|
+
const src = path31.join(defaultDir, entry);
|
|
50687
|
+
const dst = path31.join(sessionsDir, entry);
|
|
50449
50688
|
fs32.renameSync(src, dst);
|
|
50450
50689
|
movedBare += 1;
|
|
50451
50690
|
}
|
|
50452
50691
|
rmdirIfEmpty(defaultDir);
|
|
50453
50692
|
}
|
|
50454
50693
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
50455
|
-
const personaDir =
|
|
50694
|
+
const personaDir = path31.join(sessionsDir, pid);
|
|
50456
50695
|
if (!isDir(personaDir)) continue;
|
|
50457
50696
|
if (pid === "default") continue;
|
|
50458
|
-
const ownerSrc =
|
|
50697
|
+
const ownerSrc = path31.join(personaDir, "owner");
|
|
50459
50698
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
50460
|
-
const ownerDst =
|
|
50699
|
+
const ownerDst = path31.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
50461
50700
|
fs32.mkdirSync(ownerDst, { recursive: true });
|
|
50462
50701
|
for (const file of readdirSafe(ownerSrc)) {
|
|
50463
50702
|
if (!file.endsWith(".json")) continue;
|
|
50464
|
-
fs32.renameSync(
|
|
50703
|
+
fs32.renameSync(path31.join(ownerSrc, file), path31.join(ownerDst, file));
|
|
50465
50704
|
movedVmOwner += 1;
|
|
50466
50705
|
}
|
|
50467
50706
|
rmdirIfEmpty(ownerSrc);
|
|
50468
50707
|
}
|
|
50469
|
-
const listenerSrc =
|
|
50708
|
+
const listenerSrc = path31.join(personaDir, "listener");
|
|
50470
50709
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
50471
|
-
const archiveDst =
|
|
50710
|
+
const archiveDst = path31.join(dataDir, ".legacy", `listener-${pid}`);
|
|
50472
50711
|
fs32.mkdirSync(archiveDst, { recursive: true });
|
|
50473
50712
|
for (const file of readdirSafe(listenerSrc)) {
|
|
50474
50713
|
if (!file.endsWith(".json")) continue;
|
|
50475
|
-
fs32.renameSync(
|
|
50714
|
+
fs32.renameSync(path31.join(listenerSrc, file), path31.join(archiveDst, file));
|
|
50476
50715
|
archivedListener += 1;
|
|
50477
50716
|
}
|
|
50478
50717
|
rmdirIfEmpty(listenerSrc);
|
|
@@ -50520,10 +50759,10 @@ function rmdirIfEmpty(p2) {
|
|
|
50520
50759
|
|
|
50521
50760
|
// src/transport/http-router.ts
|
|
50522
50761
|
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
50523
|
-
var
|
|
50762
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
50524
50763
|
|
|
50525
50764
|
// src/attachment/mime.ts
|
|
50526
|
-
var
|
|
50765
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
50527
50766
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
50528
50767
|
var EXT_TO_NATIVE_MIME = {
|
|
50529
50768
|
// 图片
|
|
@@ -50630,7 +50869,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
50630
50869
|
".mk"
|
|
50631
50870
|
]);
|
|
50632
50871
|
function lookupMime(filePathOrName) {
|
|
50633
|
-
const ext =
|
|
50872
|
+
const ext = import_node_path24.default.extname(filePathOrName).toLowerCase();
|
|
50634
50873
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
50635
50874
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
50636
50875
|
return "application/octet-stream";
|
|
@@ -50700,7 +50939,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
50700
50939
|
|
|
50701
50940
|
// src/attachment/upload.ts
|
|
50702
50941
|
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
50703
|
-
var
|
|
50942
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
50704
50943
|
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
50705
50944
|
var import_promises2 = require("stream/promises");
|
|
50706
50945
|
var UploadError = class extends Error {
|
|
@@ -50712,14 +50951,14 @@ var UploadError = class extends Error {
|
|
|
50712
50951
|
code;
|
|
50713
50952
|
};
|
|
50714
50953
|
function assertValidFileName(fileName) {
|
|
50715
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
50954
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path25.default.basename(fileName)) {
|
|
50716
50955
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
50717
50956
|
}
|
|
50718
50957
|
}
|
|
50719
50958
|
var HASH_PREFIX_LEN = 16;
|
|
50720
50959
|
async function writeUploadedAttachment(args) {
|
|
50721
50960
|
assertValidFileName(args.fileName);
|
|
50722
|
-
const attachmentsRoot =
|
|
50961
|
+
const attachmentsRoot = import_node_path25.default.join(args.sessionDir, ".attachments");
|
|
50723
50962
|
try {
|
|
50724
50963
|
import_node_fs25.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
50725
50964
|
} catch (err) {
|
|
@@ -50727,7 +50966,7 @@ async function writeUploadedAttachment(args) {
|
|
|
50727
50966
|
}
|
|
50728
50967
|
const hasher = import_node_crypto7.default.createHash("sha256");
|
|
50729
50968
|
let actualSize = 0;
|
|
50730
|
-
const tmpPath =
|
|
50969
|
+
const tmpPath = import_node_path25.default.join(
|
|
50731
50970
|
attachmentsRoot,
|
|
50732
50971
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto7.default.randomBytes(4).toString("hex")}`
|
|
50733
50972
|
);
|
|
@@ -50762,7 +51001,7 @@ async function writeUploadedAttachment(args) {
|
|
|
50762
51001
|
);
|
|
50763
51002
|
}
|
|
50764
51003
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
50765
|
-
const hashDir =
|
|
51004
|
+
const hashDir = import_node_path25.default.join(attachmentsRoot, attachmentId);
|
|
50766
51005
|
let finalFileName;
|
|
50767
51006
|
let hashDirExists = false;
|
|
50768
51007
|
try {
|
|
@@ -50780,7 +51019,7 @@ async function writeUploadedAttachment(args) {
|
|
|
50780
51019
|
try {
|
|
50781
51020
|
import_node_fs25.default.mkdirSync(hashDir, { recursive: true });
|
|
50782
51021
|
finalFileName = args.fileName;
|
|
50783
|
-
import_node_fs25.default.renameSync(tmpPath,
|
|
51022
|
+
import_node_fs25.default.renameSync(tmpPath, import_node_path25.default.join(hashDir, finalFileName));
|
|
50784
51023
|
} catch (err) {
|
|
50785
51024
|
try {
|
|
50786
51025
|
import_node_fs25.default.unlinkSync(tmpPath);
|
|
@@ -50789,8 +51028,8 @@ async function writeUploadedAttachment(args) {
|
|
|
50789
51028
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
50790
51029
|
}
|
|
50791
51030
|
}
|
|
50792
|
-
const absPath =
|
|
50793
|
-
const relPath =
|
|
51031
|
+
const absPath = import_node_path25.default.join(hashDir, finalFileName);
|
|
51032
|
+
const relPath = import_node_path25.default.relative(args.sessionDir, absPath);
|
|
50794
51033
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
50795
51034
|
relPath: absPath,
|
|
50796
51035
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -50804,8 +51043,8 @@ async function writeUploadedAttachment(args) {
|
|
|
50804
51043
|
|
|
50805
51044
|
// src/extension/import.ts
|
|
50806
51045
|
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
50807
|
-
var
|
|
50808
|
-
var
|
|
51046
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
51047
|
+
var import_node_os12 = __toESM(require("os"), 1);
|
|
50809
51048
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
50810
51049
|
var ImportError = class extends Error {
|
|
50811
51050
|
constructor(code, message) {
|
|
@@ -50822,7 +51061,7 @@ async function importZip(buf, root) {
|
|
|
50822
51061
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
50823
51062
|
}
|
|
50824
51063
|
for (const name of Object.keys(zip.files)) {
|
|
50825
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
51064
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path26.default.isAbsolute(name)) {
|
|
50826
51065
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
50827
51066
|
}
|
|
50828
51067
|
}
|
|
@@ -50855,7 +51094,7 @@ async function importZip(buf, root) {
|
|
|
50855
51094
|
);
|
|
50856
51095
|
}
|
|
50857
51096
|
}
|
|
50858
|
-
const destDir =
|
|
51097
|
+
const destDir = import_node_path26.default.join(root, manifest.id);
|
|
50859
51098
|
let destExists = false;
|
|
50860
51099
|
try {
|
|
50861
51100
|
await import_promises3.default.access(destDir);
|
|
@@ -50865,15 +51104,15 @@ async function importZip(buf, root) {
|
|
|
50865
51104
|
if (destExists) {
|
|
50866
51105
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
50867
51106
|
}
|
|
50868
|
-
const stage = await import_promises3.default.mkdtemp(
|
|
51107
|
+
const stage = await import_promises3.default.mkdtemp(import_node_path26.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
50869
51108
|
try {
|
|
50870
51109
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
50871
|
-
const dest =
|
|
51110
|
+
const dest = import_node_path26.default.join(stage, name);
|
|
50872
51111
|
if (entry.dir) {
|
|
50873
51112
|
await import_promises3.default.mkdir(dest, { recursive: true });
|
|
50874
51113
|
continue;
|
|
50875
51114
|
}
|
|
50876
|
-
await import_promises3.default.mkdir(
|
|
51115
|
+
await import_promises3.default.mkdir(import_node_path26.default.dirname(dest), { recursive: true });
|
|
50877
51116
|
const content = await entry.async("nodebuffer");
|
|
50878
51117
|
await import_promises3.default.writeFile(dest, content);
|
|
50879
51118
|
}
|
|
@@ -50904,7 +51143,7 @@ var SHARE_UI_ASSET_MIME = {
|
|
|
50904
51143
|
".wasm": "application/wasm"
|
|
50905
51144
|
};
|
|
50906
51145
|
function shareUiAssetMime(filePath) {
|
|
50907
|
-
const ext =
|
|
51146
|
+
const ext = import_node_path27.default.extname(filePath).toLowerCase();
|
|
50908
51147
|
return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
|
|
50909
51148
|
}
|
|
50910
51149
|
var DISPATCH_HEARTBEAT_MS = 25e3;
|
|
@@ -50991,7 +51230,7 @@ function isValidUploadFileName(fileName) {
|
|
|
50991
51230
|
if (fileName === "." || fileName === "..") return false;
|
|
50992
51231
|
if (fileName.startsWith(".")) return false;
|
|
50993
51232
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
50994
|
-
return fileName ===
|
|
51233
|
+
return fileName === import_node_path27.default.basename(fileName);
|
|
50995
51234
|
}
|
|
50996
51235
|
function createHttpRouter(deps) {
|
|
50997
51236
|
return async (req, res) => {
|
|
@@ -51287,7 +51526,7 @@ function createHttpRouter(deps) {
|
|
|
51287
51526
|
sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
|
|
51288
51527
|
return true;
|
|
51289
51528
|
}
|
|
51290
|
-
sendHtml(res, 200, loader.renderViewerHtml(
|
|
51529
|
+
sendHtml(res, 200, loader.renderViewerHtml(import_node_path27.default.basename(r.absPath)));
|
|
51291
51530
|
return true;
|
|
51292
51531
|
}
|
|
51293
51532
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
@@ -51408,7 +51647,7 @@ function createHttpRouter(deps) {
|
|
|
51408
51647
|
return true;
|
|
51409
51648
|
}
|
|
51410
51649
|
let absPath;
|
|
51411
|
-
if (
|
|
51650
|
+
if (import_node_path27.default.isAbsolute(pathParam)) {
|
|
51412
51651
|
absPath = pathParam;
|
|
51413
51652
|
} else if (deps.sessionStore) {
|
|
51414
51653
|
const file = deps.sessionStore.read(sid);
|
|
@@ -51416,7 +51655,7 @@ function createHttpRouter(deps) {
|
|
|
51416
51655
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
51417
51656
|
return true;
|
|
51418
51657
|
}
|
|
51419
|
-
absPath =
|
|
51658
|
+
absPath = import_node_path27.default.join(file.cwd, pathParam);
|
|
51420
51659
|
} else {
|
|
51421
51660
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
51422
51661
|
return true;
|
|
@@ -51518,7 +51757,7 @@ function streamFile(res, absPath, logger) {
|
|
|
51518
51757
|
return;
|
|
51519
51758
|
}
|
|
51520
51759
|
const mime = lookupMime(absPath);
|
|
51521
|
-
const basename =
|
|
51760
|
+
const basename = import_node_path27.default.basename(absPath);
|
|
51522
51761
|
res.writeHead(200, {
|
|
51523
51762
|
"Content-Type": mime,
|
|
51524
51763
|
"Content-Length": String(stat.size),
|
|
@@ -51536,7 +51775,7 @@ function streamFile(res, absPath, logger) {
|
|
|
51536
51775
|
|
|
51537
51776
|
// src/attachment/gc.ts
|
|
51538
51777
|
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
51539
|
-
var
|
|
51778
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
51540
51779
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
51541
51780
|
function runAttachmentGc(args) {
|
|
51542
51781
|
const now = (args.now ?? Date.now)();
|
|
@@ -51545,17 +51784,17 @@ function runAttachmentGc(args) {
|
|
|
51545
51784
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
51546
51785
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
51547
51786
|
if (entry.stale) continue;
|
|
51548
|
-
if (
|
|
51787
|
+
if (import_node_path28.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
51549
51788
|
}
|
|
51550
51789
|
}
|
|
51551
51790
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
51552
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
51791
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path28.default.join(
|
|
51553
51792
|
args.dataDir,
|
|
51554
51793
|
"sessions",
|
|
51555
51794
|
...scopeSubPath(scope).map(safeFileName),
|
|
51556
51795
|
safeFileName(sessionId)
|
|
51557
51796
|
);
|
|
51558
|
-
const attRoot =
|
|
51797
|
+
const attRoot = import_node_path28.default.join(sessionDir, ".attachments");
|
|
51559
51798
|
let hashDirs;
|
|
51560
51799
|
try {
|
|
51561
51800
|
hashDirs = import_node_fs27.default.readdirSync(attRoot);
|
|
@@ -51565,7 +51804,7 @@ function runAttachmentGc(args) {
|
|
|
51565
51804
|
continue;
|
|
51566
51805
|
}
|
|
51567
51806
|
for (const hashDir of hashDirs) {
|
|
51568
|
-
const hashDirAbs =
|
|
51807
|
+
const hashDirAbs = import_node_path28.default.join(attRoot, hashDir);
|
|
51569
51808
|
let files;
|
|
51570
51809
|
try {
|
|
51571
51810
|
files = import_node_fs27.default.readdirSync(hashDirAbs);
|
|
@@ -51573,7 +51812,7 @@ function runAttachmentGc(args) {
|
|
|
51573
51812
|
continue;
|
|
51574
51813
|
}
|
|
51575
51814
|
for (const name of files) {
|
|
51576
|
-
const file =
|
|
51815
|
+
const file = import_node_path28.default.join(hashDirAbs, name);
|
|
51577
51816
|
let stat;
|
|
51578
51817
|
try {
|
|
51579
51818
|
stat = import_node_fs27.default.statSync(file);
|
|
@@ -51604,7 +51843,7 @@ function runAttachmentGc(args) {
|
|
|
51604
51843
|
|
|
51605
51844
|
// src/attachment/group.ts
|
|
51606
51845
|
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
51607
|
-
var
|
|
51846
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
51608
51847
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
51609
51848
|
init_protocol();
|
|
51610
51849
|
var GroupFileStore = class {
|
|
@@ -51616,11 +51855,11 @@ var GroupFileStore = class {
|
|
|
51616
51855
|
this.logger = opts.logger;
|
|
51617
51856
|
}
|
|
51618
51857
|
rootForScope(scope) {
|
|
51619
|
-
return
|
|
51858
|
+
return import_node_path29.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
51620
51859
|
}
|
|
51621
51860
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
51622
51861
|
filePath(scope, sessionId) {
|
|
51623
|
-
return
|
|
51862
|
+
return import_node_path29.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
51624
51863
|
}
|
|
51625
51864
|
cacheKey(scope, sessionId) {
|
|
51626
51865
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -51655,7 +51894,7 @@ var GroupFileStore = class {
|
|
|
51655
51894
|
}
|
|
51656
51895
|
writeFile(scope, sessionId, entries) {
|
|
51657
51896
|
const file = this.filePath(scope, sessionId);
|
|
51658
|
-
import_node_fs28.default.mkdirSync(
|
|
51897
|
+
import_node_fs28.default.mkdirSync(import_node_path29.default.dirname(file), { recursive: true });
|
|
51659
51898
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
51660
51899
|
import_node_fs28.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
51661
51900
|
import_node_fs28.default.renameSync(tmp, file);
|
|
@@ -51745,9 +51984,9 @@ var GroupFileStore = class {
|
|
|
51745
51984
|
|
|
51746
51985
|
// src/discovery/state-file.ts
|
|
51747
51986
|
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
51748
|
-
var
|
|
51987
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
51749
51988
|
function defaultStateFilePath(dataDir) {
|
|
51750
|
-
return
|
|
51989
|
+
return import_node_path30.default.join(dataDir, "state.json");
|
|
51751
51990
|
}
|
|
51752
51991
|
function isPidAlive(pid) {
|
|
51753
51992
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -51783,7 +52022,7 @@ var StateFileManager = class {
|
|
|
51783
52022
|
return { status: "stale", existing };
|
|
51784
52023
|
}
|
|
51785
52024
|
write(state) {
|
|
51786
|
-
import_node_fs29.default.mkdirSync(
|
|
52025
|
+
import_node_fs29.default.mkdirSync(import_node_path30.default.dirname(this.file), { recursive: true });
|
|
51787
52026
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
51788
52027
|
import_node_fs29.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
51789
52028
|
import_node_fs29.default.renameSync(tmp, this.file);
|
|
@@ -51812,13 +52051,13 @@ function readDaemonSourceFromEnv(env = process.env) {
|
|
|
51812
52051
|
|
|
51813
52052
|
// src/tunnel/tunnel-manager.ts
|
|
51814
52053
|
var import_node_fs33 = __toESM(require("fs"), 1);
|
|
51815
|
-
var
|
|
52054
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
51816
52055
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
51817
52056
|
var import_node_child_process9 = require("child_process");
|
|
51818
52057
|
|
|
51819
52058
|
// src/tunnel/tunnel-store.ts
|
|
51820
52059
|
var import_node_fs30 = __toESM(require("fs"), 1);
|
|
51821
|
-
var
|
|
52060
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
51822
52061
|
var TunnelStore = class {
|
|
51823
52062
|
constructor(filePath) {
|
|
51824
52063
|
this.filePath = filePath;
|
|
@@ -51837,7 +52076,7 @@ var TunnelStore = class {
|
|
|
51837
52076
|
}
|
|
51838
52077
|
}
|
|
51839
52078
|
async set(v2) {
|
|
51840
|
-
const dir =
|
|
52079
|
+
const dir = import_node_path31.default.dirname(this.filePath);
|
|
51841
52080
|
await import_node_fs30.default.promises.mkdir(dir, { recursive: true });
|
|
51842
52081
|
const data = JSON.stringify(v2, null, 2);
|
|
51843
52082
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
@@ -51948,8 +52187,8 @@ function escape(v2) {
|
|
|
51948
52187
|
|
|
51949
52188
|
// src/tunnel/frpc-binary.ts
|
|
51950
52189
|
var import_node_fs31 = __toESM(require("fs"), 1);
|
|
51951
|
-
var
|
|
51952
|
-
var
|
|
52190
|
+
var import_node_os13 = __toESM(require("os"), 1);
|
|
52191
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
51953
52192
|
var import_node_child_process7 = require("child_process");
|
|
51954
52193
|
var import_node_stream3 = require("stream");
|
|
51955
52194
|
var import_promises4 = require("stream/promises");
|
|
@@ -51988,13 +52227,13 @@ async function ensureFrpcBinary(opts) {
|
|
|
51988
52227
|
}
|
|
51989
52228
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
51990
52229
|
const platform = opts.platform ?? detectPlatform();
|
|
51991
|
-
const binDir =
|
|
52230
|
+
const binDir = import_node_path32.default.join(opts.dataDir, "bin");
|
|
51992
52231
|
import_node_fs31.default.mkdirSync(binDir, { recursive: true });
|
|
51993
52232
|
cleanupStaleArtifacts(binDir);
|
|
51994
|
-
const stableBin =
|
|
52233
|
+
const stableBin = import_node_path32.default.join(binDir, "frpc");
|
|
51995
52234
|
if (import_node_fs31.default.existsSync(stableBin)) return stableBin;
|
|
51996
52235
|
const partialBin = `${stableBin}.partial`;
|
|
51997
|
-
const tarballPath =
|
|
52236
|
+
const tarballPath = import_node_path32.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
51998
52237
|
try {
|
|
51999
52238
|
const url = frpcDownloadUrl(version2, platform);
|
|
52000
52239
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -52020,7 +52259,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
52020
52259
|
}
|
|
52021
52260
|
for (const name of entries) {
|
|
52022
52261
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
52023
|
-
const full =
|
|
52262
|
+
const full = import_node_path32.default.join(binDir, name);
|
|
52024
52263
|
try {
|
|
52025
52264
|
import_node_fs31.default.rmSync(full, { recursive: true, force: true });
|
|
52026
52265
|
} catch {
|
|
@@ -52046,7 +52285,7 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
52046
52285
|
await (0, import_promises4.pipeline)(nodeStream, out);
|
|
52047
52286
|
}
|
|
52048
52287
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
52049
|
-
const work =
|
|
52288
|
+
const work = import_node_path32.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
52050
52289
|
import_node_fs31.default.mkdirSync(work, { recursive: true });
|
|
52051
52290
|
try {
|
|
52052
52291
|
await new Promise((resolve6, reject) => {
|
|
@@ -52055,7 +52294,7 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
52055
52294
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
52056
52295
|
});
|
|
52057
52296
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
52058
|
-
const src =
|
|
52297
|
+
const src = import_node_path32.default.join(work, dirName, "frpc");
|
|
52059
52298
|
if (!import_node_fs31.default.existsSync(src)) {
|
|
52060
52299
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
52061
52300
|
}
|
|
@@ -52067,10 +52306,10 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
52067
52306
|
|
|
52068
52307
|
// src/tunnel/frpc-process.ts
|
|
52069
52308
|
var import_node_fs32 = __toESM(require("fs"), 1);
|
|
52070
|
-
var
|
|
52309
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
52071
52310
|
var import_node_child_process8 = require("child_process");
|
|
52072
52311
|
function frpcPidFilePath(dataDir) {
|
|
52073
|
-
return
|
|
52312
|
+
return import_node_path33.default.join(dataDir, "frpc.pid");
|
|
52074
52313
|
}
|
|
52075
52314
|
function writeFrpcPid(dataDir, pid) {
|
|
52076
52315
|
try {
|
|
@@ -52112,7 +52351,7 @@ function defaultSleep(ms) {
|
|
|
52112
52351
|
}
|
|
52113
52352
|
async function killStaleFrpc(deps) {
|
|
52114
52353
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
52115
|
-
const tomlPath =
|
|
52354
|
+
const tomlPath = import_node_path33.default.join(deps.dataDir, "frpc.toml");
|
|
52116
52355
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
52117
52356
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
52118
52357
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -52184,7 +52423,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
52184
52423
|
var TunnelManager = class {
|
|
52185
52424
|
constructor(deps) {
|
|
52186
52425
|
this.deps = deps;
|
|
52187
|
-
this.store = deps.store ?? new TunnelStore(
|
|
52426
|
+
this.store = deps.store ?? new TunnelStore(import_node_path34.default.join(deps.dataDir, "tunnel.json"));
|
|
52188
52427
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
52189
52428
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
52190
52429
|
}
|
|
@@ -52311,7 +52550,7 @@ var TunnelManager = class {
|
|
|
52311
52550
|
dataDir: this.deps.dataDir,
|
|
52312
52551
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
52313
52552
|
});
|
|
52314
|
-
const tomlPath =
|
|
52553
|
+
const tomlPath = import_node_path34.default.join(this.deps.dataDir, "frpc.toml");
|
|
52315
52554
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto9.default.randomBytes(3).toString("hex")}`;
|
|
52316
52555
|
const toml = buildFrpcToml({
|
|
52317
52556
|
serverAddr: t.frpsHost,
|
|
@@ -52326,7 +52565,7 @@ var TunnelManager = class {
|
|
|
52326
52565
|
const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
|
|
52327
52566
|
stdio: ["ignore", "pipe", "pipe"]
|
|
52328
52567
|
});
|
|
52329
|
-
const logFilePath =
|
|
52568
|
+
const logFilePath = import_node_path34.default.join(this.deps.dataDir, "frpc.log");
|
|
52330
52569
|
const logStream = import_node_fs33.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
52331
52570
|
logStream.on("error", () => {
|
|
52332
52571
|
});
|
|
@@ -52409,16 +52648,16 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
52409
52648
|
}
|
|
52410
52649
|
|
|
52411
52650
|
// src/tunnel/device-key.ts
|
|
52412
|
-
var
|
|
52413
|
-
var
|
|
52651
|
+
var import_node_os14 = __toESM(require("os"), 1);
|
|
52652
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
52414
52653
|
var import_node_crypto10 = __toESM(require("crypto"), 1);
|
|
52415
52654
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
52416
52655
|
function deriveStableDeviceKey(opts = {}) {
|
|
52417
|
-
const hostname = opts.hostname ??
|
|
52418
|
-
const uid = opts.uid ?? (typeof
|
|
52419
|
-
const home = opts.home ??
|
|
52420
|
-
const defaultDataDir =
|
|
52421
|
-
const normalizedDataDir = opts.dataDir ?
|
|
52656
|
+
const hostname = opts.hostname ?? import_node_os14.default.hostname();
|
|
52657
|
+
const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
|
|
52658
|
+
const home = opts.home ?? import_node_os14.default.homedir();
|
|
52659
|
+
const defaultDataDir = import_node_path35.default.resolve(import_node_path35.default.join(home, ".clawd"));
|
|
52660
|
+
const normalizedDataDir = opts.dataDir ? import_node_path35.default.resolve(opts.dataDir) : null;
|
|
52422
52661
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
52423
52662
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
52424
52663
|
return import_node_crypto10.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
@@ -52426,11 +52665,11 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
52426
52665
|
|
|
52427
52666
|
// src/auth-store.ts
|
|
52428
52667
|
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
52429
|
-
var
|
|
52668
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
52430
52669
|
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
52431
52670
|
var AUTH_FILE_NAME = "auth.json";
|
|
52432
52671
|
function authFilePath(dataDir) {
|
|
52433
|
-
return
|
|
52672
|
+
return import_node_path36.default.join(dataDir, AUTH_FILE_NAME);
|
|
52434
52673
|
}
|
|
52435
52674
|
function loadOrCreateAuthFile(opts) {
|
|
52436
52675
|
const file = authFilePath(opts.dataDir);
|
|
@@ -52486,7 +52725,7 @@ function readAuthFile(file) {
|
|
|
52486
52725
|
}
|
|
52487
52726
|
}
|
|
52488
52727
|
function writeAuthFile(file, content) {
|
|
52489
|
-
import_node_fs34.default.mkdirSync(
|
|
52728
|
+
import_node_fs34.default.mkdirSync(import_node_path36.default.dirname(file), { recursive: true });
|
|
52490
52729
|
import_node_fs34.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
52491
52730
|
try {
|
|
52492
52731
|
import_node_fs34.default.chmodSync(file, 384);
|
|
@@ -52496,12 +52735,12 @@ function writeAuthFile(file, content) {
|
|
|
52496
52735
|
|
|
52497
52736
|
// src/owner-profile.ts
|
|
52498
52737
|
var import_node_fs35 = __toESM(require("fs"), 1);
|
|
52499
|
-
var
|
|
52500
|
-
var
|
|
52738
|
+
var import_node_os15 = __toESM(require("os"), 1);
|
|
52739
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
52501
52740
|
var PROFILE_FILENAME = "profile.json";
|
|
52502
52741
|
function loadOwnerDisplayName(dataDir) {
|
|
52503
|
-
const fallback =
|
|
52504
|
-
const profilePath =
|
|
52742
|
+
const fallback = import_node_os15.default.userInfo().username;
|
|
52743
|
+
const profilePath = import_node_path37.default.join(dataDir, PROFILE_FILENAME);
|
|
52505
52744
|
let raw;
|
|
52506
52745
|
try {
|
|
52507
52746
|
raw = import_node_fs35.default.readFileSync(profilePath, "utf8");
|
|
@@ -52528,12 +52767,12 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
52528
52767
|
|
|
52529
52768
|
// src/feishu-auth/owner-identity-store.ts
|
|
52530
52769
|
var import_node_fs36 = __toESM(require("fs"), 1);
|
|
52531
|
-
var
|
|
52770
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
52532
52771
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
52533
52772
|
var OwnerIdentityStore = class {
|
|
52534
52773
|
file;
|
|
52535
52774
|
constructor(dataDir) {
|
|
52536
|
-
this.file =
|
|
52775
|
+
this.file = import_node_path38.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
52537
52776
|
}
|
|
52538
52777
|
read() {
|
|
52539
52778
|
let raw;
|
|
@@ -52566,7 +52805,7 @@ var OwnerIdentityStore = class {
|
|
|
52566
52805
|
};
|
|
52567
52806
|
}
|
|
52568
52807
|
write(record) {
|
|
52569
|
-
import_node_fs36.default.mkdirSync(
|
|
52808
|
+
import_node_fs36.default.mkdirSync(import_node_path38.default.dirname(this.file), { recursive: true });
|
|
52570
52809
|
import_node_fs36.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
52571
52810
|
try {
|
|
52572
52811
|
import_node_fs36.default.chmodSync(this.file, 384);
|
|
@@ -52696,9 +52935,9 @@ var CentralClientError = class extends Error {
|
|
|
52696
52935
|
code;
|
|
52697
52936
|
cause;
|
|
52698
52937
|
};
|
|
52699
|
-
async function centralRequest(opts,
|
|
52938
|
+
async function centralRequest(opts, path68, init) {
|
|
52700
52939
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
52701
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
52940
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path68}`;
|
|
52702
52941
|
const ctrl = new AbortController();
|
|
52703
52942
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
52704
52943
|
let res;
|
|
@@ -52841,7 +53080,7 @@ function verifyConnectToken(args) {
|
|
|
52841
53080
|
|
|
52842
53081
|
// src/feishu-auth/server-key.ts
|
|
52843
53082
|
var fs46 = __toESM(require("fs"), 1);
|
|
52844
|
-
var
|
|
53083
|
+
var path47 = __toESM(require("path"), 1);
|
|
52845
53084
|
var FILE_NAME2 = "server-signing-key.json";
|
|
52846
53085
|
var ServerKeyStore = class {
|
|
52847
53086
|
constructor(dataDir) {
|
|
@@ -52849,7 +53088,7 @@ var ServerKeyStore = class {
|
|
|
52849
53088
|
}
|
|
52850
53089
|
dataDir;
|
|
52851
53090
|
filePath() {
|
|
52852
|
-
return
|
|
53091
|
+
return path47.join(this.dataDir, FILE_NAME2);
|
|
52853
53092
|
}
|
|
52854
53093
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
52855
53094
|
read() {
|
|
@@ -52888,8 +53127,8 @@ init_protocol();
|
|
|
52888
53127
|
|
|
52889
53128
|
// src/session/fork.ts
|
|
52890
53129
|
var import_node_fs37 = __toESM(require("fs"), 1);
|
|
52891
|
-
var
|
|
52892
|
-
var
|
|
53130
|
+
var import_node_os16 = __toESM(require("os"), 1);
|
|
53131
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
52893
53132
|
init_claude_history();
|
|
52894
53133
|
function readJsonlEntries(file) {
|
|
52895
53134
|
const raw = import_node_fs37.default.readFileSync(file, "utf8");
|
|
@@ -52905,9 +53144,9 @@ function readJsonlEntries(file) {
|
|
|
52905
53144
|
return out;
|
|
52906
53145
|
}
|
|
52907
53146
|
function forkSession(input) {
|
|
52908
|
-
const baseDir = input.baseDir ??
|
|
52909
|
-
const projectDir =
|
|
52910
|
-
const sourceFile =
|
|
53147
|
+
const baseDir = input.baseDir ?? import_node_path39.default.join(import_node_os16.default.homedir(), ".claude");
|
|
53148
|
+
const projectDir = import_node_path39.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
53149
|
+
const sourceFile = import_node_path39.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
52911
53150
|
if (!import_node_fs37.default.existsSync(sourceFile)) {
|
|
52912
53151
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
52913
53152
|
}
|
|
@@ -52938,7 +53177,7 @@ function forkSession(input) {
|
|
|
52938
53177
|
}
|
|
52939
53178
|
forkedLines.push(JSON.stringify(forked));
|
|
52940
53179
|
}
|
|
52941
|
-
const forkedFilePath =
|
|
53180
|
+
const forkedFilePath = import_node_path39.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
52942
53181
|
import_node_fs37.default.mkdirSync(projectDir, { recursive: true });
|
|
52943
53182
|
import_node_fs37.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
52944
53183
|
return { forkedToolSessionId, forkedFilePath };
|
|
@@ -53292,7 +53531,7 @@ function buildPermissionHandlers(deps) {
|
|
|
53292
53531
|
}
|
|
53293
53532
|
|
|
53294
53533
|
// src/handlers/history.ts
|
|
53295
|
-
var
|
|
53534
|
+
var path50 = __toESM(require("path"), 1);
|
|
53296
53535
|
init_protocol();
|
|
53297
53536
|
|
|
53298
53537
|
// src/session/recent-dirs.ts
|
|
@@ -53310,7 +53549,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
53310
53549
|
}
|
|
53311
53550
|
|
|
53312
53551
|
// src/permission/persona-paths.ts
|
|
53313
|
-
var
|
|
53552
|
+
var path49 = __toESM(require("path"), 1);
|
|
53314
53553
|
function getAllowedPersonaIds(grants, action) {
|
|
53315
53554
|
const ids = /* @__PURE__ */ new Set();
|
|
53316
53555
|
for (const g2 of grants) {
|
|
@@ -53323,42 +53562,42 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
53323
53562
|
return ids;
|
|
53324
53563
|
}
|
|
53325
53564
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
53326
|
-
const target =
|
|
53565
|
+
const target = path49.resolve(absPath);
|
|
53327
53566
|
if (userWorkDir) {
|
|
53328
|
-
const u =
|
|
53329
|
-
const usep = u.endsWith(
|
|
53567
|
+
const u = path49.resolve(userWorkDir);
|
|
53568
|
+
const usep = u.endsWith(path49.sep) ? "" : path49.sep;
|
|
53330
53569
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
53331
53570
|
}
|
|
53332
|
-
const root =
|
|
53333
|
-
const sep3 = root.endsWith(
|
|
53571
|
+
const root = path49.resolve(personaRoot);
|
|
53572
|
+
const sep3 = root.endsWith(path49.sep) ? "" : path49.sep;
|
|
53334
53573
|
if (!target.startsWith(root + sep3)) return false;
|
|
53335
|
-
const rel =
|
|
53574
|
+
const rel = path49.relative(root, target);
|
|
53336
53575
|
if (!rel || rel.startsWith("..")) return false;
|
|
53337
|
-
const personaId = rel.split(
|
|
53576
|
+
const personaId = rel.split(path49.sep)[0];
|
|
53338
53577
|
if (!personaId) return false;
|
|
53339
53578
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
53340
53579
|
if (allowed === "*") return true;
|
|
53341
53580
|
return allowed.has(personaId);
|
|
53342
53581
|
}
|
|
53343
53582
|
function personaIdFromPath(absPath, personaRoot) {
|
|
53344
|
-
const root =
|
|
53345
|
-
const target =
|
|
53346
|
-
const sep3 = root.endsWith(
|
|
53583
|
+
const root = path49.resolve(personaRoot);
|
|
53584
|
+
const target = path49.resolve(absPath);
|
|
53585
|
+
const sep3 = root.endsWith(path49.sep) ? "" : path49.sep;
|
|
53347
53586
|
if (!target.startsWith(root + sep3)) return null;
|
|
53348
|
-
const rel =
|
|
53587
|
+
const rel = path49.relative(root, target);
|
|
53349
53588
|
if (!rel || rel.startsWith("..")) return null;
|
|
53350
|
-
const id = rel.split(
|
|
53589
|
+
const id = rel.split(path49.sep)[0];
|
|
53351
53590
|
return id || null;
|
|
53352
53591
|
}
|
|
53353
53592
|
function isPathWithin(dir, absPath) {
|
|
53354
|
-
const d =
|
|
53355
|
-
const t =
|
|
53356
|
-
const sep3 = d.endsWith(
|
|
53593
|
+
const d = path49.resolve(dir);
|
|
53594
|
+
const t = path49.resolve(absPath);
|
|
53595
|
+
const sep3 = d.endsWith(path49.sep) ? "" : path49.sep;
|
|
53357
53596
|
return t === d || t.startsWith(d + sep3);
|
|
53358
53597
|
}
|
|
53359
53598
|
function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
|
|
53360
53599
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
53361
|
-
return personaIdFromPath(
|
|
53600
|
+
return personaIdFromPath(path49.resolve(absPath), personaRoot) === personaId;
|
|
53362
53601
|
}
|
|
53363
53602
|
|
|
53364
53603
|
// src/handlers/history.ts
|
|
@@ -53384,7 +53623,7 @@ function buildHistoryHandlers(deps) {
|
|
|
53384
53623
|
if (!pid) return false;
|
|
53385
53624
|
return isGuestPathAllowed(
|
|
53386
53625
|
ctx.grants,
|
|
53387
|
-
|
|
53626
|
+
path50.join(personaRoot, pid),
|
|
53388
53627
|
personaRoot,
|
|
53389
53628
|
"read",
|
|
53390
53629
|
userWorkDir
|
|
@@ -53396,7 +53635,7 @@ function buildHistoryHandlers(deps) {
|
|
|
53396
53635
|
};
|
|
53397
53636
|
const list = async (frame, _client, ctx) => {
|
|
53398
53637
|
const args = HistoryListArgs.parse(frame);
|
|
53399
|
-
assertGuestPath(ctx,
|
|
53638
|
+
assertGuestPath(ctx, path50.resolve(args.projectPath), personaRoot, "history:list");
|
|
53400
53639
|
const sessions = await history.listSessions(args);
|
|
53401
53640
|
return { response: { type: "history:list", sessions } };
|
|
53402
53641
|
};
|
|
@@ -53428,13 +53667,13 @@ function buildHistoryHandlers(deps) {
|
|
|
53428
53667
|
};
|
|
53429
53668
|
const subagents = async (frame, _client, ctx) => {
|
|
53430
53669
|
const args = HistorySubagentsArgs.parse(frame);
|
|
53431
|
-
assertGuestPath(ctx,
|
|
53670
|
+
assertGuestPath(ctx, path50.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
53432
53671
|
const subs = await history.listSubagents(args);
|
|
53433
53672
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
53434
53673
|
};
|
|
53435
53674
|
const subagentRead = async (frame, _client, ctx) => {
|
|
53436
53675
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
53437
|
-
assertGuestPath(ctx,
|
|
53676
|
+
assertGuestPath(ctx, path50.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
53438
53677
|
const res = await history.readSubagent(args);
|
|
53439
53678
|
return { response: { type: "history:subagent-read", ...res } };
|
|
53440
53679
|
};
|
|
@@ -53443,7 +53682,7 @@ function buildHistoryHandlers(deps) {
|
|
|
53443
53682
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
53444
53683
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
53445
53684
|
const filtered = dirs.filter(
|
|
53446
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
53685
|
+
(d) => isGuestPathAllowed(ctx.grants, path50.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
53447
53686
|
);
|
|
53448
53687
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
53449
53688
|
}
|
|
@@ -53460,8 +53699,8 @@ function buildHistoryHandlers(deps) {
|
|
|
53460
53699
|
}
|
|
53461
53700
|
|
|
53462
53701
|
// src/handlers/workspace.ts
|
|
53463
|
-
var
|
|
53464
|
-
var
|
|
53702
|
+
var path51 = __toESM(require("path"), 1);
|
|
53703
|
+
var os16 = __toESM(require("os"), 1);
|
|
53465
53704
|
init_protocol();
|
|
53466
53705
|
init_protocol();
|
|
53467
53706
|
function buildEnabledPluginNames(personaManager, personaId) {
|
|
@@ -53501,23 +53740,23 @@ function buildWorkspaceHandlers(deps) {
|
|
|
53501
53740
|
const list = async (frame, _client, ctx) => {
|
|
53502
53741
|
const args = WorkspaceListArgs.parse(frame);
|
|
53503
53742
|
const isGuest = ctx?.principal.kind === "guest";
|
|
53504
|
-
const fallbackCwd = isGuest && personaRoot ? personaRoot :
|
|
53505
|
-
const resolvedCwd =
|
|
53506
|
-
const target = args.path ?
|
|
53743
|
+
const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
|
|
53744
|
+
const resolvedCwd = path51.resolve(args.cwd ?? fallbackCwd);
|
|
53745
|
+
const target = args.path ? path51.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
53507
53746
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
53508
53747
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
53509
53748
|
return { response: { type: "workspace:list", ...res } };
|
|
53510
53749
|
};
|
|
53511
53750
|
const read = async (frame, _client, ctx) => {
|
|
53512
53751
|
const args = WorkspaceReadArgs.parse(frame);
|
|
53513
|
-
const target =
|
|
53752
|
+
const target = path51.isAbsolute(args.path) ? path51.resolve(args.path) : path51.resolve(args.cwd, args.path);
|
|
53514
53753
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
53515
53754
|
const res = workspace.read(args);
|
|
53516
53755
|
return { response: { type: "workspace:read", ...res } };
|
|
53517
53756
|
};
|
|
53518
53757
|
const skillsList = async (frame, _client, ctx) => {
|
|
53519
53758
|
const args = SkillsListArgs.parse(frame);
|
|
53520
|
-
const cwdAbs =
|
|
53759
|
+
const cwdAbs = path51.resolve(args.cwd);
|
|
53521
53760
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
53522
53761
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
53523
53762
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -53529,7 +53768,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
53529
53768
|
};
|
|
53530
53769
|
const agentsList = async (frame, _client, ctx) => {
|
|
53531
53770
|
const args = AgentsListArgs.parse(frame);
|
|
53532
|
-
const cwdAbs =
|
|
53771
|
+
const cwdAbs = path51.resolve(args.cwd);
|
|
53533
53772
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
53534
53773
|
if (args.tool === "codex") {
|
|
53535
53774
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -53551,18 +53790,18 @@ function buildWorkspaceHandlers(deps) {
|
|
|
53551
53790
|
}
|
|
53552
53791
|
|
|
53553
53792
|
// src/handlers/git.ts
|
|
53554
|
-
var
|
|
53793
|
+
var path53 = __toESM(require("path"), 1);
|
|
53555
53794
|
init_protocol();
|
|
53556
53795
|
init_protocol();
|
|
53557
53796
|
|
|
53558
53797
|
// src/workspace/git.ts
|
|
53559
53798
|
var import_node_child_process10 = require("child_process");
|
|
53560
53799
|
var import_node_fs38 = __toESM(require("fs"), 1);
|
|
53561
|
-
var
|
|
53800
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
53562
53801
|
var import_node_util = require("util");
|
|
53563
53802
|
var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
|
|
53564
53803
|
function normalizePath(p2) {
|
|
53565
|
-
const resolved =
|
|
53804
|
+
const resolved = import_node_path40.default.resolve(p2);
|
|
53566
53805
|
try {
|
|
53567
53806
|
return import_node_fs38.default.realpathSync(resolved);
|
|
53568
53807
|
} catch {
|
|
@@ -53638,7 +53877,7 @@ async function listGitBranches(cwd) {
|
|
|
53638
53877
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
53639
53878
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
53640
53879
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
53641
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
53880
|
+
if (!isGuestPathAllowed(ctx.grants, path53.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
53642
53881
|
throw new ClawdError(
|
|
53643
53882
|
ERROR_CODES.UNAUTHORIZED,
|
|
53644
53883
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -54124,7 +54363,7 @@ function buildDeviceHandlers(deps) {
|
|
|
54124
54363
|
}
|
|
54125
54364
|
|
|
54126
54365
|
// src/handlers/meta.ts
|
|
54127
|
-
var
|
|
54366
|
+
var import_node_os17 = __toESM(require("os"), 1);
|
|
54128
54367
|
init_protocol();
|
|
54129
54368
|
|
|
54130
54369
|
// src/version.ts
|
|
@@ -54156,7 +54395,7 @@ function buildReadyFrame(deps, client) {
|
|
|
54156
54395
|
return {
|
|
54157
54396
|
version,
|
|
54158
54397
|
protocolVersion: PROTOCOL_VERSION,
|
|
54159
|
-
hostname:
|
|
54398
|
+
hostname: import_node_os17.default.hostname(),
|
|
54160
54399
|
os: process.platform,
|
|
54161
54400
|
tools,
|
|
54162
54401
|
runningSessions: info.runningSessions,
|
|
@@ -54253,7 +54492,7 @@ function buildPersonaHandlers(deps) {
|
|
|
54253
54492
|
}
|
|
54254
54493
|
|
|
54255
54494
|
// src/handlers/attachment.ts
|
|
54256
|
-
var
|
|
54495
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
54257
54496
|
init_protocol();
|
|
54258
54497
|
init_protocol();
|
|
54259
54498
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -54333,12 +54572,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
54333
54572
|
`session ${args.sessionId} scope unresolved`
|
|
54334
54573
|
);
|
|
54335
54574
|
}
|
|
54336
|
-
const cwdAbs =
|
|
54337
|
-
const candidateAbs =
|
|
54575
|
+
const cwdAbs = import_node_path41.default.resolve(sessionFile.cwd);
|
|
54576
|
+
const candidateAbs = import_node_path41.default.isAbsolute(args.relPath) ? import_node_path41.default.resolve(args.relPath) : import_node_path41.default.resolve(cwdAbs, args.relPath);
|
|
54338
54577
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
|
|
54339
54578
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
54340
54579
|
const entry = entries.find((e) => {
|
|
54341
|
-
const storedAbs =
|
|
54580
|
+
const storedAbs = import_node_path41.default.isAbsolute(e.relPath) ? import_node_path41.default.resolve(e.relPath) : import_node_path41.default.resolve(cwdAbs, e.relPath);
|
|
54342
54581
|
return storedAbs === candidateAbs && !e.stale;
|
|
54343
54582
|
});
|
|
54344
54583
|
if (!entry) {
|
|
@@ -54363,7 +54602,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
54363
54602
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
54364
54603
|
const f = deps.sessionStore.read(sessionId);
|
|
54365
54604
|
if (!f) return;
|
|
54366
|
-
assertGuestAttachmentPath(ctx,
|
|
54605
|
+
assertGuestAttachmentPath(ctx, import_node_path41.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
54367
54606
|
}
|
|
54368
54607
|
const groupAdd = async (frame, _client, ctx) => {
|
|
54369
54608
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -54378,8 +54617,8 @@ function buildAttachmentHandlers(deps) {
|
|
|
54378
54617
|
if (!scope) {
|
|
54379
54618
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
|
|
54380
54619
|
}
|
|
54381
|
-
const cwdAbs =
|
|
54382
|
-
const candidateAbs =
|
|
54620
|
+
const cwdAbs = import_node_path41.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
|
|
54621
|
+
const candidateAbs = import_node_path41.default.isAbsolute(args.relPath) ? import_node_path41.default.resolve(args.relPath) : import_node_path41.default.resolve(cwdAbs, args.relPath);
|
|
54383
54622
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
|
|
54384
54623
|
const from = ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
54385
54624
|
const size = 0;
|
|
@@ -54438,19 +54677,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
54438
54677
|
|
|
54439
54678
|
// src/handlers/extension.ts
|
|
54440
54679
|
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
54441
|
-
var
|
|
54680
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
54442
54681
|
init_protocol();
|
|
54443
54682
|
|
|
54444
54683
|
// src/extension/bundle-zip.ts
|
|
54445
54684
|
var import_promises5 = __toESM(require("fs/promises"), 1);
|
|
54446
|
-
var
|
|
54685
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
54447
54686
|
var import_node_crypto13 = __toESM(require("crypto"), 1);
|
|
54448
54687
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
54449
54688
|
async function bundleExtensionDir(dir) {
|
|
54450
54689
|
const entries = await listFilesSorted(dir);
|
|
54451
54690
|
const zip = new import_jszip2.default();
|
|
54452
54691
|
for (const rel of entries) {
|
|
54453
|
-
const abs =
|
|
54692
|
+
const abs = import_node_path42.default.join(dir, rel);
|
|
54454
54693
|
const content = await import_promises5.default.readFile(abs);
|
|
54455
54694
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
54456
54695
|
}
|
|
@@ -54471,7 +54710,7 @@ async function listFilesSorted(rootDir) {
|
|
|
54471
54710
|
return out;
|
|
54472
54711
|
}
|
|
54473
54712
|
async function walk(absRoot, relPrefix, out) {
|
|
54474
|
-
const dirAbs =
|
|
54713
|
+
const dirAbs = import_node_path42.default.join(absRoot, relPrefix);
|
|
54475
54714
|
const entries = await import_promises5.default.readdir(dirAbs, { withFileTypes: true });
|
|
54476
54715
|
for (const e of entries) {
|
|
54477
54716
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -54525,25 +54764,25 @@ function computePublishCheck(args) {
|
|
|
54525
54764
|
|
|
54526
54765
|
// src/extension/install-flow.ts
|
|
54527
54766
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
54528
|
-
var
|
|
54529
|
-
var
|
|
54767
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
54768
|
+
var import_node_os19 = __toESM(require("os"), 1);
|
|
54530
54769
|
var import_node_crypto14 = __toESM(require("crypto"), 1);
|
|
54531
54770
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
54532
54771
|
|
|
54533
54772
|
// src/extension/paths.ts
|
|
54534
|
-
var
|
|
54535
|
-
var
|
|
54773
|
+
var import_node_os18 = __toESM(require("os"), 1);
|
|
54774
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
54536
54775
|
function clawdHomeRoot(override) {
|
|
54537
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
54776
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path43.default.join(import_node_os18.default.homedir(), ".clawd");
|
|
54538
54777
|
}
|
|
54539
54778
|
function extensionsRoot(override) {
|
|
54540
|
-
return
|
|
54779
|
+
return import_node_path43.default.join(clawdHomeRoot(override), "extensions");
|
|
54541
54780
|
}
|
|
54542
54781
|
function publishedChannelsFile(override) {
|
|
54543
|
-
return
|
|
54782
|
+
return import_node_path43.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
54544
54783
|
}
|
|
54545
54784
|
function bundleCacheRoot(override) {
|
|
54546
|
-
return
|
|
54785
|
+
return import_node_path43.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
54547
54786
|
}
|
|
54548
54787
|
|
|
54549
54788
|
// src/extension/install-flow.ts
|
|
@@ -54570,7 +54809,7 @@ async function installFromChannel(args, deps) {
|
|
|
54570
54809
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
54571
54810
|
}
|
|
54572
54811
|
for (const name of Object.keys(zip.files)) {
|
|
54573
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
54812
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path44.default.isAbsolute(name)) {
|
|
54574
54813
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
54575
54814
|
}
|
|
54576
54815
|
}
|
|
@@ -54602,7 +54841,7 @@ async function installFromChannel(args, deps) {
|
|
|
54602
54841
|
);
|
|
54603
54842
|
}
|
|
54604
54843
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
54605
|
-
const destDir =
|
|
54844
|
+
const destDir = import_node_path44.default.join(deps.extensionsRoot, localExtId);
|
|
54606
54845
|
let destExists = false;
|
|
54607
54846
|
try {
|
|
54608
54847
|
await import_promises6.default.access(destDir);
|
|
@@ -54616,16 +54855,16 @@ async function installFromChannel(args, deps) {
|
|
|
54616
54855
|
);
|
|
54617
54856
|
}
|
|
54618
54857
|
const stage = await import_promises6.default.mkdtemp(
|
|
54619
|
-
|
|
54858
|
+
import_node_path44.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
54620
54859
|
);
|
|
54621
54860
|
try {
|
|
54622
54861
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
54623
|
-
const dest =
|
|
54862
|
+
const dest = import_node_path44.default.join(stage, name);
|
|
54624
54863
|
if (entry.dir) {
|
|
54625
54864
|
await import_promises6.default.mkdir(dest, { recursive: true });
|
|
54626
54865
|
continue;
|
|
54627
54866
|
}
|
|
54628
|
-
await import_promises6.default.mkdir(
|
|
54867
|
+
await import_promises6.default.mkdir(import_node_path44.default.dirname(dest), { recursive: true });
|
|
54629
54868
|
if (name === "manifest.json") {
|
|
54630
54869
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
54631
54870
|
await import_promises6.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -54646,8 +54885,8 @@ async function installFromChannel(args, deps) {
|
|
|
54646
54885
|
|
|
54647
54886
|
// src/extension/update-flow.ts
|
|
54648
54887
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
54649
|
-
var
|
|
54650
|
-
var
|
|
54888
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
54889
|
+
var import_node_os20 = __toESM(require("os"), 1);
|
|
54651
54890
|
var import_node_crypto15 = __toESM(require("crypto"), 1);
|
|
54652
54891
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
54653
54892
|
var UpdateError = class extends Error {
|
|
@@ -54663,11 +54902,11 @@ async function updateFromChannel(args, deps) {
|
|
|
54663
54902
|
channelRef.extId,
|
|
54664
54903
|
channelRef.ownerPrincipalId
|
|
54665
54904
|
);
|
|
54666
|
-
const liveDir =
|
|
54905
|
+
const liveDir = import_node_path45.default.join(deps.extensionsRoot, localExtId);
|
|
54667
54906
|
const prevDir = `${liveDir}.prev`;
|
|
54668
54907
|
let existingVersion;
|
|
54669
54908
|
try {
|
|
54670
|
-
const raw = await import_promises7.default.readFile(
|
|
54909
|
+
const raw = await import_promises7.default.readFile(import_node_path45.default.join(liveDir, "manifest.json"), "utf8");
|
|
54671
54910
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
54672
54911
|
if (!parsed2.success) {
|
|
54673
54912
|
throw new UpdateError(
|
|
@@ -54700,7 +54939,7 @@ async function updateFromChannel(args, deps) {
|
|
|
54700
54939
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
54701
54940
|
}
|
|
54702
54941
|
for (const name of Object.keys(zip.files)) {
|
|
54703
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
54942
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path45.default.isAbsolute(name)) {
|
|
54704
54943
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
54705
54944
|
}
|
|
54706
54945
|
}
|
|
@@ -54735,16 +54974,16 @@ async function updateFromChannel(args, deps) {
|
|
|
54735
54974
|
await import_promises7.default.rm(prevDir, { recursive: true, force: true });
|
|
54736
54975
|
await import_promises7.default.rename(liveDir, prevDir);
|
|
54737
54976
|
const stage = await import_promises7.default.mkdtemp(
|
|
54738
|
-
|
|
54977
|
+
import_node_path45.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
54739
54978
|
);
|
|
54740
54979
|
try {
|
|
54741
54980
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
54742
|
-
const dest =
|
|
54981
|
+
const dest = import_node_path45.default.join(stage, name);
|
|
54743
54982
|
if (entry.dir) {
|
|
54744
54983
|
await import_promises7.default.mkdir(dest, { recursive: true });
|
|
54745
54984
|
continue;
|
|
54746
54985
|
}
|
|
54747
|
-
await import_promises7.default.mkdir(
|
|
54986
|
+
await import_promises7.default.mkdir(import_node_path45.default.dirname(dest), { recursive: true });
|
|
54748
54987
|
if (name === "manifest.json") {
|
|
54749
54988
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
54750
54989
|
await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -54837,7 +55076,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
54837
55076
|
);
|
|
54838
55077
|
}
|
|
54839
55078
|
}
|
|
54840
|
-
const manifestPath =
|
|
55079
|
+
const manifestPath = import_node_path46.default.join(root, extId, "manifest.json");
|
|
54841
55080
|
const manifest = await readManifest(root, extId);
|
|
54842
55081
|
const next = { ...manifest, version: newVersion };
|
|
54843
55082
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -54845,7 +55084,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
54845
55084
|
await import_promises8.default.rename(tmp, manifestPath);
|
|
54846
55085
|
}
|
|
54847
55086
|
async function readManifest(root, extId) {
|
|
54848
|
-
const file =
|
|
55087
|
+
const file = import_node_path46.default.join(root, extId, "manifest.json");
|
|
54849
55088
|
let raw;
|
|
54850
55089
|
try {
|
|
54851
55090
|
raw = await import_promises8.default.readFile(file, "utf8");
|
|
@@ -54936,7 +55175,7 @@ function buildExtensionHandlers(deps) {
|
|
|
54936
55175
|
};
|
|
54937
55176
|
async function buildSnapshotMeta(extId) {
|
|
54938
55177
|
const manifest = await readManifest(deps.root, extId);
|
|
54939
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
55178
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path46.default.join(deps.root, extId));
|
|
54940
55179
|
return { manifest, contentHash: sha256, buffer };
|
|
54941
55180
|
}
|
|
54942
55181
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -55119,7 +55358,7 @@ function buildExtensionHandlers(deps) {
|
|
|
55119
55358
|
// src/app-builder/project-store.ts
|
|
55120
55359
|
var import_node_fs39 = require("fs");
|
|
55121
55360
|
var import_node_child_process11 = require("child_process");
|
|
55122
|
-
var
|
|
55361
|
+
var import_node_path47 = require("path");
|
|
55123
55362
|
init_protocol();
|
|
55124
55363
|
var PROJECTS_DIR = "projects";
|
|
55125
55364
|
var META_FILE = ".clawd-project.json";
|
|
@@ -55133,14 +55372,14 @@ var ProjectStore = class {
|
|
|
55133
55372
|
root;
|
|
55134
55373
|
/** projects/<name>/.clawd-project.json 路径 */
|
|
55135
55374
|
metaPath(name) {
|
|
55136
|
-
return (0,
|
|
55375
|
+
return (0, import_node_path47.join)(this.projectsRoot(), name, META_FILE);
|
|
55137
55376
|
}
|
|
55138
55377
|
/** projects/<name>/ 目录路径(cwd 用) */
|
|
55139
55378
|
projectDir(name) {
|
|
55140
|
-
return (0,
|
|
55379
|
+
return (0, import_node_path47.join)(this.projectsRoot(), name);
|
|
55141
55380
|
}
|
|
55142
55381
|
projectsRoot() {
|
|
55143
|
-
return (0,
|
|
55382
|
+
return (0, import_node_path47.join)(this.root, PROJECTS_DIR);
|
|
55144
55383
|
}
|
|
55145
55384
|
async list() {
|
|
55146
55385
|
let entries;
|
|
@@ -55443,7 +55682,7 @@ var PublishJobRegistry = class {
|
|
|
55443
55682
|
// src/app-builder/publish-job-runner.ts
|
|
55444
55683
|
var import_node_child_process13 = require("child_process");
|
|
55445
55684
|
var import_node_fs40 = require("fs");
|
|
55446
|
-
var
|
|
55685
|
+
var import_node_path48 = require("path");
|
|
55447
55686
|
|
|
55448
55687
|
// src/app-builder/publish-stage-parser.ts
|
|
55449
55688
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -55475,7 +55714,7 @@ async function startPublishJob(deps, args) {
|
|
|
55475
55714
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
55476
55715
|
}
|
|
55477
55716
|
const projDir = projectDir(args.name);
|
|
55478
|
-
const logPath = (0,
|
|
55717
|
+
const logPath = (0, import_node_path48.join)(projDir, ".publish.log");
|
|
55479
55718
|
let logStream = null;
|
|
55480
55719
|
try {
|
|
55481
55720
|
logStream = (0, import_node_fs40.createWriteStream)(logPath, { flags: "w" });
|
|
@@ -55735,7 +55974,7 @@ async function recoverInterruptedJobs(deps) {
|
|
|
55735
55974
|
|
|
55736
55975
|
// src/handlers/app-builder.ts
|
|
55737
55976
|
init_protocol();
|
|
55738
|
-
var
|
|
55977
|
+
var import_node_path49 = require("path");
|
|
55739
55978
|
var import_node_fs41 = require("fs");
|
|
55740
55979
|
var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
|
|
55741
55980
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
@@ -55893,8 +56132,8 @@ function buildAppBuilderHandlers(deps) {
|
|
|
55893
56132
|
const project = await userStore.create(f.name, reservedPorts);
|
|
55894
56133
|
try {
|
|
55895
56134
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
|
|
55896
|
-
const templateSrcDir = (0,
|
|
55897
|
-
const scaffoldScript = (0,
|
|
56135
|
+
const templateSrcDir = (0, import_node_path49.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
|
|
56136
|
+
const scaffoldScript = (0, import_node_path49.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
|
|
55898
56137
|
const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
|
|
55899
56138
|
deps.logger?.info("app-builder.scaffold.done", {
|
|
55900
56139
|
name: project.name,
|
|
@@ -56115,7 +56354,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
56115
56354
|
await userStore.clearPublishJob(args.name);
|
|
56116
56355
|
}
|
|
56117
56356
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
|
|
56118
|
-
const scriptPath = (0,
|
|
56357
|
+
const scriptPath = (0, import_node_path49.join)(deps.deployKitRoot, "scripts", "publish.sh");
|
|
56119
56358
|
deps.logger?.info("app-builder.publish.start", {
|
|
56120
56359
|
name: args.name,
|
|
56121
56360
|
sessionId: boundSession.sessionId,
|
|
@@ -56284,7 +56523,7 @@ function buildVisitorHandlers(deps) {
|
|
|
56284
56523
|
|
|
56285
56524
|
// src/extension/registry.ts
|
|
56286
56525
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
56287
|
-
var
|
|
56526
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
56288
56527
|
async function loadAll(root) {
|
|
56289
56528
|
let entries;
|
|
56290
56529
|
try {
|
|
@@ -56297,13 +56536,13 @@ async function loadAll(root) {
|
|
|
56297
56536
|
for (const ent of entries) {
|
|
56298
56537
|
if (!ent.isDirectory()) continue;
|
|
56299
56538
|
if (ent.name.startsWith(".")) continue;
|
|
56300
|
-
records.push(await loadOne(
|
|
56539
|
+
records.push(await loadOne(import_node_path50.default.join(root, ent.name), ent.name));
|
|
56301
56540
|
}
|
|
56302
56541
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
56303
56542
|
return records;
|
|
56304
56543
|
}
|
|
56305
56544
|
async function loadOne(dir, dirName) {
|
|
56306
|
-
const manifestPath =
|
|
56545
|
+
const manifestPath = import_node_path50.default.join(dir, "manifest.json");
|
|
56307
56546
|
let raw;
|
|
56308
56547
|
try {
|
|
56309
56548
|
raw = await import_promises9.default.readFile(manifestPath, "utf8");
|
|
@@ -56348,7 +56587,7 @@ async function loadOne(dir, dirName) {
|
|
|
56348
56587
|
|
|
56349
56588
|
// src/extension/uninstall.ts
|
|
56350
56589
|
var import_promises10 = __toESM(require("fs/promises"), 1);
|
|
56351
|
-
var
|
|
56590
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
56352
56591
|
var UninstallError = class extends Error {
|
|
56353
56592
|
constructor(code, message) {
|
|
56354
56593
|
super(message);
|
|
@@ -56357,7 +56596,7 @@ var UninstallError = class extends Error {
|
|
|
56357
56596
|
code;
|
|
56358
56597
|
};
|
|
56359
56598
|
async function uninstall(deps) {
|
|
56360
|
-
const dir =
|
|
56599
|
+
const dir = import_node_path51.default.join(deps.root, deps.extId);
|
|
56361
56600
|
try {
|
|
56362
56601
|
await import_promises10.default.access(dir);
|
|
56363
56602
|
} catch {
|
|
@@ -56926,7 +57165,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
|
|
|
56926
57165
|
|
|
56927
57166
|
// src/extension/runtime.ts
|
|
56928
57167
|
var import_node_child_process15 = require("child_process");
|
|
56929
|
-
var
|
|
57168
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
56930
57169
|
var import_promises11 = require("timers/promises");
|
|
56931
57170
|
|
|
56932
57171
|
// src/extension/port-allocator.ts
|
|
@@ -57027,7 +57266,7 @@ var Runtime = class {
|
|
|
57027
57266
|
/\$CLAWOS_EXT_PORT/g,
|
|
57028
57267
|
String(port)
|
|
57029
57268
|
);
|
|
57030
|
-
const dir =
|
|
57269
|
+
const dir = import_node_path52.default.join(this.root, extId);
|
|
57031
57270
|
const env = {
|
|
57032
57271
|
...process.env,
|
|
57033
57272
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -57139,7 +57378,7 @@ ${handle.stderrTail}`
|
|
|
57139
57378
|
|
|
57140
57379
|
// src/extension/published-channels.ts
|
|
57141
57380
|
var import_promises12 = __toESM(require("fs/promises"), 1);
|
|
57142
|
-
var
|
|
57381
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
57143
57382
|
init_zod();
|
|
57144
57383
|
var PublishedChannelsError = class extends Error {
|
|
57145
57384
|
constructor(code, message) {
|
|
@@ -57238,7 +57477,7 @@ var PublishedChannelStore = class {
|
|
|
57238
57477
|
)
|
|
57239
57478
|
};
|
|
57240
57479
|
const tmp = `${this.filePath}.tmp`;
|
|
57241
|
-
await import_promises12.default.mkdir(
|
|
57480
|
+
await import_promises12.default.mkdir(import_node_path53.default.dirname(this.filePath), { recursive: true });
|
|
57242
57481
|
await import_promises12.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
57243
57482
|
await import_promises12.default.rename(tmp, this.filePath);
|
|
57244
57483
|
}
|
|
@@ -57246,7 +57485,7 @@ var PublishedChannelStore = class {
|
|
|
57246
57485
|
|
|
57247
57486
|
// src/extension/bundle-cache.ts
|
|
57248
57487
|
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
57249
|
-
var
|
|
57488
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
57250
57489
|
var BundleCache = class {
|
|
57251
57490
|
constructor(rootDir) {
|
|
57252
57491
|
this.rootDir = rootDir;
|
|
@@ -57255,14 +57494,14 @@ var BundleCache = class {
|
|
|
57255
57494
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
57256
57495
|
async write(snapshotHash, buffer) {
|
|
57257
57496
|
await import_promises13.default.mkdir(this.rootDir, { recursive: true });
|
|
57258
|
-
const file =
|
|
57497
|
+
const file = import_node_path54.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
57259
57498
|
const tmp = `${file}.tmp`;
|
|
57260
57499
|
await import_promises13.default.writeFile(tmp, buffer, { mode: 384 });
|
|
57261
57500
|
await import_promises13.default.rename(tmp, file);
|
|
57262
57501
|
}
|
|
57263
57502
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
57264
57503
|
async read(snapshotHash) {
|
|
57265
|
-
const file =
|
|
57504
|
+
const file = import_node_path54.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
57266
57505
|
try {
|
|
57267
57506
|
return await import_promises13.default.readFile(file);
|
|
57268
57507
|
} catch (e) {
|
|
@@ -57272,7 +57511,7 @@ var BundleCache = class {
|
|
|
57272
57511
|
}
|
|
57273
57512
|
/** Idempotent — missing file is not an error. */
|
|
57274
57513
|
async delete(snapshotHash) {
|
|
57275
|
-
const file =
|
|
57514
|
+
const file = import_node_path54.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
57276
57515
|
await import_promises13.default.rm(file, { force: true });
|
|
57277
57516
|
}
|
|
57278
57517
|
};
|
|
@@ -57293,11 +57532,11 @@ async function startDaemon(config) {
|
|
|
57293
57532
|
},
|
|
57294
57533
|
source: "daemon",
|
|
57295
57534
|
sampling: logShippingCfg.sampling,
|
|
57296
|
-
homeDir:
|
|
57535
|
+
homeDir: import_node_os21.default.homedir()
|
|
57297
57536
|
});
|
|
57298
57537
|
const logger = createLogger({
|
|
57299
57538
|
level: config.logLevel,
|
|
57300
|
-
file:
|
|
57539
|
+
file: import_node_path55.default.join(config.dataDir, "clawd.log"),
|
|
57301
57540
|
logClient
|
|
57302
57541
|
});
|
|
57303
57542
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
@@ -57437,8 +57676,8 @@ async function startDaemon(config) {
|
|
|
57437
57676
|
const agents = new AgentsScanner();
|
|
57438
57677
|
const history = new ClaudeHistoryReader();
|
|
57439
57678
|
let transport = null;
|
|
57440
|
-
const personaStore = new PersonaStore(
|
|
57441
|
-
const usersRoot =
|
|
57679
|
+
const personaStore = new PersonaStore(import_node_path55.default.join(config.dataDir, "personas"));
|
|
57680
|
+
const usersRoot = import_node_path55.default.join(config.dataDir, "users");
|
|
57442
57681
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
57443
57682
|
if (defaultsRoot) {
|
|
57444
57683
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -57458,17 +57697,17 @@ async function startDaemon(config) {
|
|
|
57458
57697
|
migrateCodexSandbox({ store: personaStore, logger });
|
|
57459
57698
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
57460
57699
|
const personaDispatchManager = new PersonaDispatchManager({ genId: () => v4_default() });
|
|
57461
|
-
const here = typeof __dirname === "string" ? __dirname :
|
|
57700
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path55.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
|
|
57462
57701
|
const dispatchServerCandidates = [
|
|
57463
|
-
|
|
57702
|
+
import_node_path55.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
57464
57703
|
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
57465
|
-
|
|
57704
|
+
import_node_path55.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
57466
57705
|
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
57467
57706
|
];
|
|
57468
57707
|
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs42.default.existsSync(p2));
|
|
57469
57708
|
let dispatchMcpConfigPath2;
|
|
57470
57709
|
if (dispatchServerScriptPath) {
|
|
57471
|
-
const dispatchLogPath =
|
|
57710
|
+
const dispatchLogPath = import_node_path55.default.join(config.dataDir, "dispatch-mcp-server.log");
|
|
57472
57711
|
dispatchMcpConfigPath2 = writeDispatchMcpConfig({
|
|
57473
57712
|
dataDir: config.dataDir,
|
|
57474
57713
|
serverScriptPath: dispatchServerScriptPath,
|
|
@@ -57485,15 +57724,15 @@ async function startDaemon(config) {
|
|
|
57485
57724
|
});
|
|
57486
57725
|
}
|
|
57487
57726
|
const ticketServerCandidates = [
|
|
57488
|
-
|
|
57489
|
-
|
|
57727
|
+
import_node_path55.default.join(here, "ticket", "mcp-server.cjs"),
|
|
57728
|
+
import_node_path55.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
57490
57729
|
];
|
|
57491
57730
|
const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs42.default.existsSync(p2));
|
|
57492
57731
|
const ticketOwnerUnionId = feishuIdentity?.identity.unionId ?? "";
|
|
57493
57732
|
const ticketOwnerName = feishuIdentity?.identity.displayName ?? "";
|
|
57494
57733
|
let ticketMcpConfigPath2;
|
|
57495
57734
|
if (ticketServerScriptPath && ticketOwnerUnionId) {
|
|
57496
|
-
const ticketLogPath =
|
|
57735
|
+
const ticketLogPath = import_node_path55.default.join(config.dataDir, "ticket-mcp-server.log");
|
|
57497
57736
|
ticketMcpConfigPath2 = writeTicketMcpConfig({
|
|
57498
57737
|
dataDir: config.dataDir,
|
|
57499
57738
|
serverScriptPath: ticketServerScriptPath,
|
|
@@ -57514,13 +57753,13 @@ async function startDaemon(config) {
|
|
|
57514
57753
|
});
|
|
57515
57754
|
}
|
|
57516
57755
|
const shiftServerCandidates = [
|
|
57517
|
-
|
|
57518
|
-
|
|
57756
|
+
import_node_path55.default.join(here, "shift", "mcp-server.cjs"),
|
|
57757
|
+
import_node_path55.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
|
|
57519
57758
|
];
|
|
57520
57759
|
const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs42.default.existsSync(p2));
|
|
57521
57760
|
let shiftMcpConfigPath2;
|
|
57522
57761
|
if (shiftServerScriptPath) {
|
|
57523
|
-
const shiftLogPath =
|
|
57762
|
+
const shiftLogPath = import_node_path55.default.join(config.dataDir, "shift-mcp-server.log");
|
|
57524
57763
|
shiftMcpConfigPath2 = await writeShiftMcpConfig({
|
|
57525
57764
|
dataDir: config.dataDir,
|
|
57526
57765
|
serverScriptPath: shiftServerScriptPath,
|
|
@@ -57538,13 +57777,13 @@ async function startDaemon(config) {
|
|
|
57538
57777
|
);
|
|
57539
57778
|
}
|
|
57540
57779
|
const inboxServerCandidates = [
|
|
57541
|
-
|
|
57542
|
-
|
|
57780
|
+
import_node_path55.default.join(here, "inbox", "mcp-server.cjs"),
|
|
57781
|
+
import_node_path55.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
|
|
57543
57782
|
];
|
|
57544
57783
|
const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs42.default.existsSync(p2));
|
|
57545
57784
|
let inboxMcpConfigPath2;
|
|
57546
57785
|
if (inboxServerScriptPath) {
|
|
57547
|
-
const inboxLogPath =
|
|
57786
|
+
const inboxLogPath = import_node_path55.default.join(config.dataDir, "inbox-mcp-server.log");
|
|
57548
57787
|
inboxMcpConfigPath2 = await writeInboxMcpConfig({
|
|
57549
57788
|
dataDir: config.dataDir,
|
|
57550
57789
|
serverScriptPath: inboxServerScriptPath,
|
|
@@ -57562,7 +57801,7 @@ async function startDaemon(config) {
|
|
|
57562
57801
|
);
|
|
57563
57802
|
}
|
|
57564
57803
|
const shiftStore = createShiftStore({
|
|
57565
|
-
filePath:
|
|
57804
|
+
filePath: import_node_path55.default.join(config.dataDir, "shift.json"),
|
|
57566
57805
|
ownerIdProvider: () => ownerPrincipalId,
|
|
57567
57806
|
now: () => Date.now()
|
|
57568
57807
|
});
|
|
@@ -57580,7 +57819,7 @@ async function startDaemon(config) {
|
|
|
57580
57819
|
getAdapter,
|
|
57581
57820
|
historyReader: history,
|
|
57582
57821
|
dataDir: config.dataDir,
|
|
57583
|
-
personaRoot:
|
|
57822
|
+
personaRoot: import_node_path55.default.join(config.dataDir, "personas"),
|
|
57584
57823
|
usersRoot,
|
|
57585
57824
|
personaStore,
|
|
57586
57825
|
ownerDisplayName,
|
|
@@ -57592,9 +57831,9 @@ async function startDaemon(config) {
|
|
|
57592
57831
|
// 127.0.0.1(不是 config.host)—— cc 跑在本机,loopback 最稳;外部访问限制 + http-router
|
|
57593
57832
|
// 的 isLoopback 兜底已确保安全。
|
|
57594
57833
|
getDaemonUrl: () => `http://127.0.0.1:${config.port}`,
|
|
57595
|
-
// Persona dispatch
|
|
57596
|
-
// - personaDispatchManager:
|
|
57597
|
-
//
|
|
57834
|
+
// Persona dispatch: manager 通过这两个 deps 跟 PersonaDispatchManager 协作。
|
|
57835
|
+
// - personaDispatchManager: createDispatchedSession / resumeDispatchedSession 用它
|
|
57836
|
+
// registerBSession;complete handler 用 findInflightDispatchByBSessionId 反查回 dispatchId。
|
|
57598
57837
|
// - dispatchMcpConfigPath: reducer 透传到 SpawnContext,cc spawn 加 --mcp-config flag。
|
|
57599
57838
|
personaDispatchManager,
|
|
57600
57839
|
dispatchMcpConfigPath: dispatchMcpConfigPath2,
|
|
@@ -57623,7 +57862,7 @@ async function startDaemon(config) {
|
|
|
57623
57862
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
57624
57863
|
attachmentGroup: {
|
|
57625
57864
|
onFileEdit: (input) => {
|
|
57626
|
-
const absPath =
|
|
57865
|
+
const absPath = import_node_path55.default.isAbsolute(input.relPath) ? input.relPath : import_node_path55.default.join(input.cwd, input.relPath);
|
|
57627
57866
|
let size = 0;
|
|
57628
57867
|
try {
|
|
57629
57868
|
size = import_node_fs42.default.statSync(absPath).size;
|
|
@@ -57824,11 +58063,11 @@ async function startDaemon(config) {
|
|
|
57824
58063
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
57825
58064
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
57826
58065
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
57827
|
-
personaRoot:
|
|
58066
|
+
personaRoot: import_node_path55.default.join(config.dataDir, "personas"),
|
|
57828
58067
|
usersRoot
|
|
57829
58068
|
},
|
|
57830
58069
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
57831
|
-
personaRoot:
|
|
58070
|
+
personaRoot: import_node_path55.default.join(config.dataDir, "personas"),
|
|
57832
58071
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
57833
58072
|
usersRoot,
|
|
57834
58073
|
// capability:list / delete handler 依赖
|
|
@@ -57937,11 +58176,11 @@ async function startDaemon(config) {
|
|
|
57937
58176
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
57938
58177
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
57939
58178
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
57940
|
-
appBuilderPersonaRoot:
|
|
58179
|
+
appBuilderPersonaRoot: import_node_path55.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
57941
58180
|
// 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
|
|
57942
|
-
deployKitRoot:
|
|
58181
|
+
deployKitRoot: import_node_path55.default.join(config.dataDir, "deploy-kit"),
|
|
57943
58182
|
// scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
|
|
57944
|
-
resolvePersonaRoot: (personaId) =>
|
|
58183
|
+
resolvePersonaRoot: (personaId) => import_node_path55.default.join(config.dataDir, "personas", personaId),
|
|
57945
58184
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
57946
58185
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
57947
58186
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -57976,7 +58215,8 @@ async function startDaemon(config) {
|
|
|
57976
58215
|
logger.info("dispatch.spawnB.start", {
|
|
57977
58216
|
dispatchId: args.dispatchId,
|
|
57978
58217
|
targetPersona: args.targetPersona,
|
|
57979
|
-
sourceSessionId: args.sourceSessionId
|
|
58218
|
+
sourceSessionId: args.sourceSessionId,
|
|
58219
|
+
route: args.route
|
|
57980
58220
|
});
|
|
57981
58221
|
const sourceFile = manager.findOwnedSession(args.sourceSessionId);
|
|
57982
58222
|
if (!sourceFile && !args.guestPrincipalId) {
|
|
@@ -57984,8 +58224,8 @@ async function startDaemon(config) {
|
|
|
57984
58224
|
}
|
|
57985
58225
|
let sourceJsonlPath = "(no transcript yet \u2014 operate from the task description alone)";
|
|
57986
58226
|
if (sourceFile && sourceFile.toolSessionId) {
|
|
57987
|
-
sourceJsonlPath =
|
|
57988
|
-
|
|
58227
|
+
sourceJsonlPath = import_node_path55.default.join(
|
|
58228
|
+
import_node_os21.default.homedir(),
|
|
57989
58229
|
".claude",
|
|
57990
58230
|
"projects",
|
|
57991
58231
|
cwdToHashDir(sourceFile.cwd),
|
|
@@ -57995,9 +58235,23 @@ async function startDaemon(config) {
|
|
|
57995
58235
|
logger.info("dispatch.spawnB.source-resolved", {
|
|
57996
58236
|
dispatchId: args.dispatchId,
|
|
57997
58237
|
sourceJsonlPath,
|
|
57998
|
-
hasToolSessionId: Boolean(sourceFile?.toolSessionId)
|
|
58238
|
+
hasToolSessionId: Boolean(sourceFile?.toolSessionId),
|
|
58239
|
+
route: args.route
|
|
57999
58240
|
});
|
|
58000
|
-
|
|
58241
|
+
if (args.route === "resume") {
|
|
58242
|
+
if (!args.bSessionId) {
|
|
58243
|
+
throw new Error("resume route requires bSessionId");
|
|
58244
|
+
}
|
|
58245
|
+
const { sessionId: sessionId2 } = manager.resumeDispatchedSession({
|
|
58246
|
+
dispatchId: args.dispatchId,
|
|
58247
|
+
bSessionId: args.bSessionId,
|
|
58248
|
+
prompt: args.prompt,
|
|
58249
|
+
sourceJsonlPath,
|
|
58250
|
+
callerIdentity: args.guestPrincipalId ? { kind: "guest", sourcePrincipalId: args.guestPrincipalId } : { kind: "local", sourceSessionId: args.sourceSessionId }
|
|
58251
|
+
});
|
|
58252
|
+
return { bSessionId: sessionId2 };
|
|
58253
|
+
}
|
|
58254
|
+
const { sessionId } = manager.createDispatchedSession({
|
|
58001
58255
|
dispatchId: args.dispatchId,
|
|
58002
58256
|
sourceSessionId: args.sourceSessionId,
|
|
58003
58257
|
targetPersona: args.targetPersona,
|
|
@@ -58007,24 +58261,30 @@ async function startDaemon(config) {
|
|
|
58007
58261
|
guestPrincipalId: args.guestPrincipalId,
|
|
58008
58262
|
guestDisplayName: args.guestDisplayName
|
|
58009
58263
|
});
|
|
58264
|
+
return { bSessionId: sessionId };
|
|
58010
58265
|
},
|
|
58011
58266
|
// A 角色:从 ContactStore 取 peer 可达 URL + connect token,转发到对端 daemon /rpc。
|
|
58012
|
-
forwardToPeer: async ({ targetDeviceId, targetPersona, prompt }) => {
|
|
58267
|
+
forwardToPeer: async ({ targetDeviceId, targetPersona, prompt, targetSessionId }) => {
|
|
58013
58268
|
const contact = contactStore.get(targetDeviceId);
|
|
58014
58269
|
if (!contact || !contact.remoteUrl || !contact.connectToken) {
|
|
58015
58270
|
return {
|
|
58016
|
-
|
|
58017
|
-
|
|
58271
|
+
outcome: {
|
|
58272
|
+
kind: "failure",
|
|
58273
|
+
reason: `unknown or unreachable contact: ${targetDeviceId}`
|
|
58274
|
+
}
|
|
58018
58275
|
};
|
|
58019
58276
|
}
|
|
58020
58277
|
return forwardDispatchToPeer({
|
|
58021
58278
|
contact: { remoteUrl: contact.remoteUrl, connectToken: contact.connectToken },
|
|
58022
58279
|
targetPersona,
|
|
58023
|
-
prompt
|
|
58280
|
+
prompt,
|
|
58281
|
+
targetSessionId
|
|
58024
58282
|
});
|
|
58025
58283
|
},
|
|
58026
58284
|
// B 角色:判断 targetPersona 是否 public(跨设备授权边界,private 拒)。
|
|
58027
|
-
getPersonaPublic: (personaId) => personaRegistry.get(personaId)?.public ?? false
|
|
58285
|
+
getPersonaPublic: (personaId) => personaRegistry.get(personaId)?.public ?? false,
|
|
58286
|
+
// targetSessionId 复用路径的权限校验数据源:读 B session 的 SessionFile。
|
|
58287
|
+
findOwnedSession: (sessionId) => manager.findOwnedSession(sessionId)
|
|
58028
58288
|
});
|
|
58029
58289
|
handlers = { ...handlers, ...dispatchHandlers };
|
|
58030
58290
|
const shiftHandlers = buildShiftInternalHandlers({
|
|
@@ -58284,8 +58544,8 @@ async function startDaemon(config) {
|
|
|
58284
58544
|
const lines = [
|
|
58285
58545
|
`Tunnel: ${r.url}`,
|
|
58286
58546
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
58287
|
-
`Frpc config: ${
|
|
58288
|
-
`Frpc log: ${
|
|
58547
|
+
`Frpc config: ${import_node_path55.default.join(config.dataDir, "frpc.toml")}`,
|
|
58548
|
+
`Frpc log: ${import_node_path55.default.join(config.dataDir, "frpc.log")}`
|
|
58289
58549
|
];
|
|
58290
58550
|
const width = Math.max(...lines.map((l) => l.length));
|
|
58291
58551
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -58298,7 +58558,7 @@ ${bar}
|
|
|
58298
58558
|
|
|
58299
58559
|
`);
|
|
58300
58560
|
try {
|
|
58301
|
-
const connectPath =
|
|
58561
|
+
const connectPath = import_node_path55.default.join(config.dataDir, "connect.txt");
|
|
58302
58562
|
import_node_fs42.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
58303
58563
|
} catch {
|
|
58304
58564
|
}
|
|
@@ -58371,7 +58631,7 @@ ${bar}
|
|
|
58371
58631
|
};
|
|
58372
58632
|
}
|
|
58373
58633
|
function migrateDropPersonsDir(dataDir) {
|
|
58374
|
-
const dir =
|
|
58634
|
+
const dir = import_node_path55.default.join(dataDir, "persons");
|
|
58375
58635
|
try {
|
|
58376
58636
|
import_node_fs42.default.rmSync(dir, { recursive: true, force: true });
|
|
58377
58637
|
} catch {
|