@clawos-dev/clawd 0.2.250 → 0.2.252
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 +747 -846
- package/dist/dispatch/mcp-server.cjs +99 -30
- package/dist/persona-defaults/persona-app-builder/CLAUDE.md +1 -1
- package/dist/persona-defaults/persona-builder/CLAUDE.md +6 -3
- package/dist/persona-defaults/persona-clawd-helper/CLAUDE.md +3 -3
- package/dist/persona-defaults/persona-feishu-assistant/CLAUDE.md +1 -1
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/guest-53QJqRhe.css +32 -0
- package/dist/share-ui/assets/{guest-BsIuA95-.js → guest-B7FHhw7e.js} +119 -119
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-k2RPEdy5.css +0 -32
package/dist/cli.cjs
CHANGED
|
@@ -148,12 +148,6 @@ var init_methods = __esm({
|
|
|
148
148
|
"attachment.groupAdd",
|
|
149
149
|
"attachment.groupRemove",
|
|
150
150
|
"attachment.groupList",
|
|
151
|
-
// ---- capability:* (capability platform 鉴权底座) ----
|
|
152
|
-
// 飞书统一身份 Phase 2 (2026-06-01, spec 决策 #12): personal token / 邀请码全链路删除——
|
|
153
|
-
// device:connect 已完整替代(中心 server 签发自包含 connect token)。capability:list / capability:delete
|
|
154
|
-
// 保留:调试 + whoami 反查 + 撤销级联 + 清旧 per-peer cap。personal-cap:get 已下线。
|
|
155
|
-
"capability:list",
|
|
156
|
-
"capability:delete",
|
|
157
151
|
// ---- inbox:* (capability platform Phase 3 跨用户通知 + Phase 4 DM) ----
|
|
158
152
|
// owner 接 guest 的 cross-principal 消息事件 + DM 双向私聊.
|
|
159
153
|
// inbox:list / markRead: admin-only (Phase 3); inbox:postMessage: DM 自带能力,
|
|
@@ -751,8 +745,8 @@ var init_parseUtil = __esm({
|
|
|
751
745
|
init_errors2();
|
|
752
746
|
init_en();
|
|
753
747
|
makeIssue = (params) => {
|
|
754
|
-
const { data, path:
|
|
755
|
-
const fullPath = [...
|
|
748
|
+
const { data, path: path74, errorMaps, issueData } = params;
|
|
749
|
+
const fullPath = [...path74, ...issueData.path || []];
|
|
756
750
|
const fullIssue = {
|
|
757
751
|
...issueData,
|
|
758
752
|
path: fullPath
|
|
@@ -1063,11 +1057,11 @@ var init_types = __esm({
|
|
|
1063
1057
|
init_parseUtil();
|
|
1064
1058
|
init_util();
|
|
1065
1059
|
ParseInputLazyPath = class {
|
|
1066
|
-
constructor(parent, value,
|
|
1060
|
+
constructor(parent, value, path74, key) {
|
|
1067
1061
|
this._cachedPath = [];
|
|
1068
1062
|
this.parent = parent;
|
|
1069
1063
|
this.data = value;
|
|
1070
|
-
this._path =
|
|
1064
|
+
this._path = path74;
|
|
1071
1065
|
this._key = key;
|
|
1072
1066
|
}
|
|
1073
1067
|
get path() {
|
|
@@ -5643,11 +5637,7 @@ var init_persona_mode = __esm({
|
|
|
5643
5637
|
});
|
|
5644
5638
|
|
|
5645
5639
|
// ../protocol/src/capability.ts
|
|
5646
|
-
|
|
5647
|
-
const { secretHash: _hash, ...wire } = cap;
|
|
5648
|
-
return wire;
|
|
5649
|
-
}
|
|
5650
|
-
var ResourceSchema, ActionSchema, GrantSchema, CapabilitySchema, CapabilityWireSchema, CapabilityErrorCodeSchema, WhoamiResponseSchema, PERSONAL_CAP_GRANTS;
|
|
5640
|
+
var ResourceSchema, ActionSchema, GrantSchema, CapabilitySchema, CapabilityWireSchema, WhoamiResponseSchema, PERSONAL_CAP_GRANTS;
|
|
5651
5641
|
var init_capability = __esm({
|
|
5652
5642
|
"../protocol/src/capability.ts"() {
|
|
5653
5643
|
"use strict";
|
|
@@ -5688,12 +5678,6 @@ var init_capability = __esm({
|
|
|
5688
5678
|
peerDisplayName: external_exports.string().optional()
|
|
5689
5679
|
}).strict();
|
|
5690
5680
|
CapabilityWireSchema = CapabilitySchema.omit({ secretHash: true });
|
|
5691
|
-
CapabilityErrorCodeSchema = external_exports.enum([
|
|
5692
|
-
"TOKEN_INVALID",
|
|
5693
|
-
"TOKEN_REVOKED",
|
|
5694
|
-
"TOKEN_EXPIRED",
|
|
5695
|
-
"TOKEN_EXHAUSTED"
|
|
5696
|
-
]);
|
|
5697
5681
|
WhoamiResponseSchema = external_exports.object({
|
|
5698
5682
|
type: external_exports.literal("whoami:ok"),
|
|
5699
5683
|
owner: external_exports.object({
|
|
@@ -6099,9 +6083,6 @@ var init_feishu_auth = __esm({
|
|
|
6099
6083
|
"use strict";
|
|
6100
6084
|
init_zod();
|
|
6101
6085
|
FEISHU_GATED_METHODS = [
|
|
6102
|
-
// capability(调试 / 撤销,仍属远程身份体系)
|
|
6103
|
-
"capability:list",
|
|
6104
|
-
"capability:delete",
|
|
6105
6086
|
// 联系人列表(device:connect 落同一 store;list 读 / remove 删)
|
|
6106
6087
|
"contact:list",
|
|
6107
6088
|
"contact:remove",
|
|
@@ -6615,8 +6596,8 @@ var require_req = __commonJS({
|
|
|
6615
6596
|
if (req.originalUrl) {
|
|
6616
6597
|
_req.url = req.originalUrl;
|
|
6617
6598
|
} else {
|
|
6618
|
-
const
|
|
6619
|
-
_req.url = typeof
|
|
6599
|
+
const path74 = req.path;
|
|
6600
|
+
_req.url = typeof path74 === "string" ? path74 : req.url ? req.url.path || req.url : void 0;
|
|
6620
6601
|
}
|
|
6621
6602
|
if (req.query) {
|
|
6622
6603
|
_req.query = req.query;
|
|
@@ -6781,14 +6762,14 @@ var require_redact = __commonJS({
|
|
|
6781
6762
|
}
|
|
6782
6763
|
return obj;
|
|
6783
6764
|
}
|
|
6784
|
-
function parsePath(
|
|
6765
|
+
function parsePath(path74) {
|
|
6785
6766
|
const parts = [];
|
|
6786
6767
|
let current = "";
|
|
6787
6768
|
let inBrackets = false;
|
|
6788
6769
|
let inQuotes = false;
|
|
6789
6770
|
let quoteChar = "";
|
|
6790
|
-
for (let i = 0; i <
|
|
6791
|
-
const char =
|
|
6771
|
+
for (let i = 0; i < path74.length; i++) {
|
|
6772
|
+
const char = path74[i];
|
|
6792
6773
|
if (!inBrackets && char === ".") {
|
|
6793
6774
|
if (current) {
|
|
6794
6775
|
parts.push(current);
|
|
@@ -6919,10 +6900,10 @@ var require_redact = __commonJS({
|
|
|
6919
6900
|
return current;
|
|
6920
6901
|
}
|
|
6921
6902
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
6922
|
-
for (const
|
|
6923
|
-
const parts = parsePath(
|
|
6903
|
+
for (const path74 of paths) {
|
|
6904
|
+
const parts = parsePath(path74);
|
|
6924
6905
|
if (parts.includes("*")) {
|
|
6925
|
-
redactWildcardPath(obj, parts, censor,
|
|
6906
|
+
redactWildcardPath(obj, parts, censor, path74, remove);
|
|
6926
6907
|
} else {
|
|
6927
6908
|
if (remove) {
|
|
6928
6909
|
removeKey(obj, parts);
|
|
@@ -7007,8 +6988,8 @@ var require_redact = __commonJS({
|
|
|
7007
6988
|
}
|
|
7008
6989
|
} else {
|
|
7009
6990
|
if (afterWildcard.includes("*")) {
|
|
7010
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
7011
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
6991
|
+
const wrappedCensor = typeof censor === "function" ? (value, path74) => {
|
|
6992
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path74];
|
|
7012
6993
|
return censor(value, fullPath);
|
|
7013
6994
|
} : censor;
|
|
7014
6995
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -7043,8 +7024,8 @@ var require_redact = __commonJS({
|
|
|
7043
7024
|
return null;
|
|
7044
7025
|
}
|
|
7045
7026
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
7046
|
-
for (const
|
|
7047
|
-
const parts = parsePath(
|
|
7027
|
+
for (const path74 of pathsToClone) {
|
|
7028
|
+
const parts = parsePath(path74);
|
|
7048
7029
|
let current = pathStructure;
|
|
7049
7030
|
for (let i = 0; i < parts.length; i++) {
|
|
7050
7031
|
const part = parts[i];
|
|
@@ -7096,24 +7077,24 @@ var require_redact = __commonJS({
|
|
|
7096
7077
|
}
|
|
7097
7078
|
return cloneSelectively(obj, pathStructure);
|
|
7098
7079
|
}
|
|
7099
|
-
function validatePath(
|
|
7100
|
-
if (typeof
|
|
7080
|
+
function validatePath(path74) {
|
|
7081
|
+
if (typeof path74 !== "string") {
|
|
7101
7082
|
throw new Error("Paths must be (non-empty) strings");
|
|
7102
7083
|
}
|
|
7103
|
-
if (
|
|
7084
|
+
if (path74 === "") {
|
|
7104
7085
|
throw new Error("Invalid redaction path ()");
|
|
7105
7086
|
}
|
|
7106
|
-
if (
|
|
7107
|
-
throw new Error(`Invalid redaction path (${
|
|
7087
|
+
if (path74.includes("..")) {
|
|
7088
|
+
throw new Error(`Invalid redaction path (${path74})`);
|
|
7108
7089
|
}
|
|
7109
|
-
if (
|
|
7110
|
-
throw new Error(`Invalid redaction path (${
|
|
7090
|
+
if (path74.includes(",")) {
|
|
7091
|
+
throw new Error(`Invalid redaction path (${path74})`);
|
|
7111
7092
|
}
|
|
7112
7093
|
let bracketCount = 0;
|
|
7113
7094
|
let inQuotes = false;
|
|
7114
7095
|
let quoteChar = "";
|
|
7115
|
-
for (let i = 0; i <
|
|
7116
|
-
const char =
|
|
7096
|
+
for (let i = 0; i < path74.length; i++) {
|
|
7097
|
+
const char = path74[i];
|
|
7117
7098
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
7118
7099
|
if (!inQuotes) {
|
|
7119
7100
|
inQuotes = true;
|
|
@@ -7127,20 +7108,20 @@ var require_redact = __commonJS({
|
|
|
7127
7108
|
} else if (char === "]" && !inQuotes) {
|
|
7128
7109
|
bracketCount--;
|
|
7129
7110
|
if (bracketCount < 0) {
|
|
7130
|
-
throw new Error(`Invalid redaction path (${
|
|
7111
|
+
throw new Error(`Invalid redaction path (${path74})`);
|
|
7131
7112
|
}
|
|
7132
7113
|
}
|
|
7133
7114
|
}
|
|
7134
7115
|
if (bracketCount !== 0) {
|
|
7135
|
-
throw new Error(`Invalid redaction path (${
|
|
7116
|
+
throw new Error(`Invalid redaction path (${path74})`);
|
|
7136
7117
|
}
|
|
7137
7118
|
}
|
|
7138
7119
|
function validatePaths(paths) {
|
|
7139
7120
|
if (!Array.isArray(paths)) {
|
|
7140
7121
|
throw new TypeError("paths must be an array");
|
|
7141
7122
|
}
|
|
7142
|
-
for (const
|
|
7143
|
-
validatePath(
|
|
7123
|
+
for (const path74 of paths) {
|
|
7124
|
+
validatePath(path74);
|
|
7144
7125
|
}
|
|
7145
7126
|
}
|
|
7146
7127
|
function slowRedact(options = {}) {
|
|
@@ -7308,8 +7289,8 @@ var require_redaction = __commonJS({
|
|
|
7308
7289
|
if (shape[k2] === null) {
|
|
7309
7290
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
7310
7291
|
} else {
|
|
7311
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
7312
|
-
return censor(value, [k2, ...
|
|
7292
|
+
const wrappedCensor = typeof censor === "function" ? (value, path74) => {
|
|
7293
|
+
return censor(value, [k2, ...path74]);
|
|
7313
7294
|
} : censor;
|
|
7314
7295
|
o[k2] = Redact({
|
|
7315
7296
|
paths: shape[k2],
|
|
@@ -7530,7 +7511,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7530
7511
|
var fs65 = require("fs");
|
|
7531
7512
|
var EventEmitter3 = require("events");
|
|
7532
7513
|
var inherits = require("util").inherits;
|
|
7533
|
-
var
|
|
7514
|
+
var path74 = require("path");
|
|
7534
7515
|
var sleep2 = require_atomic_sleep();
|
|
7535
7516
|
var assert = require("assert");
|
|
7536
7517
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -7584,7 +7565,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7584
7565
|
const mode = sonic.mode;
|
|
7585
7566
|
if (sonic.sync) {
|
|
7586
7567
|
try {
|
|
7587
|
-
if (sonic.mkdir) fs65.mkdirSync(
|
|
7568
|
+
if (sonic.mkdir) fs65.mkdirSync(path74.dirname(file), { recursive: true });
|
|
7588
7569
|
const fd = fs65.openSync(file, flags, mode);
|
|
7589
7570
|
fileOpened(null, fd);
|
|
7590
7571
|
} catch (err) {
|
|
@@ -7592,7 +7573,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7592
7573
|
throw err;
|
|
7593
7574
|
}
|
|
7594
7575
|
} else if (sonic.mkdir) {
|
|
7595
|
-
fs65.mkdir(
|
|
7576
|
+
fs65.mkdir(path74.dirname(file), { recursive: true }, (err) => {
|
|
7596
7577
|
if (err) return fileOpened(err);
|
|
7597
7578
|
fs65.open(file, flags, mode, fileOpened);
|
|
7598
7579
|
});
|
|
@@ -11223,11 +11204,11 @@ var init_lib = __esm({
|
|
|
11223
11204
|
}
|
|
11224
11205
|
}
|
|
11225
11206
|
},
|
|
11226
|
-
addToPath: function addToPath(
|
|
11227
|
-
var last =
|
|
11207
|
+
addToPath: function addToPath(path74, added, removed, oldPosInc, options) {
|
|
11208
|
+
var last = path74.lastComponent;
|
|
11228
11209
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
11229
11210
|
return {
|
|
11230
|
-
oldPos:
|
|
11211
|
+
oldPos: path74.oldPos + oldPosInc,
|
|
11231
11212
|
lastComponent: {
|
|
11232
11213
|
count: last.count + 1,
|
|
11233
11214
|
added,
|
|
@@ -11237,7 +11218,7 @@ var init_lib = __esm({
|
|
|
11237
11218
|
};
|
|
11238
11219
|
} else {
|
|
11239
11220
|
return {
|
|
11240
|
-
oldPos:
|
|
11221
|
+
oldPos: path74.oldPos + oldPosInc,
|
|
11241
11222
|
lastComponent: {
|
|
11242
11223
|
count: 1,
|
|
11243
11224
|
added,
|
|
@@ -11746,10 +11727,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
11746
11727
|
const memories = raw.map((m2) => {
|
|
11747
11728
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11748
11729
|
const rec3 = m2;
|
|
11749
|
-
const
|
|
11730
|
+
const path74 = typeof rec3.path === "string" ? rec3.path : null;
|
|
11750
11731
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
11751
|
-
if (!
|
|
11752
|
-
const entry = { path:
|
|
11732
|
+
if (!path74 || content == null) return null;
|
|
11733
|
+
const entry = { path: path74, content };
|
|
11753
11734
|
if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
|
|
11754
11735
|
return entry;
|
|
11755
11736
|
}).filter((m2) => m2 !== null);
|
|
@@ -12552,10 +12533,10 @@ function parseAttachment(obj) {
|
|
|
12552
12533
|
const memories = raw.map((m2) => {
|
|
12553
12534
|
if (!m2 || typeof m2 !== "object") return null;
|
|
12554
12535
|
const rec3 = m2;
|
|
12555
|
-
const
|
|
12536
|
+
const path74 = typeof rec3.path === "string" ? rec3.path : null;
|
|
12556
12537
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
12557
|
-
if (!
|
|
12558
|
-
const out = { path:
|
|
12538
|
+
if (!path74 || content == null) return null;
|
|
12539
|
+
const out = { path: path74, content };
|
|
12559
12540
|
if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
|
|
12560
12541
|
return out;
|
|
12561
12542
|
}).filter((m2) => m2 !== null);
|
|
@@ -26932,8 +26913,8 @@ var require_CronFileParser = __commonJS({
|
|
|
26932
26913
|
* @throws If file cannot be read
|
|
26933
26914
|
*/
|
|
26934
26915
|
static parseFileSync(filePath) {
|
|
26935
|
-
const { readFileSync:
|
|
26936
|
-
const data =
|
|
26916
|
+
const { readFileSync: readFileSync6 } = require("fs");
|
|
26917
|
+
const data = readFileSync6(filePath, "utf8");
|
|
26937
26918
|
return _CronFileParser.#parseContent(data);
|
|
26938
26919
|
}
|
|
26939
26920
|
/**
|
|
@@ -29234,7 +29215,7 @@ var require_websocket = __commonJS({
|
|
|
29234
29215
|
var http3 = require("http");
|
|
29235
29216
|
var net3 = require("net");
|
|
29236
29217
|
var tls = require("tls");
|
|
29237
|
-
var { randomBytes, createHash:
|
|
29218
|
+
var { randomBytes, createHash: createHash2 } = require("crypto");
|
|
29238
29219
|
var { Duplex, Readable: Readable3 } = require("stream");
|
|
29239
29220
|
var { URL: URL2 } = require("url");
|
|
29240
29221
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -29894,7 +29875,7 @@ var require_websocket = __commonJS({
|
|
|
29894
29875
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
29895
29876
|
return;
|
|
29896
29877
|
}
|
|
29897
|
-
const digest =
|
|
29878
|
+
const digest = createHash2("sha1").update(key + GUID).digest("base64");
|
|
29898
29879
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
29899
29880
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
29900
29881
|
return;
|
|
@@ -30261,7 +30242,7 @@ var require_websocket_server = __commonJS({
|
|
|
30261
30242
|
var EventEmitter3 = require("events");
|
|
30262
30243
|
var http3 = require("http");
|
|
30263
30244
|
var { Duplex } = require("stream");
|
|
30264
|
-
var { createHash:
|
|
30245
|
+
var { createHash: createHash2 } = require("crypto");
|
|
30265
30246
|
var extension2 = require_extension();
|
|
30266
30247
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
30267
30248
|
var subprotocol2 = require_subprotocol();
|
|
@@ -30562,7 +30543,7 @@ var require_websocket_server = __commonJS({
|
|
|
30562
30543
|
);
|
|
30563
30544
|
}
|
|
30564
30545
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
30565
|
-
const digest =
|
|
30546
|
+
const digest = createHash2("sha1").update(key + GUID).digest("base64");
|
|
30566
30547
|
const headers = [
|
|
30567
30548
|
"HTTP/1.1 101 Switching Protocols",
|
|
30568
30549
|
"Upgrade: websocket",
|
|
@@ -33524,8 +33505,8 @@ var require_utils = __commonJS({
|
|
|
33524
33505
|
var result = transform[inputType][outputType](input);
|
|
33525
33506
|
return result;
|
|
33526
33507
|
};
|
|
33527
|
-
exports2.resolve = function(
|
|
33528
|
-
var parts =
|
|
33508
|
+
exports2.resolve = function(path74) {
|
|
33509
|
+
var parts = path74.split("/");
|
|
33529
33510
|
var result = [];
|
|
33530
33511
|
for (var index = 0; index < parts.length; index++) {
|
|
33531
33512
|
var part = parts[index];
|
|
@@ -39378,18 +39359,18 @@ var require_object = __commonJS({
|
|
|
39378
39359
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
39379
39360
|
this.files[name] = object;
|
|
39380
39361
|
};
|
|
39381
|
-
var parentFolder = function(
|
|
39382
|
-
if (
|
|
39383
|
-
|
|
39362
|
+
var parentFolder = function(path74) {
|
|
39363
|
+
if (path74.slice(-1) === "/") {
|
|
39364
|
+
path74 = path74.substring(0, path74.length - 1);
|
|
39384
39365
|
}
|
|
39385
|
-
var lastSlash =
|
|
39386
|
-
return lastSlash > 0 ?
|
|
39366
|
+
var lastSlash = path74.lastIndexOf("/");
|
|
39367
|
+
return lastSlash > 0 ? path74.substring(0, lastSlash) : "";
|
|
39387
39368
|
};
|
|
39388
|
-
var forceTrailingSlash = function(
|
|
39389
|
-
if (
|
|
39390
|
-
|
|
39369
|
+
var forceTrailingSlash = function(path74) {
|
|
39370
|
+
if (path74.slice(-1) !== "/") {
|
|
39371
|
+
path74 += "/";
|
|
39391
39372
|
}
|
|
39392
|
-
return
|
|
39373
|
+
return path74;
|
|
39393
39374
|
};
|
|
39394
39375
|
var folderAdd = function(name, createFolders) {
|
|
39395
39376
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -40391,7 +40372,7 @@ var require_lib3 = __commonJS({
|
|
|
40391
40372
|
// src/run-case/recorder.ts
|
|
40392
40373
|
function startRunCaseRecorder(opts) {
|
|
40393
40374
|
const now = opts.now ?? Date.now;
|
|
40394
|
-
const dir =
|
|
40375
|
+
const dir = import_node_path62.default.dirname(opts.recordPath);
|
|
40395
40376
|
let stream = null;
|
|
40396
40377
|
let closing = false;
|
|
40397
40378
|
let closedSettled = false;
|
|
@@ -40405,8 +40386,8 @@ function startRunCaseRecorder(opts) {
|
|
|
40405
40386
|
});
|
|
40406
40387
|
const ensureStream = () => {
|
|
40407
40388
|
if (stream) return stream;
|
|
40408
|
-
|
|
40409
|
-
stream =
|
|
40389
|
+
import_node_fs47.default.mkdirSync(dir, { recursive: true });
|
|
40390
|
+
stream = import_node_fs47.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
40410
40391
|
stream.on("close", () => closedResolve());
|
|
40411
40392
|
return stream;
|
|
40412
40393
|
};
|
|
@@ -40431,12 +40412,12 @@ function startRunCaseRecorder(opts) {
|
|
|
40431
40412
|
};
|
|
40432
40413
|
return { tap, close, closed };
|
|
40433
40414
|
}
|
|
40434
|
-
var
|
|
40415
|
+
var import_node_fs47, import_node_path62;
|
|
40435
40416
|
var init_recorder = __esm({
|
|
40436
40417
|
"src/run-case/recorder.ts"() {
|
|
40437
40418
|
"use strict";
|
|
40438
|
-
|
|
40439
|
-
|
|
40419
|
+
import_node_fs47 = __toESM(require("fs"), 1);
|
|
40420
|
+
import_node_path62 = __toESM(require("path"), 1);
|
|
40440
40421
|
}
|
|
40441
40422
|
});
|
|
40442
40423
|
|
|
@@ -40479,7 +40460,7 @@ var init_wire = __esm({
|
|
|
40479
40460
|
// src/run-case/controller.ts
|
|
40480
40461
|
async function runController(opts) {
|
|
40481
40462
|
const now = opts.now ?? Date.now;
|
|
40482
|
-
const cwd = opts.cwd ?? (0,
|
|
40463
|
+
const cwd = opts.cwd ?? (0, import_node_fs48.mkdtempSync)(import_node_path63.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
|
|
40483
40464
|
const ownsCwd = opts.cwd === void 0;
|
|
40484
40465
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
40485
40466
|
const spawnCtx = { cwd };
|
|
@@ -40640,19 +40621,19 @@ async function runController(opts) {
|
|
|
40640
40621
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
40641
40622
|
if (ownsCwd) {
|
|
40642
40623
|
try {
|
|
40643
|
-
(0,
|
|
40624
|
+
(0, import_node_fs48.rmSync)(cwd, { recursive: true, force: true });
|
|
40644
40625
|
} catch {
|
|
40645
40626
|
}
|
|
40646
40627
|
}
|
|
40647
40628
|
return exitCode ?? 0;
|
|
40648
40629
|
}
|
|
40649
|
-
var
|
|
40630
|
+
var import_node_fs48, import_node_os23, import_node_path63;
|
|
40650
40631
|
var init_controller = __esm({
|
|
40651
40632
|
"src/run-case/controller.ts"() {
|
|
40652
40633
|
"use strict";
|
|
40653
|
-
|
|
40634
|
+
import_node_fs48 = require("fs");
|
|
40654
40635
|
import_node_os23 = __toESM(require("os"), 1);
|
|
40655
|
-
|
|
40636
|
+
import_node_path63 = __toESM(require("path"), 1);
|
|
40656
40637
|
init_claude();
|
|
40657
40638
|
init_stdout_splitter();
|
|
40658
40639
|
init_permission_stdio();
|
|
@@ -40914,8 +40895,8 @@ Env (advanced):
|
|
|
40914
40895
|
`;
|
|
40915
40896
|
|
|
40916
40897
|
// src/index.ts
|
|
40917
|
-
var
|
|
40918
|
-
var
|
|
40898
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
40899
|
+
var import_node_fs46 = __toESM(require("fs"), 1);
|
|
40919
40900
|
var import_node_os22 = __toESM(require("os"), 1);
|
|
40920
40901
|
|
|
40921
40902
|
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
@@ -41918,17 +41899,17 @@ var ATTACHMENT_SHARING_HINT = `## \u628A\u4EA7\u51FA\u6587\u4EF6\u5206\u4EAB\u7E
|
|
|
41918
41899
|
|
|
41919
41900
|
- \`relPath\` \u5FC5\u987B\u4F20**\u7EDD\u5BF9\u8DEF\u5F84**\uFF08\u4F60\u4EA7\u51FA\u6587\u4EF6\u7684\u771F\u5B9E\u8DEF\u5F84\uFF09\uFF0C\u4E0D\u8981\u4F20\u76F8\u5BF9\u8DEF\u5F84\u3002
|
|
41920
41901
|
- \u53EA\u80FD\u5206\u4EAB\u4F60\u81EA\u5DF1\u5DE5\u4F5C\u76EE\u5F55\u5185\u7684\u6587\u4EF6\uFF0C\u8D8A\u754C\u4F1A\u88AB\u62D2\u3002
|
|
41921
|
-
- \u88AB dispatch \u63A5\u5230\u4EFB\u52A1\u3001\u8981\u56DE\u4F20\u4EA7\u7269\u65F6\uFF1A\u628A\u7B7E\u540D URL \u5199\u8FDB \`personaDispatchComplete\` \u7684 \`text\` \u91CC\uFF08\`filePaths\` \u53EA\u662F\u4F60\u672C\u673A\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u8DE8\u8BBE\u5907\u5BF9\u65B9\u6253\u4E0D\u5F00\uFF0CURL \u624D\u80FD\u6253\u5F00\uFF09\u3002`;
|
|
41902
|
+
- \u88AB dispatch \u63A5\u5230\u4EFB\u52A1\u3001\u8981\u56DE\u4F20\u4EA7\u7269\u65F6\uFF1A\u628A\u7B7E\u540D URL \u5199\u8FDB \`personaDispatchComplete\` tool\uFF08\`clawd-dispatch\` MCP\uFF09\u7684 \`text\` \u91CC\uFF08\`filePaths\` \u53EA\u662F\u4F60\u672C\u673A\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u8DE8\u8BBE\u5907\u5BF9\u65B9\u6253\u4E0D\u5F00\uFF0CURL \u624D\u80FD\u6253\u5F00\uFF09\u3002`;
|
|
41922
41903
|
|
|
41923
41904
|
// src/dispatch/system-prompt.ts
|
|
41924
41905
|
var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A persona\uFF08dispatch\uFF09
|
|
41925
41906
|
|
|
41926
|
-
\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
|
|
41907
|
+
\u5F53\u7528\u6237\u6D88\u606F\u91CC\u542B \`@persona/<id>\`\uFF08\u5982 \`@persona/persona-app-builder\`\uFF09\u65F6\uFF0C**\u4F60\u5FC5\u987B**\u7ACB\u5373\u8C03 \`clawd-dispatch\` MCP server \u7684 \`personaDispatch\` tool \u59D4\u6D3E\uFF08\u5404 agent \u5BF9 MCP tool \u7684\u5C55\u793A\u540D\u4E0D\u540C\uFF0C\u5982 claude \u663E\u793A\u4E3A \`mcp__clawd-dispatch__personaDispatch\`\uFF1B\u6309\u4F60\u73AF\u5883\u91CC\u5B9E\u9645\u5217\u51FA\u7684\u540D\u5B57\u8C03\u7528\uFF09\uFF0C\u4E0D\u8981\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF1A
|
|
41927
41908
|
|
|
41928
41909
|
- \`targetPersona = <id>\`\uFF08@ token \u91CC\u7684 persona id\uFF09
|
|
41929
41910
|
- \`prompt = \u53BB\u6389 @persona/<id> token \u7684\u7528\u6237\u539F\u6587\`
|
|
41930
41911
|
|
|
41931
|
-
tool \u4F1A**\u7ACB\u5373\u8FD4\u56DE** dispatchId\uFF08\u5F02\u6B65\u59D4\u6D3E\uFF09\uFF0C\u5BF9\u65B9\u4EBA\u683C\u5728\u540E\u53F0\u5E72\u6D3B\u3002\u4F60\u544A\u8BC9\u7528\u6237"\u4EFB\u52A1\u5DF2\u4EA4\u529E"\u5373\u53EF\u7ED3\u675F\u672C\u8F6E\u2014\u2014**\u4E0D\u8981\u7B49\u5F85\u3001\u4E0D\u8981\u8F6E\u8BE2**\u3002\u5BF9\u65B9\u5E72\u5B8C\u540E\uFF0C\u7ED3\u679C\u4F1A\u4F5C\u4E3A\u4E00\u6761\u65B0\u6D88\u606F\u81EA\u52A8\u6CE8\u5165\u56DE\u4F60\u7684 session\uFF0C\u4F60\u5C4A\u65F6\u518D\u7EFC\u5408\u8F6C\u8FBE\u7ED9\u7528\u6237\u3002\u60F3\u67E5\u8FDB\u5C55\u65F6\uFF08\u7528\u6237\u95EE\u8D77\uFF09\u8C03 \`
|
|
41912
|
+
tool \u4F1A**\u7ACB\u5373\u8FD4\u56DE** dispatchId\uFF08\u5F02\u6B65\u59D4\u6D3E\uFF09\uFF0C\u5BF9\u65B9\u4EBA\u683C\u5728\u540E\u53F0\u5E72\u6D3B\u3002\u4F60\u544A\u8BC9\u7528\u6237"\u4EFB\u52A1\u5DF2\u4EA4\u529E"\u5373\u53EF\u7ED3\u675F\u672C\u8F6E\u2014\u2014**\u4E0D\u8981\u7B49\u5F85\u3001\u4E0D\u8981\u8F6E\u8BE2**\u3002\u5BF9\u65B9\u5E72\u5B8C\u540E\uFF0C\u7ED3\u679C\u4F1A\u4F5C\u4E3A\u4E00\u6761\u65B0\u6D88\u606F\u81EA\u52A8\u6CE8\u5165\u56DE\u4F60\u7684 session\uFF0C\u4F60\u5C4A\u65F6\u518D\u7EFC\u5408\u8F6C\u8FBE\u7ED9\u7528\u6237\u3002\u60F3\u67E5\u8FDB\u5C55\u65F6\uFF08\u7528\u6237\u95EE\u8D77\uFF09\u8C03\u540C\u4E00 MCP \u7684 \`personaDispatchList\`\u3002
|
|
41932
41913
|
|
|
41933
41914
|
- **\u4E0D\u8981**\u5C1D\u8BD5\u81EA\u5DF1\u6267\u884C\uFF08\u4F60\u4E0D\u662F\u90A3\u4E2A persona\uFF09
|
|
41934
41915
|
- **\u4E0D\u8981** in-place \u6A21\u4EFF\u5BF9\u65B9\u4EBA\u683C \u2014\u2014 dispatch \u662F\u771F\u5207\u5230\u53E6\u4E00\u4E2A\u72EC\u7ACB session
|
|
@@ -41953,7 +41934,7 @@ deviceId \u76F4\u63A5\u53D6\u81EA token\uFF0C\u4E0D\u8981\u6539\u5199\u6216\u731
|
|
|
41953
41934
|
|
|
41954
41935
|
- \u4EFB\u52A1\u5728 \`Task:\` \u6BB5
|
|
41955
41936
|
- \u539F\u4F1A\u8BDD\u7684\u5BF9\u8BDD\u5386\u53F2\u5728 \`Source conversation\` \u6BB5\u7ED9\u7684 jsonl \u8DEF\u5F84\u4E0B\uFF1B\u6309\u9700 Read \u5B83\u4E86\u89E3\u4E0A\u4E0B\u6587\uFF08\u4E0D\u5FC5\u8BFB\u5B8C\uFF09
|
|
41956
|
-
- \u5E72\u5B8C\u540E**\u5FC5\u987B**\u8C03 \`
|
|
41937
|
+
- \u5E72\u5B8C\u540E**\u5FC5\u987B**\u8C03 \`clawd-dispatch\` MCP \u7684 \`personaDispatchComplete\` tool \u62A5\u544A\u7ED3\u679C\uFF1A
|
|
41957
41938
|
- \u6210\u529F\uFF1A\`{ text: "\u603B\u7ED3/\u7ED3\u8BBA", filePaths?: ["\u4F60\u4EA7\u51FA/\u6539\u7684\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84"] }\`
|
|
41958
41939
|
- \u5931\u8D25\uFF1A\`{ isFailure: true, reason: "..." }\`
|
|
41959
41940
|
- \u62A5\u544A\u5B8C\u540E\u4F60\u7684 session \u5C31\u7ED3\u675F\u4E86\uFF0C\u4E0D\u8981\u7EE7\u7EED\u8F93\u51FA`;
|
|
@@ -43353,7 +43334,8 @@ Source conversation (jsonl, CC stream-json format, one message per line):
|
|
|
43353
43334
|
${args.sourceJsonlPath}
|
|
43354
43335
|
You may read this file with your Read tool to understand context. You do not have to read it all.
|
|
43355
43336
|
|
|
43356
|
-
When done, call the
|
|
43337
|
+
When done, call the \`personaDispatchComplete\` tool from the \`clawd-dispatch\` MCP server with your result
|
|
43338
|
+
(tool display name varies by agent, e.g. \`mcp__clawd-dispatch__personaDispatchComplete\` in claude):
|
|
43357
43339
|
- Success: { text: "...", filePaths?: ["abs/path", ...] }
|
|
43358
43340
|
- Failure: { isFailure: true, reason: "..." }
|
|
43359
43341
|
|
|
@@ -43658,18 +43640,20 @@ var SessionManager = class {
|
|
|
43658
43640
|
`newRunner: guest session ${file.sessionId} \u7F3A personaRoot/userWorkDir\uFF0C\u65E0\u6CD5\u7269\u5316 OS \u6C99\u7BB1\uFF08\u62D2\u7EDD\u521B\u5EFA\u65E0\u6C99\u7BB1 guest\uFF09`
|
|
43659
43641
|
);
|
|
43660
43642
|
}
|
|
43661
|
-
|
|
43662
|
-
|
|
43663
|
-
|
|
43664
|
-
|
|
43665
|
-
|
|
43666
|
-
|
|
43667
|
-
|
|
43668
|
-
|
|
43669
|
-
|
|
43670
|
-
|
|
43643
|
+
if ((file.tool ?? "claude") === "claude") {
|
|
43644
|
+
const base = this.deps.personaStore?.readSandboxSettings(scope.personaId) ?? null;
|
|
43645
|
+
const sandboxSettings = composeGuestSandbox(base, subSessionMeta.userWorkDir, file.cwd);
|
|
43646
|
+
const ownerCreds = readOwnerCredentials(import_node_os5.default.homedir(), this.deps.logger);
|
|
43647
|
+
const merged = mergeOwnerCredentials(sandboxSettings, ownerCreds);
|
|
43648
|
+
if (ownerCreds) {
|
|
43649
|
+
this.deps.logger?.info("owner credentials injected into guest spawn", {
|
|
43650
|
+
sessionId: file.sessionId,
|
|
43651
|
+
envKeys: ownerCreds.env ? Object.keys(ownerCreds.env) : [],
|
|
43652
|
+
apiKeyHelper: ownerCreds.apiKeyHelper ? "present" : "absent"
|
|
43653
|
+
});
|
|
43654
|
+
}
|
|
43655
|
+
subSessionMeta.extraSettings = JSON.stringify(merged);
|
|
43671
43656
|
}
|
|
43672
|
-
subSessionMeta.extraSettings = JSON.stringify(merged);
|
|
43673
43657
|
const home = import_node_os5.default.homedir();
|
|
43674
43658
|
const expand = (p2) => p2 === "~" ? home : p2.startsWith("~/") ? import_node_path9.default.join(home, p2.slice(2)) : p2;
|
|
43675
43659
|
const codexCfg = this.deps.personaStore?.readCodexSandboxSettings(scope.personaId) ?? null;
|
|
@@ -44719,7 +44703,9 @@ var SessionManager = class {
|
|
|
44719
44703
|
const file = {
|
|
44720
44704
|
sessionId,
|
|
44721
44705
|
cwd,
|
|
44722
|
-
tool
|
|
44706
|
+
// dispatch B session 跟随 persona 绑定的 tool(codex persona 用 codex spawn),
|
|
44707
|
+
// 与 UI 手建路径(handlers/session.ts create 的 persona.tool 优先)同语义
|
|
44708
|
+
tool: this.deps.getPersonaTool?.(args.targetPersona) ?? "claude",
|
|
44723
44709
|
ownerPersonaId: args.targetPersona,
|
|
44724
44710
|
dispatchedFromSessionId: args.sourceSessionId,
|
|
44725
44711
|
// 跨设备显示关键(spec §8):creatorPrincipalId = A 的 deviceId,让 A 的
|
|
@@ -44809,7 +44795,8 @@ var SessionManager = class {
|
|
|
44809
44795
|
const file = {
|
|
44810
44796
|
sessionId,
|
|
44811
44797
|
cwd,
|
|
44812
|
-
tool
|
|
44798
|
+
// shift 定时 spawn 同样跟随 persona 绑定 tool(对齐 dispatch B session)
|
|
44799
|
+
tool: this.deps.getPersonaTool?.(args.targetPersona) ?? "claude",
|
|
44813
44800
|
ownerPersonaId: args.targetPersona,
|
|
44814
44801
|
...args.sourceSessionId ? { shiftFiredFromSessionId: args.sourceSessionId } : {},
|
|
44815
44802
|
createdAt: now,
|
|
@@ -45874,17 +45861,9 @@ var PersonaManager = class {
|
|
|
45874
45861
|
}
|
|
45875
45862
|
/**
|
|
45876
45863
|
* 删除 persona。
|
|
45877
|
-
* PersonaStore.remove(personaId)
|
|
45878
|
-
*
|
|
45879
|
-
*
|
|
45880
|
-
*
|
|
45881
|
-
* ⚠️ TODO (Phase 3+ design gap, reviewer P1 flagged):
|
|
45882
|
-
* ~/.clawd/capabilities.json 里若有 cap.grants 含本 personaId, grant 会变成
|
|
45883
|
-
* 悬空引用 (guest 仍能持 token 接入, 但调依赖该 persona 的 RPC 会 fail).
|
|
45884
|
-
* 选项: (A) 这里扫所有 cap 过滤掉该 personaId 的 grant; (B) revoke 所有 grant
|
|
45885
|
-
* 含该 personaId 的 cap. 当前因 cleanupGuestSessionsForCapability 用 rmSync
|
|
45886
|
-
* force=true 吞 ENOENT 不会 crash, 但 UI CapabilityManagerDrawer 会展示
|
|
45887
|
-
* "无效的 persona" grant. Phase 3 加 cross-reference 矩阵后正式实现.
|
|
45864
|
+
* PersonaStore.remove(personaId) 级联删整个 <personaRoot>/<personaId>/ 目录
|
|
45865
|
+
* (含 .clawd/sessions/owner/ 和 .clawd/sessions/guests/<capId>/),rmSync
|
|
45866
|
+
* recursive force 一锅清。
|
|
45888
45867
|
*/
|
|
45889
45868
|
delete(personaId) {
|
|
45890
45869
|
this.deps.store.remove(personaId);
|
|
@@ -46185,6 +46164,9 @@ function refreshDaemonManagedDirs(args) {
|
|
|
46185
46164
|
const dstPath = path14.join(personaDir, relPath);
|
|
46186
46165
|
try {
|
|
46187
46166
|
fs12.cpSync(srcPath, dstPath, { recursive: true, force: true, dereference: true, filter: skipNodeModulesUnder(srcPath) });
|
|
46167
|
+
if (relPath === "CLAUDE.md") {
|
|
46168
|
+
fs12.cpSync(srcPath, path14.join(personaDir, "AGENTS.md"), { force: true, dereference: true });
|
|
46169
|
+
}
|
|
46188
46170
|
args.logger.info("persona.refresh.synced", {
|
|
46189
46171
|
personaId: entry.personaId,
|
|
46190
46172
|
path: relPath
|
|
@@ -46552,11 +46534,12 @@ function createVisitorStore(opts) {
|
|
|
46552
46534
|
init_claude();
|
|
46553
46535
|
|
|
46554
46536
|
// src/tools/codex.ts
|
|
46555
|
-
var
|
|
46556
|
-
var
|
|
46537
|
+
var import_node_child_process5 = require("child_process");
|
|
46538
|
+
var import_node_fs18 = __toESM(require("fs"), 1);
|
|
46557
46539
|
|
|
46558
46540
|
// src/tools/codex-session.ts
|
|
46559
|
-
var
|
|
46541
|
+
var import_node_child_process4 = require("child_process");
|
|
46542
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
46560
46543
|
|
|
46561
46544
|
// src/tools/codex-app-server-client.ts
|
|
46562
46545
|
var import_node_readline = require("readline");
|
|
@@ -46739,7 +46722,7 @@ function resolveApprovalPolicy(ctx) {
|
|
|
46739
46722
|
if (m2 === "untrusted" || m2 === "on-failure" || m2 === "on-request" || m2 === "never") return m2;
|
|
46740
46723
|
return "on-request";
|
|
46741
46724
|
}
|
|
46742
|
-
function buildCodexGuestConfig(cs) {
|
|
46725
|
+
function buildCodexGuestConfig(cs, opts = {}) {
|
|
46743
46726
|
const filesystem = {};
|
|
46744
46727
|
for (const w2 of cs.writableRoots ?? []) filesystem[w2] = "write";
|
|
46745
46728
|
const deny = cs.denyRead ?? [];
|
|
@@ -46754,7 +46737,7 @@ function buildCodexGuestConfig(cs) {
|
|
|
46754
46737
|
clawos_guest: {
|
|
46755
46738
|
extends: ":workspace",
|
|
46756
46739
|
filesystem,
|
|
46757
|
-
network: cs.network ? { enabled: true, domains: { "*": "allow" } } : { enabled: false }
|
|
46740
|
+
network: cs.network ? { enabled: true, domains: { "*": "allow" } } : opts.loopbackDaemonAccess ? { enabled: true, allowed_domains: [], allow_local_binding: true } : { enabled: false }
|
|
46758
46741
|
}
|
|
46759
46742
|
}
|
|
46760
46743
|
};
|
|
@@ -46768,15 +46751,32 @@ function tomlValue(v2) {
|
|
|
46768
46751
|
}
|
|
46769
46752
|
return JSON.stringify(v2);
|
|
46770
46753
|
}
|
|
46771
|
-
function codexGuestCliArgs(cs) {
|
|
46772
|
-
const cfg = buildCodexGuestConfig(cs);
|
|
46754
|
+
function codexGuestCliArgs(cs, opts = {}) {
|
|
46755
|
+
const cfg = buildCodexGuestConfig(cs, opts);
|
|
46773
46756
|
const profile = cfg.permissions.clawos_guest;
|
|
46774
|
-
|
|
46757
|
+
const args = [
|
|
46775
46758
|
"-c",
|
|
46776
46759
|
`default_permissions=${tomlValue("clawos_guest")}`,
|
|
46777
46760
|
"-c",
|
|
46778
46761
|
`permissions.clawos_guest=${tomlValue(profile)}`
|
|
46779
46762
|
];
|
|
46763
|
+
if (!cs.network && opts.loopbackDaemonAccess) {
|
|
46764
|
+
args.push("-c", "features.network_proxy=true");
|
|
46765
|
+
}
|
|
46766
|
+
return args;
|
|
46767
|
+
}
|
|
46768
|
+
function codexMcpCliArgs(defs) {
|
|
46769
|
+
const out = [];
|
|
46770
|
+
for (const d of defs) {
|
|
46771
|
+
const cfg = {
|
|
46772
|
+
command: d.command,
|
|
46773
|
+
...d.args && d.args.length > 0 ? { args: d.args } : {},
|
|
46774
|
+
...d.env && Object.keys(d.env).length > 0 ? { env: d.env } : {}
|
|
46775
|
+
};
|
|
46776
|
+
const key = /^[A-Za-z0-9_-]+$/.test(d.name) ? d.name : JSON.stringify(d.name);
|
|
46777
|
+
out.push("-c", `mcp_servers.${key}=${tomlValue(cfg)}`);
|
|
46778
|
+
}
|
|
46779
|
+
return out;
|
|
46780
46780
|
}
|
|
46781
46781
|
function threadStartParams(ctx) {
|
|
46782
46782
|
const params = {
|
|
@@ -46801,8 +46801,8 @@ function turnStartInput(text) {
|
|
|
46801
46801
|
const items = [];
|
|
46802
46802
|
let leftover = text;
|
|
46803
46803
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
46804
|
-
const [marker, name,
|
|
46805
|
-
items.push({ type: "skill", name, path:
|
|
46804
|
+
const [marker, name, path74] = m2;
|
|
46805
|
+
items.push({ type: "skill", name, path: path74 });
|
|
46806
46806
|
leftover = leftover.replace(marker, "");
|
|
46807
46807
|
}
|
|
46808
46808
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -46817,15 +46817,122 @@ function turnStartInput(text) {
|
|
|
46817
46817
|
return items;
|
|
46818
46818
|
}
|
|
46819
46819
|
|
|
46820
|
+
// src/tools/codex-mcp-config.ts
|
|
46821
|
+
var import_node_fs17 = __toESM(require("fs"), 1);
|
|
46822
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
46823
|
+
function loadCodexMcpServerDefs(args) {
|
|
46824
|
+
const out = [];
|
|
46825
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46826
|
+
const sources = [...args.mcpConfigPaths, import_node_path15.default.join(args.cwd, ".mcp.json")];
|
|
46827
|
+
for (const file of sources) {
|
|
46828
|
+
let parsed;
|
|
46829
|
+
try {
|
|
46830
|
+
parsed = JSON.parse(import_node_fs17.default.readFileSync(file, "utf8"));
|
|
46831
|
+
} catch (e) {
|
|
46832
|
+
const code = e.code;
|
|
46833
|
+
if (code !== "ENOENT") {
|
|
46834
|
+
args.logger?.warn("codex mcp config unreadable, skipped", { file, code: code ?? "parse-error" });
|
|
46835
|
+
}
|
|
46836
|
+
continue;
|
|
46837
|
+
}
|
|
46838
|
+
const servers = parsed?.mcpServers;
|
|
46839
|
+
if (!servers || typeof servers !== "object") continue;
|
|
46840
|
+
for (const [name, raw] of Object.entries(servers)) {
|
|
46841
|
+
const def = raw ?? {};
|
|
46842
|
+
const type = typeof def.type === "string" ? def.type : "stdio";
|
|
46843
|
+
if (type !== "stdio") {
|
|
46844
|
+
args.logger?.warn("codex mcp server type unsupported, skipped", { file, name, type });
|
|
46845
|
+
continue;
|
|
46846
|
+
}
|
|
46847
|
+
if (typeof def.command !== "string" || !def.command) {
|
|
46848
|
+
args.logger?.warn("codex mcp server missing command, skipped", { file, name });
|
|
46849
|
+
continue;
|
|
46850
|
+
}
|
|
46851
|
+
if (seen.has(name)) {
|
|
46852
|
+
args.logger?.warn("codex mcp server name collision, first-wins", { file, name });
|
|
46853
|
+
continue;
|
|
46854
|
+
}
|
|
46855
|
+
seen.add(name);
|
|
46856
|
+
const fileEnv = def.env && typeof def.env === "object" ? Object.fromEntries(
|
|
46857
|
+
Object.entries(def.env).filter(
|
|
46858
|
+
(kv) => typeof kv[1] === "string"
|
|
46859
|
+
)
|
|
46860
|
+
) : {};
|
|
46861
|
+
const env = { ...args.baseEnv ?? {}, ...fileEnv };
|
|
46862
|
+
out.push({
|
|
46863
|
+
name,
|
|
46864
|
+
command: def.command,
|
|
46865
|
+
...Array.isArray(def.args) && def.args.every((a) => typeof a === "string") ? { args: def.args } : {},
|
|
46866
|
+
...Object.keys(env).length > 0 ? { env } : {}
|
|
46867
|
+
});
|
|
46868
|
+
}
|
|
46869
|
+
}
|
|
46870
|
+
return out;
|
|
46871
|
+
}
|
|
46872
|
+
|
|
46873
|
+
// src/tools/codex-features.ts
|
|
46874
|
+
var import_node_child_process3 = require("child_process");
|
|
46875
|
+
var cachedNetworkProxy;
|
|
46876
|
+
function hasNetworkProxyFeature(deps = {}) {
|
|
46877
|
+
if (cachedNetworkProxy !== void 0) return cachedNetworkProxy;
|
|
46878
|
+
try {
|
|
46879
|
+
const out = deps.execOverride ? deps.execOverride() : (0, import_node_child_process3.execFileSync)(process.env.CODEX_BIN ?? "codex", ["features", "list"], {
|
|
46880
|
+
encoding: "utf8",
|
|
46881
|
+
timeout: 3e3
|
|
46882
|
+
});
|
|
46883
|
+
const m2 = /^network_proxy\s+(.+?)\s+(?:true|false)\s*$/m.exec(out);
|
|
46884
|
+
cachedNetworkProxy = m2 !== null && m2[1].trim() !== "removed";
|
|
46885
|
+
} catch {
|
|
46886
|
+
cachedNetworkProxy = false;
|
|
46887
|
+
}
|
|
46888
|
+
return cachedNetworkProxy;
|
|
46889
|
+
}
|
|
46890
|
+
var warming = false;
|
|
46891
|
+
function warmCodexFeatureCache() {
|
|
46892
|
+
if (cachedNetworkProxy !== void 0 || warming) return;
|
|
46893
|
+
warming = true;
|
|
46894
|
+
(0, import_node_child_process3.execFile)(
|
|
46895
|
+
process.env.CODEX_BIN ?? "codex",
|
|
46896
|
+
["features", "list"],
|
|
46897
|
+
{ encoding: "utf8", timeout: 3e3 },
|
|
46898
|
+
(err, stdout) => {
|
|
46899
|
+
warming = false;
|
|
46900
|
+
if (cachedNetworkProxy !== void 0) return;
|
|
46901
|
+
if (err) {
|
|
46902
|
+
cachedNetworkProxy = false;
|
|
46903
|
+
return;
|
|
46904
|
+
}
|
|
46905
|
+
const m2 = /^network_proxy\s+(.+?)\s+(?:true|false)\s*$/m.exec(stdout);
|
|
46906
|
+
cachedNetworkProxy = m2 !== null && m2[1].trim() !== "removed";
|
|
46907
|
+
}
|
|
46908
|
+
);
|
|
46909
|
+
}
|
|
46910
|
+
|
|
46820
46911
|
// src/tools/codex-session.ts
|
|
46821
46912
|
function createCodexSession(ctx, sink, deps = {}) {
|
|
46822
46913
|
const cmd = process.env.CODEX_BIN ?? "codex";
|
|
46823
46914
|
const args = ["app-server", "--listen", "stdio://"];
|
|
46824
46915
|
if (ctx.personaMode === "guest" && ctx.codexSandbox) {
|
|
46825
|
-
|
|
46916
|
+
const loopbackDaemonAccess = deps.hasNetworkProxyOverride ? deps.hasNetworkProxyOverride() : hasNetworkProxyFeature();
|
|
46917
|
+
args.push(...codexGuestCliArgs(ctx.codexSandbox, { loopbackDaemonAccess }));
|
|
46826
46918
|
}
|
|
46919
|
+
const clawdEnv = Object.fromEntries(
|
|
46920
|
+
Object.entries(ctx.env ?? {}).filter(
|
|
46921
|
+
(kv) => kv[0].startsWith("CLAWD_") && typeof kv[1] === "string"
|
|
46922
|
+
)
|
|
46923
|
+
);
|
|
46924
|
+
args.push(
|
|
46925
|
+
...codexMcpCliArgs(
|
|
46926
|
+
loadCodexMcpServerDefs({
|
|
46927
|
+
mcpConfigPaths: (ctx.mcpConfigs ?? []).map((m2) => m2.path),
|
|
46928
|
+
cwd: ctx.cwd,
|
|
46929
|
+
baseEnv: clawdEnv,
|
|
46930
|
+
logger: deps.logger
|
|
46931
|
+
})
|
|
46932
|
+
)
|
|
46933
|
+
);
|
|
46827
46934
|
const env = { ...process.env, ...ctx.env };
|
|
46828
|
-
const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, ctx.cwd, env) : (0,
|
|
46935
|
+
const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, ctx.cwd, env) : (0, import_node_child_process4.spawn)(cmd, args, { cwd: ctx.cwd, env, stdio: ["pipe", "pipe", "pipe"] });
|
|
46829
46936
|
let threadId = ctx.toolSessionId;
|
|
46830
46937
|
let turnId;
|
|
46831
46938
|
const approvalIds = /* @__PURE__ */ new Map();
|
|
@@ -46882,6 +46989,7 @@ function createCodexSession(ctx, sink, deps = {}) {
|
|
|
46882
46989
|
capabilities: null
|
|
46883
46990
|
});
|
|
46884
46991
|
client.notify("initialized", {});
|
|
46992
|
+
void client.request("skills/extraRoots/set", { extraRoots: [import_node_path16.default.join(ctx.cwd, ".claude", "skills")] }).catch((e) => deps.logger?.warn("codex skills/extraRoots/set failed", { message: e.message }));
|
|
46885
46993
|
if (threadId) {
|
|
46886
46994
|
await client.request("thread/resume", { threadId, ...threadStartParams(ctx) });
|
|
46887
46995
|
} else {
|
|
@@ -46928,6 +47036,7 @@ function createCodexSession(ctx, sink, deps = {}) {
|
|
|
46928
47036
|
}
|
|
46929
47037
|
|
|
46930
47038
|
// src/tools/codex.ts
|
|
47039
|
+
var CODEX_MODEL_IDS = ["gpt-5.5", "gpt-5.4", "gpt-5.4-mini"];
|
|
46931
47040
|
var CODEX_MODELS = [
|
|
46932
47041
|
{ id: "", label: "Default", description: "codex config.toml \u9ED8\u8BA4", contextWindowSize: 258400, default: true },
|
|
46933
47042
|
{ id: "gpt-5.5", label: "GPT-5.5", description: "Frontier model for complex coding", contextWindowSize: 258400 },
|
|
@@ -46986,10 +47095,10 @@ function sanitizeCodexModel(model) {
|
|
|
46986
47095
|
return CODEX_MODELS.some((m2) => m2.id === model) ? model : void 0;
|
|
46987
47096
|
}
|
|
46988
47097
|
async function probeCodex(env = process.env) {
|
|
46989
|
-
if (env.CODEX_BIN &&
|
|
47098
|
+
if (env.CODEX_BIN && import_node_fs18.default.existsSync(env.CODEX_BIN)) return { available: true, path: env.CODEX_BIN };
|
|
46990
47099
|
try {
|
|
46991
|
-
const out = (0,
|
|
46992
|
-
if (out &&
|
|
47100
|
+
const out = (0, import_node_child_process5.execFileSync)("which", ["codex"], { encoding: "utf8" }).trim();
|
|
47101
|
+
if (out && import_node_fs18.default.existsSync(out)) return { available: true, path: out };
|
|
46993
47102
|
} catch {
|
|
46994
47103
|
}
|
|
46995
47104
|
return { available: false };
|
|
@@ -47035,9 +47144,9 @@ var CodexAdapter = class {
|
|
|
47035
47144
|
|
|
47036
47145
|
// src/tools/claude-tui.ts
|
|
47037
47146
|
var import_node_crypto5 = require("crypto");
|
|
47038
|
-
var
|
|
47147
|
+
var import_node_fs19 = __toESM(require("fs"), 1);
|
|
47039
47148
|
var import_node_os7 = __toESM(require("os"), 1);
|
|
47040
|
-
var
|
|
47149
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
47041
47150
|
var import_headless = __toESM(require_xterm_headless(), 1);
|
|
47042
47151
|
|
|
47043
47152
|
// ../node_modules/.pnpm/@xterm+addon-serialize@0.14.0/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs
|
|
@@ -48270,9 +48379,9 @@ function buildTuiSpawnArgs(ctx, isResume = false) {
|
|
|
48270
48379
|
function jsonlExistsForCtx(ctx) {
|
|
48271
48380
|
if (!ctx.toolSessionId) return false;
|
|
48272
48381
|
const home = import_node_os7.default.homedir();
|
|
48273
|
-
const file =
|
|
48382
|
+
const file = import_node_path17.default.join(home, ".claude", "projects", cwdToHashDir(ctx.cwd), `${ctx.toolSessionId}.jsonl`);
|
|
48274
48383
|
try {
|
|
48275
|
-
return
|
|
48384
|
+
return import_node_fs19.default.statSync(file).isFile();
|
|
48276
48385
|
} catch {
|
|
48277
48386
|
return false;
|
|
48278
48387
|
}
|
|
@@ -48382,7 +48491,7 @@ var PersonaDispatchManager = class {
|
|
|
48382
48491
|
|
|
48383
48492
|
// src/dispatch/store.ts
|
|
48384
48493
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
48385
|
-
var
|
|
48494
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
48386
48495
|
|
|
48387
48496
|
// src/shift/constants.ts
|
|
48388
48497
|
var MAX_RUNS_PER_SHIFT = 30;
|
|
@@ -48420,7 +48529,7 @@ function createDispatchStore(deps) {
|
|
|
48420
48529
|
flushTimer = null;
|
|
48421
48530
|
}
|
|
48422
48531
|
const content = { version: 1, records };
|
|
48423
|
-
await import_promises.default.mkdir(
|
|
48532
|
+
await import_promises.default.mkdir(import_node_path18.default.dirname(deps.filePath), { recursive: true });
|
|
48424
48533
|
const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
|
|
48425
48534
|
await import_promises.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
|
|
48426
48535
|
await import_promises.default.rename(tmp, deps.filePath);
|
|
@@ -48482,10 +48591,10 @@ function createDispatchStore(deps) {
|
|
|
48482
48591
|
}
|
|
48483
48592
|
|
|
48484
48593
|
// src/dispatch/mcp-config.ts
|
|
48485
|
-
var
|
|
48486
|
-
var
|
|
48594
|
+
var import_node_fs20 = __toESM(require("fs"), 1);
|
|
48595
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
48487
48596
|
function dispatchMcpConfigPath(dataDir) {
|
|
48488
|
-
return
|
|
48597
|
+
return import_node_path19.default.join(dataDir, "dispatch.mcp.json");
|
|
48489
48598
|
}
|
|
48490
48599
|
function writeDispatchMcpConfig(args) {
|
|
48491
48600
|
const cfgPath = dispatchMcpConfigPath(args.dataDir);
|
|
@@ -48500,16 +48609,16 @@ function writeDispatchMcpConfig(args) {
|
|
|
48500
48609
|
}
|
|
48501
48610
|
}
|
|
48502
48611
|
};
|
|
48503
|
-
|
|
48504
|
-
|
|
48612
|
+
import_node_fs20.default.mkdirSync(args.dataDir, { recursive: true });
|
|
48613
|
+
import_node_fs20.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
|
|
48505
48614
|
return cfgPath;
|
|
48506
48615
|
}
|
|
48507
48616
|
|
|
48508
48617
|
// src/ticket/mcp-config.ts
|
|
48509
|
-
var
|
|
48510
|
-
var
|
|
48618
|
+
var import_node_fs21 = __toESM(require("fs"), 1);
|
|
48619
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
48511
48620
|
function ticketMcpConfigPath(dataDir) {
|
|
48512
|
-
return
|
|
48621
|
+
return import_node_path20.default.join(dataDir, "ticket.mcp.json");
|
|
48513
48622
|
}
|
|
48514
48623
|
function writeTicketMcpConfig(args) {
|
|
48515
48624
|
const cfgPath = ticketMcpConfigPath(args.dataDir);
|
|
@@ -48529,16 +48638,16 @@ function writeTicketMcpConfig(args) {
|
|
|
48529
48638
|
}
|
|
48530
48639
|
}
|
|
48531
48640
|
};
|
|
48532
|
-
|
|
48533
|
-
|
|
48641
|
+
import_node_fs21.default.mkdirSync(args.dataDir, { recursive: true });
|
|
48642
|
+
import_node_fs21.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
|
|
48534
48643
|
return cfgPath;
|
|
48535
48644
|
}
|
|
48536
48645
|
|
|
48537
48646
|
// src/shift/mcp-config.ts
|
|
48538
|
-
var
|
|
48539
|
-
var
|
|
48647
|
+
var import_node_fs22 = __toESM(require("fs"), 1);
|
|
48648
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
48540
48649
|
function shiftMcpConfigPath(dataDir) {
|
|
48541
|
-
return
|
|
48650
|
+
return import_node_path21.default.join(dataDir, "shift.mcp.json");
|
|
48542
48651
|
}
|
|
48543
48652
|
async function writeShiftMcpConfig(args) {
|
|
48544
48653
|
const cfgPath = shiftMcpConfigPath(args.dataDir);
|
|
@@ -48553,16 +48662,16 @@ async function writeShiftMcpConfig(args) {
|
|
|
48553
48662
|
}
|
|
48554
48663
|
}
|
|
48555
48664
|
};
|
|
48556
|
-
await
|
|
48557
|
-
await
|
|
48665
|
+
await import_node_fs22.default.promises.mkdir(args.dataDir, { recursive: true });
|
|
48666
|
+
await import_node_fs22.default.promises.writeFile(cfgPath, JSON.stringify(content, null, 2), "utf8");
|
|
48558
48667
|
return cfgPath;
|
|
48559
48668
|
}
|
|
48560
48669
|
|
|
48561
48670
|
// src/inbox/mcp-config.ts
|
|
48562
|
-
var
|
|
48563
|
-
var
|
|
48671
|
+
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
48672
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
48564
48673
|
function inboxMcpConfigPath(dataDir) {
|
|
48565
|
-
return
|
|
48674
|
+
return import_node_path22.default.join(dataDir, "inbox.mcp.json");
|
|
48566
48675
|
}
|
|
48567
48676
|
async function writeInboxMcpConfig(args) {
|
|
48568
48677
|
const cfgPath = inboxMcpConfigPath(args.dataDir);
|
|
@@ -48577,16 +48686,16 @@ async function writeInboxMcpConfig(args) {
|
|
|
48577
48686
|
}
|
|
48578
48687
|
}
|
|
48579
48688
|
};
|
|
48580
|
-
await
|
|
48581
|
-
await
|
|
48689
|
+
await import_node_fs23.default.promises.mkdir(args.dataDir, { recursive: true });
|
|
48690
|
+
await import_node_fs23.default.promises.writeFile(cfgPath, JSON.stringify(content, null, 2), "utf8");
|
|
48582
48691
|
return cfgPath;
|
|
48583
48692
|
}
|
|
48584
48693
|
|
|
48585
48694
|
// src/peer-ops/mcp-config.ts
|
|
48586
|
-
var
|
|
48587
|
-
var
|
|
48695
|
+
var import_node_fs24 = __toESM(require("fs"), 1);
|
|
48696
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
48588
48697
|
function peerOpsMcpConfigPath(dataDir) {
|
|
48589
|
-
return
|
|
48698
|
+
return import_node_path23.default.join(dataDir, "peer-ops.mcp.json");
|
|
48590
48699
|
}
|
|
48591
48700
|
function writePeerOpsMcpConfig(args) {
|
|
48592
48701
|
const cfgPath = peerOpsMcpConfigPath(args.dataDir);
|
|
@@ -48599,14 +48708,14 @@ function writePeerOpsMcpConfig(args) {
|
|
|
48599
48708
|
}
|
|
48600
48709
|
}
|
|
48601
48710
|
};
|
|
48602
|
-
|
|
48603
|
-
|
|
48711
|
+
import_node_fs24.default.mkdirSync(args.dataDir, { recursive: true });
|
|
48712
|
+
import_node_fs24.default.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2));
|
|
48604
48713
|
return cfgPath;
|
|
48605
48714
|
}
|
|
48606
48715
|
|
|
48607
48716
|
// src/shift/store.ts
|
|
48608
48717
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
48609
|
-
var
|
|
48718
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
48610
48719
|
var import_node_crypto6 = require("crypto");
|
|
48611
48720
|
|
|
48612
48721
|
// src/shift/schedule.ts
|
|
@@ -48681,7 +48790,7 @@ function createShiftStore(deps) {
|
|
|
48681
48790
|
flushTimer = null;
|
|
48682
48791
|
}
|
|
48683
48792
|
const content = { version: 1, shifts };
|
|
48684
|
-
await import_promises2.default.mkdir(
|
|
48793
|
+
await import_promises2.default.mkdir(import_node_path24.default.dirname(deps.filePath), { recursive: true });
|
|
48685
48794
|
const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
|
|
48686
48795
|
await import_promises2.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
|
|
48687
48796
|
await import_promises2.default.rename(tmp, deps.filePath);
|
|
@@ -49114,11 +49223,16 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
49114
49223
|
const { type: _t, requestId: _r, ...rest } = frame;
|
|
49115
49224
|
const sourceSessionId = typeof rest.sessionId === "string" ? rest.sessionId : void 0;
|
|
49116
49225
|
const args = DispatchRunArgsSchema.parse(rest);
|
|
49117
|
-
if (args.model !== void 0
|
|
49118
|
-
|
|
49119
|
-
|
|
49120
|
-
|
|
49121
|
-
)
|
|
49226
|
+
if (args.model !== void 0) {
|
|
49227
|
+
const targetPersona2 = args.targetPersona ?? (args.dispatchId ? deps.store.get(args.dispatchId)?.targetPersonaId : void 0);
|
|
49228
|
+
const targetTool = (targetPersona2 ? deps.getPersonaTool?.(targetPersona2) : void 0) ?? "claude";
|
|
49229
|
+
const allowed = targetTool === "codex" ? CODEX_MODEL_IDS : CLAUDE_MODEL_IDS;
|
|
49230
|
+
if (!allowed.includes(args.model)) {
|
|
49231
|
+
throw new ClawdError(
|
|
49232
|
+
ERROR_CODES.INVALID_PARAM,
|
|
49233
|
+
`model '${args.model}' not supported for tool '${targetTool}'; allowed: ${allowed.join(", ")}`
|
|
49234
|
+
);
|
|
49235
|
+
}
|
|
49122
49236
|
}
|
|
49123
49237
|
if (args.dispatchId) {
|
|
49124
49238
|
if (ctx?.principal.kind === "guest") {
|
|
@@ -49453,7 +49567,7 @@ async function forwardPeerExecToPeer(args) {
|
|
|
49453
49567
|
}
|
|
49454
49568
|
|
|
49455
49569
|
// src/tools/codex-history.ts
|
|
49456
|
-
var
|
|
49570
|
+
var import_node_child_process6 = require("child_process");
|
|
49457
49571
|
var DEFAULT_TIMEOUT_MS2 = 8e3;
|
|
49458
49572
|
function rec2(v2) {
|
|
49459
49573
|
return v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
|
|
@@ -49516,7 +49630,7 @@ function threadItemToHistoryMessages(item) {
|
|
|
49516
49630
|
async function queryCodexAppServer(cwd, method, params, deps) {
|
|
49517
49631
|
const cmd = process.env.CODEX_BIN ?? "codex";
|
|
49518
49632
|
const args = ["app-server", "--listen", "stdio://"];
|
|
49519
|
-
const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, cwd) : (0,
|
|
49633
|
+
const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, cwd) : (0, import_node_child_process6.spawn)(cmd, args, { cwd, env: process.env, stdio: ["pipe", "pipe", "pipe"] });
|
|
49520
49634
|
const client = new CodexAppServerClient(proc, {});
|
|
49521
49635
|
const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
49522
49636
|
let timer;
|
|
@@ -49622,7 +49736,8 @@ var CodexHistoryReader = class {
|
|
|
49622
49736
|
};
|
|
49623
49737
|
|
|
49624
49738
|
// src/tools/codex-skills.ts
|
|
49625
|
-
var
|
|
49739
|
+
var import_node_child_process7 = require("child_process");
|
|
49740
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
49626
49741
|
var DEFAULT_TIMEOUT_MS3 = 8e3;
|
|
49627
49742
|
function str3(v2) {
|
|
49628
49743
|
return typeof v2 === "string" ? v2 : void 0;
|
|
@@ -49638,13 +49753,13 @@ function mapSkillsListResponse(res) {
|
|
|
49638
49753
|
const r = s ?? {};
|
|
49639
49754
|
const name = str3(r.name);
|
|
49640
49755
|
if (!name) continue;
|
|
49641
|
-
const
|
|
49756
|
+
const path74 = str3(r.path);
|
|
49642
49757
|
const description = str3(r.description);
|
|
49643
49758
|
const isPlugin = name.includes(":");
|
|
49644
49759
|
out.push({
|
|
49645
49760
|
name,
|
|
49646
49761
|
source: isPlugin ? "plugin" : "project",
|
|
49647
|
-
...
|
|
49762
|
+
...path74 ? { path: path74 } : {},
|
|
49648
49763
|
...description ? { description } : {},
|
|
49649
49764
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
49650
49765
|
});
|
|
@@ -49655,7 +49770,7 @@ function mapSkillsListResponse(res) {
|
|
|
49655
49770
|
async function listCodexSkills(cwd, deps = {}) {
|
|
49656
49771
|
const cmd = process.env.CODEX_BIN ?? "codex";
|
|
49657
49772
|
const args = ["app-server", "--listen", "stdio://"];
|
|
49658
|
-
const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, cwd) : (0,
|
|
49773
|
+
const proc = deps.spawnOverride ? deps.spawnOverride(cmd, args, cwd) : (0, import_node_child_process7.spawn)(cmd, args, { cwd, env: process.env, stdio: ["pipe", "pipe", "pipe"] });
|
|
49659
49774
|
const client = new CodexAppServerClient(proc, {});
|
|
49660
49775
|
const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
|
|
49661
49776
|
let timer;
|
|
@@ -49674,6 +49789,7 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
49674
49789
|
})(),
|
|
49675
49790
|
timeout
|
|
49676
49791
|
]);
|
|
49792
|
+
void client.request("skills/extraRoots/set", { extraRoots: [import_node_path25.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
|
|
49677
49793
|
const res = await Promise.race([client.request("skills/list", { cwds: [cwd] }), timeout]);
|
|
49678
49794
|
return mapSkillsListResponse(res);
|
|
49679
49795
|
} finally {
|
|
@@ -49683,23 +49799,23 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
49683
49799
|
}
|
|
49684
49800
|
|
|
49685
49801
|
// src/workspace/browser.ts
|
|
49686
|
-
var
|
|
49802
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
49687
49803
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
49688
|
-
var
|
|
49804
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
49689
49805
|
init_protocol();
|
|
49690
49806
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
49691
49807
|
function resolveInsideCwd(cwd, subpath) {
|
|
49692
|
-
const absCwd =
|
|
49693
|
-
const joined =
|
|
49694
|
-
const rel =
|
|
49695
|
-
if (rel.startsWith("..") ||
|
|
49808
|
+
const absCwd = import_node_path26.default.resolve(cwd);
|
|
49809
|
+
const joined = import_node_path26.default.resolve(absCwd, subpath ?? ".");
|
|
49810
|
+
const rel = import_node_path26.default.relative(absCwd, joined);
|
|
49811
|
+
if (rel.startsWith("..") || import_node_path26.default.isAbsolute(rel)) {
|
|
49696
49812
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
49697
49813
|
}
|
|
49698
49814
|
return joined;
|
|
49699
49815
|
}
|
|
49700
49816
|
function ensureCwd(cwd) {
|
|
49701
49817
|
try {
|
|
49702
|
-
const stat =
|
|
49818
|
+
const stat = import_node_fs25.default.statSync(cwd);
|
|
49703
49819
|
if (!stat.isDirectory()) {
|
|
49704
49820
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
|
|
49705
49821
|
}
|
|
@@ -49713,7 +49829,7 @@ var WorkspaceBrowser = class {
|
|
|
49713
49829
|
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os8.default.homedir();
|
|
49714
49830
|
ensureCwd(cwd);
|
|
49715
49831
|
const full = resolveInsideCwd(cwd, args.path);
|
|
49716
|
-
const dirents =
|
|
49832
|
+
const dirents = import_node_fs25.default.readdirSync(full, { withFileTypes: true });
|
|
49717
49833
|
const entries = [];
|
|
49718
49834
|
for (const d of dirents) {
|
|
49719
49835
|
if (!args.showHidden && d.name.startsWith(".")) continue;
|
|
@@ -49723,7 +49839,7 @@ var WorkspaceBrowser = class {
|
|
|
49723
49839
|
mtime: ""
|
|
49724
49840
|
};
|
|
49725
49841
|
try {
|
|
49726
|
-
const st =
|
|
49842
|
+
const st = import_node_fs25.default.statSync(import_node_path26.default.join(full, d.name));
|
|
49727
49843
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
49728
49844
|
if (d.isFile()) entry.size = st.size;
|
|
49729
49845
|
} catch {
|
|
@@ -49739,14 +49855,14 @@ var WorkspaceBrowser = class {
|
|
|
49739
49855
|
read(args) {
|
|
49740
49856
|
ensureCwd(args.cwd);
|
|
49741
49857
|
const full = resolveInsideCwd(args.cwd, args.path);
|
|
49742
|
-
const st =
|
|
49858
|
+
const st = import_node_fs25.default.statSync(full);
|
|
49743
49859
|
if (!st.isFile()) {
|
|
49744
49860
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
|
|
49745
49861
|
}
|
|
49746
49862
|
if (st.size > MAX_FILE_BYTES) {
|
|
49747
49863
|
throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
|
|
49748
49864
|
}
|
|
49749
|
-
const buf =
|
|
49865
|
+
const buf = import_node_fs25.default.readFileSync(full);
|
|
49750
49866
|
const isBinary = buf.includes(0);
|
|
49751
49867
|
if (isBinary) {
|
|
49752
49868
|
return {
|
|
@@ -49768,20 +49884,20 @@ var WorkspaceBrowser = class {
|
|
|
49768
49884
|
};
|
|
49769
49885
|
|
|
49770
49886
|
// src/skills/agents-scanner.ts
|
|
49771
|
-
var
|
|
49887
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
49772
49888
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
49773
|
-
var
|
|
49889
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
49774
49890
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
49775
49891
|
function isDirLikeSync2(p2) {
|
|
49776
49892
|
try {
|
|
49777
|
-
return
|
|
49893
|
+
return import_node_fs26.default.statSync(p2).isDirectory();
|
|
49778
49894
|
} catch {
|
|
49779
49895
|
return false;
|
|
49780
49896
|
}
|
|
49781
49897
|
}
|
|
49782
49898
|
function fileExistsSync(p2) {
|
|
49783
49899
|
try {
|
|
49784
|
-
return
|
|
49900
|
+
return import_node_fs26.default.statSync(p2).isFile();
|
|
49785
49901
|
} catch {
|
|
49786
49902
|
return false;
|
|
49787
49903
|
}
|
|
@@ -49789,7 +49905,7 @@ function fileExistsSync(p2) {
|
|
|
49789
49905
|
function parseAgentFile(filePath) {
|
|
49790
49906
|
let content;
|
|
49791
49907
|
try {
|
|
49792
|
-
content =
|
|
49908
|
+
content = import_node_fs26.default.readFileSync(filePath, "utf8");
|
|
49793
49909
|
} catch {
|
|
49794
49910
|
return {};
|
|
49795
49911
|
}
|
|
@@ -49802,16 +49918,16 @@ function parseAgentFile(filePath) {
|
|
|
49802
49918
|
function scanAgentsDir(dir, source, seen, out) {
|
|
49803
49919
|
let entries;
|
|
49804
49920
|
try {
|
|
49805
|
-
entries =
|
|
49921
|
+
entries = import_node_fs26.default.readdirSync(dir, { withFileTypes: true });
|
|
49806
49922
|
} catch {
|
|
49807
49923
|
return;
|
|
49808
49924
|
}
|
|
49809
49925
|
for (const ent of entries) {
|
|
49810
49926
|
if (!ent.name.endsWith(".md")) continue;
|
|
49811
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
49927
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path27.default.join(dir, ent.name)))) {
|
|
49812
49928
|
continue;
|
|
49813
49929
|
}
|
|
49814
|
-
const filePath =
|
|
49930
|
+
const filePath = import_node_path27.default.join(dir, ent.name);
|
|
49815
49931
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
49816
49932
|
if (seen.has(baseName)) continue;
|
|
49817
49933
|
seen.add(baseName);
|
|
@@ -49829,12 +49945,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
49829
49945
|
function walk2(dir, namespaces) {
|
|
49830
49946
|
let entries;
|
|
49831
49947
|
try {
|
|
49832
|
-
entries =
|
|
49948
|
+
entries = import_node_fs26.default.readdirSync(dir, { withFileTypes: true });
|
|
49833
49949
|
} catch {
|
|
49834
49950
|
return;
|
|
49835
49951
|
}
|
|
49836
49952
|
for (const ent of entries) {
|
|
49837
|
-
const childPath =
|
|
49953
|
+
const childPath = import_node_path27.default.join(dir, ent.name);
|
|
49838
49954
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
49839
49955
|
walk2(childPath, [...namespaces, ent.name]);
|
|
49840
49956
|
continue;
|
|
@@ -49859,13 +49975,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
49859
49975
|
walk2(root, []);
|
|
49860
49976
|
}
|
|
49861
49977
|
function readInstalledPlugins2(home) {
|
|
49862
|
-
const pluginsDir =
|
|
49863
|
-
const v2 =
|
|
49864
|
-
const v1 =
|
|
49978
|
+
const pluginsDir = import_node_path27.default.join(home, ".claude", "plugins");
|
|
49979
|
+
const v2 = import_node_path27.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
49980
|
+
const v1 = import_node_path27.default.join(pluginsDir, "installed_plugins.json");
|
|
49865
49981
|
let raw = null;
|
|
49866
49982
|
for (const candidate of [v2, v1]) {
|
|
49867
49983
|
try {
|
|
49868
|
-
raw =
|
|
49984
|
+
raw = import_node_fs26.default.readFileSync(candidate, "utf8");
|
|
49869
49985
|
break;
|
|
49870
49986
|
} catch {
|
|
49871
49987
|
}
|
|
@@ -49890,19 +50006,19 @@ function readInstalledPlugins2(home) {
|
|
|
49890
50006
|
return out;
|
|
49891
50007
|
}
|
|
49892
50008
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
49893
|
-
let cur =
|
|
49894
|
-
const fsRoot =
|
|
50009
|
+
let cur = import_node_path27.default.resolve(startCwd);
|
|
50010
|
+
const fsRoot = import_node_path27.default.parse(cur).root;
|
|
49895
50011
|
while (true) {
|
|
49896
|
-
scanAgentsDir(
|
|
50012
|
+
scanAgentsDir(import_node_path27.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
49897
50013
|
let hasGit = false;
|
|
49898
50014
|
try {
|
|
49899
|
-
hasGit =
|
|
50015
|
+
hasGit = import_node_fs26.default.existsSync(import_node_path27.default.join(cur, ".git"));
|
|
49900
50016
|
} catch {
|
|
49901
50017
|
}
|
|
49902
50018
|
if (hasGit) return;
|
|
49903
50019
|
if (cur === home) return;
|
|
49904
50020
|
if (cur === fsRoot) return;
|
|
49905
|
-
const parent =
|
|
50021
|
+
const parent = import_node_path27.default.dirname(cur);
|
|
49906
50022
|
if (parent === cur) return;
|
|
49907
50023
|
cur = parent;
|
|
49908
50024
|
}
|
|
@@ -49937,7 +50053,7 @@ var AgentsScanner = class {
|
|
|
49937
50053
|
}
|
|
49938
50054
|
const fsBlock = [];
|
|
49939
50055
|
scanAgentsDir(
|
|
49940
|
-
|
|
50056
|
+
import_node_path27.default.join(this.home, ".claude", "agents"),
|
|
49941
50057
|
"global",
|
|
49942
50058
|
seen,
|
|
49943
50059
|
fsBlock
|
|
@@ -49951,7 +50067,7 @@ var AgentsScanner = class {
|
|
|
49951
50067
|
...this.extraPluginRoots
|
|
49952
50068
|
];
|
|
49953
50069
|
for (const { name, root } of plugins) {
|
|
49954
|
-
const agentsRoot =
|
|
50070
|
+
const agentsRoot = import_node_path27.default.join(root, "agents");
|
|
49955
50071
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
49956
50072
|
}
|
|
49957
50073
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -49959,15 +50075,15 @@ var AgentsScanner = class {
|
|
|
49959
50075
|
};
|
|
49960
50076
|
|
|
49961
50077
|
// src/observer/session-observer.ts
|
|
49962
|
-
var
|
|
50078
|
+
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
49963
50079
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
49964
|
-
var
|
|
50080
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
49965
50081
|
init_claude_history();
|
|
49966
50082
|
|
|
49967
50083
|
// src/observer/subagent-meta-observer.ts
|
|
49968
|
-
var
|
|
50084
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
49969
50085
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
49970
|
-
var
|
|
50086
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
49971
50087
|
init_claude_history();
|
|
49972
50088
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
49973
50089
|
var SubagentMetaObserver = class {
|
|
@@ -49980,7 +50096,7 @@ var SubagentMetaObserver = class {
|
|
|
49980
50096
|
watches = /* @__PURE__ */ new Map();
|
|
49981
50097
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
49982
50098
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
49983
|
-
return
|
|
50099
|
+
return import_node_path28.default.join(
|
|
49984
50100
|
this.home,
|
|
49985
50101
|
".claude",
|
|
49986
50102
|
"projects",
|
|
@@ -50010,7 +50126,7 @@ var SubagentMetaObserver = class {
|
|
|
50010
50126
|
attachWatcher(w2) {
|
|
50011
50127
|
if (w2.watcher) return;
|
|
50012
50128
|
try {
|
|
50013
|
-
w2.watcher =
|
|
50129
|
+
w2.watcher = import_node_fs27.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
|
|
50014
50130
|
if (!name) return;
|
|
50015
50131
|
const m2 = META_RE.exec(String(name));
|
|
50016
50132
|
if (!m2) return;
|
|
@@ -50022,7 +50138,7 @@ var SubagentMetaObserver = class {
|
|
|
50022
50138
|
scan(w2) {
|
|
50023
50139
|
let entries;
|
|
50024
50140
|
try {
|
|
50025
|
-
entries =
|
|
50141
|
+
entries = import_node_fs27.default.readdirSync(w2.dirPath);
|
|
50026
50142
|
} catch {
|
|
50027
50143
|
return;
|
|
50028
50144
|
}
|
|
@@ -50036,10 +50152,10 @@ var SubagentMetaObserver = class {
|
|
|
50036
50152
|
if (!m2) return;
|
|
50037
50153
|
const agentId = m2[1];
|
|
50038
50154
|
if (w2.emitted.has(agentId)) return;
|
|
50039
|
-
const file =
|
|
50155
|
+
const file = import_node_path28.default.join(w2.dirPath, name);
|
|
50040
50156
|
let raw;
|
|
50041
50157
|
try {
|
|
50042
|
-
raw =
|
|
50158
|
+
raw = import_node_fs27.default.readFileSync(file, "utf8");
|
|
50043
50159
|
} catch {
|
|
50044
50160
|
return;
|
|
50045
50161
|
}
|
|
@@ -50096,14 +50212,14 @@ var SessionObserver = class {
|
|
|
50096
50212
|
metaObserver;
|
|
50097
50213
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
50098
50214
|
if (override) return override;
|
|
50099
|
-
return
|
|
50215
|
+
return import_node_path29.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
50100
50216
|
}
|
|
50101
50217
|
start(args) {
|
|
50102
50218
|
this.stop(args.sessionId);
|
|
50103
50219
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
50104
50220
|
let size = 0;
|
|
50105
50221
|
try {
|
|
50106
|
-
size =
|
|
50222
|
+
size = import_node_fs28.default.statSync(filePath).size;
|
|
50107
50223
|
} catch {
|
|
50108
50224
|
}
|
|
50109
50225
|
const w2 = {
|
|
@@ -50116,16 +50232,16 @@ var SessionObserver = class {
|
|
|
50116
50232
|
adapter: args.adapter,
|
|
50117
50233
|
prevIsRejectSentinel: false,
|
|
50118
50234
|
toolSessionId: args.toolSessionId,
|
|
50119
|
-
sawFile:
|
|
50235
|
+
sawFile: import_node_fs28.default.existsSync(filePath),
|
|
50120
50236
|
lastRelocateScanMs: 0,
|
|
50121
50237
|
pendingCwdDerive: false,
|
|
50122
50238
|
lastDeriveMs: 0
|
|
50123
50239
|
};
|
|
50124
50240
|
try {
|
|
50125
|
-
|
|
50241
|
+
import_node_fs28.default.mkdirSync(import_node_path29.default.dirname(filePath), { recursive: true });
|
|
50126
50242
|
} catch {
|
|
50127
50243
|
}
|
|
50128
|
-
w2.watcher =
|
|
50244
|
+
w2.watcher = import_node_fs28.default.watch(import_node_path29.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
50129
50245
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
50130
50246
|
this.poll(w2);
|
|
50131
50247
|
});
|
|
@@ -50148,7 +50264,7 @@ var SessionObserver = class {
|
|
|
50148
50264
|
// 异常静默吞,不阻塞 watcher 启动
|
|
50149
50265
|
hydrateMetaTail(w2, maxLines = 200) {
|
|
50150
50266
|
try {
|
|
50151
|
-
const raw =
|
|
50267
|
+
const raw = import_node_fs28.default.readFileSync(w2.filePath, "utf8");
|
|
50152
50268
|
if (!raw) return;
|
|
50153
50269
|
const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
50154
50270
|
if (allLines.length === 0) return;
|
|
@@ -50172,7 +50288,7 @@ var SessionObserver = class {
|
|
|
50172
50288
|
poll(w2) {
|
|
50173
50289
|
let size = 0;
|
|
50174
50290
|
try {
|
|
50175
|
-
size =
|
|
50291
|
+
size = import_node_fs28.default.statSync(w2.filePath).size;
|
|
50176
50292
|
} catch {
|
|
50177
50293
|
if (w2.sawFile) this.maybeRelocate(w2);
|
|
50178
50294
|
return;
|
|
@@ -50183,11 +50299,11 @@ var SessionObserver = class {
|
|
|
50183
50299
|
w2.buf = "";
|
|
50184
50300
|
}
|
|
50185
50301
|
if (size === w2.lastSize) return;
|
|
50186
|
-
const fd =
|
|
50302
|
+
const fd = import_node_fs28.default.openSync(w2.filePath, "r");
|
|
50187
50303
|
try {
|
|
50188
50304
|
const len = size - w2.lastSize;
|
|
50189
50305
|
const buf = Buffer.alloc(len);
|
|
50190
|
-
|
|
50306
|
+
import_node_fs28.default.readSync(fd, buf, 0, len, w2.lastSize);
|
|
50191
50307
|
w2.lastSize = size;
|
|
50192
50308
|
w2.buf += buf.toString("utf8");
|
|
50193
50309
|
let newlineIndex;
|
|
@@ -50210,7 +50326,7 @@ var SessionObserver = class {
|
|
|
50210
50326
|
}
|
|
50211
50327
|
}
|
|
50212
50328
|
} finally {
|
|
50213
|
-
|
|
50329
|
+
import_node_fs28.default.closeSync(fd);
|
|
50214
50330
|
}
|
|
50215
50331
|
if (w2.pendingCwdDerive) this.maybeDeriveCwd(w2);
|
|
50216
50332
|
}
|
|
@@ -50222,7 +50338,7 @@ var SessionObserver = class {
|
|
|
50222
50338
|
const now = Date.now();
|
|
50223
50339
|
if (now - w2.lastRelocateScanMs < 1e3) return;
|
|
50224
50340
|
w2.lastRelocateScanMs = now;
|
|
50225
|
-
const projectsRoot =
|
|
50341
|
+
const projectsRoot = import_node_path29.default.join(this.home, ".claude", "projects");
|
|
50226
50342
|
const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
|
|
50227
50343
|
if (!found || found === w2.filePath) return;
|
|
50228
50344
|
try {
|
|
@@ -50231,7 +50347,7 @@ var SessionObserver = class {
|
|
|
50231
50347
|
}
|
|
50232
50348
|
w2.filePath = found;
|
|
50233
50349
|
try {
|
|
50234
|
-
w2.watcher =
|
|
50350
|
+
w2.watcher = import_node_fs28.default.watch(import_node_path29.default.dirname(found), { persistent: false }, (_event, changedName) => {
|
|
50235
50351
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
50236
50352
|
this.poll(w2);
|
|
50237
50353
|
});
|
|
@@ -50535,9 +50651,9 @@ var LocalWsServer = class {
|
|
|
50535
50651
|
this.safeSend(c.ws, frame);
|
|
50536
50652
|
}
|
|
50537
50653
|
}
|
|
50538
|
-
//
|
|
50539
|
-
//
|
|
50540
|
-
// guest
|
|
50654
|
+
// 仅广播给 owner 连接(跳过 guest ws)。用于 contact:added / contact:removed /
|
|
50655
|
+
// contact:pinned / friend:reverseTokenOffered / appBuilder:project-updated 等
|
|
50656
|
+
// owner-only push frame——guest 无需消费。noAuth localhost ws 无 ctx,视作 owner。
|
|
50541
50657
|
broadcastToOwners(frame) {
|
|
50542
50658
|
const gate = this.opts.authGate;
|
|
50543
50659
|
for (const c of this.clients.values()) {
|
|
@@ -50611,10 +50727,8 @@ var LocalWsServer = class {
|
|
|
50611
50727
|
}
|
|
50612
50728
|
}
|
|
50613
50729
|
}
|
|
50614
|
-
//
|
|
50615
|
-
//
|
|
50616
|
-
// capability:delete 级联用 cap.id 调本方法——noAuth 旧 per-peer cap guest 的
|
|
50617
|
-
// principal.id ≡ cap.id,级联语义不变(Phase 3 决策 #14 正名)。
|
|
50730
|
+
// 关闭某 guest principal 的所有活跃 ws 连接。close code 4401 让客户端识别
|
|
50731
|
+
// 'TOKEN_REVOKED' 而非普通断连;调用方按需触发(如 contact:remove 后要断对方现有连接)。
|
|
50618
50732
|
closeConnectionsByGuestId(guestPrincipalId, code = 4401, reason = "TOKEN_REVOKED") {
|
|
50619
50733
|
const set = this.guestIdToClients.get(guestPrincipalId);
|
|
50620
50734
|
if (!set) return;
|
|
@@ -51088,178 +51202,25 @@ async function authenticate(token, deps) {
|
|
|
51088
51202
|
};
|
|
51089
51203
|
}
|
|
51090
51204
|
|
|
51091
|
-
// src/
|
|
51092
|
-
var
|
|
51093
|
-
var
|
|
51094
|
-
var
|
|
51095
|
-
|
|
51096
|
-
|
|
51097
|
-
|
|
51098
|
-
|
|
51099
|
-
|
|
51100
|
-
this.cache = this.readFromDisk();
|
|
51101
|
-
}
|
|
51102
|
-
dataDir;
|
|
51103
|
-
cache;
|
|
51104
|
-
list() {
|
|
51105
|
-
return [...this.cache];
|
|
51106
|
-
}
|
|
51107
|
-
upsert(cap) {
|
|
51108
|
-
const idx = this.cache.findIndex((c) => c.id === cap.id);
|
|
51109
|
-
if (idx >= 0) {
|
|
51110
|
-
this.cache[idx] = cap;
|
|
51111
|
-
} else {
|
|
51112
|
-
this.cache.push(cap);
|
|
51113
|
-
}
|
|
51114
|
-
this.flush();
|
|
51115
|
-
}
|
|
51116
|
-
remove(id) {
|
|
51117
|
-
const next = this.cache.filter((c) => c.id !== id);
|
|
51118
|
-
if (next.length === this.cache.length) return;
|
|
51119
|
-
this.cache = next;
|
|
51120
|
-
this.flush();
|
|
51121
|
-
}
|
|
51122
|
-
filePath() {
|
|
51123
|
-
return path31.join(this.dataDir, CAPABILITIES_FILE_NAME);
|
|
51124
|
-
}
|
|
51125
|
-
readFromDisk() {
|
|
51126
|
-
const file = this.filePath();
|
|
51127
|
-
let raw;
|
|
51128
|
-
try {
|
|
51129
|
-
raw = fs32.readFileSync(file, "utf8");
|
|
51130
|
-
} catch (err) {
|
|
51131
|
-
if (err?.code === "ENOENT") return [];
|
|
51132
|
-
return [];
|
|
51133
|
-
}
|
|
51134
|
-
if (!raw.trim()) return [];
|
|
51135
|
-
let parsed;
|
|
51136
|
-
try {
|
|
51137
|
-
parsed = JSON.parse(raw);
|
|
51138
|
-
} catch {
|
|
51139
|
-
return [];
|
|
51140
|
-
}
|
|
51141
|
-
if (!parsed || typeof parsed !== "object") return [];
|
|
51142
|
-
const arr = parsed.capabilities;
|
|
51143
|
-
if (!Array.isArray(arr)) return [];
|
|
51144
|
-
const out = [];
|
|
51145
|
-
for (const item of arr) {
|
|
51146
|
-
const r = CapabilitySchema.safeParse(item);
|
|
51147
|
-
if (r.success) out.push(r.data);
|
|
51148
|
-
}
|
|
51149
|
-
return out;
|
|
51150
|
-
}
|
|
51151
|
-
flush() {
|
|
51152
|
-
const content = { version: FILE_VERSION, capabilities: this.cache };
|
|
51153
|
-
this.atomicWrite(this.filePath(), JSON.stringify(content, null, 2));
|
|
51154
|
-
}
|
|
51155
|
-
atomicWrite(file, content) {
|
|
51156
|
-
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
51157
|
-
fs32.writeFileSync(tmp, content, { mode: 384 });
|
|
51158
|
-
fs32.renameSync(tmp, file);
|
|
51159
|
-
try {
|
|
51160
|
-
fs32.chmodSync(file, 384);
|
|
51161
|
-
} catch {
|
|
51162
|
-
}
|
|
51163
|
-
}
|
|
51164
|
-
};
|
|
51165
|
-
|
|
51166
|
-
// src/permission/capability-registry.ts
|
|
51167
|
-
var crypto5 = __toESM(require("crypto"), 1);
|
|
51168
|
-
var CapabilityRegistry = class {
|
|
51169
|
-
constructor(store, now = () => Date.now()) {
|
|
51170
|
-
this.store = store;
|
|
51171
|
-
this.now = now;
|
|
51172
|
-
for (const cap of store.list()) {
|
|
51173
|
-
this.bySecretHash.set(cap.secretHash, cap);
|
|
51174
|
-
}
|
|
51175
|
-
}
|
|
51176
|
-
store;
|
|
51177
|
-
now;
|
|
51178
|
-
// sha256(token) → Capability
|
|
51179
|
-
bySecretHash = /* @__PURE__ */ new Map();
|
|
51180
|
-
list() {
|
|
51181
|
-
return this.store.list();
|
|
51182
|
-
}
|
|
51183
|
-
verifyToken(token) {
|
|
51184
|
-
if (!token) return { ok: false, code: "TOKEN_INVALID" };
|
|
51185
|
-
const hash = sha256Hex(token);
|
|
51186
|
-
const cap = this.bySecretHash.get(hash);
|
|
51187
|
-
if (!cap) return { ok: false, code: "TOKEN_INVALID" };
|
|
51188
|
-
if (cap.expiresAt && this.now() >= cap.expiresAt) {
|
|
51189
|
-
return { ok: false, code: "TOKEN_EXPIRED" };
|
|
51190
|
-
}
|
|
51191
|
-
if (cap.maxUses && cap.usedCount >= cap.maxUses) {
|
|
51192
|
-
return { ok: false, code: "TOKEN_EXHAUSTED" };
|
|
51193
|
-
}
|
|
51194
|
-
const updated = { ...cap, usedCount: cap.usedCount + 1 };
|
|
51195
|
-
this.bySecretHash.set(hash, updated);
|
|
51196
|
-
this.store.upsert(updated);
|
|
51197
|
-
return { ok: true, capability: updated };
|
|
51198
|
-
}
|
|
51199
|
-
upsertCapability(cap) {
|
|
51200
|
-
this.bySecretHash.set(cap.secretHash, cap);
|
|
51201
|
-
this.store.upsert(cap);
|
|
51202
|
-
}
|
|
51203
|
-
/**
|
|
51204
|
-
* Hard delete:从 store 物理移除 + 从 Map 清掉 secretHash 索引。
|
|
51205
|
-
* 后续 verifyToken 该 token 走 'TOKEN_INVALID' 分支(secretHash 已不在 Map)。
|
|
51206
|
-
* idempotent:不存在 → null。
|
|
51207
|
-
*/
|
|
51208
|
-
delete(id) {
|
|
51209
|
-
const current = this.store.list().find((c) => c.id === id);
|
|
51210
|
-
if (!current) return null;
|
|
51211
|
-
this.bySecretHash.delete(current.secretHash);
|
|
51212
|
-
this.store.remove(id);
|
|
51213
|
-
return current;
|
|
51214
|
-
}
|
|
51215
|
-
findById(id) {
|
|
51216
|
-
return this.store.list().find((c) => c.id === id) ?? null;
|
|
51217
|
-
}
|
|
51218
|
-
};
|
|
51219
|
-
function sha256Hex(s) {
|
|
51220
|
-
return crypto5.createHash("sha256").update(s).digest("hex");
|
|
51221
|
-
}
|
|
51222
|
-
|
|
51223
|
-
// src/permission/capability-manager.ts
|
|
51224
|
-
var CapabilityManager = class {
|
|
51225
|
-
constructor(registry2, hooks = {}) {
|
|
51226
|
-
this.registry = registry2;
|
|
51227
|
-
this.hooks = hooks;
|
|
51228
|
-
}
|
|
51229
|
-
registry;
|
|
51230
|
-
hooks;
|
|
51231
|
-
list() {
|
|
51232
|
-
return this.registry.list();
|
|
51233
|
-
}
|
|
51234
|
-
// 调试 / 旧 per-peer cap 反查用(Phase 3 决策 #14 后无生产调用方,保留属三件套范围)。
|
|
51235
|
-
// 返回 Capability 持久化形态;调用方需 stripSecretHash 后再上 wire。
|
|
51236
|
-
findById(id) {
|
|
51237
|
-
return this.registry.findById(id);
|
|
51238
|
-
}
|
|
51239
|
-
/**
|
|
51240
|
-
* Hard delete:从 registry / store 物理移除 capability。
|
|
51241
|
-
* idempotent:不存在 → null(handler 翻译成 VALIDATION_ERROR)
|
|
51242
|
-
* onDeleted hook 在 daemon/index.ts wire 负责 close 连接 + cleanup 文件 + 广播
|
|
51243
|
-
*/
|
|
51244
|
-
delete(id) {
|
|
51245
|
-
const removed = this.registry.delete(id);
|
|
51246
|
-
if (!removed) return null;
|
|
51247
|
-
this.hooks.onDeleted?.(removed);
|
|
51248
|
-
return { capability: removed };
|
|
51249
|
-
}
|
|
51250
|
-
};
|
|
51251
|
-
|
|
51252
|
-
// src/permission/cleanup.ts
|
|
51253
|
-
var fs33 = __toESM(require("fs"), 1);
|
|
51254
|
-
function cleanupGuestSessionsForCapability(cap, factory) {
|
|
51205
|
+
// src/legacy-cleanup.ts
|
|
51206
|
+
var fs33 = __toESM(require("fs/promises"), 1);
|
|
51207
|
+
var path34 = __toESM(require("path"), 1);
|
|
51208
|
+
var LEGACY_FILES = [
|
|
51209
|
+
"personal-capability.json",
|
|
51210
|
+
"received-capabilities.json",
|
|
51211
|
+
"capabilities.json"
|
|
51212
|
+
];
|
|
51213
|
+
async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
51255
51214
|
const removed = [];
|
|
51256
|
-
for (const
|
|
51257
|
-
|
|
51258
|
-
const dir = factory.vmGuestRoot(g2.resource.id, cap.id);
|
|
51215
|
+
for (const name of LEGACY_FILES) {
|
|
51216
|
+
const p2 = path34.join(dataDir, name);
|
|
51259
51217
|
try {
|
|
51260
|
-
fs33.
|
|
51261
|
-
removed.push(
|
|
51262
|
-
|
|
51218
|
+
await fs33.unlink(p2);
|
|
51219
|
+
removed.push(name);
|
|
51220
|
+
logger.debug("legacy capability file removed", { file: name });
|
|
51221
|
+
} catch (err) {
|
|
51222
|
+
if (err?.code === "ENOENT") continue;
|
|
51223
|
+
throw err;
|
|
51263
51224
|
}
|
|
51264
51225
|
}
|
|
51265
51226
|
return { removed };
|
|
@@ -51267,7 +51228,7 @@ function cleanupGuestSessionsForCapability(cap, factory) {
|
|
|
51267
51228
|
|
|
51268
51229
|
// src/inbox/inbox-store.ts
|
|
51269
51230
|
var fs34 = __toESM(require("fs"), 1);
|
|
51270
|
-
var
|
|
51231
|
+
var path35 = __toESM(require("path"), 1);
|
|
51271
51232
|
var INBOX_SUBDIR = "inbox";
|
|
51272
51233
|
var InboxStore = class {
|
|
51273
51234
|
constructor(dataDir) {
|
|
@@ -51365,10 +51326,10 @@ var InboxStore = class {
|
|
|
51365
51326
|
}
|
|
51366
51327
|
}
|
|
51367
51328
|
dirPath() {
|
|
51368
|
-
return
|
|
51329
|
+
return path35.join(this.dataDir, INBOX_SUBDIR);
|
|
51369
51330
|
}
|
|
51370
51331
|
filePath(peerDeviceId) {
|
|
51371
|
-
return
|
|
51332
|
+
return path35.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
51372
51333
|
}
|
|
51373
51334
|
};
|
|
51374
51335
|
function parseAllLines(raw) {
|
|
@@ -51457,7 +51418,7 @@ var InboxManager = class {
|
|
|
51457
51418
|
|
|
51458
51419
|
// src/state/contact-store.ts
|
|
51459
51420
|
var fs35 = __toESM(require("fs"), 1);
|
|
51460
|
-
var
|
|
51421
|
+
var path36 = __toESM(require("path"), 1);
|
|
51461
51422
|
var FILE_NAME = "contacts.json";
|
|
51462
51423
|
var ContactStore = class {
|
|
51463
51424
|
constructor(dataDir) {
|
|
@@ -51467,7 +51428,7 @@ var ContactStore = class {
|
|
|
51467
51428
|
contacts = /* @__PURE__ */ new Map();
|
|
51468
51429
|
load() {
|
|
51469
51430
|
this.contacts.clear();
|
|
51470
|
-
const file =
|
|
51431
|
+
const file = path36.join(this.dataDir, FILE_NAME);
|
|
51471
51432
|
let raw;
|
|
51472
51433
|
try {
|
|
51473
51434
|
raw = fs35.readFileSync(file, "utf8");
|
|
@@ -51539,7 +51500,7 @@ var ContactStore = class {
|
|
|
51539
51500
|
return true;
|
|
51540
51501
|
}
|
|
51541
51502
|
flush() {
|
|
51542
|
-
const file =
|
|
51503
|
+
const file = path36.join(this.dataDir, FILE_NAME);
|
|
51543
51504
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
51544
51505
|
const content = JSON.stringify(
|
|
51545
51506
|
{ contacts: Array.from(this.contacts.values()) },
|
|
@@ -51559,7 +51520,7 @@ var ContactStore = class {
|
|
|
51559
51520
|
};
|
|
51560
51521
|
|
|
51561
51522
|
// src/contact/connect-remote.ts
|
|
51562
|
-
var
|
|
51523
|
+
var crypto5 = __toESM(require("crypto"), 1);
|
|
51563
51524
|
var HANDSHAKE_TIMEOUT_MS = 5e3;
|
|
51564
51525
|
var RPC_TIMEOUT_MS = 5e3;
|
|
51565
51526
|
async function connectRemote(args) {
|
|
@@ -51623,7 +51584,7 @@ async function connectRemote(args) {
|
|
|
51623
51584
|
ws.once("close", onClose);
|
|
51624
51585
|
});
|
|
51625
51586
|
function call(method, payload) {
|
|
51626
|
-
const requestId =
|
|
51587
|
+
const requestId = crypto5.randomUUID();
|
|
51627
51588
|
return new Promise((resolve6, reject) => {
|
|
51628
51589
|
const onMessage = (raw) => {
|
|
51629
51590
|
let f;
|
|
@@ -51706,52 +51667,52 @@ async function autoReverseContact(args) {
|
|
|
51706
51667
|
|
|
51707
51668
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
51708
51669
|
var fs36 = __toESM(require("fs"), 1);
|
|
51709
|
-
var
|
|
51670
|
+
var path37 = __toESM(require("path"), 1);
|
|
51710
51671
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
51711
51672
|
function migrateFlattenSessions(opts) {
|
|
51712
51673
|
const dataDir = opts.dataDir;
|
|
51713
51674
|
const now = opts.now ?? Date.now;
|
|
51714
|
-
const sessionsDir =
|
|
51715
|
-
const flagPath =
|
|
51675
|
+
const sessionsDir = path37.join(dataDir, "sessions");
|
|
51676
|
+
const flagPath = path37.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
51716
51677
|
if (existsSync3(flagPath)) {
|
|
51717
51678
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
51718
51679
|
}
|
|
51719
51680
|
let movedBare = 0;
|
|
51720
51681
|
let movedVmOwner = 0;
|
|
51721
51682
|
let archivedListener = 0;
|
|
51722
|
-
const defaultDir =
|
|
51683
|
+
const defaultDir = path37.join(sessionsDir, "default");
|
|
51723
51684
|
if (existsSync3(defaultDir)) {
|
|
51724
51685
|
for (const entry of readdirSafe(defaultDir)) {
|
|
51725
51686
|
if (!entry.endsWith(".json")) continue;
|
|
51726
|
-
const src =
|
|
51727
|
-
const dst =
|
|
51687
|
+
const src = path37.join(defaultDir, entry);
|
|
51688
|
+
const dst = path37.join(sessionsDir, entry);
|
|
51728
51689
|
fs36.renameSync(src, dst);
|
|
51729
51690
|
movedBare += 1;
|
|
51730
51691
|
}
|
|
51731
51692
|
rmdirIfEmpty(defaultDir);
|
|
51732
51693
|
}
|
|
51733
51694
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
51734
|
-
const personaDir =
|
|
51695
|
+
const personaDir = path37.join(sessionsDir, pid);
|
|
51735
51696
|
if (!isDir(personaDir)) continue;
|
|
51736
51697
|
if (pid === "default") continue;
|
|
51737
|
-
const ownerSrc =
|
|
51698
|
+
const ownerSrc = path37.join(personaDir, "owner");
|
|
51738
51699
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
51739
|
-
const ownerDst =
|
|
51700
|
+
const ownerDst = path37.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
51740
51701
|
fs36.mkdirSync(ownerDst, { recursive: true });
|
|
51741
51702
|
for (const file of readdirSafe(ownerSrc)) {
|
|
51742
51703
|
if (!file.endsWith(".json")) continue;
|
|
51743
|
-
fs36.renameSync(
|
|
51704
|
+
fs36.renameSync(path37.join(ownerSrc, file), path37.join(ownerDst, file));
|
|
51744
51705
|
movedVmOwner += 1;
|
|
51745
51706
|
}
|
|
51746
51707
|
rmdirIfEmpty(ownerSrc);
|
|
51747
51708
|
}
|
|
51748
|
-
const listenerSrc =
|
|
51709
|
+
const listenerSrc = path37.join(personaDir, "listener");
|
|
51749
51710
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
51750
|
-
const archiveDst =
|
|
51711
|
+
const archiveDst = path37.join(dataDir, ".legacy", `listener-${pid}`);
|
|
51751
51712
|
fs36.mkdirSync(archiveDst, { recursive: true });
|
|
51752
51713
|
for (const file of readdirSafe(listenerSrc)) {
|
|
51753
51714
|
if (!file.endsWith(".json")) continue;
|
|
51754
|
-
fs36.renameSync(
|
|
51715
|
+
fs36.renameSync(path37.join(listenerSrc, file), path37.join(archiveDst, file));
|
|
51755
51716
|
archivedListener += 1;
|
|
51756
51717
|
}
|
|
51757
51718
|
rmdirIfEmpty(listenerSrc);
|
|
@@ -51798,11 +51759,11 @@ function rmdirIfEmpty(p2) {
|
|
|
51798
51759
|
}
|
|
51799
51760
|
|
|
51800
51761
|
// src/transport/http-router.ts
|
|
51801
|
-
var
|
|
51802
|
-
var
|
|
51762
|
+
var import_node_fs30 = __toESM(require("fs"), 1);
|
|
51763
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
51803
51764
|
|
|
51804
51765
|
// src/attachment/mime.ts
|
|
51805
|
-
var
|
|
51766
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
51806
51767
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
51807
51768
|
var EXT_TO_NATIVE_MIME = {
|
|
51808
51769
|
// 图片
|
|
@@ -51909,7 +51870,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
51909
51870
|
".mk"
|
|
51910
51871
|
]);
|
|
51911
51872
|
function lookupMime(filePathOrName) {
|
|
51912
|
-
const ext =
|
|
51873
|
+
const ext = import_node_path30.default.extname(filePathOrName).toLowerCase();
|
|
51913
51874
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
51914
51875
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
51915
51876
|
return "application/octet-stream";
|
|
@@ -51978,8 +51939,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
51978
51939
|
}
|
|
51979
51940
|
|
|
51980
51941
|
// src/attachment/upload.ts
|
|
51981
|
-
var
|
|
51982
|
-
var
|
|
51942
|
+
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
51943
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
51983
51944
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
51984
51945
|
var import_promises3 = require("stream/promises");
|
|
51985
51946
|
var UploadError = class extends Error {
|
|
@@ -51991,22 +51952,22 @@ var UploadError = class extends Error {
|
|
|
51991
51952
|
code;
|
|
51992
51953
|
};
|
|
51993
51954
|
function assertValidFileName(fileName) {
|
|
51994
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
51955
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path31.default.basename(fileName)) {
|
|
51995
51956
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
51996
51957
|
}
|
|
51997
51958
|
}
|
|
51998
51959
|
var HASH_PREFIX_LEN = 16;
|
|
51999
51960
|
async function writeUploadedAttachment(args) {
|
|
52000
51961
|
assertValidFileName(args.fileName);
|
|
52001
|
-
const attachmentsRoot =
|
|
51962
|
+
const attachmentsRoot = import_node_path31.default.join(args.sessionDir, ".attachments");
|
|
52002
51963
|
try {
|
|
52003
|
-
|
|
51964
|
+
import_node_fs29.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
52004
51965
|
} catch (err) {
|
|
52005
51966
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
52006
51967
|
}
|
|
52007
51968
|
const hasher = import_node_crypto8.default.createHash("sha256");
|
|
52008
51969
|
let actualSize = 0;
|
|
52009
|
-
const tmpPath =
|
|
51970
|
+
const tmpPath = import_node_path31.default.join(
|
|
52010
51971
|
attachmentsRoot,
|
|
52011
51972
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
|
|
52012
51973
|
);
|
|
@@ -52021,18 +51982,18 @@ async function writeUploadedAttachment(args) {
|
|
|
52021
51982
|
yield buf;
|
|
52022
51983
|
}
|
|
52023
51984
|
},
|
|
52024
|
-
|
|
51985
|
+
import_node_fs29.default.createWriteStream(tmpPath, { mode: 384 })
|
|
52025
51986
|
);
|
|
52026
51987
|
} catch (err) {
|
|
52027
51988
|
try {
|
|
52028
|
-
|
|
51989
|
+
import_node_fs29.default.unlinkSync(tmpPath);
|
|
52029
51990
|
} catch {
|
|
52030
51991
|
}
|
|
52031
51992
|
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
52032
51993
|
}
|
|
52033
51994
|
if (actualSize !== args.contentLength) {
|
|
52034
51995
|
try {
|
|
52035
|
-
|
|
51996
|
+
import_node_fs29.default.unlinkSync(tmpPath);
|
|
52036
51997
|
} catch {
|
|
52037
51998
|
}
|
|
52038
51999
|
throw new UploadError(
|
|
@@ -52041,35 +52002,35 @@ async function writeUploadedAttachment(args) {
|
|
|
52041
52002
|
);
|
|
52042
52003
|
}
|
|
52043
52004
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
52044
|
-
const hashDir =
|
|
52005
|
+
const hashDir = import_node_path31.default.join(attachmentsRoot, attachmentId);
|
|
52045
52006
|
let finalFileName;
|
|
52046
52007
|
let hashDirExists = false;
|
|
52047
52008
|
try {
|
|
52048
|
-
hashDirExists =
|
|
52009
|
+
hashDirExists = import_node_fs29.default.statSync(hashDir).isDirectory();
|
|
52049
52010
|
} catch {
|
|
52050
52011
|
}
|
|
52051
52012
|
if (hashDirExists) {
|
|
52052
|
-
const existing =
|
|
52013
|
+
const existing = import_node_fs29.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
|
|
52053
52014
|
finalFileName = existing[0] ?? args.fileName;
|
|
52054
52015
|
try {
|
|
52055
|
-
|
|
52016
|
+
import_node_fs29.default.unlinkSync(tmpPath);
|
|
52056
52017
|
} catch {
|
|
52057
52018
|
}
|
|
52058
52019
|
} else {
|
|
52059
52020
|
try {
|
|
52060
|
-
|
|
52021
|
+
import_node_fs29.default.mkdirSync(hashDir, { recursive: true });
|
|
52061
52022
|
finalFileName = args.fileName;
|
|
52062
|
-
|
|
52023
|
+
import_node_fs29.default.renameSync(tmpPath, import_node_path31.default.join(hashDir, finalFileName));
|
|
52063
52024
|
} catch (err) {
|
|
52064
52025
|
try {
|
|
52065
|
-
|
|
52026
|
+
import_node_fs29.default.unlinkSync(tmpPath);
|
|
52066
52027
|
} catch {
|
|
52067
52028
|
}
|
|
52068
52029
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
52069
52030
|
}
|
|
52070
52031
|
}
|
|
52071
|
-
const absPath =
|
|
52072
|
-
const relPath =
|
|
52032
|
+
const absPath = import_node_path31.default.join(hashDir, finalFileName);
|
|
52033
|
+
const relPath = import_node_path31.default.relative(args.sessionDir, absPath);
|
|
52073
52034
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
52074
52035
|
relPath: absPath,
|
|
52075
52036
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -52083,7 +52044,7 @@ async function writeUploadedAttachment(args) {
|
|
|
52083
52044
|
|
|
52084
52045
|
// src/extension/import.ts
|
|
52085
52046
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
52086
|
-
var
|
|
52047
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
52087
52048
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
52088
52049
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
52089
52050
|
var ImportError = class extends Error {
|
|
@@ -52101,7 +52062,7 @@ async function importZip(buf, root) {
|
|
|
52101
52062
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
52102
52063
|
}
|
|
52103
52064
|
for (const name of Object.keys(zip.files)) {
|
|
52104
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
52065
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path32.default.isAbsolute(name)) {
|
|
52105
52066
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
52106
52067
|
}
|
|
52107
52068
|
}
|
|
@@ -52134,7 +52095,7 @@ async function importZip(buf, root) {
|
|
|
52134
52095
|
);
|
|
52135
52096
|
}
|
|
52136
52097
|
}
|
|
52137
|
-
const destDir =
|
|
52098
|
+
const destDir = import_node_path32.default.join(root, manifest.id);
|
|
52138
52099
|
let destExists = false;
|
|
52139
52100
|
try {
|
|
52140
52101
|
await import_promises4.default.access(destDir);
|
|
@@ -52144,15 +52105,15 @@ async function importZip(buf, root) {
|
|
|
52144
52105
|
if (destExists) {
|
|
52145
52106
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
52146
52107
|
}
|
|
52147
|
-
const stage = await import_promises4.default.mkdtemp(
|
|
52108
|
+
const stage = await import_promises4.default.mkdtemp(import_node_path32.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
52148
52109
|
try {
|
|
52149
52110
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
52150
|
-
const dest =
|
|
52111
|
+
const dest = import_node_path32.default.join(stage, name);
|
|
52151
52112
|
if (entry.dir) {
|
|
52152
52113
|
await import_promises4.default.mkdir(dest, { recursive: true });
|
|
52153
52114
|
continue;
|
|
52154
52115
|
}
|
|
52155
|
-
await import_promises4.default.mkdir(
|
|
52116
|
+
await import_promises4.default.mkdir(import_node_path32.default.dirname(dest), { recursive: true });
|
|
52156
52117
|
const content = await entry.async("nodebuffer");
|
|
52157
52118
|
await import_promises4.default.writeFile(dest, content);
|
|
52158
52119
|
}
|
|
@@ -52183,7 +52144,7 @@ var SHARE_UI_ASSET_MIME = {
|
|
|
52183
52144
|
".wasm": "application/wasm"
|
|
52184
52145
|
};
|
|
52185
52146
|
function shareUiAssetMime(filePath) {
|
|
52186
|
-
const ext =
|
|
52147
|
+
const ext = import_node_path33.default.extname(filePath).toLowerCase();
|
|
52187
52148
|
return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
|
|
52188
52149
|
}
|
|
52189
52150
|
var DISPATCH_HEARTBEAT_MS = 25e3;
|
|
@@ -52270,7 +52231,7 @@ function isValidUploadFileName(fileName) {
|
|
|
52270
52231
|
if (fileName === "." || fileName === "..") return false;
|
|
52271
52232
|
if (fileName.startsWith(".")) return false;
|
|
52272
52233
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
52273
|
-
return fileName ===
|
|
52234
|
+
return fileName === import_node_path33.default.basename(fileName);
|
|
52274
52235
|
}
|
|
52275
52236
|
function createHttpRouter(deps) {
|
|
52276
52237
|
return async (req, res) => {
|
|
@@ -52342,7 +52303,7 @@ function createHttpRouter(deps) {
|
|
|
52342
52303
|
}
|
|
52343
52304
|
let buf;
|
|
52344
52305
|
try {
|
|
52345
|
-
buf = await
|
|
52306
|
+
buf = await import_node_fs30.default.promises.readFile(abs);
|
|
52346
52307
|
} catch {
|
|
52347
52308
|
sendJson(res, 404, { code: "NOT_FOUND", message: "asset not found" });
|
|
52348
52309
|
return true;
|
|
@@ -52566,7 +52527,7 @@ function createHttpRouter(deps) {
|
|
|
52566
52527
|
sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
|
|
52567
52528
|
return true;
|
|
52568
52529
|
}
|
|
52569
|
-
sendHtml(res, 200, loader.renderViewerHtml(
|
|
52530
|
+
sendHtml(res, 200, loader.renderViewerHtml(import_node_path33.default.basename(r.absPath)));
|
|
52570
52531
|
return true;
|
|
52571
52532
|
}
|
|
52572
52533
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
@@ -52687,7 +52648,7 @@ function createHttpRouter(deps) {
|
|
|
52687
52648
|
return true;
|
|
52688
52649
|
}
|
|
52689
52650
|
let absPath;
|
|
52690
|
-
if (
|
|
52651
|
+
if (import_node_path33.default.isAbsolute(pathParam)) {
|
|
52691
52652
|
absPath = pathParam;
|
|
52692
52653
|
} else if (deps.sessionStore) {
|
|
52693
52654
|
const file = deps.sessionStore.read(sid);
|
|
@@ -52695,7 +52656,7 @@ function createHttpRouter(deps) {
|
|
|
52695
52656
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
52696
52657
|
return true;
|
|
52697
52658
|
}
|
|
52698
|
-
absPath =
|
|
52659
|
+
absPath = import_node_path33.default.join(file.cwd, pathParam);
|
|
52699
52660
|
} else {
|
|
52700
52661
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
52701
52662
|
return true;
|
|
@@ -52782,7 +52743,7 @@ function withCtx(ctx, body) {
|
|
|
52782
52743
|
function streamFile(res, absPath, logger) {
|
|
52783
52744
|
let stat;
|
|
52784
52745
|
try {
|
|
52785
|
-
stat =
|
|
52746
|
+
stat = import_node_fs30.default.statSync(absPath);
|
|
52786
52747
|
} catch (err) {
|
|
52787
52748
|
const code = err?.code;
|
|
52788
52749
|
if (code === "ENOENT") {
|
|
@@ -52797,7 +52758,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52797
52758
|
return;
|
|
52798
52759
|
}
|
|
52799
52760
|
const mime = lookupMime(absPath);
|
|
52800
|
-
const basename =
|
|
52761
|
+
const basename = import_node_path33.default.basename(absPath);
|
|
52801
52762
|
res.writeHead(200, {
|
|
52802
52763
|
"Content-Type": mime,
|
|
52803
52764
|
"Content-Length": String(stat.size),
|
|
@@ -52805,7 +52766,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52805
52766
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
52806
52767
|
"X-Content-Type-Options": "nosniff"
|
|
52807
52768
|
});
|
|
52808
|
-
const stream =
|
|
52769
|
+
const stream = import_node_fs30.default.createReadStream(absPath);
|
|
52809
52770
|
stream.on("error", (err) => {
|
|
52810
52771
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
52811
52772
|
res.destroy();
|
|
@@ -52814,8 +52775,8 @@ function streamFile(res, absPath, logger) {
|
|
|
52814
52775
|
}
|
|
52815
52776
|
|
|
52816
52777
|
// src/attachment/gc.ts
|
|
52817
|
-
var
|
|
52818
|
-
var
|
|
52778
|
+
var import_node_fs31 = __toESM(require("fs"), 1);
|
|
52779
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
52819
52780
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
52820
52781
|
function runAttachmentGc(args) {
|
|
52821
52782
|
const now = (args.now ?? Date.now)();
|
|
@@ -52824,38 +52785,38 @@ function runAttachmentGc(args) {
|
|
|
52824
52785
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52825
52786
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
52826
52787
|
if (entry.stale) continue;
|
|
52827
|
-
if (
|
|
52788
|
+
if (import_node_path34.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
52828
52789
|
}
|
|
52829
52790
|
}
|
|
52830
52791
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52831
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
52792
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path34.default.join(
|
|
52832
52793
|
args.dataDir,
|
|
52833
52794
|
"sessions",
|
|
52834
52795
|
...scopeSubPath(scope).map(safeFileName),
|
|
52835
52796
|
safeFileName(sessionId)
|
|
52836
52797
|
);
|
|
52837
|
-
const attRoot =
|
|
52798
|
+
const attRoot = import_node_path34.default.join(sessionDir, ".attachments");
|
|
52838
52799
|
let hashDirs;
|
|
52839
52800
|
try {
|
|
52840
|
-
hashDirs =
|
|
52801
|
+
hashDirs = import_node_fs31.default.readdirSync(attRoot);
|
|
52841
52802
|
} catch (err) {
|
|
52842
52803
|
if (err.code === "ENOENT") continue;
|
|
52843
52804
|
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
52844
52805
|
continue;
|
|
52845
52806
|
}
|
|
52846
52807
|
for (const hashDir of hashDirs) {
|
|
52847
|
-
const hashDirAbs =
|
|
52808
|
+
const hashDirAbs = import_node_path34.default.join(attRoot, hashDir);
|
|
52848
52809
|
let files;
|
|
52849
52810
|
try {
|
|
52850
|
-
files =
|
|
52811
|
+
files = import_node_fs31.default.readdirSync(hashDirAbs);
|
|
52851
52812
|
} catch {
|
|
52852
52813
|
continue;
|
|
52853
52814
|
}
|
|
52854
52815
|
for (const name of files) {
|
|
52855
|
-
const file =
|
|
52816
|
+
const file = import_node_path34.default.join(hashDirAbs, name);
|
|
52856
52817
|
let stat;
|
|
52857
52818
|
try {
|
|
52858
|
-
stat =
|
|
52819
|
+
stat = import_node_fs31.default.statSync(file);
|
|
52859
52820
|
} catch {
|
|
52860
52821
|
continue;
|
|
52861
52822
|
}
|
|
@@ -52864,26 +52825,26 @@ function runAttachmentGc(args) {
|
|
|
52864
52825
|
if (age < ttlMs) continue;
|
|
52865
52826
|
if (liveAbs.has(file)) continue;
|
|
52866
52827
|
try {
|
|
52867
|
-
|
|
52828
|
+
import_node_fs31.default.unlinkSync(file);
|
|
52868
52829
|
} catch (err) {
|
|
52869
52830
|
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
52870
52831
|
}
|
|
52871
52832
|
}
|
|
52872
52833
|
try {
|
|
52873
|
-
if (
|
|
52834
|
+
if (import_node_fs31.default.readdirSync(hashDirAbs).length === 0) import_node_fs31.default.rmdirSync(hashDirAbs);
|
|
52874
52835
|
} catch {
|
|
52875
52836
|
}
|
|
52876
52837
|
}
|
|
52877
52838
|
try {
|
|
52878
|
-
if (
|
|
52839
|
+
if (import_node_fs31.default.readdirSync(attRoot).length === 0) import_node_fs31.default.rmdirSync(attRoot);
|
|
52879
52840
|
} catch {
|
|
52880
52841
|
}
|
|
52881
52842
|
}
|
|
52882
52843
|
}
|
|
52883
52844
|
|
|
52884
52845
|
// src/attachment/group.ts
|
|
52885
|
-
var
|
|
52886
|
-
var
|
|
52846
|
+
var import_node_fs32 = __toESM(require("fs"), 1);
|
|
52847
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
52887
52848
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
52888
52849
|
init_protocol();
|
|
52889
52850
|
var GroupFileStore = class {
|
|
@@ -52895,11 +52856,11 @@ var GroupFileStore = class {
|
|
|
52895
52856
|
this.logger = opts.logger;
|
|
52896
52857
|
}
|
|
52897
52858
|
rootForScope(scope) {
|
|
52898
|
-
return
|
|
52859
|
+
return import_node_path35.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
52899
52860
|
}
|
|
52900
52861
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
52901
52862
|
filePath(scope, sessionId) {
|
|
52902
|
-
return
|
|
52863
|
+
return import_node_path35.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
52903
52864
|
}
|
|
52904
52865
|
cacheKey(scope, sessionId) {
|
|
52905
52866
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -52908,7 +52869,7 @@ var GroupFileStore = class {
|
|
|
52908
52869
|
readFile(scope, sessionId) {
|
|
52909
52870
|
const file = this.filePath(scope, sessionId);
|
|
52910
52871
|
try {
|
|
52911
|
-
const raw =
|
|
52872
|
+
const raw = import_node_fs32.default.readFileSync(file, "utf8");
|
|
52912
52873
|
const parsed = JSON.parse(raw);
|
|
52913
52874
|
if (!Array.isArray(parsed)) {
|
|
52914
52875
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -52934,10 +52895,10 @@ var GroupFileStore = class {
|
|
|
52934
52895
|
}
|
|
52935
52896
|
writeFile(scope, sessionId, entries) {
|
|
52936
52897
|
const file = this.filePath(scope, sessionId);
|
|
52937
|
-
|
|
52898
|
+
import_node_fs32.default.mkdirSync(import_node_path35.default.dirname(file), { recursive: true });
|
|
52938
52899
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
52939
|
-
|
|
52940
|
-
|
|
52900
|
+
import_node_fs32.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
52901
|
+
import_node_fs32.default.renameSync(tmp, file);
|
|
52941
52902
|
}
|
|
52942
52903
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
52943
52904
|
list(scope, sessionId) {
|
|
@@ -53023,10 +52984,10 @@ var GroupFileStore = class {
|
|
|
53023
52984
|
};
|
|
53024
52985
|
|
|
53025
52986
|
// src/discovery/state-file.ts
|
|
53026
|
-
var
|
|
53027
|
-
var
|
|
52987
|
+
var import_node_fs33 = __toESM(require("fs"), 1);
|
|
52988
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
53028
52989
|
function defaultStateFilePath(dataDir) {
|
|
53029
|
-
return
|
|
52990
|
+
return import_node_path36.default.join(dataDir, "state.json");
|
|
53030
52991
|
}
|
|
53031
52992
|
function isPidAlive(pid) {
|
|
53032
52993
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -53048,7 +53009,7 @@ var StateFileManager = class {
|
|
|
53048
53009
|
}
|
|
53049
53010
|
read() {
|
|
53050
53011
|
try {
|
|
53051
|
-
const raw =
|
|
53012
|
+
const raw = import_node_fs33.default.readFileSync(this.file, "utf8");
|
|
53052
53013
|
const parsed = JSON.parse(raw);
|
|
53053
53014
|
return parsed;
|
|
53054
53015
|
} catch {
|
|
@@ -53062,20 +53023,20 @@ var StateFileManager = class {
|
|
|
53062
53023
|
return { status: "stale", existing };
|
|
53063
53024
|
}
|
|
53064
53025
|
write(state) {
|
|
53065
|
-
|
|
53026
|
+
import_node_fs33.default.mkdirSync(import_node_path36.default.dirname(this.file), { recursive: true });
|
|
53066
53027
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
53067
|
-
|
|
53068
|
-
|
|
53028
|
+
import_node_fs33.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
53029
|
+
import_node_fs33.default.renameSync(tmp, this.file);
|
|
53069
53030
|
if (process.platform !== "win32") {
|
|
53070
53031
|
try {
|
|
53071
|
-
|
|
53032
|
+
import_node_fs33.default.chmodSync(this.file, 384);
|
|
53072
53033
|
} catch {
|
|
53073
53034
|
}
|
|
53074
53035
|
}
|
|
53075
53036
|
}
|
|
53076
53037
|
delete() {
|
|
53077
53038
|
try {
|
|
53078
|
-
|
|
53039
|
+
import_node_fs33.default.unlinkSync(this.file);
|
|
53079
53040
|
} catch {
|
|
53080
53041
|
}
|
|
53081
53042
|
}
|
|
@@ -53089,14 +53050,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
|
|
|
53089
53050
|
}
|
|
53090
53051
|
|
|
53091
53052
|
// src/tunnel/tunnel-manager.ts
|
|
53092
|
-
var
|
|
53093
|
-
var
|
|
53053
|
+
var import_node_fs37 = __toESM(require("fs"), 1);
|
|
53054
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
53094
53055
|
var import_node_crypto10 = __toESM(require("crypto"), 1);
|
|
53095
|
-
var
|
|
53056
|
+
var import_node_child_process10 = require("child_process");
|
|
53096
53057
|
|
|
53097
53058
|
// src/tunnel/tunnel-store.ts
|
|
53098
|
-
var
|
|
53099
|
-
var
|
|
53059
|
+
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
53060
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
53100
53061
|
var TunnelStore = class {
|
|
53101
53062
|
constructor(filePath) {
|
|
53102
53063
|
this.filePath = filePath;
|
|
@@ -53104,7 +53065,7 @@ var TunnelStore = class {
|
|
|
53104
53065
|
filePath;
|
|
53105
53066
|
async get() {
|
|
53106
53067
|
try {
|
|
53107
|
-
const raw = await
|
|
53068
|
+
const raw = await import_node_fs34.default.promises.readFile(this.filePath, "utf8");
|
|
53108
53069
|
const obj = JSON.parse(raw);
|
|
53109
53070
|
if (!isPersistedTunnel(obj)) return null;
|
|
53110
53071
|
return obj;
|
|
@@ -53115,22 +53076,22 @@ var TunnelStore = class {
|
|
|
53115
53076
|
}
|
|
53116
53077
|
}
|
|
53117
53078
|
async set(v2) {
|
|
53118
|
-
const dir =
|
|
53119
|
-
await
|
|
53079
|
+
const dir = import_node_path37.default.dirname(this.filePath);
|
|
53080
|
+
await import_node_fs34.default.promises.mkdir(dir, { recursive: true });
|
|
53120
53081
|
const data = JSON.stringify(v2, null, 2);
|
|
53121
53082
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
53122
|
-
await
|
|
53083
|
+
await import_node_fs34.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
53123
53084
|
if (process.platform !== "win32") {
|
|
53124
53085
|
try {
|
|
53125
|
-
await
|
|
53086
|
+
await import_node_fs34.default.promises.chmod(tmp, 384);
|
|
53126
53087
|
} catch {
|
|
53127
53088
|
}
|
|
53128
53089
|
}
|
|
53129
|
-
await
|
|
53090
|
+
await import_node_fs34.default.promises.rename(tmp, this.filePath);
|
|
53130
53091
|
}
|
|
53131
53092
|
async clear() {
|
|
53132
53093
|
try {
|
|
53133
|
-
await
|
|
53094
|
+
await import_node_fs34.default.promises.unlink(this.filePath);
|
|
53134
53095
|
} catch (err) {
|
|
53135
53096
|
const code = err?.code;
|
|
53136
53097
|
if (code !== "ENOENT") throw err;
|
|
@@ -53225,10 +53186,10 @@ function escape(v2) {
|
|
|
53225
53186
|
}
|
|
53226
53187
|
|
|
53227
53188
|
// src/tunnel/frpc-binary.ts
|
|
53228
|
-
var
|
|
53189
|
+
var import_node_fs35 = __toESM(require("fs"), 1);
|
|
53229
53190
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
53230
|
-
var
|
|
53231
|
-
var
|
|
53191
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
53192
|
+
var import_node_child_process8 = require("child_process");
|
|
53232
53193
|
var import_node_stream3 = require("stream");
|
|
53233
53194
|
var import_promises5 = require("stream/promises");
|
|
53234
53195
|
var FRPC_VERSION = "0.68.0";
|
|
@@ -53259,20 +53220,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
53259
53220
|
}
|
|
53260
53221
|
async function ensureFrpcBinary(opts) {
|
|
53261
53222
|
if (opts.override) {
|
|
53262
|
-
if (!
|
|
53223
|
+
if (!import_node_fs35.default.existsSync(opts.override)) {
|
|
53263
53224
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
53264
53225
|
}
|
|
53265
53226
|
return opts.override;
|
|
53266
53227
|
}
|
|
53267
53228
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
53268
53229
|
const platform = opts.platform ?? detectPlatform();
|
|
53269
|
-
const binDir =
|
|
53270
|
-
|
|
53230
|
+
const binDir = import_node_path38.default.join(opts.dataDir, "bin");
|
|
53231
|
+
import_node_fs35.default.mkdirSync(binDir, { recursive: true });
|
|
53271
53232
|
cleanupStaleArtifacts(binDir);
|
|
53272
|
-
const stableBin =
|
|
53273
|
-
if (
|
|
53233
|
+
const stableBin = import_node_path38.default.join(binDir, "frpc");
|
|
53234
|
+
if (import_node_fs35.default.existsSync(stableBin)) return stableBin;
|
|
53274
53235
|
const partialBin = `${stableBin}.partial`;
|
|
53275
|
-
const tarballPath =
|
|
53236
|
+
const tarballPath = import_node_path38.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
53276
53237
|
try {
|
|
53277
53238
|
const url = frpcDownloadUrl(version2, platform);
|
|
53278
53239
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -53281,8 +53242,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
53281
53242
|
} else {
|
|
53282
53243
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
53283
53244
|
}
|
|
53284
|
-
|
|
53285
|
-
|
|
53245
|
+
import_node_fs35.default.chmodSync(partialBin, 493);
|
|
53246
|
+
import_node_fs35.default.renameSync(partialBin, stableBin);
|
|
53286
53247
|
} finally {
|
|
53287
53248
|
safeUnlink(tarballPath);
|
|
53288
53249
|
safeUnlink(partialBin);
|
|
@@ -53292,15 +53253,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
53292
53253
|
function cleanupStaleArtifacts(binDir) {
|
|
53293
53254
|
let entries;
|
|
53294
53255
|
try {
|
|
53295
|
-
entries =
|
|
53256
|
+
entries = import_node_fs35.default.readdirSync(binDir);
|
|
53296
53257
|
} catch {
|
|
53297
53258
|
return;
|
|
53298
53259
|
}
|
|
53299
53260
|
for (const name of entries) {
|
|
53300
53261
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
53301
|
-
const full =
|
|
53262
|
+
const full = import_node_path38.default.join(binDir, name);
|
|
53302
53263
|
try {
|
|
53303
|
-
|
|
53264
|
+
import_node_fs35.default.rmSync(full, { recursive: true, force: true });
|
|
53304
53265
|
} catch {
|
|
53305
53266
|
}
|
|
53306
53267
|
}
|
|
@@ -53308,7 +53269,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
53308
53269
|
}
|
|
53309
53270
|
function safeUnlink(p2) {
|
|
53310
53271
|
try {
|
|
53311
|
-
|
|
53272
|
+
import_node_fs35.default.unlinkSync(p2);
|
|
53312
53273
|
} catch {
|
|
53313
53274
|
}
|
|
53314
53275
|
}
|
|
@@ -53319,46 +53280,46 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
53319
53280
|
if (!res.ok || !res.body) {
|
|
53320
53281
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
53321
53282
|
}
|
|
53322
|
-
const out =
|
|
53283
|
+
const out = import_node_fs35.default.createWriteStream(dest);
|
|
53323
53284
|
const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
|
|
53324
53285
|
await (0, import_promises5.pipeline)(nodeStream, out);
|
|
53325
53286
|
}
|
|
53326
53287
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
53327
|
-
const work =
|
|
53328
|
-
|
|
53288
|
+
const work = import_node_path38.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
53289
|
+
import_node_fs35.default.mkdirSync(work, { recursive: true });
|
|
53329
53290
|
try {
|
|
53330
53291
|
await new Promise((resolve6, reject) => {
|
|
53331
|
-
const proc = (0,
|
|
53292
|
+
const proc = (0, import_node_child_process8.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
53332
53293
|
proc.on("error", reject);
|
|
53333
53294
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
53334
53295
|
});
|
|
53335
53296
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
53336
|
-
const src =
|
|
53337
|
-
if (!
|
|
53297
|
+
const src = import_node_path38.default.join(work, dirName, "frpc");
|
|
53298
|
+
if (!import_node_fs35.default.existsSync(src)) {
|
|
53338
53299
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
53339
53300
|
}
|
|
53340
|
-
|
|
53301
|
+
import_node_fs35.default.copyFileSync(src, destBin);
|
|
53341
53302
|
} finally {
|
|
53342
|
-
|
|
53303
|
+
import_node_fs35.default.rmSync(work, { recursive: true, force: true });
|
|
53343
53304
|
}
|
|
53344
53305
|
}
|
|
53345
53306
|
|
|
53346
53307
|
// src/tunnel/frpc-process.ts
|
|
53347
|
-
var
|
|
53348
|
-
var
|
|
53349
|
-
var
|
|
53308
|
+
var import_node_fs36 = __toESM(require("fs"), 1);
|
|
53309
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
53310
|
+
var import_node_child_process9 = require("child_process");
|
|
53350
53311
|
function frpcPidFilePath(dataDir) {
|
|
53351
|
-
return
|
|
53312
|
+
return import_node_path39.default.join(dataDir, "frpc.pid");
|
|
53352
53313
|
}
|
|
53353
53314
|
function writeFrpcPid(dataDir, pid) {
|
|
53354
53315
|
try {
|
|
53355
|
-
|
|
53316
|
+
import_node_fs36.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
53356
53317
|
} catch {
|
|
53357
53318
|
}
|
|
53358
53319
|
}
|
|
53359
53320
|
function clearFrpcPid(dataDir) {
|
|
53360
53321
|
try {
|
|
53361
|
-
|
|
53322
|
+
import_node_fs36.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
53362
53323
|
} catch {
|
|
53363
53324
|
}
|
|
53364
53325
|
}
|
|
@@ -53374,7 +53335,7 @@ function defaultIsPidAlive(pid) {
|
|
|
53374
53335
|
}
|
|
53375
53336
|
function defaultReadPidFile(file) {
|
|
53376
53337
|
try {
|
|
53377
|
-
return
|
|
53338
|
+
return import_node_fs36.default.readFileSync(file, "utf8");
|
|
53378
53339
|
} catch {
|
|
53379
53340
|
return null;
|
|
53380
53341
|
}
|
|
@@ -53390,7 +53351,7 @@ function defaultSleep(ms) {
|
|
|
53390
53351
|
}
|
|
53391
53352
|
async function killStaleFrpc(deps) {
|
|
53392
53353
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
53393
|
-
const tomlPath =
|
|
53354
|
+
const tomlPath = import_node_path39.default.join(deps.dataDir, "frpc.toml");
|
|
53394
53355
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
53395
53356
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
53396
53357
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -53414,7 +53375,7 @@ async function killStaleFrpc(deps) {
|
|
|
53414
53375
|
}
|
|
53415
53376
|
if (victims.size === 0) {
|
|
53416
53377
|
try {
|
|
53417
|
-
|
|
53378
|
+
import_node_fs36.default.unlinkSync(pidFile);
|
|
53418
53379
|
} catch {
|
|
53419
53380
|
}
|
|
53420
53381
|
return;
|
|
@@ -53425,14 +53386,14 @@ async function killStaleFrpc(deps) {
|
|
|
53425
53386
|
}
|
|
53426
53387
|
await sleep2(deps.reapWaitMs ?? 300);
|
|
53427
53388
|
try {
|
|
53428
|
-
|
|
53389
|
+
import_node_fs36.default.unlinkSync(pidFile);
|
|
53429
53390
|
} catch {
|
|
53430
53391
|
}
|
|
53431
53392
|
}
|
|
53432
53393
|
async function defaultScanFrpcPidsByCmdline(tomlPath, logger) {
|
|
53433
53394
|
if (process.platform === "win32") return [];
|
|
53434
53395
|
return new Promise((resolve6) => {
|
|
53435
|
-
const ps = (0,
|
|
53396
|
+
const ps = (0, import_node_child_process9.spawn)("ps", ["-axo", "pid=,command="], { stdio: ["ignore", "pipe", "ignore"] });
|
|
53436
53397
|
let buf = "";
|
|
53437
53398
|
ps.stdout.on("data", (c) => {
|
|
53438
53399
|
buf += c.toString();
|
|
@@ -53462,7 +53423,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
53462
53423
|
var TunnelManager = class {
|
|
53463
53424
|
constructor(deps) {
|
|
53464
53425
|
this.deps = deps;
|
|
53465
|
-
this.store = deps.store ?? new TunnelStore(
|
|
53426
|
+
this.store = deps.store ?? new TunnelStore(import_node_path40.default.join(deps.dataDir, "tunnel.json"));
|
|
53466
53427
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
53467
53428
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
53468
53429
|
}
|
|
@@ -53589,7 +53550,7 @@ var TunnelManager = class {
|
|
|
53589
53550
|
dataDir: this.deps.dataDir,
|
|
53590
53551
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
53591
53552
|
});
|
|
53592
|
-
const tomlPath =
|
|
53553
|
+
const tomlPath = import_node_path40.default.join(this.deps.dataDir, "frpc.toml");
|
|
53593
53554
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
|
|
53594
53555
|
const toml = buildFrpcToml({
|
|
53595
53556
|
serverAddr: t.frpsHost,
|
|
@@ -53600,14 +53561,14 @@ var TunnelManager = class {
|
|
|
53600
53561
|
localPort,
|
|
53601
53562
|
logLevel: "info"
|
|
53602
53563
|
});
|
|
53603
|
-
await
|
|
53604
|
-
const proc = (this.deps.spawnImpl ??
|
|
53564
|
+
await import_node_fs37.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
53565
|
+
const proc = (this.deps.spawnImpl ?? import_node_child_process10.spawn)(frpcBin, ["-c", tomlPath], {
|
|
53605
53566
|
stdio: ["ignore", "pipe", "pipe"]
|
|
53606
53567
|
});
|
|
53607
|
-
const logDir =
|
|
53608
|
-
|
|
53609
|
-
const logFilePath =
|
|
53610
|
-
const logStream =
|
|
53568
|
+
const logDir = import_node_path40.default.join(this.deps.dataDir, "log");
|
|
53569
|
+
import_node_fs37.default.mkdirSync(logDir, { recursive: true });
|
|
53570
|
+
const logFilePath = import_node_path40.default.join(logDir, "frpc.log");
|
|
53571
|
+
const logStream = import_node_fs37.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
53611
53572
|
logStream.on("error", () => {
|
|
53612
53573
|
});
|
|
53613
53574
|
const tee = (chunk) => {
|
|
@@ -53690,27 +53651,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
53690
53651
|
|
|
53691
53652
|
// src/tunnel/device-key.ts
|
|
53692
53653
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
53693
|
-
var
|
|
53654
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
53694
53655
|
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
53695
53656
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
53696
53657
|
function deriveStableDeviceKey(opts = {}) {
|
|
53697
53658
|
const hostname = opts.hostname ?? import_node_os14.default.hostname();
|
|
53698
53659
|
const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
|
|
53699
53660
|
const home = opts.home ?? import_node_os14.default.homedir();
|
|
53700
|
-
const defaultDataDir =
|
|
53701
|
-
const normalizedDataDir = opts.dataDir ?
|
|
53661
|
+
const defaultDataDir = import_node_path41.default.resolve(import_node_path41.default.join(home, ".clawd"));
|
|
53662
|
+
const normalizedDataDir = opts.dataDir ? import_node_path41.default.resolve(opts.dataDir) : null;
|
|
53702
53663
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
53703
53664
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
53704
53665
|
return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
53705
53666
|
}
|
|
53706
53667
|
|
|
53707
53668
|
// src/auth-store.ts
|
|
53708
|
-
var
|
|
53709
|
-
var
|
|
53669
|
+
var import_node_fs38 = __toESM(require("fs"), 1);
|
|
53670
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
53710
53671
|
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
53711
53672
|
var AUTH_FILE_NAME = "auth.json";
|
|
53712
53673
|
function authFilePath(dataDir) {
|
|
53713
|
-
return
|
|
53674
|
+
return import_node_path42.default.join(dataDir, AUTH_FILE_NAME);
|
|
53714
53675
|
}
|
|
53715
53676
|
function loadOrCreateAuthFile(opts) {
|
|
53716
53677
|
const file = authFilePath(opts.dataDir);
|
|
@@ -53746,7 +53707,7 @@ function defaultGenerateOwnerPrincipalId() {
|
|
|
53746
53707
|
}
|
|
53747
53708
|
function readAuthFile(file) {
|
|
53748
53709
|
try {
|
|
53749
|
-
const raw =
|
|
53710
|
+
const raw = import_node_fs38.default.readFileSync(file, "utf8");
|
|
53750
53711
|
const parsed = JSON.parse(raw);
|
|
53751
53712
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
53752
53713
|
return null;
|
|
@@ -53766,25 +53727,25 @@ function readAuthFile(file) {
|
|
|
53766
53727
|
}
|
|
53767
53728
|
}
|
|
53768
53729
|
function writeAuthFile(file, content) {
|
|
53769
|
-
|
|
53770
|
-
|
|
53730
|
+
import_node_fs38.default.mkdirSync(import_node_path42.default.dirname(file), { recursive: true });
|
|
53731
|
+
import_node_fs38.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
53771
53732
|
try {
|
|
53772
|
-
|
|
53733
|
+
import_node_fs38.default.chmodSync(file, 384);
|
|
53773
53734
|
} catch {
|
|
53774
53735
|
}
|
|
53775
53736
|
}
|
|
53776
53737
|
|
|
53777
53738
|
// src/owner-profile.ts
|
|
53778
|
-
var
|
|
53739
|
+
var import_node_fs39 = __toESM(require("fs"), 1);
|
|
53779
53740
|
var import_node_os15 = __toESM(require("os"), 1);
|
|
53780
|
-
var
|
|
53741
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
53781
53742
|
var PROFILE_FILENAME = "profile.json";
|
|
53782
53743
|
function loadOwnerDisplayName(dataDir) {
|
|
53783
53744
|
const fallback = import_node_os15.default.userInfo().username;
|
|
53784
|
-
const profilePath =
|
|
53745
|
+
const profilePath = import_node_path43.default.join(dataDir, PROFILE_FILENAME);
|
|
53785
53746
|
let raw;
|
|
53786
53747
|
try {
|
|
53787
|
-
raw =
|
|
53748
|
+
raw = import_node_fs39.default.readFileSync(profilePath, "utf8");
|
|
53788
53749
|
} catch {
|
|
53789
53750
|
return fallback;
|
|
53790
53751
|
}
|
|
@@ -53807,18 +53768,18 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
53807
53768
|
}
|
|
53808
53769
|
|
|
53809
53770
|
// src/feishu-auth/owner-identity-store.ts
|
|
53810
|
-
var
|
|
53811
|
-
var
|
|
53771
|
+
var import_node_fs40 = __toESM(require("fs"), 1);
|
|
53772
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
53812
53773
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
53813
53774
|
var OwnerIdentityStore = class {
|
|
53814
53775
|
file;
|
|
53815
53776
|
constructor(dataDir) {
|
|
53816
|
-
this.file =
|
|
53777
|
+
this.file = import_node_path44.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
53817
53778
|
}
|
|
53818
53779
|
read() {
|
|
53819
53780
|
let raw;
|
|
53820
53781
|
try {
|
|
53821
|
-
raw =
|
|
53782
|
+
raw = import_node_fs40.default.readFileSync(this.file, "utf8");
|
|
53822
53783
|
} catch {
|
|
53823
53784
|
return null;
|
|
53824
53785
|
}
|
|
@@ -53846,16 +53807,16 @@ var OwnerIdentityStore = class {
|
|
|
53846
53807
|
};
|
|
53847
53808
|
}
|
|
53848
53809
|
write(record) {
|
|
53849
|
-
|
|
53850
|
-
|
|
53810
|
+
import_node_fs40.default.mkdirSync(import_node_path44.default.dirname(this.file), { recursive: true });
|
|
53811
|
+
import_node_fs40.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
53851
53812
|
try {
|
|
53852
|
-
|
|
53813
|
+
import_node_fs40.default.chmodSync(this.file, 384);
|
|
53853
53814
|
} catch {
|
|
53854
53815
|
}
|
|
53855
53816
|
}
|
|
53856
53817
|
clear() {
|
|
53857
53818
|
try {
|
|
53858
|
-
|
|
53819
|
+
import_node_fs40.default.unlinkSync(this.file);
|
|
53859
53820
|
} catch (err) {
|
|
53860
53821
|
const code = err?.code;
|
|
53861
53822
|
if (code !== "ENOENT") throw err;
|
|
@@ -53992,9 +53953,9 @@ var CentralClientError = class extends Error {
|
|
|
53992
53953
|
code;
|
|
53993
53954
|
cause;
|
|
53994
53955
|
};
|
|
53995
|
-
async function centralRequest(opts,
|
|
53956
|
+
async function centralRequest(opts, path74, init) {
|
|
53996
53957
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
53997
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
53958
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path74}`;
|
|
53998
53959
|
const ctrl = new AbortController();
|
|
53999
53960
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
54000
53961
|
let res;
|
|
@@ -54139,7 +54100,7 @@ async function upsertDeviceBinding(opts) {
|
|
|
54139
54100
|
}
|
|
54140
54101
|
|
|
54141
54102
|
// src/feishu-auth/verify-token.ts
|
|
54142
|
-
var
|
|
54103
|
+
var crypto13 = __toESM(require("crypto"), 1);
|
|
54143
54104
|
var CONNECT_TOKEN_PREFIX = "clawdtk1";
|
|
54144
54105
|
function verifyConnectToken(args) {
|
|
54145
54106
|
const now = args.nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
@@ -54151,7 +54112,7 @@ function verifyConnectToken(args) {
|
|
|
54151
54112
|
const data = `${prefix}.${payloadB64}`;
|
|
54152
54113
|
let signatureValid = false;
|
|
54153
54114
|
try {
|
|
54154
|
-
signatureValid =
|
|
54115
|
+
signatureValid = crypto13.verify(
|
|
54155
54116
|
null,
|
|
54156
54117
|
Buffer.from(data, "utf8"),
|
|
54157
54118
|
args.publicKeyPem,
|
|
@@ -54189,7 +54150,7 @@ function verifyConnectToken(args) {
|
|
|
54189
54150
|
|
|
54190
54151
|
// src/feishu-auth/server-key.ts
|
|
54191
54152
|
var fs50 = __toESM(require("fs"), 1);
|
|
54192
|
-
var
|
|
54153
|
+
var path53 = __toESM(require("path"), 1);
|
|
54193
54154
|
var FILE_NAME2 = "server-signing-key.json";
|
|
54194
54155
|
var ServerKeyStore = class {
|
|
54195
54156
|
constructor(dataDir) {
|
|
@@ -54197,7 +54158,7 @@ var ServerKeyStore = class {
|
|
|
54197
54158
|
}
|
|
54198
54159
|
dataDir;
|
|
54199
54160
|
filePath() {
|
|
54200
|
-
return
|
|
54161
|
+
return path53.join(this.dataDir, FILE_NAME2);
|
|
54201
54162
|
}
|
|
54202
54163
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
54203
54164
|
read() {
|
|
@@ -54235,12 +54196,12 @@ init_protocol();
|
|
|
54235
54196
|
init_protocol();
|
|
54236
54197
|
|
|
54237
54198
|
// src/session/fork.ts
|
|
54238
|
-
var
|
|
54199
|
+
var import_node_fs41 = __toESM(require("fs"), 1);
|
|
54239
54200
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
54240
|
-
var
|
|
54201
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
54241
54202
|
init_claude_history();
|
|
54242
54203
|
function readJsonlEntries(file) {
|
|
54243
|
-
const raw =
|
|
54204
|
+
const raw = import_node_fs41.default.readFileSync(file, "utf8");
|
|
54244
54205
|
const out = [];
|
|
54245
54206
|
for (const line of raw.split("\n")) {
|
|
54246
54207
|
const t = line.trim();
|
|
@@ -54253,19 +54214,19 @@ function readJsonlEntries(file) {
|
|
|
54253
54214
|
return out;
|
|
54254
54215
|
}
|
|
54255
54216
|
function forkSession(input) {
|
|
54256
|
-
const baseDir = input.baseDir ??
|
|
54257
|
-
let projectDir =
|
|
54258
|
-
let sourceFile =
|
|
54259
|
-
if (!
|
|
54217
|
+
const baseDir = input.baseDir ?? import_node_path45.default.join(import_node_os16.default.homedir(), ".claude");
|
|
54218
|
+
let projectDir = import_node_path45.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
54219
|
+
let sourceFile = import_node_path45.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
54220
|
+
if (!import_node_fs41.default.existsSync(sourceFile)) {
|
|
54260
54221
|
const found = findTranscriptByToolSessionId(
|
|
54261
|
-
|
|
54222
|
+
import_node_path45.default.join(baseDir, "projects"),
|
|
54262
54223
|
input.toolSessionId
|
|
54263
54224
|
);
|
|
54264
54225
|
if (!found) {
|
|
54265
54226
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
54266
54227
|
}
|
|
54267
54228
|
sourceFile = found;
|
|
54268
|
-
projectDir =
|
|
54229
|
+
projectDir = import_node_path45.default.dirname(found);
|
|
54269
54230
|
}
|
|
54270
54231
|
const entries = readJsonlEntries(sourceFile);
|
|
54271
54232
|
const mainEntries = entries.filter((e) => e.isSidechain !== true);
|
|
@@ -54294,9 +54255,9 @@ function forkSession(input) {
|
|
|
54294
54255
|
}
|
|
54295
54256
|
forkedLines.push(JSON.stringify(forked));
|
|
54296
54257
|
}
|
|
54297
|
-
const forkedFilePath =
|
|
54298
|
-
|
|
54299
|
-
|
|
54258
|
+
const forkedFilePath = import_node_path45.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
54259
|
+
import_node_fs41.default.mkdirSync(projectDir, { recursive: true });
|
|
54260
|
+
import_node_fs41.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
54300
54261
|
return { forkedToolSessionId, forkedFilePath };
|
|
54301
54262
|
}
|
|
54302
54263
|
|
|
@@ -54458,21 +54419,34 @@ function buildSessionHandlers(deps) {
|
|
|
54458
54419
|
const { broadcast } = await manager.interrupt(args);
|
|
54459
54420
|
return { response: { type: "session:interrupt", ok: true }, broadcast };
|
|
54460
54421
|
};
|
|
54422
|
+
const ensureRewindSupported = async (sessionId) => {
|
|
54423
|
+
const file = manager.get({ sessionId }).response;
|
|
54424
|
+
const caps = await getAdapter2(file.tool ?? "claude").capabilities();
|
|
54425
|
+
if (caps.features.rewind === false) {
|
|
54426
|
+
throw new ClawdError(
|
|
54427
|
+
ERROR_CODES.TOOL_NOT_SUPPORTED,
|
|
54428
|
+
`tool ${file.tool ?? "claude"} does not support rewind`
|
|
54429
|
+
);
|
|
54430
|
+
}
|
|
54431
|
+
};
|
|
54461
54432
|
const rewind = async (frame, _client, ctx) => {
|
|
54462
54433
|
const args = SessionRewindArgs.parse(frame);
|
|
54463
54434
|
ensureSessionAccess(ctx, args.sessionId, "send");
|
|
54435
|
+
await ensureRewindSupported(args.sessionId);
|
|
54464
54436
|
const { response, broadcast } = await manager.rewind(args);
|
|
54465
54437
|
return { response: { type: "session:rewind", ...response }, broadcast };
|
|
54466
54438
|
};
|
|
54467
54439
|
const rewindDiff = async (frame, _client, ctx) => {
|
|
54468
54440
|
const args = SessionRewindDiffArgs.parse(frame);
|
|
54469
54441
|
ensureSessionAccess(ctx, args.sessionId, "read");
|
|
54442
|
+
await ensureRewindSupported(args.sessionId);
|
|
54470
54443
|
const { response } = await manager.rewindDiff(args);
|
|
54471
54444
|
return { response: { type: "session:rewind-diff", ...response } };
|
|
54472
54445
|
};
|
|
54473
54446
|
const rewindableMessageIds = async (frame, _client, ctx) => {
|
|
54474
54447
|
const args = SessionRewindableMessageIdsArgs.parse(frame);
|
|
54475
54448
|
ensureSessionAccess(ctx, args.sessionId, "read");
|
|
54449
|
+
await ensureRewindSupported(args.sessionId);
|
|
54476
54450
|
const { response } = manager.rewindableMessageIds(args);
|
|
54477
54451
|
return {
|
|
54478
54452
|
response: { type: "session:rewindable-message-ids", ...response }
|
|
@@ -54695,7 +54669,7 @@ function buildPermissionHandlers(deps) {
|
|
|
54695
54669
|
}
|
|
54696
54670
|
|
|
54697
54671
|
// src/handlers/history.ts
|
|
54698
|
-
var
|
|
54672
|
+
var path56 = __toESM(require("path"), 1);
|
|
54699
54673
|
init_protocol();
|
|
54700
54674
|
|
|
54701
54675
|
// src/session/recent-dirs.ts
|
|
@@ -54713,7 +54687,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
54713
54687
|
}
|
|
54714
54688
|
|
|
54715
54689
|
// src/permission/persona-paths.ts
|
|
54716
|
-
var
|
|
54690
|
+
var path55 = __toESM(require("path"), 1);
|
|
54717
54691
|
function getAllowedPersonaIds(grants, action) {
|
|
54718
54692
|
const ids = /* @__PURE__ */ new Set();
|
|
54719
54693
|
for (const g2 of grants) {
|
|
@@ -54726,42 +54700,42 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
54726
54700
|
return ids;
|
|
54727
54701
|
}
|
|
54728
54702
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
54729
|
-
const target =
|
|
54703
|
+
const target = path55.resolve(absPath);
|
|
54730
54704
|
if (userWorkDir) {
|
|
54731
|
-
const u =
|
|
54732
|
-
const usep = u.endsWith(
|
|
54705
|
+
const u = path55.resolve(userWorkDir);
|
|
54706
|
+
const usep = u.endsWith(path55.sep) ? "" : path55.sep;
|
|
54733
54707
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
54734
54708
|
}
|
|
54735
|
-
const root =
|
|
54736
|
-
const sep3 = root.endsWith(
|
|
54709
|
+
const root = path55.resolve(personaRoot);
|
|
54710
|
+
const sep3 = root.endsWith(path55.sep) ? "" : path55.sep;
|
|
54737
54711
|
if (!target.startsWith(root + sep3)) return false;
|
|
54738
|
-
const rel =
|
|
54712
|
+
const rel = path55.relative(root, target);
|
|
54739
54713
|
if (!rel || rel.startsWith("..")) return false;
|
|
54740
|
-
const personaId = rel.split(
|
|
54714
|
+
const personaId = rel.split(path55.sep)[0];
|
|
54741
54715
|
if (!personaId) return false;
|
|
54742
54716
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
54743
54717
|
if (allowed === "*") return true;
|
|
54744
54718
|
return allowed.has(personaId);
|
|
54745
54719
|
}
|
|
54746
54720
|
function personaIdFromPath(absPath, personaRoot) {
|
|
54747
|
-
const root =
|
|
54748
|
-
const target =
|
|
54749
|
-
const sep3 = root.endsWith(
|
|
54721
|
+
const root = path55.resolve(personaRoot);
|
|
54722
|
+
const target = path55.resolve(absPath);
|
|
54723
|
+
const sep3 = root.endsWith(path55.sep) ? "" : path55.sep;
|
|
54750
54724
|
if (!target.startsWith(root + sep3)) return null;
|
|
54751
|
-
const rel =
|
|
54725
|
+
const rel = path55.relative(root, target);
|
|
54752
54726
|
if (!rel || rel.startsWith("..")) return null;
|
|
54753
|
-
const id = rel.split(
|
|
54727
|
+
const id = rel.split(path55.sep)[0];
|
|
54754
54728
|
return id || null;
|
|
54755
54729
|
}
|
|
54756
54730
|
function isPathWithin(dir, absPath) {
|
|
54757
|
-
const d =
|
|
54758
|
-
const t =
|
|
54759
|
-
const sep3 = d.endsWith(
|
|
54731
|
+
const d = path55.resolve(dir);
|
|
54732
|
+
const t = path55.resolve(absPath);
|
|
54733
|
+
const sep3 = d.endsWith(path55.sep) ? "" : path55.sep;
|
|
54760
54734
|
return t === d || t.startsWith(d + sep3);
|
|
54761
54735
|
}
|
|
54762
54736
|
function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
|
|
54763
54737
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
54764
|
-
return personaIdFromPath(
|
|
54738
|
+
return personaIdFromPath(path55.resolve(absPath), personaRoot) === personaId;
|
|
54765
54739
|
}
|
|
54766
54740
|
|
|
54767
54741
|
// src/handlers/history.ts
|
|
@@ -54813,7 +54787,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54813
54787
|
if (!pid) return false;
|
|
54814
54788
|
return isGuestPathAllowed(
|
|
54815
54789
|
ctx.grants,
|
|
54816
|
-
|
|
54790
|
+
path56.join(personaRoot, pid),
|
|
54817
54791
|
personaRoot,
|
|
54818
54792
|
"read",
|
|
54819
54793
|
userWorkDir
|
|
@@ -54825,7 +54799,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54825
54799
|
};
|
|
54826
54800
|
const list = async (frame, _client, ctx) => {
|
|
54827
54801
|
const args = HistoryListArgs.parse(frame);
|
|
54828
|
-
assertGuestPath(ctx,
|
|
54802
|
+
assertGuestPath(ctx, path56.resolve(args.projectPath), personaRoot, "history:list");
|
|
54829
54803
|
const sessions = await history.listSessions(args);
|
|
54830
54804
|
return { response: { type: "history:list", sessions } };
|
|
54831
54805
|
};
|
|
@@ -54858,13 +54832,13 @@ function buildHistoryHandlers(deps) {
|
|
|
54858
54832
|
};
|
|
54859
54833
|
const subagents = async (frame, _client, ctx) => {
|
|
54860
54834
|
const args = HistorySubagentsArgs.parse(frame);
|
|
54861
|
-
assertGuestPath(ctx,
|
|
54835
|
+
assertGuestPath(ctx, path56.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
54862
54836
|
const subs = await history.listSubagents(args);
|
|
54863
54837
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
54864
54838
|
};
|
|
54865
54839
|
const subagentRead = async (frame, _client, ctx) => {
|
|
54866
54840
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
54867
|
-
assertGuestPath(ctx,
|
|
54841
|
+
assertGuestPath(ctx, path56.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
54868
54842
|
const res = await history.readSubagent(args);
|
|
54869
54843
|
return { response: { type: "history:subagent-read", ...res } };
|
|
54870
54844
|
};
|
|
@@ -54873,7 +54847,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54873
54847
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
54874
54848
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
54875
54849
|
const filtered = dirs.filter(
|
|
54876
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
54850
|
+
(d) => isGuestPathAllowed(ctx.grants, path56.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
54877
54851
|
);
|
|
54878
54852
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
54879
54853
|
}
|
|
@@ -54890,7 +54864,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54890
54864
|
}
|
|
54891
54865
|
|
|
54892
54866
|
// src/handlers/workspace.ts
|
|
54893
|
-
var
|
|
54867
|
+
var path57 = __toESM(require("path"), 1);
|
|
54894
54868
|
var os16 = __toESM(require("os"), 1);
|
|
54895
54869
|
init_protocol();
|
|
54896
54870
|
init_protocol();
|
|
@@ -54932,22 +54906,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54932
54906
|
const args = WorkspaceListArgs.parse(frame);
|
|
54933
54907
|
const isGuest = ctx?.principal.kind === "guest";
|
|
54934
54908
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
|
|
54935
|
-
const resolvedCwd =
|
|
54936
|
-
const target = args.path ?
|
|
54909
|
+
const resolvedCwd = path57.resolve(args.cwd ?? fallbackCwd);
|
|
54910
|
+
const target = args.path ? path57.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
54937
54911
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
54938
54912
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
54939
54913
|
return { response: { type: "workspace:list", ...res } };
|
|
54940
54914
|
};
|
|
54941
54915
|
const read = async (frame, _client, ctx) => {
|
|
54942
54916
|
const args = WorkspaceReadArgs.parse(frame);
|
|
54943
|
-
const target =
|
|
54917
|
+
const target = path57.isAbsolute(args.path) ? path57.resolve(args.path) : path57.resolve(args.cwd, args.path);
|
|
54944
54918
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
54945
54919
|
const res = workspace.read(args);
|
|
54946
54920
|
return { response: { type: "workspace:read", ...res } };
|
|
54947
54921
|
};
|
|
54948
54922
|
const skillsList = async (frame, _client, ctx) => {
|
|
54949
54923
|
const args = SkillsListArgs.parse(frame);
|
|
54950
|
-
const cwdAbs =
|
|
54924
|
+
const cwdAbs = path57.resolve(args.cwd);
|
|
54951
54925
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
54952
54926
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
54953
54927
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -54959,7 +54933,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54959
54933
|
};
|
|
54960
54934
|
const agentsList = async (frame, _client, ctx) => {
|
|
54961
54935
|
const args = AgentsListArgs.parse(frame);
|
|
54962
|
-
const cwdAbs =
|
|
54936
|
+
const cwdAbs = path57.resolve(args.cwd);
|
|
54963
54937
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
54964
54938
|
if (args.tool === "codex") {
|
|
54965
54939
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -54981,20 +54955,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54981
54955
|
}
|
|
54982
54956
|
|
|
54983
54957
|
// src/handlers/git.ts
|
|
54984
|
-
var
|
|
54958
|
+
var path59 = __toESM(require("path"), 1);
|
|
54985
54959
|
init_protocol();
|
|
54986
54960
|
init_protocol();
|
|
54987
54961
|
|
|
54988
54962
|
// src/workspace/git.ts
|
|
54989
|
-
var
|
|
54990
|
-
var
|
|
54991
|
-
var
|
|
54963
|
+
var import_node_child_process11 = require("child_process");
|
|
54964
|
+
var import_node_fs42 = __toESM(require("fs"), 1);
|
|
54965
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
54992
54966
|
var import_node_util = require("util");
|
|
54993
|
-
var pexec = (0, import_node_util.promisify)(
|
|
54967
|
+
var pexec = (0, import_node_util.promisify)(import_node_child_process11.execFile);
|
|
54994
54968
|
function normalizePath(p2) {
|
|
54995
|
-
const resolved =
|
|
54969
|
+
const resolved = import_node_path46.default.resolve(p2);
|
|
54996
54970
|
try {
|
|
54997
|
-
return
|
|
54971
|
+
return import_node_fs42.default.realpathSync(resolved);
|
|
54998
54972
|
} catch {
|
|
54999
54973
|
return resolved;
|
|
55000
54974
|
}
|
|
@@ -55068,7 +55042,7 @@ async function listGitBranches(cwd) {
|
|
|
55068
55042
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
55069
55043
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
55070
55044
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
55071
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
55045
|
+
if (!isGuestPathAllowed(ctx.grants, path59.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
55072
55046
|
throw new ClawdError(
|
|
55073
55047
|
ERROR_CODES.UNAUTHORIZED,
|
|
55074
55048
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -55116,45 +55090,6 @@ function buildCapabilitiesHandlers(deps) {
|
|
|
55116
55090
|
};
|
|
55117
55091
|
}
|
|
55118
55092
|
|
|
55119
|
-
// src/handlers/capability.ts
|
|
55120
|
-
init_zod();
|
|
55121
|
-
init_protocol();
|
|
55122
|
-
var DeleteArgsSchema = external_exports.object({
|
|
55123
|
-
capabilityId: external_exports.string().min(1)
|
|
55124
|
-
}).strict();
|
|
55125
|
-
function buildCapabilityHandlers(deps) {
|
|
55126
|
-
const { manager } = deps;
|
|
55127
|
-
const list = async () => {
|
|
55128
|
-
return {
|
|
55129
|
-
response: {
|
|
55130
|
-
type: "capability:list",
|
|
55131
|
-
capabilities: manager.list().map(stripSecretHash)
|
|
55132
|
-
}
|
|
55133
|
-
};
|
|
55134
|
-
};
|
|
55135
|
-
const del = async (frame) => {
|
|
55136
|
-
const { type: _type, requestId: _requestId, ...rest } = frame;
|
|
55137
|
-
const args = DeleteArgsSchema.parse(rest);
|
|
55138
|
-
const result = manager.delete(args.capabilityId);
|
|
55139
|
-
if (!result) {
|
|
55140
|
-
throw new ClawdError(
|
|
55141
|
-
ERROR_CODES.VALIDATION_ERROR,
|
|
55142
|
-
`capability not found: ${args.capabilityId}`
|
|
55143
|
-
);
|
|
55144
|
-
}
|
|
55145
|
-
return {
|
|
55146
|
-
response: {
|
|
55147
|
-
type: "capability:deleted",
|
|
55148
|
-
capabilityId: args.capabilityId
|
|
55149
|
-
}
|
|
55150
|
-
};
|
|
55151
|
-
};
|
|
55152
|
-
return {
|
|
55153
|
-
"capability:list": list,
|
|
55154
|
-
"capability:delete": del
|
|
55155
|
-
};
|
|
55156
|
-
}
|
|
55157
|
-
|
|
55158
55093
|
// src/handlers/inbox.ts
|
|
55159
55094
|
init_protocol();
|
|
55160
55095
|
function resolvePeerDeviceId(ctx, argsPeerDeviceId) {
|
|
@@ -55754,7 +55689,7 @@ function buildPersonaHandlers(deps) {
|
|
|
55754
55689
|
}
|
|
55755
55690
|
|
|
55756
55691
|
// src/handlers/attachment.ts
|
|
55757
|
-
var
|
|
55692
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
55758
55693
|
init_protocol();
|
|
55759
55694
|
init_protocol();
|
|
55760
55695
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -55834,12 +55769,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
55834
55769
|
`session ${args.sessionId} scope unresolved`
|
|
55835
55770
|
);
|
|
55836
55771
|
}
|
|
55837
|
-
const cwdAbs =
|
|
55838
|
-
const candidateAbs =
|
|
55772
|
+
const cwdAbs = import_node_path47.default.resolve(sessionFile.cwd);
|
|
55773
|
+
const candidateAbs = import_node_path47.default.isAbsolute(args.relPath) ? import_node_path47.default.resolve(args.relPath) : import_node_path47.default.resolve(cwdAbs, args.relPath);
|
|
55839
55774
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
|
|
55840
55775
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
55841
55776
|
const entry = entries.find((e) => {
|
|
55842
|
-
const storedAbs =
|
|
55777
|
+
const storedAbs = import_node_path47.default.isAbsolute(e.relPath) ? import_node_path47.default.resolve(e.relPath) : import_node_path47.default.resolve(cwdAbs, e.relPath);
|
|
55843
55778
|
return storedAbs === candidateAbs && !e.stale;
|
|
55844
55779
|
});
|
|
55845
55780
|
if (!entry) {
|
|
@@ -55864,7 +55799,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
55864
55799
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
55865
55800
|
const f = deps.sessionStore.read(sessionId);
|
|
55866
55801
|
if (!f) return;
|
|
55867
|
-
assertGuestAttachmentPath(ctx,
|
|
55802
|
+
assertGuestAttachmentPath(ctx, import_node_path47.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
55868
55803
|
}
|
|
55869
55804
|
const groupAdd = async (frame, _client, ctx) => {
|
|
55870
55805
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -55879,8 +55814,8 @@ function buildAttachmentHandlers(deps) {
|
|
|
55879
55814
|
if (!scope) {
|
|
55880
55815
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
|
|
55881
55816
|
}
|
|
55882
|
-
const cwdAbs =
|
|
55883
|
-
const candidateAbs =
|
|
55817
|
+
const cwdAbs = import_node_path47.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
|
|
55818
|
+
const candidateAbs = import_node_path47.default.isAbsolute(args.relPath) ? import_node_path47.default.resolve(args.relPath) : import_node_path47.default.resolve(cwdAbs, args.relPath);
|
|
55884
55819
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
|
|
55885
55820
|
const from = ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
55886
55821
|
const size = 0;
|
|
@@ -55939,19 +55874,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
55939
55874
|
|
|
55940
55875
|
// src/handlers/extension.ts
|
|
55941
55876
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
55942
|
-
var
|
|
55877
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
55943
55878
|
init_protocol();
|
|
55944
55879
|
|
|
55945
55880
|
// src/extension/bundle-zip.ts
|
|
55946
55881
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
55947
|
-
var
|
|
55882
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
55948
55883
|
var import_node_crypto14 = __toESM(require("crypto"), 1);
|
|
55949
55884
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
55950
55885
|
async function bundleExtensionDir(dir) {
|
|
55951
55886
|
const entries = await listFilesSorted(dir);
|
|
55952
55887
|
const zip = new import_jszip2.default();
|
|
55953
55888
|
for (const rel of entries) {
|
|
55954
|
-
const abs =
|
|
55889
|
+
const abs = import_node_path48.default.join(dir, rel);
|
|
55955
55890
|
const content = await import_promises6.default.readFile(abs);
|
|
55956
55891
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
55957
55892
|
}
|
|
@@ -55972,7 +55907,7 @@ async function listFilesSorted(rootDir) {
|
|
|
55972
55907
|
return out;
|
|
55973
55908
|
}
|
|
55974
55909
|
async function walk(absRoot, relPrefix, out) {
|
|
55975
|
-
const dirAbs =
|
|
55910
|
+
const dirAbs = import_node_path48.default.join(absRoot, relPrefix);
|
|
55976
55911
|
const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
|
|
55977
55912
|
for (const e of entries) {
|
|
55978
55913
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -56026,25 +55961,25 @@ function computePublishCheck(args) {
|
|
|
56026
55961
|
|
|
56027
55962
|
// src/extension/install-flow.ts
|
|
56028
55963
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
56029
|
-
var
|
|
55964
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
56030
55965
|
var import_node_os19 = __toESM(require("os"), 1);
|
|
56031
55966
|
var import_node_crypto15 = __toESM(require("crypto"), 1);
|
|
56032
55967
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
56033
55968
|
|
|
56034
55969
|
// src/extension/paths.ts
|
|
56035
55970
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
56036
|
-
var
|
|
55971
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
56037
55972
|
function clawdHomeRoot(override) {
|
|
56038
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
55973
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path49.default.join(import_node_os18.default.homedir(), ".clawd");
|
|
56039
55974
|
}
|
|
56040
55975
|
function extensionsRoot(override) {
|
|
56041
|
-
return
|
|
55976
|
+
return import_node_path49.default.join(clawdHomeRoot(override), "extensions");
|
|
56042
55977
|
}
|
|
56043
55978
|
function publishedChannelsFile(override) {
|
|
56044
|
-
return
|
|
55979
|
+
return import_node_path49.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
56045
55980
|
}
|
|
56046
55981
|
function bundleCacheRoot(override) {
|
|
56047
|
-
return
|
|
55982
|
+
return import_node_path49.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
56048
55983
|
}
|
|
56049
55984
|
|
|
56050
55985
|
// src/extension/install-flow.ts
|
|
@@ -56071,7 +56006,7 @@ async function installFromChannel(args, deps) {
|
|
|
56071
56006
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
56072
56007
|
}
|
|
56073
56008
|
for (const name of Object.keys(zip.files)) {
|
|
56074
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
56009
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path50.default.isAbsolute(name)) {
|
|
56075
56010
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
56076
56011
|
}
|
|
56077
56012
|
}
|
|
@@ -56103,7 +56038,7 @@ async function installFromChannel(args, deps) {
|
|
|
56103
56038
|
);
|
|
56104
56039
|
}
|
|
56105
56040
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
56106
|
-
const destDir =
|
|
56041
|
+
const destDir = import_node_path50.default.join(deps.extensionsRoot, localExtId);
|
|
56107
56042
|
let destExists = false;
|
|
56108
56043
|
try {
|
|
56109
56044
|
await import_promises7.default.access(destDir);
|
|
@@ -56117,16 +56052,16 @@ async function installFromChannel(args, deps) {
|
|
|
56117
56052
|
);
|
|
56118
56053
|
}
|
|
56119
56054
|
const stage = await import_promises7.default.mkdtemp(
|
|
56120
|
-
|
|
56055
|
+
import_node_path50.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
56121
56056
|
);
|
|
56122
56057
|
try {
|
|
56123
56058
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
56124
|
-
const dest =
|
|
56059
|
+
const dest = import_node_path50.default.join(stage, name);
|
|
56125
56060
|
if (entry.dir) {
|
|
56126
56061
|
await import_promises7.default.mkdir(dest, { recursive: true });
|
|
56127
56062
|
continue;
|
|
56128
56063
|
}
|
|
56129
|
-
await import_promises7.default.mkdir(
|
|
56064
|
+
await import_promises7.default.mkdir(import_node_path50.default.dirname(dest), { recursive: true });
|
|
56130
56065
|
if (name === "manifest.json") {
|
|
56131
56066
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
56132
56067
|
await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -56147,7 +56082,7 @@ async function installFromChannel(args, deps) {
|
|
|
56147
56082
|
|
|
56148
56083
|
// src/extension/update-flow.ts
|
|
56149
56084
|
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
56150
|
-
var
|
|
56085
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
56151
56086
|
var import_node_os20 = __toESM(require("os"), 1);
|
|
56152
56087
|
var import_node_crypto16 = __toESM(require("crypto"), 1);
|
|
56153
56088
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
@@ -56164,11 +56099,11 @@ async function updateFromChannel(args, deps) {
|
|
|
56164
56099
|
channelRef.extId,
|
|
56165
56100
|
channelRef.ownerPrincipalId
|
|
56166
56101
|
);
|
|
56167
|
-
const liveDir =
|
|
56102
|
+
const liveDir = import_node_path51.default.join(deps.extensionsRoot, localExtId);
|
|
56168
56103
|
const prevDir = `${liveDir}.prev`;
|
|
56169
56104
|
let existingVersion;
|
|
56170
56105
|
try {
|
|
56171
|
-
const raw = await import_promises8.default.readFile(
|
|
56106
|
+
const raw = await import_promises8.default.readFile(import_node_path51.default.join(liveDir, "manifest.json"), "utf8");
|
|
56172
56107
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
56173
56108
|
if (!parsed2.success) {
|
|
56174
56109
|
throw new UpdateError(
|
|
@@ -56201,7 +56136,7 @@ async function updateFromChannel(args, deps) {
|
|
|
56201
56136
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
56202
56137
|
}
|
|
56203
56138
|
for (const name of Object.keys(zip.files)) {
|
|
56204
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
56139
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path51.default.isAbsolute(name)) {
|
|
56205
56140
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
56206
56141
|
}
|
|
56207
56142
|
}
|
|
@@ -56236,16 +56171,16 @@ async function updateFromChannel(args, deps) {
|
|
|
56236
56171
|
await import_promises8.default.rm(prevDir, { recursive: true, force: true });
|
|
56237
56172
|
await import_promises8.default.rename(liveDir, prevDir);
|
|
56238
56173
|
const stage = await import_promises8.default.mkdtemp(
|
|
56239
|
-
|
|
56174
|
+
import_node_path51.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
56240
56175
|
);
|
|
56241
56176
|
try {
|
|
56242
56177
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
56243
|
-
const dest =
|
|
56178
|
+
const dest = import_node_path51.default.join(stage, name);
|
|
56244
56179
|
if (entry.dir) {
|
|
56245
56180
|
await import_promises8.default.mkdir(dest, { recursive: true });
|
|
56246
56181
|
continue;
|
|
56247
56182
|
}
|
|
56248
|
-
await import_promises8.default.mkdir(
|
|
56183
|
+
await import_promises8.default.mkdir(import_node_path51.default.dirname(dest), { recursive: true });
|
|
56249
56184
|
if (name === "manifest.json") {
|
|
56250
56185
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
56251
56186
|
await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -56338,7 +56273,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
56338
56273
|
);
|
|
56339
56274
|
}
|
|
56340
56275
|
}
|
|
56341
|
-
const manifestPath =
|
|
56276
|
+
const manifestPath = import_node_path52.default.join(root, extId, "manifest.json");
|
|
56342
56277
|
const manifest = await readManifest(root, extId);
|
|
56343
56278
|
const next = { ...manifest, version: newVersion };
|
|
56344
56279
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -56346,7 +56281,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
56346
56281
|
await import_promises9.default.rename(tmp, manifestPath);
|
|
56347
56282
|
}
|
|
56348
56283
|
async function readManifest(root, extId) {
|
|
56349
|
-
const file =
|
|
56284
|
+
const file = import_node_path52.default.join(root, extId, "manifest.json");
|
|
56350
56285
|
let raw;
|
|
56351
56286
|
try {
|
|
56352
56287
|
raw = await import_promises9.default.readFile(file, "utf8");
|
|
@@ -56437,7 +56372,7 @@ function buildExtensionHandlers(deps) {
|
|
|
56437
56372
|
};
|
|
56438
56373
|
async function buildSnapshotMeta(extId) {
|
|
56439
56374
|
const manifest = await readManifest(deps.root, extId);
|
|
56440
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
56375
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path52.default.join(deps.root, extId));
|
|
56441
56376
|
return { manifest, contentHash: sha256, buffer };
|
|
56442
56377
|
}
|
|
56443
56378
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -56618,9 +56553,9 @@ function buildExtensionHandlers(deps) {
|
|
|
56618
56553
|
}
|
|
56619
56554
|
|
|
56620
56555
|
// src/app-builder/project-store.ts
|
|
56621
|
-
var
|
|
56622
|
-
var
|
|
56623
|
-
var
|
|
56556
|
+
var import_node_fs43 = require("fs");
|
|
56557
|
+
var import_node_child_process12 = require("child_process");
|
|
56558
|
+
var import_node_path53 = require("path");
|
|
56624
56559
|
init_protocol();
|
|
56625
56560
|
var PROJECTS_DIR = "projects";
|
|
56626
56561
|
var META_FILE = ".clawd-project.json";
|
|
@@ -56634,19 +56569,19 @@ var ProjectStore = class {
|
|
|
56634
56569
|
root;
|
|
56635
56570
|
/** projects/<name>/.clawd-project.json 路径 */
|
|
56636
56571
|
metaPath(name) {
|
|
56637
|
-
return (0,
|
|
56572
|
+
return (0, import_node_path53.join)(this.projectsRoot(), name, META_FILE);
|
|
56638
56573
|
}
|
|
56639
56574
|
/** projects/<name>/ 目录路径(cwd 用) */
|
|
56640
56575
|
projectDir(name) {
|
|
56641
|
-
return (0,
|
|
56576
|
+
return (0, import_node_path53.join)(this.projectsRoot(), name);
|
|
56642
56577
|
}
|
|
56643
56578
|
projectsRoot() {
|
|
56644
|
-
return (0,
|
|
56579
|
+
return (0, import_node_path53.join)(this.root, PROJECTS_DIR);
|
|
56645
56580
|
}
|
|
56646
56581
|
async list() {
|
|
56647
56582
|
let entries;
|
|
56648
56583
|
try {
|
|
56649
|
-
entries = await
|
|
56584
|
+
entries = await import_node_fs43.promises.readdir(this.projectsRoot());
|
|
56650
56585
|
} catch (err) {
|
|
56651
56586
|
if (err.code === "ENOENT") return [];
|
|
56652
56587
|
throw err;
|
|
@@ -56654,7 +56589,7 @@ var ProjectStore = class {
|
|
|
56654
56589
|
const out = [];
|
|
56655
56590
|
for (const name of entries) {
|
|
56656
56591
|
try {
|
|
56657
|
-
const raw = await
|
|
56592
|
+
const raw = await import_node_fs43.promises.readFile(this.metaPath(name), "utf8");
|
|
56658
56593
|
const json = JSON.parse(raw);
|
|
56659
56594
|
let migrated = false;
|
|
56660
56595
|
if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
|
|
@@ -56665,7 +56600,7 @@ var ProjectStore = class {
|
|
|
56665
56600
|
if (parsed.success) {
|
|
56666
56601
|
out.push(parsed.data);
|
|
56667
56602
|
if (migrated) {
|
|
56668
|
-
void
|
|
56603
|
+
void import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
|
|
56669
56604
|
});
|
|
56670
56605
|
}
|
|
56671
56606
|
}
|
|
@@ -56709,8 +56644,8 @@ var ProjectStore = class {
|
|
|
56709
56644
|
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
56710
56645
|
}
|
|
56711
56646
|
const dir = this.projectDir(name);
|
|
56712
|
-
await
|
|
56713
|
-
await
|
|
56647
|
+
await import_node_fs43.promises.mkdir(dir, { recursive: true });
|
|
56648
|
+
await import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
56714
56649
|
return meta;
|
|
56715
56650
|
}
|
|
56716
56651
|
/**
|
|
@@ -56724,7 +56659,7 @@ var ProjectStore = class {
|
|
|
56724
56659
|
async scaffold(name, templateSrcDir, scaffoldScriptPath) {
|
|
56725
56660
|
const destDir = this.projectDir(name);
|
|
56726
56661
|
return await new Promise((resolve6, reject) => {
|
|
56727
|
-
const child = (0,
|
|
56662
|
+
const child = (0, import_node_child_process12.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
|
|
56728
56663
|
env: { ...process.env, PATH: process.env.PATH ?? "" },
|
|
56729
56664
|
stdio: ["ignore", "pipe", "pipe"]
|
|
56730
56665
|
});
|
|
@@ -56753,7 +56688,7 @@ var ProjectStore = class {
|
|
|
56753
56688
|
}
|
|
56754
56689
|
async delete(name) {
|
|
56755
56690
|
const dir = this.projectDir(name);
|
|
56756
|
-
await
|
|
56691
|
+
await import_node_fs43.promises.rm(dir, { recursive: true, force: true });
|
|
56757
56692
|
}
|
|
56758
56693
|
async updatePort(name, newPort) {
|
|
56759
56694
|
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
@@ -56769,7 +56704,7 @@ var ProjectStore = class {
|
|
|
56769
56704
|
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
56770
56705
|
}
|
|
56771
56706
|
const updated = { ...target, port: newPort };
|
|
56772
|
-
await
|
|
56707
|
+
await import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
56773
56708
|
return updated;
|
|
56774
56709
|
}
|
|
56775
56710
|
/**
|
|
@@ -56786,7 +56721,7 @@ var ProjectStore = class {
|
|
|
56786
56721
|
if (!validated.success) {
|
|
56787
56722
|
throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
|
|
56788
56723
|
}
|
|
56789
|
-
await
|
|
56724
|
+
await import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
56790
56725
|
return validated.data;
|
|
56791
56726
|
}
|
|
56792
56727
|
/**
|
|
@@ -56807,7 +56742,7 @@ var ProjectStore = class {
|
|
|
56807
56742
|
if (!validated.success) {
|
|
56808
56743
|
throw new Error(`invalid publishJob: ${validated.error.message}`);
|
|
56809
56744
|
}
|
|
56810
|
-
await
|
|
56745
|
+
await import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
56811
56746
|
return validated.data;
|
|
56812
56747
|
}
|
|
56813
56748
|
/** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
|
|
@@ -56822,13 +56757,13 @@ var ProjectStore = class {
|
|
|
56822
56757
|
if (!validated.success) {
|
|
56823
56758
|
throw new Error(`failed to clear publishJob: ${validated.error.message}`);
|
|
56824
56759
|
}
|
|
56825
|
-
await
|
|
56760
|
+
await import_node_fs43.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
56826
56761
|
return validated.data;
|
|
56827
56762
|
}
|
|
56828
56763
|
};
|
|
56829
56764
|
|
|
56830
56765
|
// src/app-builder/kill-port.ts
|
|
56831
|
-
var
|
|
56766
|
+
var import_node_child_process13 = require("child_process");
|
|
56832
56767
|
async function killPortOccupants(port, ownedPids, logger) {
|
|
56833
56768
|
let pids;
|
|
56834
56769
|
try {
|
|
@@ -56870,7 +56805,7 @@ async function killPortOccupants(port, ownedPids, logger) {
|
|
|
56870
56805
|
}
|
|
56871
56806
|
function listPidsOnPort(port) {
|
|
56872
56807
|
return new Promise((resolve6, reject) => {
|
|
56873
|
-
(0,
|
|
56808
|
+
(0, import_node_child_process13.execFile)(
|
|
56874
56809
|
"lsof",
|
|
56875
56810
|
["-ti", `:${port}`],
|
|
56876
56811
|
{ timeout: 3e3 },
|
|
@@ -56942,9 +56877,9 @@ var PublishJobRegistry = class {
|
|
|
56942
56877
|
};
|
|
56943
56878
|
|
|
56944
56879
|
// src/app-builder/publish-job-runner.ts
|
|
56945
|
-
var
|
|
56946
|
-
var
|
|
56947
|
-
var
|
|
56880
|
+
var import_node_child_process14 = require("child_process");
|
|
56881
|
+
var import_node_fs44 = require("fs");
|
|
56882
|
+
var import_node_path54 = require("path");
|
|
56948
56883
|
|
|
56949
56884
|
// src/app-builder/publish-stage-parser.ts
|
|
56950
56885
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -56971,15 +56906,15 @@ function tailStderrLines(buf, n) {
|
|
|
56971
56906
|
// src/app-builder/publish-job-runner.ts
|
|
56972
56907
|
async function startPublishJob(deps, args) {
|
|
56973
56908
|
const { registry: registry2, projectDir } = deps;
|
|
56974
|
-
const spawn13 = deps.spawnImpl ??
|
|
56909
|
+
const spawn13 = deps.spawnImpl ?? import_node_child_process14.spawn;
|
|
56975
56910
|
if (registry2.has(args.name)) {
|
|
56976
56911
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
56977
56912
|
}
|
|
56978
56913
|
const projDir = projectDir(args.name);
|
|
56979
|
-
const logPath = (0,
|
|
56914
|
+
const logPath = (0, import_node_path54.join)(projDir, ".publish.log");
|
|
56980
56915
|
let logStream = null;
|
|
56981
56916
|
try {
|
|
56982
|
-
logStream = (0,
|
|
56917
|
+
logStream = (0, import_node_fs44.createWriteStream)(logPath, { flags: "w" });
|
|
56983
56918
|
} catch {
|
|
56984
56919
|
logStream = null;
|
|
56985
56920
|
}
|
|
@@ -57236,8 +57171,8 @@ async function recoverInterruptedJobs(deps) {
|
|
|
57236
57171
|
|
|
57237
57172
|
// src/handlers/app-builder.ts
|
|
57238
57173
|
init_protocol();
|
|
57239
|
-
var
|
|
57240
|
-
var
|
|
57174
|
+
var import_node_path55 = require("path");
|
|
57175
|
+
var import_node_fs45 = require("fs");
|
|
57241
57176
|
var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
|
|
57242
57177
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
57243
57178
|
async function recoverInterruptedPublishJobs(store, logger) {
|
|
@@ -57318,7 +57253,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57318
57253
|
async function listAllUsersProjects() {
|
|
57319
57254
|
if (!deps.usersRoot || !deps.getStore) return [];
|
|
57320
57255
|
const getStore = deps.getStore;
|
|
57321
|
-
const userIds = await
|
|
57256
|
+
const userIds = await import_node_fs45.promises.readdir(deps.usersRoot).catch(() => []);
|
|
57322
57257
|
const perUser = await Promise.all(
|
|
57323
57258
|
userIds.map((uid) => getStore(uid).list().catch(() => []))
|
|
57324
57259
|
);
|
|
@@ -57394,8 +57329,8 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57394
57329
|
const project = await userStore.create(f.name, reservedPorts);
|
|
57395
57330
|
try {
|
|
57396
57331
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
|
|
57397
|
-
const templateSrcDir = (0,
|
|
57398
|
-
const scaffoldScript = (0,
|
|
57332
|
+
const templateSrcDir = (0, import_node_path55.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
|
|
57333
|
+
const scaffoldScript = (0, import_node_path55.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
|
|
57399
57334
|
const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
|
|
57400
57335
|
deps.logger?.info("app-builder.scaffold.done", {
|
|
57401
57336
|
name: project.name,
|
|
@@ -57616,7 +57551,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57616
57551
|
await userStore.clearPublishJob(args.name);
|
|
57617
57552
|
}
|
|
57618
57553
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
|
|
57619
|
-
const scriptPath = (0,
|
|
57554
|
+
const scriptPath = (0, import_node_path55.join)(deps.deployKitRoot, "scripts", "publish.sh");
|
|
57620
57555
|
deps.logger?.info("app-builder.publish.start", {
|
|
57621
57556
|
name: args.name,
|
|
57622
57557
|
sessionId: boundSession.sessionId,
|
|
@@ -57792,7 +57727,7 @@ function buildVisitorHandlers(deps) {
|
|
|
57792
57727
|
|
|
57793
57728
|
// src/extension/registry.ts
|
|
57794
57729
|
var import_promises10 = __toESM(require("fs/promises"), 1);
|
|
57795
|
-
var
|
|
57730
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
57796
57731
|
async function loadAll(root) {
|
|
57797
57732
|
let entries;
|
|
57798
57733
|
try {
|
|
@@ -57805,13 +57740,13 @@ async function loadAll(root) {
|
|
|
57805
57740
|
for (const ent of entries) {
|
|
57806
57741
|
if (!ent.isDirectory()) continue;
|
|
57807
57742
|
if (ent.name.startsWith(".")) continue;
|
|
57808
|
-
records.push(await loadOne(
|
|
57743
|
+
records.push(await loadOne(import_node_path56.default.join(root, ent.name), ent.name));
|
|
57809
57744
|
}
|
|
57810
57745
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
57811
57746
|
return records;
|
|
57812
57747
|
}
|
|
57813
57748
|
async function loadOne(dir, dirName) {
|
|
57814
|
-
const manifestPath =
|
|
57749
|
+
const manifestPath = import_node_path56.default.join(dir, "manifest.json");
|
|
57815
57750
|
let raw;
|
|
57816
57751
|
try {
|
|
57817
57752
|
raw = await import_promises10.default.readFile(manifestPath, "utf8");
|
|
@@ -57856,7 +57791,7 @@ async function loadOne(dir, dirName) {
|
|
|
57856
57791
|
|
|
57857
57792
|
// src/extension/uninstall.ts
|
|
57858
57793
|
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
57859
|
-
var
|
|
57794
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
57860
57795
|
var UninstallError = class extends Error {
|
|
57861
57796
|
constructor(code, message) {
|
|
57862
57797
|
super(message);
|
|
@@ -57865,7 +57800,7 @@ var UninstallError = class extends Error {
|
|
|
57865
57800
|
code;
|
|
57866
57801
|
};
|
|
57867
57802
|
async function uninstall(deps) {
|
|
57868
|
-
const dir =
|
|
57803
|
+
const dir = import_node_path57.default.join(deps.root, deps.extId);
|
|
57869
57804
|
try {
|
|
57870
57805
|
await import_promises11.default.access(dir);
|
|
57871
57806
|
} catch {
|
|
@@ -57882,7 +57817,7 @@ var import_node_crypto18 = require("crypto");
|
|
|
57882
57817
|
init_protocol();
|
|
57883
57818
|
|
|
57884
57819
|
// src/peer-ops/run-command.ts
|
|
57885
|
-
var
|
|
57820
|
+
var import_node_child_process15 = require("child_process");
|
|
57886
57821
|
var import_node_os21 = __toESM(require("os"), 1);
|
|
57887
57822
|
var DEFAULT_TIMEOUT_MS5 = 3e4;
|
|
57888
57823
|
var MAX_TIMEOUT_MS = 3e5;
|
|
@@ -57890,7 +57825,7 @@ var MAX_OUTPUT_BYTES = 1048576;
|
|
|
57890
57825
|
function runCommand(command, opts = {}) {
|
|
57891
57826
|
const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS5, MAX_TIMEOUT_MS);
|
|
57892
57827
|
return new Promise((resolve6) => {
|
|
57893
|
-
const child = (0,
|
|
57828
|
+
const child = (0, import_node_child_process15.spawn)("bash", ["-c", command], { cwd: import_node_os21.default.homedir() });
|
|
57894
57829
|
const out = [];
|
|
57895
57830
|
const err = [];
|
|
57896
57831
|
let outBytes = 0;
|
|
@@ -58022,9 +57957,6 @@ function buildMethodHandlers(deps) {
|
|
|
58022
57957
|
personaManager: deps.personaManager,
|
|
58023
57958
|
personaRegistry: deps.personaRegistry
|
|
58024
57959
|
}),
|
|
58025
|
-
...buildCapabilityHandlers({
|
|
58026
|
-
manager: deps.capabilityManager
|
|
58027
|
-
}),
|
|
58028
57960
|
...buildInboxHandlers({
|
|
58029
57961
|
manager: deps.inboxManager,
|
|
58030
57962
|
sendDmDeps: {
|
|
@@ -58060,8 +57992,7 @@ function buildMethodHandlers(deps) {
|
|
|
58060
57992
|
ownerPrincipalId: deps.ownerPrincipalId,
|
|
58061
57993
|
ownerId: deps.ownerId,
|
|
58062
57994
|
ownerProvider: deps.ownerProvider,
|
|
58063
|
-
personaStore: deps.personaStore
|
|
58064
|
-
capabilityManager: deps.capabilityManager
|
|
57995
|
+
personaStore: deps.personaStore
|
|
58065
57996
|
}),
|
|
58066
57997
|
...buildFeishuAuthHandlers(deps.feishuAuth),
|
|
58067
57998
|
...buildDeviceHandlers(deps.feishuDevice),
|
|
@@ -58104,7 +58035,7 @@ function buildMethodHandlers(deps) {
|
|
|
58104
58035
|
}
|
|
58105
58036
|
|
|
58106
58037
|
// src/app-builder/dev-server-supervisor.ts
|
|
58107
|
-
var
|
|
58038
|
+
var import_node_child_process16 = require("child_process");
|
|
58108
58039
|
var import_node_events2 = require("events");
|
|
58109
58040
|
var DEFAULT_READY_PATTERN = /Local:\s+https?:\/\/|Nest application successfully started|server listening on/i;
|
|
58110
58041
|
var DevServerSupervisor = class extends import_node_events2.EventEmitter {
|
|
@@ -58141,7 +58072,7 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
|
|
|
58141
58072
|
tunnelHost: args.tunnelHost,
|
|
58142
58073
|
devCommand: cmd
|
|
58143
58074
|
});
|
|
58144
|
-
const child = (0,
|
|
58075
|
+
const child = (0, import_node_child_process16.spawn)("sh", ["-c", cmd], {
|
|
58145
58076
|
cwd: args.cwd,
|
|
58146
58077
|
env,
|
|
58147
58078
|
stdio: "pipe",
|
|
@@ -58375,12 +58306,6 @@ var METHOD_GRANT_MAP = {
|
|
|
58375
58306
|
// handler 内部按 ctx.principal.kind 决定返回 "合成 owner self capability" 还是
|
|
58376
58307
|
// "查 capabilityManager 拿 caller 的 guest capability"。
|
|
58377
58308
|
"whoami": { kind: "public" },
|
|
58378
|
-
// ---- capability platform(admin-only) ----
|
|
58379
|
-
// 飞书统一身份 Phase 2 (2026-06-01, spec 决策 #12): personal-cap:get / capability:issue /
|
|
58380
|
-
// bindPeer 已下线(personal token / 邀请码全链路删除)。capability:list / delete 保留供调试 +
|
|
58381
|
-
// 撤销级联 + 清旧 per-peer cap。
|
|
58382
|
-
"capability:list": ADMIN_ANY,
|
|
58383
|
-
"capability:delete": ADMIN_ANY,
|
|
58384
58309
|
// ---- inbox: 双投 P2P IM ----
|
|
58385
58310
|
// 三条都 'public' — 能连上 = 已通过本地验票. handler 内额外校验 guest 的
|
|
58386
58311
|
// args.peerDeviceId 与 ctx.principal.id(=deviceId) 一致, 防 guest 越权操作别的 DM 桶.
|
|
@@ -58584,8 +58509,8 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
|
|
|
58584
58509
|
}
|
|
58585
58510
|
|
|
58586
58511
|
// src/extension/runtime.ts
|
|
58587
|
-
var
|
|
58588
|
-
var
|
|
58512
|
+
var import_node_child_process17 = require("child_process");
|
|
58513
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
58589
58514
|
var import_promises12 = require("timers/promises");
|
|
58590
58515
|
|
|
58591
58516
|
// src/extension/port-allocator.ts
|
|
@@ -58686,13 +58611,13 @@ var Runtime = class {
|
|
|
58686
58611
|
/\$CLAWOS_EXT_PORT/g,
|
|
58687
58612
|
String(port)
|
|
58688
58613
|
);
|
|
58689
|
-
const dir =
|
|
58614
|
+
const dir = import_node_path58.default.join(this.root, extId);
|
|
58690
58615
|
const env = {
|
|
58691
58616
|
...process.env,
|
|
58692
58617
|
CLAWOS_EXT_PORT: String(port),
|
|
58693
58618
|
CLAWOS_EXT_ID: extId
|
|
58694
58619
|
};
|
|
58695
|
-
const child = (0,
|
|
58620
|
+
const child = (0, import_node_child_process17.spawn)("sh", ["-c", cmd], {
|
|
58696
58621
|
cwd: dir,
|
|
58697
58622
|
env,
|
|
58698
58623
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -58798,7 +58723,7 @@ ${handle.stderrTail}`
|
|
|
58798
58723
|
|
|
58799
58724
|
// src/extension/published-channels.ts
|
|
58800
58725
|
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
58801
|
-
var
|
|
58726
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
58802
58727
|
init_zod();
|
|
58803
58728
|
var PublishedChannelsError = class extends Error {
|
|
58804
58729
|
constructor(code, message) {
|
|
@@ -58897,7 +58822,7 @@ var PublishedChannelStore = class {
|
|
|
58897
58822
|
)
|
|
58898
58823
|
};
|
|
58899
58824
|
const tmp = `${this.filePath}.tmp`;
|
|
58900
|
-
await import_promises13.default.mkdir(
|
|
58825
|
+
await import_promises13.default.mkdir(import_node_path59.default.dirname(this.filePath), { recursive: true });
|
|
58901
58826
|
await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
58902
58827
|
await import_promises13.default.rename(tmp, this.filePath);
|
|
58903
58828
|
}
|
|
@@ -58905,7 +58830,7 @@ var PublishedChannelStore = class {
|
|
|
58905
58830
|
|
|
58906
58831
|
// src/extension/bundle-cache.ts
|
|
58907
58832
|
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
58908
|
-
var
|
|
58833
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
58909
58834
|
var BundleCache = class {
|
|
58910
58835
|
constructor(rootDir) {
|
|
58911
58836
|
this.rootDir = rootDir;
|
|
@@ -58914,14 +58839,14 @@ var BundleCache = class {
|
|
|
58914
58839
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
58915
58840
|
async write(snapshotHash, buffer) {
|
|
58916
58841
|
await import_promises14.default.mkdir(this.rootDir, { recursive: true });
|
|
58917
|
-
const file =
|
|
58842
|
+
const file = import_node_path60.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58918
58843
|
const tmp = `${file}.tmp`;
|
|
58919
58844
|
await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
|
|
58920
58845
|
await import_promises14.default.rename(tmp, file);
|
|
58921
58846
|
}
|
|
58922
58847
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
58923
58848
|
async read(snapshotHash) {
|
|
58924
|
-
const file =
|
|
58849
|
+
const file = import_node_path60.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58925
58850
|
try {
|
|
58926
58851
|
return await import_promises14.default.readFile(file);
|
|
58927
58852
|
} catch (e) {
|
|
@@ -58931,7 +58856,7 @@ var BundleCache = class {
|
|
|
58931
58856
|
}
|
|
58932
58857
|
/** Idempotent — missing file is not an error. */
|
|
58933
58858
|
async delete(snapshotHash) {
|
|
58934
|
-
const file =
|
|
58859
|
+
const file = import_node_path60.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58935
58860
|
await import_promises14.default.rm(file, { force: true });
|
|
58936
58861
|
}
|
|
58937
58862
|
};
|
|
@@ -58954,24 +58879,24 @@ async function startDaemon(config) {
|
|
|
58954
58879
|
sampling: logShippingCfg.sampling,
|
|
58955
58880
|
homeDir: import_node_os22.default.homedir()
|
|
58956
58881
|
});
|
|
58957
|
-
const logDir =
|
|
58958
|
-
|
|
58882
|
+
const logDir = import_node_path61.default.join(config.dataDir, "log");
|
|
58883
|
+
import_node_fs46.default.mkdirSync(logDir, { recursive: true });
|
|
58959
58884
|
const logger = createLogger({
|
|
58960
58885
|
level: config.logLevel,
|
|
58961
|
-
file:
|
|
58886
|
+
file: import_node_path61.default.join(logDir, "clawd.log"),
|
|
58962
58887
|
logClient
|
|
58963
58888
|
});
|
|
58964
58889
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
58965
58890
|
const screenIdleProbeLogger = createFileOnlyLogger({
|
|
58966
|
-
file:
|
|
58891
|
+
file: import_node_path61.default.join(logDir, "screen-idle-probe.log"),
|
|
58967
58892
|
level: "debug"
|
|
58968
58893
|
});
|
|
58969
58894
|
logger.info("screen-idle probe logger enabled", {
|
|
58970
|
-
file:
|
|
58895
|
+
file: import_node_path61.default.join(logDir, "screen-idle-probe.log")
|
|
58971
58896
|
});
|
|
58972
58897
|
const CAP_TARGETS = [
|
|
58973
|
-
|
|
58974
|
-
|
|
58898
|
+
import_node_path61.default.join(logDir, "clawd.log"),
|
|
58899
|
+
import_node_path61.default.join(logDir, "screen-idle-probe.log")
|
|
58975
58900
|
];
|
|
58976
58901
|
const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
|
|
58977
58902
|
const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
|
|
@@ -59040,32 +58965,13 @@ async function startDaemon(config) {
|
|
|
59040
58965
|
}
|
|
59041
58966
|
} : {}
|
|
59042
58967
|
});
|
|
59043
|
-
|
|
59044
|
-
const capabilityRegistry = new CapabilityRegistry(capabilityStore);
|
|
59045
|
-
const capabilityManager = new CapabilityManager(capabilityRegistry, {
|
|
59046
|
-
onDeleted: (cap) => {
|
|
59047
|
-
const deletedAt = Date.now();
|
|
59048
|
-
wsServer?.broadcastToOwners({
|
|
59049
|
-
type: "capability:tokenDeleted",
|
|
59050
|
-
capabilityId: cap.id,
|
|
59051
|
-
deletedAt
|
|
59052
|
-
});
|
|
59053
|
-
wsServer?.closeConnectionsByGuestId(cap.id);
|
|
59054
|
-
const cleanup = cleanupGuestSessionsForCapability(cap, sessionStoreFactory);
|
|
59055
|
-
if (cleanup.removed.length > 0) {
|
|
59056
|
-
logger.info("capability delete cascade: guest sessions removed", {
|
|
59057
|
-
capabilityId: cap.id,
|
|
59058
|
-
removedDirs: cleanup.removed
|
|
59059
|
-
});
|
|
59060
|
-
}
|
|
59061
|
-
}
|
|
59062
|
-
});
|
|
58968
|
+
await cleanupLegacyCapabilityFiles(config.dataDir, logger);
|
|
59063
58969
|
migrateDropPersonsDir(config.dataDir);
|
|
59064
58970
|
let wsServer = null;
|
|
59065
58971
|
const authGate = authMode === "first-message" ? new AuthGate({
|
|
59066
58972
|
shouldEnforce: buildShouldEnforce({ tunnel: config.tunnel }),
|
|
59067
58973
|
// Task 1.7:authenticate 注入路径替代 expectedToken 单 token 比对。
|
|
59068
|
-
// owner 路径 constantTimeEqual 防侧信道;guest 路径走
|
|
58974
|
+
// owner 路径 constantTimeEqual 防侧信道;guest 路径走 verifyConnectToken (Ed25519).
|
|
59069
58975
|
expectedToken: resolvedAuthToken,
|
|
59070
58976
|
authenticate: async (t, selfUrl) => {
|
|
59071
58977
|
const result = await authenticate(t, buildConnectAuthDeps());
|
|
@@ -59125,8 +59031,8 @@ async function startDaemon(config) {
|
|
|
59125
59031
|
const agents = new AgentsScanner();
|
|
59126
59032
|
const history = new ClaudeHistoryReader();
|
|
59127
59033
|
let transport = null;
|
|
59128
|
-
const personaStore = new PersonaStore(
|
|
59129
|
-
const usersRoot =
|
|
59034
|
+
const personaStore = new PersonaStore(import_node_path61.default.join(config.dataDir, "personas"));
|
|
59035
|
+
const usersRoot = import_node_path61.default.join(config.dataDir, "users");
|
|
59130
59036
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
59131
59037
|
if (defaultsRoot) {
|
|
59132
59038
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -59146,7 +59052,7 @@ async function startDaemon(config) {
|
|
|
59146
59052
|
migrateCodexSandbox({ store: personaStore, logger });
|
|
59147
59053
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
59148
59054
|
const dispatchStore = createDispatchStore({
|
|
59149
|
-
filePath:
|
|
59055
|
+
filePath: import_node_path61.default.join(config.dataDir, "dispatch.json"),
|
|
59150
59056
|
now: () => Date.now(),
|
|
59151
59057
|
onFlushError: (err) => logger.error("dispatch store flush failed", {
|
|
59152
59058
|
reason: err instanceof Error ? err.message : String(err)
|
|
@@ -59161,17 +59067,17 @@ async function startDaemon(config) {
|
|
|
59161
59067
|
now: () => Date.now(),
|
|
59162
59068
|
onCompleted: (sid) => deliverPendingRef?.(sid)
|
|
59163
59069
|
});
|
|
59164
|
-
const here = typeof __dirname === "string" ? __dirname :
|
|
59070
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path61.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
|
|
59165
59071
|
const mcpConfigs = [];
|
|
59166
59072
|
const dispatchServerCandidates = [
|
|
59167
|
-
|
|
59073
|
+
import_node_path61.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
59168
59074
|
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
59169
|
-
|
|
59075
|
+
import_node_path61.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
59170
59076
|
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
59171
59077
|
];
|
|
59172
|
-
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) =>
|
|
59078
|
+
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs46.default.existsSync(p2));
|
|
59173
59079
|
if (dispatchServerScriptPath) {
|
|
59174
|
-
const dispatchLogPath =
|
|
59080
|
+
const dispatchLogPath = import_node_path61.default.join(logDir, "dispatch-mcp-server.log");
|
|
59175
59081
|
const dispatchCfgPath = writeDispatchMcpConfig({
|
|
59176
59082
|
dataDir: config.dataDir,
|
|
59177
59083
|
serverScriptPath: dispatchServerScriptPath,
|
|
@@ -59189,12 +59095,12 @@ async function startDaemon(config) {
|
|
|
59189
59095
|
});
|
|
59190
59096
|
}
|
|
59191
59097
|
const ticketServerCandidates = [
|
|
59192
|
-
|
|
59193
|
-
|
|
59098
|
+
import_node_path61.default.join(here, "ticket", "mcp-server.cjs"),
|
|
59099
|
+
import_node_path61.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
59194
59100
|
];
|
|
59195
|
-
const ticketServerScriptPath = ticketServerCandidates.find((p2) =>
|
|
59101
|
+
const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs46.default.existsSync(p2));
|
|
59196
59102
|
if (ticketServerScriptPath) {
|
|
59197
|
-
const ticketLogPath =
|
|
59103
|
+
const ticketLogPath = import_node_path61.default.join(logDir, "ticket-mcp-server.log");
|
|
59198
59104
|
const ticketCfgPath = writeTicketMcpConfig({
|
|
59199
59105
|
dataDir: config.dataDir,
|
|
59200
59106
|
serverScriptPath: ticketServerScriptPath,
|
|
@@ -59214,12 +59120,12 @@ async function startDaemon(config) {
|
|
|
59214
59120
|
});
|
|
59215
59121
|
}
|
|
59216
59122
|
const shiftServerCandidates = [
|
|
59217
|
-
|
|
59218
|
-
|
|
59123
|
+
import_node_path61.default.join(here, "shift", "mcp-server.cjs"),
|
|
59124
|
+
import_node_path61.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
|
|
59219
59125
|
];
|
|
59220
|
-
const shiftServerScriptPath = shiftServerCandidates.find((p2) =>
|
|
59126
|
+
const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs46.default.existsSync(p2));
|
|
59221
59127
|
if (shiftServerScriptPath) {
|
|
59222
|
-
const shiftLogPath =
|
|
59128
|
+
const shiftLogPath = import_node_path61.default.join(logDir, "shift-mcp-server.log");
|
|
59223
59129
|
const shiftCfgPath = await writeShiftMcpConfig({
|
|
59224
59130
|
dataDir: config.dataDir,
|
|
59225
59131
|
serverScriptPath: shiftServerScriptPath,
|
|
@@ -59238,12 +59144,12 @@ async function startDaemon(config) {
|
|
|
59238
59144
|
);
|
|
59239
59145
|
}
|
|
59240
59146
|
const inboxServerCandidates = [
|
|
59241
|
-
|
|
59242
|
-
|
|
59147
|
+
import_node_path61.default.join(here, "inbox", "mcp-server.cjs"),
|
|
59148
|
+
import_node_path61.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
|
|
59243
59149
|
];
|
|
59244
|
-
const inboxServerScriptPath = inboxServerCandidates.find((p2) =>
|
|
59150
|
+
const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs46.default.existsSync(p2));
|
|
59245
59151
|
if (inboxServerScriptPath) {
|
|
59246
|
-
const inboxLogPath =
|
|
59152
|
+
const inboxLogPath = import_node_path61.default.join(logDir, "inbox-mcp-server.log");
|
|
59247
59153
|
const inboxCfgPath = await writeInboxMcpConfig({
|
|
59248
59154
|
dataDir: config.dataDir,
|
|
59249
59155
|
serverScriptPath: inboxServerScriptPath,
|
|
@@ -59262,10 +59168,10 @@ async function startDaemon(config) {
|
|
|
59262
59168
|
);
|
|
59263
59169
|
}
|
|
59264
59170
|
const peerOpsServerCandidates = [
|
|
59265
|
-
|
|
59266
|
-
|
|
59171
|
+
import_node_path61.default.join(here, "peer-ops", "mcp-server.cjs"),
|
|
59172
|
+
import_node_path61.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
|
|
59267
59173
|
];
|
|
59268
|
-
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) =>
|
|
59174
|
+
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs46.default.existsSync(p2));
|
|
59269
59175
|
if (peerOpsServerScriptPath) {
|
|
59270
59176
|
const peerOpsCfgPath = writePeerOpsMcpConfig({
|
|
59271
59177
|
dataDir: config.dataDir,
|
|
@@ -59283,7 +59189,7 @@ async function startDaemon(config) {
|
|
|
59283
59189
|
);
|
|
59284
59190
|
}
|
|
59285
59191
|
const shiftStore = createShiftStore({
|
|
59286
|
-
filePath:
|
|
59192
|
+
filePath: import_node_path61.default.join(config.dataDir, "shift.json"),
|
|
59287
59193
|
ownerIdProvider: () => ownerPrincipalId,
|
|
59288
59194
|
now: () => Date.now()
|
|
59289
59195
|
});
|
|
@@ -59305,7 +59211,10 @@ async function startDaemon(config) {
|
|
|
59305
59211
|
getAdapter,
|
|
59306
59212
|
historyReader: history,
|
|
59307
59213
|
dataDir: config.dataDir,
|
|
59308
|
-
personaRoot:
|
|
59214
|
+
personaRoot: import_node_path61.default.join(config.dataDir, "personas"),
|
|
59215
|
+
// dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
|
|
59216
|
+
// personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
|
|
59217
|
+
getPersonaTool: (personaId) => personaRegistry.get(personaId)?.tool,
|
|
59309
59218
|
usersRoot,
|
|
59310
59219
|
personaStore,
|
|
59311
59220
|
ownerDisplayName,
|
|
@@ -59345,10 +59254,10 @@ async function startDaemon(config) {
|
|
|
59345
59254
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
59346
59255
|
attachmentGroup: {
|
|
59347
59256
|
onFileEdit: (input) => {
|
|
59348
|
-
const absPath =
|
|
59257
|
+
const absPath = import_node_path61.default.isAbsolute(input.relPath) ? input.relPath : import_node_path61.default.join(input.cwd, input.relPath);
|
|
59349
59258
|
let size = 0;
|
|
59350
59259
|
try {
|
|
59351
|
-
size =
|
|
59260
|
+
size = import_node_fs46.default.statSync(absPath).size;
|
|
59352
59261
|
} catch (err) {
|
|
59353
59262
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
59354
59263
|
sessionId: input.sessionId,
|
|
@@ -59431,6 +59340,7 @@ async function startDaemon(config) {
|
|
|
59431
59340
|
}) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
|
|
59432
59341
|
registerAdapter("claude", claudeAdapter);
|
|
59433
59342
|
registerAdapter("codex", new CodexAdapter({ logger, historyReader: new CodexHistoryReader() }));
|
|
59343
|
+
warmCodexFeatureCache();
|
|
59434
59344
|
const personaRegistry = new PersonaRegistry(personaStore);
|
|
59435
59345
|
const personaManager = new PersonaManager({
|
|
59436
59346
|
store: personaStore,
|
|
@@ -59578,15 +59488,13 @@ async function startDaemon(config) {
|
|
|
59578
59488
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
59579
59489
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
59580
59490
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
59581
|
-
personaRoot:
|
|
59491
|
+
personaRoot: import_node_path61.default.join(config.dataDir, "personas"),
|
|
59582
59492
|
usersRoot
|
|
59583
59493
|
},
|
|
59584
59494
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
59585
|
-
personaRoot:
|
|
59495
|
+
personaRoot: import_node_path61.default.join(config.dataDir, "personas"),
|
|
59586
59496
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
59587
59497
|
usersRoot,
|
|
59588
|
-
// capability:list / delete handler 依赖
|
|
59589
|
-
capabilityManager,
|
|
59590
59498
|
// v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
|
|
59591
59499
|
ownerDisplayName,
|
|
59592
59500
|
// 决策 #16: whoami owner.id = 本机 deviceId(路由主键)+ ownerId/provider 归属人
|
|
@@ -59596,8 +59504,6 @@ async function startDaemon(config) {
|
|
|
59596
59504
|
ownerId,
|
|
59597
59505
|
ownerProvider,
|
|
59598
59506
|
personaStore,
|
|
59599
|
-
// capability handler 也用 (capability:issue 走 registry / capability:list)
|
|
59600
|
-
capabilityRegistry,
|
|
59601
59507
|
// capability platform v3 inbox: handler 接 manager (post/list/markRead),
|
|
59602
59508
|
// cascade 接 store (list 统计 deletedInboxEvents).
|
|
59603
59509
|
inboxManager,
|
|
@@ -59693,11 +59599,11 @@ async function startDaemon(config) {
|
|
|
59693
59599
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
59694
59600
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
59695
59601
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
59696
|
-
appBuilderPersonaRoot:
|
|
59602
|
+
appBuilderPersonaRoot: import_node_path61.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
59697
59603
|
// 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
|
|
59698
|
-
deployKitRoot:
|
|
59604
|
+
deployKitRoot: import_node_path61.default.join(config.dataDir, "deploy-kit"),
|
|
59699
59605
|
// scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
|
|
59700
|
-
resolvePersonaRoot: (personaId) =>
|
|
59606
|
+
resolvePersonaRoot: (personaId) => import_node_path61.default.join(config.dataDir, "personas", personaId),
|
|
59701
59607
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
59702
59608
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
59703
59609
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -59743,7 +59649,7 @@ async function startDaemon(config) {
|
|
|
59743
59649
|
}
|
|
59744
59650
|
let sourceJsonlPath = "(no transcript yet \u2014 operate from the task description alone)";
|
|
59745
59651
|
if (sourceFile && sourceFile.toolSessionId) {
|
|
59746
|
-
sourceJsonlPath =
|
|
59652
|
+
sourceJsonlPath = import_node_path61.default.join(
|
|
59747
59653
|
import_node_os22.default.homedir(),
|
|
59748
59654
|
".claude",
|
|
59749
59655
|
"projects",
|
|
@@ -59789,7 +59695,9 @@ async function startDaemon(config) {
|
|
|
59789
59695
|
});
|
|
59790
59696
|
},
|
|
59791
59697
|
// B 角色:判断 targetPersona 是否 public(跨设备授权边界,private 拒)。
|
|
59792
|
-
getPersonaPublic: (personaId) => personaRegistry.get(personaId)?.public ?? false
|
|
59698
|
+
getPersonaPublic: (personaId) => personaRegistry.get(personaId)?.public ?? false,
|
|
59699
|
+
// model 校验按 target persona 绑定 tool 选表(claude / codex 模型集不同)
|
|
59700
|
+
getPersonaTool: (personaId) => personaRegistry.get(personaId)?.tool
|
|
59793
59701
|
});
|
|
59794
59702
|
handlers = { ...handlers, ...dispatchHandlers };
|
|
59795
59703
|
const shiftHandlers = buildShiftInternalHandlers({
|
|
@@ -59930,18 +59838,11 @@ async function startDaemon(config) {
|
|
|
59930
59838
|
),
|
|
59931
59839
|
protocolVersion: PROTOCOL_VERSION,
|
|
59932
59840
|
authGate: authGate ?? void 0,
|
|
59933
|
-
//
|
|
59934
|
-
//
|
|
59935
|
-
//
|
|
59936
|
-
//
|
|
59841
|
+
// T-35: capability path retired;本 hook 只剩 persona web 分享 visitor token 分支:
|
|
59842
|
+
// noAuth localhost daemon 上访客 token 若命中 → attach guest ctx,否则 fallback owner
|
|
59843
|
+
// (非 persona-web 场景静默 return null;tunnel 模式走 AuthGate 不经此路)。参数名
|
|
59844
|
+
// tryVerifyCapabilityToken 不再准确,跨 local-ws-server 改名属 followup 清理。
|
|
59937
59845
|
tryVerifyCapabilityToken: (token) => {
|
|
59938
|
-
const v2 = capabilityRegistry.verifyToken(token);
|
|
59939
|
-
if (v2.ok) {
|
|
59940
|
-
return {
|
|
59941
|
-
principal: { id: v2.capability.id, kind: "guest", displayName: v2.capability.displayName },
|
|
59942
|
-
grants: v2.capability.grants
|
|
59943
|
-
};
|
|
59944
|
-
}
|
|
59945
59846
|
const vis = verifyVisitorToken(authFile.visitorTokenSecret, token, Math.floor(Date.now() / 1e3));
|
|
59946
59847
|
if (vis.ok) return visitorGuestContext(vis.payload);
|
|
59947
59848
|
return null;
|
|
@@ -60061,8 +59962,8 @@ async function startDaemon(config) {
|
|
|
60061
59962
|
const lines = [
|
|
60062
59963
|
`Tunnel: ${r.url}`,
|
|
60063
59964
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
60064
|
-
`Frpc config: ${
|
|
60065
|
-
`Frpc log: ${
|
|
59965
|
+
`Frpc config: ${import_node_path61.default.join(config.dataDir, "frpc.toml")}`,
|
|
59966
|
+
`Frpc log: ${import_node_path61.default.join(logDir, "frpc.log")}`
|
|
60066
59967
|
];
|
|
60067
59968
|
const width = Math.max(...lines.map((l) => l.length));
|
|
60068
59969
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -60075,8 +59976,8 @@ ${bar}
|
|
|
60075
59976
|
|
|
60076
59977
|
`);
|
|
60077
59978
|
try {
|
|
60078
|
-
const connectPath =
|
|
60079
|
-
|
|
59979
|
+
const connectPath = import_node_path61.default.join(config.dataDir, "connect.txt");
|
|
59980
|
+
import_node_fs46.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
60080
59981
|
} catch {
|
|
60081
59982
|
}
|
|
60082
59983
|
} catch (err) {
|
|
@@ -60148,9 +60049,9 @@ ${bar}
|
|
|
60148
60049
|
};
|
|
60149
60050
|
}
|
|
60150
60051
|
function migrateDropPersonsDir(dataDir) {
|
|
60151
|
-
const dir =
|
|
60052
|
+
const dir = import_node_path61.default.join(dataDir, "persons");
|
|
60152
60053
|
try {
|
|
60153
|
-
|
|
60054
|
+
import_node_fs46.default.rmSync(dir, { recursive: true, force: true });
|
|
60154
60055
|
} catch {
|
|
60155
60056
|
}
|
|
60156
60057
|
}
|