@clawos-dev/clawd 0.2.257 → 0.2.259
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 +774 -792
- package/dist/dispatch/mcp-server.cjs +36 -17
- package/dist/inbox/mcp-server.cjs +9 -7
- package/dist/peer-ops/mcp-server.cjs +7 -5
- package/dist/persona-defaults/persona-app-builder/CLAUDE.md +36 -56
- package/dist/persona-defaults/persona-clawd-butler/.claude/skills/clawd-orchestration/SKILL.md +2 -2
- package/dist/persona-defaults/persona-clawd-butler/CLAUDE.md +2 -2
- package/dist/persona-defaults/persona-dataclaw-builder/CLAUDE.md +9 -20
- package/dist/rpc-tool/mcp-server.cjs +21209 -0
- package/dist/share-ui/assets/{guest-D7iXbNdh.js → guest-SFe_5tKr.js} +65 -65
- package/dist/share-ui/guest.html +1 -1
- package/dist/shift/mcp-server.cjs +15 -16
- package/dist/ticket/mcp-server.cjs +10 -5
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -46,7 +46,7 @@ var init_methods = __esm({
|
|
|
46
46
|
"session:delete",
|
|
47
47
|
"session:send",
|
|
48
48
|
// per-turn sender 2026-07-08 spec §4.6:MCP servers (ticket / inbox ...) 走 HTTP RPC
|
|
49
|
-
// /
|
|
49
|
+
// /rpc/session:currentTurnSender(Bearer)拉当前 turn caller;WS handler 同名
|
|
50
50
|
"session:currentTurnSender",
|
|
51
51
|
"session:stop",
|
|
52
52
|
// 温柔中断当前轮次,不杀进程(走 CC IPC control_request.subtype=interrupt)
|
|
@@ -94,6 +94,14 @@ var init_methods = __esm({
|
|
|
94
94
|
"workspace:list",
|
|
95
95
|
"workspace:read",
|
|
96
96
|
"shift:list",
|
|
97
|
+
// ---- shift-internal:* (cc 内 shift MCP server 管理 owner 排班,spec 2026-06-24-clawd-shift) ----
|
|
98
|
+
// 统一 RPC 鉴权(spec 2026-07-28)后经 /rpc + Bearer owner token 调;personaId 归因
|
|
99
|
+
// 从 body 来(env CLAWD_PERSONA_ID),handler 内 createdByPersona 自检防跨 persona 误操作。
|
|
100
|
+
"shift-internal:add",
|
|
101
|
+
"shift-internal:list",
|
|
102
|
+
"shift-internal:cancel",
|
|
103
|
+
"shift-internal:update",
|
|
104
|
+
"shift-internal:history",
|
|
97
105
|
"skills:list",
|
|
98
106
|
"agents:list",
|
|
99
107
|
"git:root",
|
|
@@ -111,14 +119,17 @@ var init_methods = __esm({
|
|
|
111
119
|
"persona:get",
|
|
112
120
|
"persona:update",
|
|
113
121
|
"persona:delete",
|
|
114
|
-
// ---- personaDispatch:* (
|
|
115
|
-
//
|
|
116
|
-
|
|
117
|
-
//
|
|
118
|
-
//
|
|
122
|
+
// ---- personaDispatch:* (dispatch 全家,spec 2026-07-28-unify-rpc-auth 统一登记) ----
|
|
123
|
+
// run:本地 MCP server 经 /rpc(Bearer owner token);跨设备 A 的 peer daemon 经 /rpc
|
|
124
|
+
//(Bearer connect token)。capability-scoped(handler 自检 persona.public + assertGrant(send))。
|
|
125
|
+
// complete / list:B / A 本机 MCP server 调(owner token → ADMIN_ANY)。
|
|
126
|
+
// get:跨设备轮询——A 端 daemon 凭 connect token 查 B 台账终态;handler 校验行归属。
|
|
119
127
|
"personaDispatch:run",
|
|
128
|
+
"personaDispatch:complete",
|
|
129
|
+
"personaDispatch:list",
|
|
130
|
+
"personaDispatch:get",
|
|
120
131
|
// ---- peerExec:run (跨设备 exec,spec 2026-07-16-cross-device-exec-mcp) ----
|
|
121
|
-
// A
|
|
132
|
+
// A 侧本机 MCP server 经 /rpc(Bearer owner token)带 peerDeviceId → daemon forward;
|
|
122
133
|
// B 侧对端经 /rpc(Bearer connect token)无 peerDeviceId → 本地 spawn。METHOD_GRANT_MAP
|
|
123
134
|
// 设 public,handler 内判 remoteAccessAllowed(跟 inbox:postMessage 同款)。
|
|
124
135
|
"peerExec:run",
|
|
@@ -155,6 +166,9 @@ var init_methods = __esm({
|
|
|
155
166
|
"inbox:list",
|
|
156
167
|
"inbox:markRead",
|
|
157
168
|
"inbox:postMessage",
|
|
169
|
+
// inbox:sendDm——persona 代发 DM 编排(inbox MCP server 经 /rpc + Bearer owner token 调)。
|
|
170
|
+
// sender/mode 由 handler 按 body.sessionId 反查 session scope 归因(业务逻辑非鉴权)。
|
|
171
|
+
"inbox:sendDm",
|
|
158
172
|
// ---- contact:* (联系人列表) ----
|
|
159
173
|
// 飞书统一身份 Phase 3 (决策 #14): received-capability:* 正名为 contact:*——Phase 2 后
|
|
160
174
|
// 联系人身份由中心 server introspect 背书,不再是"对方颁发的 capability"。
|
|
@@ -319,7 +333,10 @@ var init_errors = __esm({
|
|
|
319
333
|
WRONG_PERSONA: "WRONG_PERSONA",
|
|
320
334
|
SESSION_ALREADY_BOUND: "SESSION_ALREADY_BOUND",
|
|
321
335
|
// 2026-07-02 unified people sidebar: contact:pin 时 deviceId 不在 store(可能被别处删了)
|
|
322
|
-
CONTACT_NOT_FOUND: "CONTACT_NOT_FOUND"
|
|
336
|
+
CONTACT_NOT_FOUND: "CONTACT_NOT_FOUND",
|
|
337
|
+
// 统一 RPC 鉴权(spec 2026-07-28):personaDispatch:get 查不到台账行,或 guest ctx
|
|
338
|
+
// 查非自己发起的行(越权与未知 id 同码,不泄露存在性)。A 端轮询遇此码立即判失败。
|
|
339
|
+
DISPATCH_NOT_FOUND: "DISPATCH_NOT_FOUND"
|
|
323
340
|
};
|
|
324
341
|
ClawdError = class extends Error {
|
|
325
342
|
constructor(code, message) {
|
|
@@ -749,8 +766,8 @@ var init_parseUtil = __esm({
|
|
|
749
766
|
init_errors2();
|
|
750
767
|
init_en();
|
|
751
768
|
makeIssue = (params) => {
|
|
752
|
-
const { data, path:
|
|
753
|
-
const fullPath = [...
|
|
769
|
+
const { data, path: path75, errorMaps, issueData } = params;
|
|
770
|
+
const fullPath = [...path75, ...issueData.path || []];
|
|
754
771
|
const fullIssue = {
|
|
755
772
|
...issueData,
|
|
756
773
|
path: fullPath
|
|
@@ -1061,11 +1078,11 @@ var init_types = __esm({
|
|
|
1061
1078
|
init_parseUtil();
|
|
1062
1079
|
init_util();
|
|
1063
1080
|
ParseInputLazyPath = class {
|
|
1064
|
-
constructor(parent, value,
|
|
1081
|
+
constructor(parent, value, path75, key) {
|
|
1065
1082
|
this._cachedPath = [];
|
|
1066
1083
|
this.parent = parent;
|
|
1067
1084
|
this.data = value;
|
|
1068
|
-
this._path =
|
|
1085
|
+
this._path = path75;
|
|
1069
1086
|
this._key = key;
|
|
1070
1087
|
}
|
|
1071
1088
|
get path() {
|
|
@@ -4496,7 +4513,12 @@ var init_attachment_schemas = __esm({
|
|
|
4496
4513
|
sessionId: external_exports.string().min(1),
|
|
4497
4514
|
relPath: external_exports.string().min(1),
|
|
4498
4515
|
/** owner 手动加入时可选备注;agent 自动入清单不走此 RPC */
|
|
4499
|
-
label: external_exports.string().optional()
|
|
4516
|
+
label: external_exports.string().optional(),
|
|
4517
|
+
/**
|
|
4518
|
+
* 统一 RPC 鉴权(spec 2026-07-28 §8 决策 B):agent 经 clawd-rpc 调用持 owner token,
|
|
4519
|
+
* ctx 已推不出"这是 agent";body 显式标 origin:'agent' 保留群清单 from 的展示语义。
|
|
4520
|
+
*/
|
|
4521
|
+
origin: external_exports.literal("agent").optional()
|
|
4500
4522
|
});
|
|
4501
4523
|
AttachmentGroupAddResponseSchema = external_exports.object({
|
|
4502
4524
|
entry: GroupFileEntrySchema
|
|
@@ -6207,7 +6229,7 @@ var init_feishu_auth = __esm({
|
|
|
6207
6229
|
});
|
|
6208
6230
|
|
|
6209
6231
|
// ../protocol/src/dispatch.ts
|
|
6210
|
-
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema, DISPATCH_STATUSES, DispatchStatusSchema, DispatchRecordSchema, DispatchListArgsSchema, DispatchListResultSchema;
|
|
6232
|
+
var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema, DISPATCH_STATUSES, DispatchStatusSchema, DispatchRecordSchema, DispatchListArgsSchema, DispatchListResultSchema, DispatchGetArgsSchema, DispatchGetOkSchema;
|
|
6211
6233
|
var init_dispatch = __esm({
|
|
6212
6234
|
"../protocol/src/dispatch.ts"() {
|
|
6213
6235
|
"use strict";
|
|
@@ -6280,6 +6302,14 @@ var init_dispatch = __esm({
|
|
|
6280
6302
|
DispatchListResultSchema = external_exports.object({
|
|
6281
6303
|
records: external_exports.array(DispatchRecordSchema)
|
|
6282
6304
|
});
|
|
6305
|
+
DispatchGetArgsSchema = external_exports.object({
|
|
6306
|
+
dispatchId: external_exports.string().min(1)
|
|
6307
|
+
});
|
|
6308
|
+
DispatchGetOkSchema = external_exports.object({
|
|
6309
|
+
type: external_exports.literal("personaDispatch:get:ok"),
|
|
6310
|
+
status: DispatchStatusSchema,
|
|
6311
|
+
outcome: DispatchOutcomeSchema.optional()
|
|
6312
|
+
});
|
|
6283
6313
|
}
|
|
6284
6314
|
});
|
|
6285
6315
|
|
|
@@ -6633,8 +6663,8 @@ var require_req = __commonJS({
|
|
|
6633
6663
|
if (req.originalUrl) {
|
|
6634
6664
|
_req.url = req.originalUrl;
|
|
6635
6665
|
} else {
|
|
6636
|
-
const
|
|
6637
|
-
_req.url = typeof
|
|
6666
|
+
const path75 = req.path;
|
|
6667
|
+
_req.url = typeof path75 === "string" ? path75 : req.url ? req.url.path || req.url : void 0;
|
|
6638
6668
|
}
|
|
6639
6669
|
if (req.query) {
|
|
6640
6670
|
_req.query = req.query;
|
|
@@ -6799,14 +6829,14 @@ var require_redact = __commonJS({
|
|
|
6799
6829
|
}
|
|
6800
6830
|
return obj;
|
|
6801
6831
|
}
|
|
6802
|
-
function parsePath(
|
|
6832
|
+
function parsePath(path75) {
|
|
6803
6833
|
const parts = [];
|
|
6804
6834
|
let current = "";
|
|
6805
6835
|
let inBrackets = false;
|
|
6806
6836
|
let inQuotes = false;
|
|
6807
6837
|
let quoteChar = "";
|
|
6808
|
-
for (let i = 0; i <
|
|
6809
|
-
const char =
|
|
6838
|
+
for (let i = 0; i < path75.length; i++) {
|
|
6839
|
+
const char = path75[i];
|
|
6810
6840
|
if (!inBrackets && char === ".") {
|
|
6811
6841
|
if (current) {
|
|
6812
6842
|
parts.push(current);
|
|
@@ -6937,10 +6967,10 @@ var require_redact = __commonJS({
|
|
|
6937
6967
|
return current;
|
|
6938
6968
|
}
|
|
6939
6969
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
6940
|
-
for (const
|
|
6941
|
-
const parts = parsePath(
|
|
6970
|
+
for (const path75 of paths) {
|
|
6971
|
+
const parts = parsePath(path75);
|
|
6942
6972
|
if (parts.includes("*")) {
|
|
6943
|
-
redactWildcardPath(obj, parts, censor,
|
|
6973
|
+
redactWildcardPath(obj, parts, censor, path75, remove);
|
|
6944
6974
|
} else {
|
|
6945
6975
|
if (remove) {
|
|
6946
6976
|
removeKey(obj, parts);
|
|
@@ -7025,8 +7055,8 @@ var require_redact = __commonJS({
|
|
|
7025
7055
|
}
|
|
7026
7056
|
} else {
|
|
7027
7057
|
if (afterWildcard.includes("*")) {
|
|
7028
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
7029
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
7058
|
+
const wrappedCensor = typeof censor === "function" ? (value, path75) => {
|
|
7059
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path75];
|
|
7030
7060
|
return censor(value, fullPath);
|
|
7031
7061
|
} : censor;
|
|
7032
7062
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -7061,8 +7091,8 @@ var require_redact = __commonJS({
|
|
|
7061
7091
|
return null;
|
|
7062
7092
|
}
|
|
7063
7093
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
7064
|
-
for (const
|
|
7065
|
-
const parts = parsePath(
|
|
7094
|
+
for (const path75 of pathsToClone) {
|
|
7095
|
+
const parts = parsePath(path75);
|
|
7066
7096
|
let current = pathStructure;
|
|
7067
7097
|
for (let i = 0; i < parts.length; i++) {
|
|
7068
7098
|
const part = parts[i];
|
|
@@ -7114,24 +7144,24 @@ var require_redact = __commonJS({
|
|
|
7114
7144
|
}
|
|
7115
7145
|
return cloneSelectively(obj, pathStructure);
|
|
7116
7146
|
}
|
|
7117
|
-
function validatePath(
|
|
7118
|
-
if (typeof
|
|
7147
|
+
function validatePath(path75) {
|
|
7148
|
+
if (typeof path75 !== "string") {
|
|
7119
7149
|
throw new Error("Paths must be (non-empty) strings");
|
|
7120
7150
|
}
|
|
7121
|
-
if (
|
|
7151
|
+
if (path75 === "") {
|
|
7122
7152
|
throw new Error("Invalid redaction path ()");
|
|
7123
7153
|
}
|
|
7124
|
-
if (
|
|
7125
|
-
throw new Error(`Invalid redaction path (${
|
|
7154
|
+
if (path75.includes("..")) {
|
|
7155
|
+
throw new Error(`Invalid redaction path (${path75})`);
|
|
7126
7156
|
}
|
|
7127
|
-
if (
|
|
7128
|
-
throw new Error(`Invalid redaction path (${
|
|
7157
|
+
if (path75.includes(",")) {
|
|
7158
|
+
throw new Error(`Invalid redaction path (${path75})`);
|
|
7129
7159
|
}
|
|
7130
7160
|
let bracketCount = 0;
|
|
7131
7161
|
let inQuotes = false;
|
|
7132
7162
|
let quoteChar = "";
|
|
7133
|
-
for (let i = 0; i <
|
|
7134
|
-
const char =
|
|
7163
|
+
for (let i = 0; i < path75.length; i++) {
|
|
7164
|
+
const char = path75[i];
|
|
7135
7165
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
7136
7166
|
if (!inQuotes) {
|
|
7137
7167
|
inQuotes = true;
|
|
@@ -7145,20 +7175,20 @@ var require_redact = __commonJS({
|
|
|
7145
7175
|
} else if (char === "]" && !inQuotes) {
|
|
7146
7176
|
bracketCount--;
|
|
7147
7177
|
if (bracketCount < 0) {
|
|
7148
|
-
throw new Error(`Invalid redaction path (${
|
|
7178
|
+
throw new Error(`Invalid redaction path (${path75})`);
|
|
7149
7179
|
}
|
|
7150
7180
|
}
|
|
7151
7181
|
}
|
|
7152
7182
|
if (bracketCount !== 0) {
|
|
7153
|
-
throw new Error(`Invalid redaction path (${
|
|
7183
|
+
throw new Error(`Invalid redaction path (${path75})`);
|
|
7154
7184
|
}
|
|
7155
7185
|
}
|
|
7156
7186
|
function validatePaths(paths) {
|
|
7157
7187
|
if (!Array.isArray(paths)) {
|
|
7158
7188
|
throw new TypeError("paths must be an array");
|
|
7159
7189
|
}
|
|
7160
|
-
for (const
|
|
7161
|
-
validatePath(
|
|
7190
|
+
for (const path75 of paths) {
|
|
7191
|
+
validatePath(path75);
|
|
7162
7192
|
}
|
|
7163
7193
|
}
|
|
7164
7194
|
function slowRedact(options = {}) {
|
|
@@ -7326,8 +7356,8 @@ var require_redaction = __commonJS({
|
|
|
7326
7356
|
if (shape[k2] === null) {
|
|
7327
7357
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
7328
7358
|
} else {
|
|
7329
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
7330
|
-
return censor(value, [k2, ...
|
|
7359
|
+
const wrappedCensor = typeof censor === "function" ? (value, path75) => {
|
|
7360
|
+
return censor(value, [k2, ...path75]);
|
|
7331
7361
|
} : censor;
|
|
7332
7362
|
o[k2] = Redact({
|
|
7333
7363
|
paths: shape[k2],
|
|
@@ -7545,10 +7575,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
7545
7575
|
var require_sonic_boom = __commonJS({
|
|
7546
7576
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
7547
7577
|
"use strict";
|
|
7548
|
-
var
|
|
7578
|
+
var fs66 = require("fs");
|
|
7549
7579
|
var EventEmitter3 = require("events");
|
|
7550
7580
|
var inherits = require("util").inherits;
|
|
7551
|
-
var
|
|
7581
|
+
var path75 = require("path");
|
|
7552
7582
|
var sleep2 = require_atomic_sleep();
|
|
7553
7583
|
var assert = require("assert");
|
|
7554
7584
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -7602,20 +7632,20 @@ var require_sonic_boom = __commonJS({
|
|
|
7602
7632
|
const mode = sonic.mode;
|
|
7603
7633
|
if (sonic.sync) {
|
|
7604
7634
|
try {
|
|
7605
|
-
if (sonic.mkdir)
|
|
7606
|
-
const fd =
|
|
7635
|
+
if (sonic.mkdir) fs66.mkdirSync(path75.dirname(file), { recursive: true });
|
|
7636
|
+
const fd = fs66.openSync(file, flags, mode);
|
|
7607
7637
|
fileOpened(null, fd);
|
|
7608
7638
|
} catch (err) {
|
|
7609
7639
|
fileOpened(err);
|
|
7610
7640
|
throw err;
|
|
7611
7641
|
}
|
|
7612
7642
|
} else if (sonic.mkdir) {
|
|
7613
|
-
|
|
7643
|
+
fs66.mkdir(path75.dirname(file), { recursive: true }, (err) => {
|
|
7614
7644
|
if (err) return fileOpened(err);
|
|
7615
|
-
|
|
7645
|
+
fs66.open(file, flags, mode, fileOpened);
|
|
7616
7646
|
});
|
|
7617
7647
|
} else {
|
|
7618
|
-
|
|
7648
|
+
fs66.open(file, flags, mode, fileOpened);
|
|
7619
7649
|
}
|
|
7620
7650
|
}
|
|
7621
7651
|
function SonicBoom(opts) {
|
|
@@ -7656,8 +7686,8 @@ var require_sonic_boom = __commonJS({
|
|
|
7656
7686
|
this.flush = flushBuffer;
|
|
7657
7687
|
this.flushSync = flushBufferSync;
|
|
7658
7688
|
this._actualWrite = actualWriteBuffer;
|
|
7659
|
-
fsWriteSync = () =>
|
|
7660
|
-
fsWrite = () =>
|
|
7689
|
+
fsWriteSync = () => fs66.writeSync(this.fd, this._writingBuf);
|
|
7690
|
+
fsWrite = () => fs66.write(this.fd, this._writingBuf, this.release);
|
|
7661
7691
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
7662
7692
|
this._writingBuf = "";
|
|
7663
7693
|
this.write = write;
|
|
@@ -7666,15 +7696,15 @@ var require_sonic_boom = __commonJS({
|
|
|
7666
7696
|
this._actualWrite = actualWrite;
|
|
7667
7697
|
fsWriteSync = () => {
|
|
7668
7698
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7669
|
-
return
|
|
7699
|
+
return fs66.writeSync(this.fd, this._writingBuf);
|
|
7670
7700
|
}
|
|
7671
|
-
return
|
|
7701
|
+
return fs66.writeSync(this.fd, this._writingBuf, "utf8");
|
|
7672
7702
|
};
|
|
7673
7703
|
fsWrite = () => {
|
|
7674
7704
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
7675
|
-
return
|
|
7705
|
+
return fs66.write(this.fd, this._writingBuf, this.release);
|
|
7676
7706
|
}
|
|
7677
|
-
return
|
|
7707
|
+
return fs66.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
7678
7708
|
};
|
|
7679
7709
|
} else {
|
|
7680
7710
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -7731,7 +7761,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7731
7761
|
}
|
|
7732
7762
|
}
|
|
7733
7763
|
if (this._fsync) {
|
|
7734
|
-
|
|
7764
|
+
fs66.fsyncSync(this.fd);
|
|
7735
7765
|
}
|
|
7736
7766
|
const len = this._len;
|
|
7737
7767
|
if (this._reopening) {
|
|
@@ -7845,7 +7875,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7845
7875
|
const onDrain = () => {
|
|
7846
7876
|
if (!this._fsync) {
|
|
7847
7877
|
try {
|
|
7848
|
-
|
|
7878
|
+
fs66.fsync(this.fd, (err) => {
|
|
7849
7879
|
this._flushPending = false;
|
|
7850
7880
|
cb(err);
|
|
7851
7881
|
});
|
|
@@ -7947,7 +7977,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7947
7977
|
const fd = this.fd;
|
|
7948
7978
|
this.once("ready", () => {
|
|
7949
7979
|
if (fd !== this.fd) {
|
|
7950
|
-
|
|
7980
|
+
fs66.close(fd, (err) => {
|
|
7951
7981
|
if (err) {
|
|
7952
7982
|
return this.emit("error", err);
|
|
7953
7983
|
}
|
|
@@ -7996,7 +8026,7 @@ var require_sonic_boom = __commonJS({
|
|
|
7996
8026
|
buf = this._bufs[0];
|
|
7997
8027
|
}
|
|
7998
8028
|
try {
|
|
7999
|
-
const n = Buffer.isBuffer(buf) ?
|
|
8029
|
+
const n = Buffer.isBuffer(buf) ? fs66.writeSync(this.fd, buf) : fs66.writeSync(this.fd, buf, "utf8");
|
|
8000
8030
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
8001
8031
|
buf = releasedBufObj.writingBuf;
|
|
8002
8032
|
this._len = releasedBufObj.len;
|
|
@@ -8012,7 +8042,7 @@ var require_sonic_boom = __commonJS({
|
|
|
8012
8042
|
}
|
|
8013
8043
|
}
|
|
8014
8044
|
try {
|
|
8015
|
-
|
|
8045
|
+
fs66.fsyncSync(this.fd);
|
|
8016
8046
|
} catch {
|
|
8017
8047
|
}
|
|
8018
8048
|
}
|
|
@@ -8033,7 +8063,7 @@ var require_sonic_boom = __commonJS({
|
|
|
8033
8063
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
8034
8064
|
}
|
|
8035
8065
|
try {
|
|
8036
|
-
const n =
|
|
8066
|
+
const n = fs66.writeSync(this.fd, buf);
|
|
8037
8067
|
buf = buf.subarray(n);
|
|
8038
8068
|
this._len = Math.max(this._len - n, 0);
|
|
8039
8069
|
if (buf.length <= 0) {
|
|
@@ -8061,13 +8091,13 @@ var require_sonic_boom = __commonJS({
|
|
|
8061
8091
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
8062
8092
|
if (this.sync) {
|
|
8063
8093
|
try {
|
|
8064
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
8094
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs66.writeSync(this.fd, this._writingBuf) : fs66.writeSync(this.fd, this._writingBuf, "utf8");
|
|
8065
8095
|
release(null, written);
|
|
8066
8096
|
} catch (err) {
|
|
8067
8097
|
release(err);
|
|
8068
8098
|
}
|
|
8069
8099
|
} else {
|
|
8070
|
-
|
|
8100
|
+
fs66.write(this.fd, this._writingBuf, release);
|
|
8071
8101
|
}
|
|
8072
8102
|
}
|
|
8073
8103
|
function actualWriteBuffer() {
|
|
@@ -8076,7 +8106,7 @@ var require_sonic_boom = __commonJS({
|
|
|
8076
8106
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
8077
8107
|
if (this.sync) {
|
|
8078
8108
|
try {
|
|
8079
|
-
const written =
|
|
8109
|
+
const written = fs66.writeSync(this.fd, this._writingBuf);
|
|
8080
8110
|
release(null, written);
|
|
8081
8111
|
} catch (err) {
|
|
8082
8112
|
release(err);
|
|
@@ -8085,7 +8115,7 @@ var require_sonic_boom = __commonJS({
|
|
|
8085
8115
|
if (kCopyBuffer) {
|
|
8086
8116
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
8087
8117
|
}
|
|
8088
|
-
|
|
8118
|
+
fs66.write(this.fd, this._writingBuf, release);
|
|
8089
8119
|
}
|
|
8090
8120
|
}
|
|
8091
8121
|
function actualClose(sonic) {
|
|
@@ -8101,12 +8131,12 @@ var require_sonic_boom = __commonJS({
|
|
|
8101
8131
|
sonic._lens = [];
|
|
8102
8132
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
8103
8133
|
try {
|
|
8104
|
-
|
|
8134
|
+
fs66.fsync(sonic.fd, closeWrapped);
|
|
8105
8135
|
} catch {
|
|
8106
8136
|
}
|
|
8107
8137
|
function closeWrapped() {
|
|
8108
8138
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
8109
|
-
|
|
8139
|
+
fs66.close(sonic.fd, done);
|
|
8110
8140
|
} else {
|
|
8111
8141
|
done();
|
|
8112
8142
|
}
|
|
@@ -11241,11 +11271,11 @@ var init_lib = __esm({
|
|
|
11241
11271
|
}
|
|
11242
11272
|
}
|
|
11243
11273
|
},
|
|
11244
|
-
addToPath: function addToPath(
|
|
11245
|
-
var last =
|
|
11274
|
+
addToPath: function addToPath(path75, added, removed, oldPosInc, options) {
|
|
11275
|
+
var last = path75.lastComponent;
|
|
11246
11276
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
11247
11277
|
return {
|
|
11248
|
-
oldPos:
|
|
11278
|
+
oldPos: path75.oldPos + oldPosInc,
|
|
11249
11279
|
lastComponent: {
|
|
11250
11280
|
count: last.count + 1,
|
|
11251
11281
|
added,
|
|
@@ -11255,7 +11285,7 @@ var init_lib = __esm({
|
|
|
11255
11285
|
};
|
|
11256
11286
|
} else {
|
|
11257
11287
|
return {
|
|
11258
|
-
oldPos:
|
|
11288
|
+
oldPos: path75.oldPos + oldPosInc,
|
|
11259
11289
|
lastComponent: {
|
|
11260
11290
|
count: 1,
|
|
11261
11291
|
added,
|
|
@@ -11764,10 +11794,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
11764
11794
|
const memories = raw.map((m2) => {
|
|
11765
11795
|
if (!m2 || typeof m2 !== "object") return null;
|
|
11766
11796
|
const rec3 = m2;
|
|
11767
|
-
const
|
|
11797
|
+
const path75 = typeof rec3.path === "string" ? rec3.path : null;
|
|
11768
11798
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
11769
|
-
if (!
|
|
11770
|
-
const entry = { path:
|
|
11799
|
+
if (!path75 || content == null) return null;
|
|
11800
|
+
const entry = { path: path75, content };
|
|
11771
11801
|
if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
|
|
11772
11802
|
return entry;
|
|
11773
11803
|
}).filter((m2) => m2 !== null);
|
|
@@ -12570,10 +12600,10 @@ function parseAttachment(obj) {
|
|
|
12570
12600
|
const memories = raw.map((m2) => {
|
|
12571
12601
|
if (!m2 || typeof m2 !== "object") return null;
|
|
12572
12602
|
const rec3 = m2;
|
|
12573
|
-
const
|
|
12603
|
+
const path75 = typeof rec3.path === "string" ? rec3.path : null;
|
|
12574
12604
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
12575
|
-
if (!
|
|
12576
|
-
const out = { path:
|
|
12605
|
+
if (!path75 || content == null) return null;
|
|
12606
|
+
const out = { path: path75, content };
|
|
12577
12607
|
if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
|
|
12578
12608
|
return out;
|
|
12579
12609
|
}).filter((m2) => m2 !== null);
|
|
@@ -33542,8 +33572,8 @@ var require_utils = __commonJS({
|
|
|
33542
33572
|
var result = transform[inputType][outputType](input);
|
|
33543
33573
|
return result;
|
|
33544
33574
|
};
|
|
33545
|
-
exports2.resolve = function(
|
|
33546
|
-
var parts =
|
|
33575
|
+
exports2.resolve = function(path75) {
|
|
33576
|
+
var parts = path75.split("/");
|
|
33547
33577
|
var result = [];
|
|
33548
33578
|
for (var index = 0; index < parts.length; index++) {
|
|
33549
33579
|
var part = parts[index];
|
|
@@ -39396,18 +39426,18 @@ var require_object = __commonJS({
|
|
|
39396
39426
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
39397
39427
|
this.files[name] = object;
|
|
39398
39428
|
};
|
|
39399
|
-
var parentFolder = function(
|
|
39400
|
-
if (
|
|
39401
|
-
|
|
39429
|
+
var parentFolder = function(path75) {
|
|
39430
|
+
if (path75.slice(-1) === "/") {
|
|
39431
|
+
path75 = path75.substring(0, path75.length - 1);
|
|
39402
39432
|
}
|
|
39403
|
-
var lastSlash =
|
|
39404
|
-
return lastSlash > 0 ?
|
|
39433
|
+
var lastSlash = path75.lastIndexOf("/");
|
|
39434
|
+
return lastSlash > 0 ? path75.substring(0, lastSlash) : "";
|
|
39405
39435
|
};
|
|
39406
|
-
var forceTrailingSlash = function(
|
|
39407
|
-
if (
|
|
39408
|
-
|
|
39436
|
+
var forceTrailingSlash = function(path75) {
|
|
39437
|
+
if (path75.slice(-1) !== "/") {
|
|
39438
|
+
path75 += "/";
|
|
39409
39439
|
}
|
|
39410
|
-
return
|
|
39440
|
+
return path75;
|
|
39411
39441
|
};
|
|
39412
39442
|
var folderAdd = function(name, createFolders) {
|
|
39413
39443
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -40409,7 +40439,7 @@ var require_lib3 = __commonJS({
|
|
|
40409
40439
|
// src/run-case/recorder.ts
|
|
40410
40440
|
function startRunCaseRecorder(opts) {
|
|
40411
40441
|
const now = opts.now ?? Date.now;
|
|
40412
|
-
const dir =
|
|
40442
|
+
const dir = import_node_path63.default.dirname(opts.recordPath);
|
|
40413
40443
|
let stream = null;
|
|
40414
40444
|
let closing = false;
|
|
40415
40445
|
let closedSettled = false;
|
|
@@ -40423,8 +40453,8 @@ function startRunCaseRecorder(opts) {
|
|
|
40423
40453
|
});
|
|
40424
40454
|
const ensureStream = () => {
|
|
40425
40455
|
if (stream) return stream;
|
|
40426
|
-
|
|
40427
|
-
stream =
|
|
40456
|
+
import_node_fs48.default.mkdirSync(dir, { recursive: true });
|
|
40457
|
+
stream = import_node_fs48.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
40428
40458
|
stream.on("close", () => closedResolve());
|
|
40429
40459
|
return stream;
|
|
40430
40460
|
};
|
|
@@ -40449,12 +40479,12 @@ function startRunCaseRecorder(opts) {
|
|
|
40449
40479
|
};
|
|
40450
40480
|
return { tap, close, closed };
|
|
40451
40481
|
}
|
|
40452
|
-
var
|
|
40482
|
+
var import_node_fs48, import_node_path63;
|
|
40453
40483
|
var init_recorder = __esm({
|
|
40454
40484
|
"src/run-case/recorder.ts"() {
|
|
40455
40485
|
"use strict";
|
|
40456
|
-
|
|
40457
|
-
|
|
40486
|
+
import_node_fs48 = __toESM(require("fs"), 1);
|
|
40487
|
+
import_node_path63 = __toESM(require("path"), 1);
|
|
40458
40488
|
}
|
|
40459
40489
|
});
|
|
40460
40490
|
|
|
@@ -40497,7 +40527,7 @@ var init_wire = __esm({
|
|
|
40497
40527
|
// src/run-case/controller.ts
|
|
40498
40528
|
async function runController(opts) {
|
|
40499
40529
|
const now = opts.now ?? Date.now;
|
|
40500
|
-
const cwd = opts.cwd ?? (0,
|
|
40530
|
+
const cwd = opts.cwd ?? (0, import_node_fs49.mkdtempSync)(import_node_path64.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
|
|
40501
40531
|
const ownsCwd = opts.cwd === void 0;
|
|
40502
40532
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
40503
40533
|
const spawnCtx = { cwd };
|
|
@@ -40658,19 +40688,19 @@ async function runController(opts) {
|
|
|
40658
40688
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
40659
40689
|
if (ownsCwd) {
|
|
40660
40690
|
try {
|
|
40661
|
-
(0,
|
|
40691
|
+
(0, import_node_fs49.rmSync)(cwd, { recursive: true, force: true });
|
|
40662
40692
|
} catch {
|
|
40663
40693
|
}
|
|
40664
40694
|
}
|
|
40665
40695
|
return exitCode ?? 0;
|
|
40666
40696
|
}
|
|
40667
|
-
var
|
|
40697
|
+
var import_node_fs49, import_node_os23, import_node_path64;
|
|
40668
40698
|
var init_controller = __esm({
|
|
40669
40699
|
"src/run-case/controller.ts"() {
|
|
40670
40700
|
"use strict";
|
|
40671
|
-
|
|
40701
|
+
import_node_fs49 = require("fs");
|
|
40672
40702
|
import_node_os23 = __toESM(require("os"), 1);
|
|
40673
|
-
|
|
40703
|
+
import_node_path64 = __toESM(require("path"), 1);
|
|
40674
40704
|
init_claude();
|
|
40675
40705
|
init_stdout_splitter();
|
|
40676
40706
|
init_permission_stdio();
|
|
@@ -40945,8 +40975,8 @@ Env (advanced):
|
|
|
40945
40975
|
`;
|
|
40946
40976
|
|
|
40947
40977
|
// src/index.ts
|
|
40948
|
-
var
|
|
40949
|
-
var
|
|
40978
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
40979
|
+
var import_node_fs47 = __toESM(require("fs"), 1);
|
|
40950
40980
|
var import_node_os22 = __toESM(require("os"), 1);
|
|
40951
40981
|
|
|
40952
40982
|
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
@@ -41933,24 +41963,16 @@ function buildConnectionPrompt(args) {
|
|
|
41933
41963
|
// src/persona/sharing-prompt.ts
|
|
41934
41964
|
var ATTACHMENT_SHARING_HINT = `## \u628A\u4EA7\u51FA\u6587\u4EF6\u5206\u4EAB\u7ED9\u5BF9\u65B9\uFF08attachment\uFF09
|
|
41935
41965
|
|
|
41936
|
-
\u5F53\u4F60\u4EA7\u51FA\u4E86\u6587\u4EF6\u3001\u9700\u8981\u8BA9\u5BF9\u65B9\u62FF\u5230\u65F6\uFF08\u5C24\u5176 Bash \u89E3\u538B/\u751F\u6210\u7684\u6587\u4EF6\uFF0C\u6216\u8DE8\u8BBE\u5907\u88AB\u59D4\u6D3E\u65F6\u5BF9\u65B9\u5728\u53E6\u4E00\u53F0\u673A\u5668\u3001\u770B\u4E0D\u5230\u4F60\u7684\u672C\u5730\u8DEF\u5F84\uFF09\uFF0C\u7528
|
|
41966
|
+
\u5F53\u4F60\u4EA7\u51FA\u4E86\u6587\u4EF6\u3001\u9700\u8981\u8BA9\u5BF9\u65B9\u62FF\u5230\u65F6\uFF08\u5C24\u5176 Bash \u89E3\u538B/\u751F\u6210\u7684\u6587\u4EF6\uFF0C\u6216\u8DE8\u8BBE\u5907\u88AB\u59D4\u6D3E\u65F6\u5BF9\u65B9\u5728\u53E6\u4E00\u53F0\u673A\u5668\u3001\u770B\u4E0D\u5230\u4F60\u7684\u672C\u5730\u8DEF\u5F84\uFF09\uFF0C\u7528 \`clawd-rpc\` MCP \u7684 \`call\` tool \u628A\u6587\u4EF6\u8F6C\u6210\u4E00\u4E2A\u5E26\u7B7E\u540D\u7684\u4E0B\u8F7D URL\uFF1A
|
|
41937
41967
|
|
|
41938
41968
|
1. \u5165\u7FA4\uFF08\u767B\u8BB0\u5230\u672C session \u7684\u5171\u4EAB\u6E05\u5355\uFF09\uFF1A
|
|
41939
|
-
|
|
41940
|
-
curl -sS -X POST "$CLAWD_DAEMON_URL/api/rpc/attachment.groupAdd" \\
|
|
41941
|
-
-H "X-Clawd-Session-Id: $CLAWD_SESSION_ID" -H 'Content-Type: application/json' \\
|
|
41942
|
-
-d '{"relPath":"<\u6587\u4EF6\u7684\u7EDD\u5BF9\u8DEF\u5F84>"}'
|
|
41943
|
-
\`\`\`
|
|
41969
|
+
call({ method: "attachment.groupAdd", args: { relPath: "<\u6587\u4EF6\u7684\u7EDD\u5BF9\u8DEF\u5F84>", origin: "agent" } })
|
|
41944
41970
|
2. \u7B7E\u540D\u62FF URL\uFF1A
|
|
41945
|
-
|
|
41946
|
-
curl -sS -X POST "$CLAWD_DAEMON_URL/api/rpc/attachment.signUrl" \\
|
|
41947
|
-
-H "X-Clawd-Session-Id: $CLAWD_SESSION_ID" -H 'Content-Type: application/json' \\
|
|
41948
|
-
-d '{"relPath":"<\u540C\u4E00\u4E2A\u7EDD\u5BF9\u8DEF\u5F84>"}'
|
|
41949
|
-
\`\`\`
|
|
41971
|
+
call({ method: "attachment.signUrl", args: { relPath: "<\u540C\u4E00\u4E2A\u7EDD\u5BF9\u8DEF\u5F84>" } })
|
|
41950
41972
|
\u8FD4\u56DE\u7684 \`url\` \u5C31\u662F\u5BF9\u65B9\u53EF\u76F4\u63A5\u6253\u5F00/\u4E0B\u8F7D\u7684\u94FE\u63A5\u3002
|
|
41951
41973
|
|
|
41952
41974
|
- \`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
|
|
41953
|
-
- \u53EA\u80FD\u5206\u4EAB\
|
|
41975
|
+
- \u8DE8\u8BBE\u5907\u88AB\u59D4\u6D3E\uFF08guest\uFF09\u7684\u4F1A\u8BDD\u53EA\u80FD\u5206\u4EAB\u81EA\u5DF1\u5DE5\u4F5C\u76EE\u5F55\u5185\u7684\u6587\u4EF6\uFF0C\u8D8A\u754C\u4F1A\u88AB\u62D2\u3002
|
|
41954
41976
|
- \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`;
|
|
41955
41977
|
|
|
41956
41978
|
// src/persona/no-ask-user-question-prompt.ts
|
|
@@ -42950,7 +42972,7 @@ var SessionRunner = class {
|
|
|
42950
42972
|
ownerFeishuUnionId: this.hooks.ownerFeishuUnionId,
|
|
42951
42973
|
personaRoot: this.hooks.personaRoot,
|
|
42952
42974
|
// 单栏 refactor (spec 2026-06-02 §5.1): cc 子进程 env 注入 CLAWD_DAEMON_URL,让 assistant
|
|
42953
|
-
//
|
|
42975
|
+
// MCP server 拼 /rpc/<method>(Bearer)调 daemon。null = HTTP RPC 未启。
|
|
42954
42976
|
getDaemonUrl: this.hooks.getDaemonUrl,
|
|
42955
42977
|
// clawd 管家 (spec 2026-07-22-clawd-butler-persona §3.1): cc 子进程 env 注入 CLAWOS_API,
|
|
42956
42978
|
// 让 clawd 管家 skill fetch `${CLAWOS_API}/docs/**` 线上文档。
|
|
@@ -46506,8 +46528,9 @@ var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
|
46506
46528
|
init_runtime();
|
|
46507
46529
|
|
|
46508
46530
|
// src/visitor/visitor-token.ts
|
|
46531
|
+
var DOMAIN_PREFIX = "clawd-visitor-v1|";
|
|
46509
46532
|
function hmac(secret, body) {
|
|
46510
|
-
return import_node_crypto4.default.createHmac("sha256", secret).update(body).digest("base64url");
|
|
46533
|
+
return import_node_crypto4.default.createHmac("sha256", secret).update(`${DOMAIN_PREFIX}${body}`).digest("base64url");
|
|
46511
46534
|
}
|
|
46512
46535
|
function signVisitorToken(secret, payload) {
|
|
46513
46536
|
const body = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
@@ -46880,8 +46903,8 @@ function turnStartInput(text) {
|
|
|
46880
46903
|
const items = [];
|
|
46881
46904
|
let leftover = text;
|
|
46882
46905
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
46883
|
-
const [marker, name,
|
|
46884
|
-
items.push({ type: "skill", name, path:
|
|
46906
|
+
const [marker, name, path75] = m2;
|
|
46907
|
+
items.push({ type: "skill", name, path: path75 });
|
|
46885
46908
|
leftover = leftover.replace(marker, "");
|
|
46886
46909
|
}
|
|
46887
46910
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -48470,13 +48493,6 @@ function jsonlExistsForCtx(ctx) {
|
|
|
48470
48493
|
init_claude_history();
|
|
48471
48494
|
|
|
48472
48495
|
// src/dispatch/manager.ts
|
|
48473
|
-
function defer() {
|
|
48474
|
-
let resolve6;
|
|
48475
|
-
const promise = new Promise((r) => {
|
|
48476
|
-
resolve6 = r;
|
|
48477
|
-
});
|
|
48478
|
-
return { promise, resolve: resolve6 };
|
|
48479
|
-
}
|
|
48480
48496
|
var PersonaDispatchManager = class {
|
|
48481
48497
|
constructor(deps) {
|
|
48482
48498
|
this.deps = deps;
|
|
@@ -48488,8 +48504,7 @@ var PersonaDispatchManager = class {
|
|
|
48488
48504
|
this.map.set(dispatchId, {
|
|
48489
48505
|
dispatchId,
|
|
48490
48506
|
sourceSessionId: args.sourceSessionId,
|
|
48491
|
-
targetPersona: args.targetPersona
|
|
48492
|
-
waiters: []
|
|
48507
|
+
targetPersona: args.targetPersona
|
|
48493
48508
|
});
|
|
48494
48509
|
this.deps.store.add({
|
|
48495
48510
|
dispatchId,
|
|
@@ -48511,45 +48526,21 @@ var PersonaDispatchManager = class {
|
|
|
48511
48526
|
outcome,
|
|
48512
48527
|
completedAt: new Date(this.deps.now()).toISOString()
|
|
48513
48528
|
});
|
|
48514
|
-
if (state)
|
|
48515
|
-
const waiters = state.waiters;
|
|
48516
|
-
state.waiters = [];
|
|
48517
|
-
for (const w2 of waiters) w2.resolve(outcome);
|
|
48518
|
-
this.map.delete(dispatchId);
|
|
48519
|
-
}
|
|
48529
|
+
if (state) this.map.delete(dispatchId);
|
|
48520
48530
|
const sourceSessionId = updated?.sourceSessionId ?? state?.sourceSessionId;
|
|
48521
48531
|
if (sourceSessionId) this.deps.onCompleted?.(sourceSessionId);
|
|
48522
48532
|
}
|
|
48523
|
-
/**
|
|
48524
|
-
* mesh B 角色 hold 专用(跨设备 dispatch 的 peer 侧):guest B-role handler 用它
|
|
48525
|
-
* 挂住 /rpc HTTP 响应直到 complete,把 outcome 回传给 A 侧 daemon 的 forwardToPeer
|
|
48526
|
-
* (A 侧后台 await,A 的 tool call 不受影响照样秒回)。
|
|
48527
|
-
* 本地 dispatch 链路**不用**这个——本地 outcome 只走台账 + deliverPending。
|
|
48528
|
-
*/
|
|
48529
|
-
async waitForOutcome(dispatchId) {
|
|
48530
|
-
const state = this.map.get(dispatchId);
|
|
48531
|
-
if (!state) {
|
|
48532
|
-
const rec3 = this.deps.store.get(dispatchId);
|
|
48533
|
-
if (rec3?.outcome) return rec3.outcome;
|
|
48534
|
-
throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
48535
|
-
}
|
|
48536
|
-
const d = defer();
|
|
48537
|
-
state.waiters.push(d);
|
|
48538
|
-
return d.promise;
|
|
48539
|
-
}
|
|
48540
48533
|
/**
|
|
48541
48534
|
* 续派(spec 2026-07-21):complete 已清掉 map 条目,续派前重建——bSessionId 映射
|
|
48542
48535
|
* 保证 worker 进程死后 respawn 时 reducer lookupDispatchByBSessionId 仍注回同一
|
|
48543
48536
|
* CLAWD_DISPATCH_ID env。台账行的复位由 handler 直接走 store(本方法只管内存态)。
|
|
48544
48537
|
*/
|
|
48545
48538
|
reopen(dispatchId, args) {
|
|
48546
|
-
const existing = this.map.get(dispatchId);
|
|
48547
48539
|
this.map.set(dispatchId, {
|
|
48548
48540
|
dispatchId,
|
|
48549
48541
|
sourceSessionId: args.sourceSessionId,
|
|
48550
48542
|
targetPersona: args.targetPersona,
|
|
48551
|
-
bSessionId: args.workerSessionId
|
|
48552
|
-
waiters: existing?.waiters ?? []
|
|
48543
|
+
bSessionId: args.workerSessionId
|
|
48553
48544
|
});
|
|
48554
48545
|
}
|
|
48555
48546
|
/** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
|
|
@@ -48678,13 +48669,17 @@ function dispatchMcpConfigPath(dataDir) {
|
|
|
48678
48669
|
function writeDispatchMcpConfig(args) {
|
|
48679
48670
|
const cfgPath = dispatchMcpConfigPath(args.dataDir);
|
|
48680
48671
|
const content = {
|
|
48681
|
-
_comment: "daemon \u542F\u52A8\u65F6\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002dispatch-mcp-server.cjs \u662F daemon \u81EA\u5E26\u7684 stdio MCP server\u3002env.CLAWD_DISPATCH_LOG \u6307 server \u5199\u65E5\u5FD7\u7684 append \u6587\u4EF6\u8DEF\u5F84\uFF08dispatch \u6D41\u7A0B\u8282\u70B9 + fetch \u9519\u8BEF\u7EC6\u8282\uFF09\u3002",
|
|
48672
|
+
_comment: "daemon \u542F\u52A8\u65F6\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002dispatch-mcp-server.cjs \u662F daemon \u81EA\u5E26\u7684 stdio MCP server\uFF0C\u7ECF /rpc + Bearer\uFF08env CLAWD_DAEMON_TOKEN\uFF0C\u4EC5\u672C server \u8FDB\u7A0B\u53EF\u89C1\uFF09\u8C03 daemon\u3002env.CLAWD_DISPATCH_LOG \u6307 server \u5199\u65E5\u5FD7\u7684 append \u6587\u4EF6\u8DEF\u5F84\uFF08dispatch \u6D41\u7A0B\u8282\u70B9 + fetch \u9519\u8BEF\u7EC6\u8282\uFF09\u3002",
|
|
48682
48673
|
mcpServers: {
|
|
48683
48674
|
"clawd-dispatch": {
|
|
48684
48675
|
type: "stdio",
|
|
48685
48676
|
command: "node",
|
|
48686
48677
|
args: [args.serverScriptPath],
|
|
48687
|
-
|
|
48678
|
+
env: {
|
|
48679
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48680
|
+
CLAWD_DAEMON_URL: args.daemonUrl,
|
|
48681
|
+
...args.logPath ? { CLAWD_DISPATCH_LOG: args.logPath } : {}
|
|
48682
|
+
}
|
|
48688
48683
|
}
|
|
48689
48684
|
}
|
|
48690
48685
|
};
|
|
@@ -48702,7 +48697,7 @@ function ticketMcpConfigPath(dataDir) {
|
|
|
48702
48697
|
function writeTicketMcpConfig(args) {
|
|
48703
48698
|
const cfgPath = ticketMcpConfigPath(args.dataDir);
|
|
48704
48699
|
const content = {
|
|
48705
|
-
_comment: "daemon \u542F\u52A8\u65F6\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002ticket-mcp-server.cjs \u662F daemon \u81EA\u5E26\u7684 stdio MCP server\uFF0CHTTP client \u8C03 clawos api /api/tickets/*\u3002env \u542B api url\u3001\u5199\u6B7B API key\u3001scene\uFF1Bdid/name \u6BCF\u6B21 tool call \u8D70
|
|
48700
|
+
_comment: "daemon \u542F\u52A8\u65F6\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002ticket-mcp-server.cjs \u662F daemon \u81EA\u5E26\u7684 stdio MCP server\uFF0CHTTP client \u8C03 clawos api /api/tickets/*\u3002env \u542B api url\u3001\u5199\u6B7B API key\u3001scene\uFF1Bdid/name \u6BCF\u6B21 tool call \u8D70 /rpc/session:currentTurnSender (Bearer CLAWD_DAEMON_TOKEN) \u62FF\u5F53\u524D turn caller (2026-07-08 spec \xA74.7)\u3002CLAWD_TICKET_LOG \u6307 server \u5199\u65E5\u5FD7\u7684 append \u6587\u4EF6\u8DEF\u5F84\u3002cc \u573A\u666F scene \u56FA\u5B9A persona\u3002",
|
|
48706
48701
|
mcpServers: {
|
|
48707
48702
|
"clawd-ticket": {
|
|
48708
48703
|
type: "stdio",
|
|
@@ -48712,6 +48707,8 @@ function writeTicketMcpConfig(args) {
|
|
|
48712
48707
|
CLAWD_TICKET_API_URL: args.apiBaseUrl,
|
|
48713
48708
|
CLAWD_TICKET_API_KEY: args.apiKey,
|
|
48714
48709
|
CLAWD_TICKET_SCENE: "persona",
|
|
48710
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48711
|
+
CLAWD_DAEMON_URL: args.daemonUrl,
|
|
48715
48712
|
...args.logPath ? { CLAWD_TICKET_LOG: args.logPath } : {}
|
|
48716
48713
|
}
|
|
48717
48714
|
}
|
|
@@ -48737,7 +48734,11 @@ async function writeShiftMcpConfig(args) {
|
|
|
48737
48734
|
type: "stdio",
|
|
48738
48735
|
command: "node",
|
|
48739
48736
|
args: [args.serverScriptPath],
|
|
48740
|
-
|
|
48737
|
+
env: {
|
|
48738
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48739
|
+
CLAWD_DAEMON_URL: args.daemonUrl,
|
|
48740
|
+
...args.logPath ? { CLAWD_SHIFT_LOG: args.logPath } : {}
|
|
48741
|
+
}
|
|
48741
48742
|
}
|
|
48742
48743
|
}
|
|
48743
48744
|
};
|
|
@@ -48761,7 +48762,11 @@ async function writeInboxMcpConfig(args) {
|
|
|
48761
48762
|
type: "stdio",
|
|
48762
48763
|
command: "node",
|
|
48763
48764
|
args: [args.serverScriptPath],
|
|
48764
|
-
|
|
48765
|
+
env: {
|
|
48766
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48767
|
+
CLAWD_DAEMON_URL: args.daemonUrl,
|
|
48768
|
+
...args.logPath ? { CLAWD_INBOX_LOG: args.logPath } : {}
|
|
48769
|
+
}
|
|
48765
48770
|
}
|
|
48766
48771
|
}
|
|
48767
48772
|
};
|
|
@@ -48779,11 +48784,15 @@ function peerOpsMcpConfigPath(dataDir) {
|
|
|
48779
48784
|
function writePeerOpsMcpConfig(args) {
|
|
48780
48785
|
const cfgPath = peerOpsMcpConfigPath(args.dataDir);
|
|
48781
48786
|
const cfg = {
|
|
48782
|
-
_comment: "daemon \u542F\u52A8\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002peer-ops-mcp-server.cjs \u662F daemon \u81EA\u5E26 stdio MCP server\uFF08\u8DE8\u8BBE\u5907 exec\uFF09\u3002",
|
|
48787
|
+
_comment: "daemon \u542F\u52A8\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002peer-ops-mcp-server.cjs \u662F daemon \u81EA\u5E26 stdio MCP server\uFF08\u8DE8\u8BBE\u5907 exec\uFF09\uFF0C\u7ECF /rpc + Bearer\uFF08env CLAWD_DAEMON_TOKEN\uFF09\u8C03 daemon\u3002",
|
|
48783
48788
|
mcpServers: {
|
|
48784
48789
|
"peer-ops": {
|
|
48785
48790
|
command: "node",
|
|
48786
|
-
args: [args.serverScriptPath]
|
|
48791
|
+
args: [args.serverScriptPath],
|
|
48792
|
+
env: {
|
|
48793
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48794
|
+
CLAWD_DAEMON_URL: args.daemonUrl
|
|
48795
|
+
}
|
|
48787
48796
|
}
|
|
48788
48797
|
}
|
|
48789
48798
|
};
|
|
@@ -48792,9 +48801,37 @@ function writePeerOpsMcpConfig(args) {
|
|
|
48792
48801
|
return cfgPath;
|
|
48793
48802
|
}
|
|
48794
48803
|
|
|
48804
|
+
// src/rpc-tool/mcp-config.ts
|
|
48805
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
48806
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
48807
|
+
function rpcToolMcpConfigPath(dataDir) {
|
|
48808
|
+
return import_node_path24.default.join(dataDir, "rpc-tool.mcp.json");
|
|
48809
|
+
}
|
|
48810
|
+
function writeRpcToolMcpConfig(args) {
|
|
48811
|
+
const cfgPath = rpcToolMcpConfigPath(args.dataDir);
|
|
48812
|
+
const content = {
|
|
48813
|
+
_comment: "daemon \u542F\u52A8\u65F6\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002rpc-tool/mcp-server.cjs \u662F daemon \u81EA\u5E26\u7684 stdio MCP server\uFF0C\u66B4\u9732\u6CDB\u5316 call(method, args) tool\u2014\u2014agent \u8C03 daemon RPC \u7684\u552F\u4E00\u6536\u53E3\uFF08/rpc + Bearer\uFF0Ctoken \u4EC5\u672C server \u8FDB\u7A0B\u53EF\u89C1\uFF09\u3002",
|
|
48814
|
+
mcpServers: {
|
|
48815
|
+
"clawd-rpc": {
|
|
48816
|
+
type: "stdio",
|
|
48817
|
+
command: "node",
|
|
48818
|
+
args: [args.serverScriptPath],
|
|
48819
|
+
env: {
|
|
48820
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48821
|
+
CLAWD_DAEMON_URL: args.daemonUrl,
|
|
48822
|
+
...args.logPath ? { CLAWD_RPC_LOG: args.logPath } : {}
|
|
48823
|
+
}
|
|
48824
|
+
}
|
|
48825
|
+
}
|
|
48826
|
+
};
|
|
48827
|
+
import_node_fs25.default.mkdirSync(args.dataDir, { recursive: true });
|
|
48828
|
+
import_node_fs25.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
|
|
48829
|
+
return cfgPath;
|
|
48830
|
+
}
|
|
48831
|
+
|
|
48795
48832
|
// src/shift/store.ts
|
|
48796
48833
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
48797
|
-
var
|
|
48834
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
48798
48835
|
var import_node_crypto6 = require("crypto");
|
|
48799
48836
|
|
|
48800
48837
|
// src/shift/schedule.ts
|
|
@@ -48869,7 +48906,7 @@ function createShiftStore(deps) {
|
|
|
48869
48906
|
flushTimer = null;
|
|
48870
48907
|
}
|
|
48871
48908
|
const content = { version: 1, shifts };
|
|
48872
|
-
await import_promises2.default.mkdir(
|
|
48909
|
+
await import_promises2.default.mkdir(import_node_path25.default.dirname(deps.filePath), { recursive: true });
|
|
48873
48910
|
const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
|
|
48874
48911
|
await import_promises2.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
|
|
48875
48912
|
await import_promises2.default.rename(tmp, deps.filePath);
|
|
@@ -49322,7 +49359,7 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
49322
49359
|
}
|
|
49323
49360
|
if (!sourceSessionId) {
|
|
49324
49361
|
throw new Error(
|
|
49325
|
-
"personaDispatch:run requires sessionId
|
|
49362
|
+
"personaDispatch:run requires sessionId in the request body"
|
|
49326
49363
|
);
|
|
49327
49364
|
}
|
|
49328
49365
|
const rec3 = deps.store.get(args.dispatchId);
|
|
@@ -49395,7 +49432,7 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
49395
49432
|
}
|
|
49396
49433
|
if (!sourceSessionId) {
|
|
49397
49434
|
throw new Error(
|
|
49398
|
-
"personaDispatch:run requires sessionId
|
|
49435
|
+
"personaDispatch:run requires sessionId in the request body"
|
|
49399
49436
|
);
|
|
49400
49437
|
}
|
|
49401
49438
|
const { dispatchId: dispatchId2 } = mgr.start({
|
|
@@ -49462,14 +49499,13 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
49462
49499
|
reason: `failed to spawn B: ${reason}`
|
|
49463
49500
|
});
|
|
49464
49501
|
});
|
|
49465
|
-
const outcome = await mgr.waitForOutcome(dispatchId2);
|
|
49466
49502
|
return {
|
|
49467
|
-
response: { type: "personaDispatch:run:ok",
|
|
49503
|
+
response: { type: "personaDispatch:run:ok", dispatchId: dispatchId2 }
|
|
49468
49504
|
};
|
|
49469
49505
|
}
|
|
49470
49506
|
if (!sourceSessionId) {
|
|
49471
49507
|
throw new Error(
|
|
49472
|
-
"personaDispatch:run requires sessionId
|
|
49508
|
+
"personaDispatch:run requires sessionId in the request body"
|
|
49473
49509
|
);
|
|
49474
49510
|
}
|
|
49475
49511
|
const { dispatchId } = mgr.start({
|
|
@@ -49517,6 +49553,22 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
49517
49553
|
response: { type: "personaDispatch:complete:ok" }
|
|
49518
49554
|
};
|
|
49519
49555
|
};
|
|
49556
|
+
const get = async (frame, _client, ctx) => {
|
|
49557
|
+
const { type: _t, requestId: _r, ...rest } = frame;
|
|
49558
|
+
const args = DispatchGetArgsSchema.parse(rest);
|
|
49559
|
+
const rec3 = deps.store.get(args.dispatchId);
|
|
49560
|
+
const denied = ctx?.principal.kind === "guest" && rec3?.sourceSessionId !== ctx.principal.id;
|
|
49561
|
+
if (!rec3 || denied) {
|
|
49562
|
+
throw new ClawdError(ERROR_CODES.DISPATCH_NOT_FOUND, `unknown dispatchId: ${args.dispatchId}`);
|
|
49563
|
+
}
|
|
49564
|
+
return {
|
|
49565
|
+
response: {
|
|
49566
|
+
type: "personaDispatch:get:ok",
|
|
49567
|
+
status: rec3.status,
|
|
49568
|
+
...rec3.outcome ? { outcome: rec3.outcome } : {}
|
|
49569
|
+
}
|
|
49570
|
+
};
|
|
49571
|
+
};
|
|
49520
49572
|
const list = async (frame) => {
|
|
49521
49573
|
const { type: _t, requestId: _r, ...rest } = frame;
|
|
49522
49574
|
const args = DispatchListArgsSchema.parse(rest);
|
|
@@ -49530,7 +49582,8 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
49530
49582
|
return {
|
|
49531
49583
|
"personaDispatch:run": run,
|
|
49532
49584
|
"personaDispatch:complete": complete,
|
|
49533
|
-
"personaDispatch:list": list
|
|
49585
|
+
"personaDispatch:list": list,
|
|
49586
|
+
"personaDispatch:get": get
|
|
49534
49587
|
};
|
|
49535
49588
|
}
|
|
49536
49589
|
|
|
@@ -49541,8 +49594,13 @@ function wsUrlToHttp(url) {
|
|
|
49541
49594
|
if (url.startsWith("ws://")) return "http://" + url.slice("ws://".length);
|
|
49542
49595
|
return url;
|
|
49543
49596
|
}
|
|
49597
|
+
var DISPATCH_POLL_INTERVAL_MS = 5e3;
|
|
49598
|
+
var DISPATCH_POLL_UNREACHABLE_MS = 6e5;
|
|
49599
|
+
var DISPATCH_POLL_TOTAL_MS = 864e5;
|
|
49600
|
+
var defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
49544
49601
|
async function forwardDispatchToPeer(args) {
|
|
49545
49602
|
const f = args.fetchImpl ?? fetch;
|
|
49603
|
+
const sleep2 = args.sleepImpl ?? defaultSleep;
|
|
49546
49604
|
const base = wsUrlToHttp(args.contact.remoteUrl).replace(/\/+$/, "");
|
|
49547
49605
|
const url = `${base}/rpc/personaDispatch:run`;
|
|
49548
49606
|
let res;
|
|
@@ -49577,7 +49635,58 @@ async function forwardDispatchToPeer(args) {
|
|
|
49577
49635
|
if (json.ok === false) {
|
|
49578
49636
|
return { kind: "failure", reason: `peer rejected: ${json.error}: ${json.message}` };
|
|
49579
49637
|
}
|
|
49580
|
-
return json.result.outcome;
|
|
49638
|
+
if ("outcome" in json.result) return json.result.outcome;
|
|
49639
|
+
const dispatchId = json.result.dispatchId;
|
|
49640
|
+
let elapsed = 0;
|
|
49641
|
+
let unreachableFor = 0;
|
|
49642
|
+
while (elapsed < DISPATCH_POLL_TOTAL_MS) {
|
|
49643
|
+
await sleep2(DISPATCH_POLL_INTERVAL_MS);
|
|
49644
|
+
elapsed += DISPATCH_POLL_INTERVAL_MS;
|
|
49645
|
+
const markUnreachable = () => {
|
|
49646
|
+
unreachableFor += DISPATCH_POLL_INTERVAL_MS;
|
|
49647
|
+
return unreachableFor >= DISPATCH_POLL_UNREACHABLE_MS ? {
|
|
49648
|
+
kind: "failure",
|
|
49649
|
+
reason: "peer unreachable while polling dispatch outcome (TARGET_UNREACHABLE)"
|
|
49650
|
+
} : null;
|
|
49651
|
+
};
|
|
49652
|
+
let getRes;
|
|
49653
|
+
try {
|
|
49654
|
+
getRes = await f(`${base}/rpc/personaDispatch:get`, {
|
|
49655
|
+
method: "POST",
|
|
49656
|
+
headers: {
|
|
49657
|
+
"content-type": "application/json",
|
|
49658
|
+
authorization: `Bearer ${args.contact.connectToken}`
|
|
49659
|
+
},
|
|
49660
|
+
body: JSON.stringify({ dispatchId })
|
|
49661
|
+
});
|
|
49662
|
+
} catch {
|
|
49663
|
+
const dead = markUnreachable();
|
|
49664
|
+
if (dead) return dead;
|
|
49665
|
+
continue;
|
|
49666
|
+
}
|
|
49667
|
+
let getJson;
|
|
49668
|
+
try {
|
|
49669
|
+
getJson = await getRes.json();
|
|
49670
|
+
} catch {
|
|
49671
|
+
const dead = markUnreachable();
|
|
49672
|
+
if (dead) return dead;
|
|
49673
|
+
continue;
|
|
49674
|
+
}
|
|
49675
|
+
if (getJson.ok === false) {
|
|
49676
|
+
if (getJson.error === ERROR_CODES.DISPATCH_NOT_FOUND) {
|
|
49677
|
+
return { kind: "failure", reason: `peer lost dispatch ${dispatchId} (daemon restarted?)` };
|
|
49678
|
+
}
|
|
49679
|
+
const dead = markUnreachable();
|
|
49680
|
+
if (dead) return dead;
|
|
49681
|
+
continue;
|
|
49682
|
+
}
|
|
49683
|
+
unreachableFor = 0;
|
|
49684
|
+
const { status, outcome } = getJson.result;
|
|
49685
|
+
if (status === "completed" || status === "failed") {
|
|
49686
|
+
return outcome ?? { kind: "failure", reason: "peer returned terminal status without outcome" };
|
|
49687
|
+
}
|
|
49688
|
+
}
|
|
49689
|
+
return { kind: "failure", reason: "dispatch polling exceeded 24h (TIMEOUT)" };
|
|
49581
49690
|
}
|
|
49582
49691
|
async function forwardInboxPostToPeer(args) {
|
|
49583
49692
|
const f = args.fetchImpl ?? fetch;
|
|
@@ -49821,7 +49930,7 @@ var CodexHistoryReader = class {
|
|
|
49821
49930
|
|
|
49822
49931
|
// src/tools/codex-skills.ts
|
|
49823
49932
|
var import_node_child_process7 = require("child_process");
|
|
49824
|
-
var
|
|
49933
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
49825
49934
|
var DEFAULT_TIMEOUT_MS3 = 8e3;
|
|
49826
49935
|
function str3(v2) {
|
|
49827
49936
|
return typeof v2 === "string" ? v2 : void 0;
|
|
@@ -49837,13 +49946,13 @@ function mapSkillsListResponse(res) {
|
|
|
49837
49946
|
const r = s ?? {};
|
|
49838
49947
|
const name = str3(r.name);
|
|
49839
49948
|
if (!name) continue;
|
|
49840
|
-
const
|
|
49949
|
+
const path75 = str3(r.path);
|
|
49841
49950
|
const description = str3(r.description);
|
|
49842
49951
|
const isPlugin = name.includes(":");
|
|
49843
49952
|
out.push({
|
|
49844
49953
|
name,
|
|
49845
49954
|
source: isPlugin ? "plugin" : "project",
|
|
49846
|
-
...
|
|
49955
|
+
...path75 ? { path: path75 } : {},
|
|
49847
49956
|
...description ? { description } : {},
|
|
49848
49957
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
49849
49958
|
});
|
|
@@ -49873,7 +49982,7 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
49873
49982
|
})(),
|
|
49874
49983
|
timeout
|
|
49875
49984
|
]);
|
|
49876
|
-
void client.request("skills/extraRoots/set", { extraRoots: [
|
|
49985
|
+
void client.request("skills/extraRoots/set", { extraRoots: [import_node_path26.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
|
|
49877
49986
|
const res = await Promise.race([client.request("skills/list", { cwds: [cwd] }), timeout]);
|
|
49878
49987
|
return mapSkillsListResponse(res);
|
|
49879
49988
|
} finally {
|
|
@@ -49883,23 +49992,23 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
49883
49992
|
}
|
|
49884
49993
|
|
|
49885
49994
|
// src/workspace/browser.ts
|
|
49886
|
-
var
|
|
49995
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
49887
49996
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
49888
|
-
var
|
|
49997
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
49889
49998
|
init_protocol();
|
|
49890
49999
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
49891
50000
|
function resolveInsideCwd(cwd, subpath) {
|
|
49892
|
-
const absCwd =
|
|
49893
|
-
const joined =
|
|
49894
|
-
const rel =
|
|
49895
|
-
if (rel.startsWith("..") ||
|
|
50001
|
+
const absCwd = import_node_path27.default.resolve(cwd);
|
|
50002
|
+
const joined = import_node_path27.default.resolve(absCwd, subpath ?? ".");
|
|
50003
|
+
const rel = import_node_path27.default.relative(absCwd, joined);
|
|
50004
|
+
if (rel.startsWith("..") || import_node_path27.default.isAbsolute(rel)) {
|
|
49896
50005
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
49897
50006
|
}
|
|
49898
50007
|
return joined;
|
|
49899
50008
|
}
|
|
49900
50009
|
function ensureCwd(cwd) {
|
|
49901
50010
|
try {
|
|
49902
|
-
const stat =
|
|
50011
|
+
const stat = import_node_fs26.default.statSync(cwd);
|
|
49903
50012
|
if (!stat.isDirectory()) {
|
|
49904
50013
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
|
|
49905
50014
|
}
|
|
@@ -49913,7 +50022,7 @@ var WorkspaceBrowser = class {
|
|
|
49913
50022
|
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os8.default.homedir();
|
|
49914
50023
|
ensureCwd(cwd);
|
|
49915
50024
|
const full = resolveInsideCwd(cwd, args.path);
|
|
49916
|
-
const dirents =
|
|
50025
|
+
const dirents = import_node_fs26.default.readdirSync(full, { withFileTypes: true });
|
|
49917
50026
|
const entries = [];
|
|
49918
50027
|
for (const d of dirents) {
|
|
49919
50028
|
if (!args.showHidden && d.name.startsWith(".")) continue;
|
|
@@ -49923,7 +50032,7 @@ var WorkspaceBrowser = class {
|
|
|
49923
50032
|
mtime: ""
|
|
49924
50033
|
};
|
|
49925
50034
|
try {
|
|
49926
|
-
const st =
|
|
50035
|
+
const st = import_node_fs26.default.statSync(import_node_path27.default.join(full, d.name));
|
|
49927
50036
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
49928
50037
|
if (d.isFile()) entry.size = st.size;
|
|
49929
50038
|
} catch {
|
|
@@ -49939,14 +50048,14 @@ var WorkspaceBrowser = class {
|
|
|
49939
50048
|
read(args) {
|
|
49940
50049
|
ensureCwd(args.cwd);
|
|
49941
50050
|
const full = resolveInsideCwd(args.cwd, args.path);
|
|
49942
|
-
const st =
|
|
50051
|
+
const st = import_node_fs26.default.statSync(full);
|
|
49943
50052
|
if (!st.isFile()) {
|
|
49944
50053
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
|
|
49945
50054
|
}
|
|
49946
50055
|
if (st.size > MAX_FILE_BYTES) {
|
|
49947
50056
|
throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
|
|
49948
50057
|
}
|
|
49949
|
-
const buf =
|
|
50058
|
+
const buf = import_node_fs26.default.readFileSync(full);
|
|
49950
50059
|
const isBinary = buf.includes(0);
|
|
49951
50060
|
if (isBinary) {
|
|
49952
50061
|
return {
|
|
@@ -49968,20 +50077,20 @@ var WorkspaceBrowser = class {
|
|
|
49968
50077
|
};
|
|
49969
50078
|
|
|
49970
50079
|
// src/skills/agents-scanner.ts
|
|
49971
|
-
var
|
|
50080
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
49972
50081
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
49973
|
-
var
|
|
50082
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
49974
50083
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
49975
50084
|
function isDirLikeSync2(p2) {
|
|
49976
50085
|
try {
|
|
49977
|
-
return
|
|
50086
|
+
return import_node_fs27.default.statSync(p2).isDirectory();
|
|
49978
50087
|
} catch {
|
|
49979
50088
|
return false;
|
|
49980
50089
|
}
|
|
49981
50090
|
}
|
|
49982
50091
|
function fileExistsSync(p2) {
|
|
49983
50092
|
try {
|
|
49984
|
-
return
|
|
50093
|
+
return import_node_fs27.default.statSync(p2).isFile();
|
|
49985
50094
|
} catch {
|
|
49986
50095
|
return false;
|
|
49987
50096
|
}
|
|
@@ -49989,7 +50098,7 @@ function fileExistsSync(p2) {
|
|
|
49989
50098
|
function parseAgentFile(filePath) {
|
|
49990
50099
|
let content;
|
|
49991
50100
|
try {
|
|
49992
|
-
content =
|
|
50101
|
+
content = import_node_fs27.default.readFileSync(filePath, "utf8");
|
|
49993
50102
|
} catch {
|
|
49994
50103
|
return {};
|
|
49995
50104
|
}
|
|
@@ -50002,16 +50111,16 @@ function parseAgentFile(filePath) {
|
|
|
50002
50111
|
function scanAgentsDir(dir, source, seen, out) {
|
|
50003
50112
|
let entries;
|
|
50004
50113
|
try {
|
|
50005
|
-
entries =
|
|
50114
|
+
entries = import_node_fs27.default.readdirSync(dir, { withFileTypes: true });
|
|
50006
50115
|
} catch {
|
|
50007
50116
|
return;
|
|
50008
50117
|
}
|
|
50009
50118
|
for (const ent of entries) {
|
|
50010
50119
|
if (!ent.name.endsWith(".md")) continue;
|
|
50011
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
50120
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path28.default.join(dir, ent.name)))) {
|
|
50012
50121
|
continue;
|
|
50013
50122
|
}
|
|
50014
|
-
const filePath =
|
|
50123
|
+
const filePath = import_node_path28.default.join(dir, ent.name);
|
|
50015
50124
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
50016
50125
|
if (seen.has(baseName)) continue;
|
|
50017
50126
|
seen.add(baseName);
|
|
@@ -50029,12 +50138,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
50029
50138
|
function walk2(dir, namespaces) {
|
|
50030
50139
|
let entries;
|
|
50031
50140
|
try {
|
|
50032
|
-
entries =
|
|
50141
|
+
entries = import_node_fs27.default.readdirSync(dir, { withFileTypes: true });
|
|
50033
50142
|
} catch {
|
|
50034
50143
|
return;
|
|
50035
50144
|
}
|
|
50036
50145
|
for (const ent of entries) {
|
|
50037
|
-
const childPath =
|
|
50146
|
+
const childPath = import_node_path28.default.join(dir, ent.name);
|
|
50038
50147
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
50039
50148
|
walk2(childPath, [...namespaces, ent.name]);
|
|
50040
50149
|
continue;
|
|
@@ -50059,13 +50168,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
50059
50168
|
walk2(root, []);
|
|
50060
50169
|
}
|
|
50061
50170
|
function readInstalledPlugins2(home) {
|
|
50062
|
-
const pluginsDir =
|
|
50063
|
-
const v2 =
|
|
50064
|
-
const v1 =
|
|
50171
|
+
const pluginsDir = import_node_path28.default.join(home, ".claude", "plugins");
|
|
50172
|
+
const v2 = import_node_path28.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
50173
|
+
const v1 = import_node_path28.default.join(pluginsDir, "installed_plugins.json");
|
|
50065
50174
|
let raw = null;
|
|
50066
50175
|
for (const candidate of [v2, v1]) {
|
|
50067
50176
|
try {
|
|
50068
|
-
raw =
|
|
50177
|
+
raw = import_node_fs27.default.readFileSync(candidate, "utf8");
|
|
50069
50178
|
break;
|
|
50070
50179
|
} catch {
|
|
50071
50180
|
}
|
|
@@ -50090,19 +50199,19 @@ function readInstalledPlugins2(home) {
|
|
|
50090
50199
|
return out;
|
|
50091
50200
|
}
|
|
50092
50201
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
50093
|
-
let cur =
|
|
50094
|
-
const fsRoot =
|
|
50202
|
+
let cur = import_node_path28.default.resolve(startCwd);
|
|
50203
|
+
const fsRoot = import_node_path28.default.parse(cur).root;
|
|
50095
50204
|
while (true) {
|
|
50096
|
-
scanAgentsDir(
|
|
50205
|
+
scanAgentsDir(import_node_path28.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
50097
50206
|
let hasGit = false;
|
|
50098
50207
|
try {
|
|
50099
|
-
hasGit =
|
|
50208
|
+
hasGit = import_node_fs27.default.existsSync(import_node_path28.default.join(cur, ".git"));
|
|
50100
50209
|
} catch {
|
|
50101
50210
|
}
|
|
50102
50211
|
if (hasGit) return;
|
|
50103
50212
|
if (cur === home) return;
|
|
50104
50213
|
if (cur === fsRoot) return;
|
|
50105
|
-
const parent =
|
|
50214
|
+
const parent = import_node_path28.default.dirname(cur);
|
|
50106
50215
|
if (parent === cur) return;
|
|
50107
50216
|
cur = parent;
|
|
50108
50217
|
}
|
|
@@ -50137,7 +50246,7 @@ var AgentsScanner = class {
|
|
|
50137
50246
|
}
|
|
50138
50247
|
const fsBlock = [];
|
|
50139
50248
|
scanAgentsDir(
|
|
50140
|
-
|
|
50249
|
+
import_node_path28.default.join(this.home, ".claude", "agents"),
|
|
50141
50250
|
"global",
|
|
50142
50251
|
seen,
|
|
50143
50252
|
fsBlock
|
|
@@ -50151,7 +50260,7 @@ var AgentsScanner = class {
|
|
|
50151
50260
|
...this.extraPluginRoots
|
|
50152
50261
|
];
|
|
50153
50262
|
for (const { name, root } of plugins) {
|
|
50154
|
-
const agentsRoot =
|
|
50263
|
+
const agentsRoot = import_node_path28.default.join(root, "agents");
|
|
50155
50264
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
50156
50265
|
}
|
|
50157
50266
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -50159,15 +50268,15 @@ var AgentsScanner = class {
|
|
|
50159
50268
|
};
|
|
50160
50269
|
|
|
50161
50270
|
// src/observer/session-observer.ts
|
|
50162
|
-
var
|
|
50271
|
+
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
50163
50272
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
50164
|
-
var
|
|
50273
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
50165
50274
|
init_claude_history();
|
|
50166
50275
|
|
|
50167
50276
|
// src/observer/subagent-meta-observer.ts
|
|
50168
|
-
var
|
|
50277
|
+
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
50169
50278
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
50170
|
-
var
|
|
50279
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
50171
50280
|
init_claude_history();
|
|
50172
50281
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
50173
50282
|
var SubagentMetaObserver = class {
|
|
@@ -50180,7 +50289,7 @@ var SubagentMetaObserver = class {
|
|
|
50180
50289
|
watches = /* @__PURE__ */ new Map();
|
|
50181
50290
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
50182
50291
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
50183
|
-
return
|
|
50292
|
+
return import_node_path29.default.join(
|
|
50184
50293
|
this.home,
|
|
50185
50294
|
".claude",
|
|
50186
50295
|
"projects",
|
|
@@ -50210,7 +50319,7 @@ var SubagentMetaObserver = class {
|
|
|
50210
50319
|
attachWatcher(w2) {
|
|
50211
50320
|
if (w2.watcher) return;
|
|
50212
50321
|
try {
|
|
50213
|
-
w2.watcher =
|
|
50322
|
+
w2.watcher = import_node_fs28.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
|
|
50214
50323
|
if (!name) return;
|
|
50215
50324
|
const m2 = META_RE.exec(String(name));
|
|
50216
50325
|
if (!m2) return;
|
|
@@ -50222,7 +50331,7 @@ var SubagentMetaObserver = class {
|
|
|
50222
50331
|
scan(w2) {
|
|
50223
50332
|
let entries;
|
|
50224
50333
|
try {
|
|
50225
|
-
entries =
|
|
50334
|
+
entries = import_node_fs28.default.readdirSync(w2.dirPath);
|
|
50226
50335
|
} catch {
|
|
50227
50336
|
return;
|
|
50228
50337
|
}
|
|
@@ -50236,10 +50345,10 @@ var SubagentMetaObserver = class {
|
|
|
50236
50345
|
if (!m2) return;
|
|
50237
50346
|
const agentId = m2[1];
|
|
50238
50347
|
if (w2.emitted.has(agentId)) return;
|
|
50239
|
-
const file =
|
|
50348
|
+
const file = import_node_path29.default.join(w2.dirPath, name);
|
|
50240
50349
|
let raw;
|
|
50241
50350
|
try {
|
|
50242
|
-
raw =
|
|
50351
|
+
raw = import_node_fs28.default.readFileSync(file, "utf8");
|
|
50243
50352
|
} catch {
|
|
50244
50353
|
return;
|
|
50245
50354
|
}
|
|
@@ -50296,14 +50405,14 @@ var SessionObserver = class {
|
|
|
50296
50405
|
metaObserver;
|
|
50297
50406
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
50298
50407
|
if (override) return override;
|
|
50299
|
-
return
|
|
50408
|
+
return import_node_path30.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
50300
50409
|
}
|
|
50301
50410
|
start(args) {
|
|
50302
50411
|
this.stop(args.sessionId);
|
|
50303
50412
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
50304
50413
|
let size = 0;
|
|
50305
50414
|
try {
|
|
50306
|
-
size =
|
|
50415
|
+
size = import_node_fs29.default.statSync(filePath).size;
|
|
50307
50416
|
} catch {
|
|
50308
50417
|
}
|
|
50309
50418
|
const w2 = {
|
|
@@ -50316,16 +50425,16 @@ var SessionObserver = class {
|
|
|
50316
50425
|
adapter: args.adapter,
|
|
50317
50426
|
prevIsRejectSentinel: false,
|
|
50318
50427
|
toolSessionId: args.toolSessionId,
|
|
50319
|
-
sawFile:
|
|
50428
|
+
sawFile: import_node_fs29.default.existsSync(filePath),
|
|
50320
50429
|
lastRelocateScanMs: 0,
|
|
50321
50430
|
pendingCwdDerive: false,
|
|
50322
50431
|
lastDeriveMs: 0
|
|
50323
50432
|
};
|
|
50324
50433
|
try {
|
|
50325
|
-
|
|
50434
|
+
import_node_fs29.default.mkdirSync(import_node_path30.default.dirname(filePath), { recursive: true });
|
|
50326
50435
|
} catch {
|
|
50327
50436
|
}
|
|
50328
|
-
w2.watcher =
|
|
50437
|
+
w2.watcher = import_node_fs29.default.watch(import_node_path30.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
50329
50438
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
50330
50439
|
this.poll(w2);
|
|
50331
50440
|
});
|
|
@@ -50348,7 +50457,7 @@ var SessionObserver = class {
|
|
|
50348
50457
|
// 异常静默吞,不阻塞 watcher 启动
|
|
50349
50458
|
hydrateMetaTail(w2, maxLines = 200) {
|
|
50350
50459
|
try {
|
|
50351
|
-
const raw =
|
|
50460
|
+
const raw = import_node_fs29.default.readFileSync(w2.filePath, "utf8");
|
|
50352
50461
|
if (!raw) return;
|
|
50353
50462
|
const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
50354
50463
|
if (allLines.length === 0) return;
|
|
@@ -50372,7 +50481,7 @@ var SessionObserver = class {
|
|
|
50372
50481
|
poll(w2) {
|
|
50373
50482
|
let size = 0;
|
|
50374
50483
|
try {
|
|
50375
|
-
size =
|
|
50484
|
+
size = import_node_fs29.default.statSync(w2.filePath).size;
|
|
50376
50485
|
} catch {
|
|
50377
50486
|
if (w2.sawFile) this.maybeRelocate(w2);
|
|
50378
50487
|
return;
|
|
@@ -50383,11 +50492,11 @@ var SessionObserver = class {
|
|
|
50383
50492
|
w2.buf = "";
|
|
50384
50493
|
}
|
|
50385
50494
|
if (size === w2.lastSize) return;
|
|
50386
|
-
const fd =
|
|
50495
|
+
const fd = import_node_fs29.default.openSync(w2.filePath, "r");
|
|
50387
50496
|
try {
|
|
50388
50497
|
const len = size - w2.lastSize;
|
|
50389
50498
|
const buf = Buffer.alloc(len);
|
|
50390
|
-
|
|
50499
|
+
import_node_fs29.default.readSync(fd, buf, 0, len, w2.lastSize);
|
|
50391
50500
|
w2.lastSize = size;
|
|
50392
50501
|
w2.buf += buf.toString("utf8");
|
|
50393
50502
|
let newlineIndex;
|
|
@@ -50410,7 +50519,7 @@ var SessionObserver = class {
|
|
|
50410
50519
|
}
|
|
50411
50520
|
}
|
|
50412
50521
|
} finally {
|
|
50413
|
-
|
|
50522
|
+
import_node_fs29.default.closeSync(fd);
|
|
50414
50523
|
}
|
|
50415
50524
|
if (w2.pendingCwdDerive) this.maybeDeriveCwd(w2);
|
|
50416
50525
|
}
|
|
@@ -50422,7 +50531,7 @@ var SessionObserver = class {
|
|
|
50422
50531
|
const now = Date.now();
|
|
50423
50532
|
if (now - w2.lastRelocateScanMs < 1e3) return;
|
|
50424
50533
|
w2.lastRelocateScanMs = now;
|
|
50425
|
-
const projectsRoot =
|
|
50534
|
+
const projectsRoot = import_node_path30.default.join(this.home, ".claude", "projects");
|
|
50426
50535
|
const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
|
|
50427
50536
|
if (!found || found === w2.filePath) return;
|
|
50428
50537
|
try {
|
|
@@ -50431,7 +50540,7 @@ var SessionObserver = class {
|
|
|
50431
50540
|
}
|
|
50432
50541
|
w2.filePath = found;
|
|
50433
50542
|
try {
|
|
50434
|
-
w2.watcher =
|
|
50543
|
+
w2.watcher = import_node_fs29.default.watch(import_node_path30.default.dirname(found), { persistent: false }, (_event, changedName) => {
|
|
50435
50544
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
50436
50545
|
this.poll(w2);
|
|
50437
50546
|
});
|
|
@@ -50998,79 +51107,6 @@ function removeSubscription(client, sessionId) {
|
|
|
50998
51107
|
else client.subscribedSessions.set(sessionId, next);
|
|
50999
51108
|
}
|
|
51000
51109
|
|
|
51001
|
-
// src/transport/rpc-adapter.ts
|
|
51002
|
-
var EXPOSED_RPC_METHODS = [
|
|
51003
|
-
"appBuilder.createProject",
|
|
51004
|
-
"appBuilder.listProjects",
|
|
51005
|
-
"appBuilder.updateProjectPort",
|
|
51006
|
-
"appBuilder.setProdUrl",
|
|
51007
|
-
// 单栏 refactor §5.6.2 stage fix:scaffold + install 完成调 startDevServer 起 dev server;
|
|
51008
|
-
// 中间用 reportStage 上报阶段(scaffolding / installing / failed),UI 据 stage 推帧切 PreviewPane。
|
|
51009
|
-
"appBuilder.startDevServer",
|
|
51010
|
-
"appBuilder.reportStage",
|
|
51011
|
-
// 单栏 §5.6.5 fix: UI 切 session 时调(assistant 不需要主动调,但暴露白名单避免误猜成 forbidden)
|
|
51012
|
-
"appBuilder.setActiveSession",
|
|
51013
|
-
// dataclaw-builder:persona 建页时取建页人身份(含 union_id)写进生成 app 的配置。
|
|
51014
|
-
// 路由到 handlers['auth:getIdentity'],只返 identity、绝不带 ttcToken(见 handlers/feishu-auth.ts)。
|
|
51015
|
-
"auth.getIdentity",
|
|
51016
|
-
// Persona dispatch(异步,spec 2026-07-20):A 端 dispatch MCP server 调 run(秒回 dispatchId);
|
|
51017
|
-
// B 端调 complete(带 outcome → 台账 + 投递);发起方调 list 查台账。详见 protocol/src/dispatch.ts。
|
|
51018
|
-
"personaDispatch.run",
|
|
51019
|
-
// 跨设备 exec(spec 2026-07-16):A 侧本地 cc 经 /api/rpc 调,带 peerDeviceId → daemon forward。
|
|
51020
|
-
"peerExec.run",
|
|
51021
|
-
"personaDispatch.complete",
|
|
51022
|
-
"personaDispatch.list",
|
|
51023
|
-
// persona 清单(spec 2026-07-21):两级路由第一级——发起方 cc(loopback owner 语义)
|
|
51024
|
-
// 用 curl 拿全量 personaId+label 紧凑清单,再按需读候选 CLAUDE.md 首段做终选。
|
|
51025
|
-
"persona.list",
|
|
51026
|
-
// clawd-shift v1 (spec 2026-06-24-clawd-shift):cc 子进程内的 shift MCP server 调
|
|
51027
|
-
// 这 5 个 method 管理 owner 的 shift(fire-and-forget 排班)。鉴权靠 body.personaId
|
|
51028
|
-
// (mcp-server 从 process.env.CLAWD_PERSONA_ID 读,源 = SessionFile.ownerPersonaId)。
|
|
51029
|
-
// handler 内 cancel/update/history 校验 createdByPersona === personaId 防越权。
|
|
51030
|
-
"shift-internal.add",
|
|
51031
|
-
"shift-internal.list",
|
|
51032
|
-
"shift-internal.cancel",
|
|
51033
|
-
"shift-internal.update",
|
|
51034
|
-
"shift-internal.history",
|
|
51035
|
-
// file-sharing:persona guest agent 把自己工作目录内的产物入群+签名分享。
|
|
51036
|
-
// 路径越界由 handlers/attachment.ts guardAttachmentPath(scope-based)拦截。
|
|
51037
|
-
"attachment.groupAdd",
|
|
51038
|
-
"attachment.signUrl",
|
|
51039
|
-
// persona 受控发 P2P IM DM(sender 由 session scope 推,driver 分级授权见 handlers/inbox.ts)
|
|
51040
|
-
"inbox.sendDm",
|
|
51041
|
-
// per-turn sender 2026-07-08 spec §4.1:MCP servers (ticket / inbox / ...) 每 tool call
|
|
51042
|
-
// 查当前 turn caller —— cc 长驻 + owner/guest 交替驱动同一 session 时不能靠启动时 env
|
|
51043
|
-
// 写死身份,必须运行时 fetch。header X-Clawd-Session-Id 作 session 定位,handler 内查
|
|
51044
|
-
// manager.tryGetState(sid).currentTurnSender 返 SenderInfo | null。
|
|
51045
|
-
"session.currentTurnSender"
|
|
51046
|
-
];
|
|
51047
|
-
async function handleRpcRequest(input) {
|
|
51048
|
-
const { method, body, sessionId, dispatcher } = input;
|
|
51049
|
-
if (!sessionId) {
|
|
51050
|
-
return { status: 400, body: { ok: false, error: "MISSING_SESSION_ID", message: "X-Clawd-Session-Id header required" } };
|
|
51051
|
-
}
|
|
51052
|
-
if (!EXPOSED_RPC_METHODS.includes(method)) {
|
|
51053
|
-
return { status: 403, body: { ok: false, error: "METHOD_NOT_EXPOSED", message: `method "${method}" not exposed via HTTP RPC` } };
|
|
51054
|
-
}
|
|
51055
|
-
const internalMethod = method.replace(".", ":");
|
|
51056
|
-
const augmentedBody = {
|
|
51057
|
-
...typeof body === "object" && body != null ? body : {},
|
|
51058
|
-
sessionId
|
|
51059
|
-
};
|
|
51060
|
-
try {
|
|
51061
|
-
const result = await dispatcher.dispatch(internalMethod, augmentedBody, { sessionId });
|
|
51062
|
-
return { status: 200, body: { ok: true, result } };
|
|
51063
|
-
} catch (err) {
|
|
51064
|
-
const e = err;
|
|
51065
|
-
const code = e?.code ?? "INTERNAL";
|
|
51066
|
-
const message = e?.message ?? String(err);
|
|
51067
|
-
return { status: 400, body: { ok: false, error: code, message } };
|
|
51068
|
-
}
|
|
51069
|
-
}
|
|
51070
|
-
function resolveExposedHandler(handlers, internalMethod) {
|
|
51071
|
-
return handlers[internalMethod] ?? handlers[internalMethod.replace(":", ".")];
|
|
51072
|
-
}
|
|
51073
|
-
|
|
51074
51110
|
// src/transport/auth.ts
|
|
51075
51111
|
init_protocol();
|
|
51076
51112
|
var AuthGate = class {
|
|
@@ -51287,8 +51323,8 @@ async function authenticate(token, deps) {
|
|
|
51287
51323
|
}
|
|
51288
51324
|
|
|
51289
51325
|
// src/legacy-cleanup.ts
|
|
51290
|
-
var
|
|
51291
|
-
var
|
|
51326
|
+
var fs34 = __toESM(require("fs/promises"), 1);
|
|
51327
|
+
var path35 = __toESM(require("path"), 1);
|
|
51292
51328
|
var LEGACY_FILES = [
|
|
51293
51329
|
"personal-capability.json",
|
|
51294
51330
|
"received-capabilities.json",
|
|
@@ -51297,9 +51333,9 @@ var LEGACY_FILES = [
|
|
|
51297
51333
|
async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
51298
51334
|
const removed = [];
|
|
51299
51335
|
for (const name of LEGACY_FILES) {
|
|
51300
|
-
const p2 =
|
|
51336
|
+
const p2 = path35.join(dataDir, name);
|
|
51301
51337
|
try {
|
|
51302
|
-
await
|
|
51338
|
+
await fs34.unlink(p2);
|
|
51303
51339
|
removed.push(name);
|
|
51304
51340
|
logger.debug("legacy capability file removed", { file: name });
|
|
51305
51341
|
} catch (err) {
|
|
@@ -51311,13 +51347,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
|
51311
51347
|
}
|
|
51312
51348
|
|
|
51313
51349
|
// src/inbox/inbox-store.ts
|
|
51314
|
-
var
|
|
51315
|
-
var
|
|
51350
|
+
var fs35 = __toESM(require("fs"), 1);
|
|
51351
|
+
var path36 = __toESM(require("path"), 1);
|
|
51316
51352
|
var INBOX_SUBDIR = "inbox";
|
|
51317
51353
|
var InboxStore = class {
|
|
51318
51354
|
constructor(dataDir) {
|
|
51319
51355
|
this.dataDir = dataDir;
|
|
51320
|
-
|
|
51356
|
+
fs35.mkdirSync(this.dirPath(), { recursive: true });
|
|
51321
51357
|
}
|
|
51322
51358
|
dataDir;
|
|
51323
51359
|
/**
|
|
@@ -51329,7 +51365,7 @@ var InboxStore = class {
|
|
|
51329
51365
|
const file = this.filePath(peerDeviceId);
|
|
51330
51366
|
let raw;
|
|
51331
51367
|
try {
|
|
51332
|
-
raw =
|
|
51368
|
+
raw = fs35.readFileSync(file, "utf8");
|
|
51333
51369
|
} catch (err) {
|
|
51334
51370
|
if (err?.code === "ENOENT") return [];
|
|
51335
51371
|
return [];
|
|
@@ -51345,7 +51381,7 @@ var InboxStore = class {
|
|
|
51345
51381
|
const dir = this.dirPath();
|
|
51346
51382
|
let entries;
|
|
51347
51383
|
try {
|
|
51348
|
-
entries =
|
|
51384
|
+
entries = fs35.readdirSync(dir);
|
|
51349
51385
|
} catch (err) {
|
|
51350
51386
|
if (err?.code === "ENOENT") return [];
|
|
51351
51387
|
return [];
|
|
@@ -51361,9 +51397,9 @@ var InboxStore = class {
|
|
|
51361
51397
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
51362
51398
|
const file = this.filePath(message.peerDeviceId);
|
|
51363
51399
|
const line = JSON.stringify(message) + "\n";
|
|
51364
|
-
|
|
51400
|
+
fs35.appendFileSync(file, line, { mode: 384 });
|
|
51365
51401
|
try {
|
|
51366
|
-
|
|
51402
|
+
fs35.chmodSync(file, 384);
|
|
51367
51403
|
} catch {
|
|
51368
51404
|
}
|
|
51369
51405
|
}
|
|
@@ -51393,7 +51429,7 @@ var InboxStore = class {
|
|
|
51393
51429
|
removeByPeerDeviceId(peerDeviceId) {
|
|
51394
51430
|
const file = this.filePath(peerDeviceId);
|
|
51395
51431
|
try {
|
|
51396
|
-
|
|
51432
|
+
fs35.unlinkSync(file);
|
|
51397
51433
|
} catch (err) {
|
|
51398
51434
|
if (err?.code === "ENOENT") return;
|
|
51399
51435
|
}
|
|
@@ -51402,18 +51438,18 @@ var InboxStore = class {
|
|
|
51402
51438
|
const file = this.filePath(peerDeviceId);
|
|
51403
51439
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
51404
51440
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
51405
|
-
|
|
51406
|
-
|
|
51441
|
+
fs35.writeFileSync(tmp, content, { mode: 384 });
|
|
51442
|
+
fs35.renameSync(tmp, file);
|
|
51407
51443
|
try {
|
|
51408
|
-
|
|
51444
|
+
fs35.chmodSync(file, 384);
|
|
51409
51445
|
} catch {
|
|
51410
51446
|
}
|
|
51411
51447
|
}
|
|
51412
51448
|
dirPath() {
|
|
51413
|
-
return
|
|
51449
|
+
return path36.join(this.dataDir, INBOX_SUBDIR);
|
|
51414
51450
|
}
|
|
51415
51451
|
filePath(peerDeviceId) {
|
|
51416
|
-
return
|
|
51452
|
+
return path36.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
51417
51453
|
}
|
|
51418
51454
|
};
|
|
51419
51455
|
function parseAllLines(raw) {
|
|
@@ -51501,8 +51537,8 @@ var InboxManager = class {
|
|
|
51501
51537
|
};
|
|
51502
51538
|
|
|
51503
51539
|
// src/state/contact-store.ts
|
|
51504
|
-
var
|
|
51505
|
-
var
|
|
51540
|
+
var fs36 = __toESM(require("fs"), 1);
|
|
51541
|
+
var path37 = __toESM(require("path"), 1);
|
|
51506
51542
|
var FILE_NAME = "contacts.json";
|
|
51507
51543
|
var ContactStore = class {
|
|
51508
51544
|
constructor(dataDir) {
|
|
@@ -51512,10 +51548,10 @@ var ContactStore = class {
|
|
|
51512
51548
|
contacts = /* @__PURE__ */ new Map();
|
|
51513
51549
|
load() {
|
|
51514
51550
|
this.contacts.clear();
|
|
51515
|
-
const file =
|
|
51551
|
+
const file = path37.join(this.dataDir, FILE_NAME);
|
|
51516
51552
|
let raw;
|
|
51517
51553
|
try {
|
|
51518
|
-
raw =
|
|
51554
|
+
raw = fs36.readFileSync(file, "utf8");
|
|
51519
51555
|
} catch (err) {
|
|
51520
51556
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
51521
51557
|
return;
|
|
@@ -51584,20 +51620,20 @@ var ContactStore = class {
|
|
|
51584
51620
|
return true;
|
|
51585
51621
|
}
|
|
51586
51622
|
flush() {
|
|
51587
|
-
const file =
|
|
51623
|
+
const file = path37.join(this.dataDir, FILE_NAME);
|
|
51588
51624
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
51589
51625
|
const content = JSON.stringify(
|
|
51590
51626
|
{ contacts: Array.from(this.contacts.values()) },
|
|
51591
51627
|
null,
|
|
51592
51628
|
2
|
|
51593
51629
|
);
|
|
51594
|
-
|
|
51595
|
-
|
|
51596
|
-
|
|
51630
|
+
fs36.mkdirSync(this.dataDir, { recursive: true });
|
|
51631
|
+
fs36.writeFileSync(tmp, content, { mode: 384 });
|
|
51632
|
+
fs36.renameSync(tmp, file);
|
|
51597
51633
|
}
|
|
51598
51634
|
renameBak(file) {
|
|
51599
51635
|
try {
|
|
51600
|
-
|
|
51636
|
+
fs36.renameSync(file, `${file}.bak`);
|
|
51601
51637
|
} catch {
|
|
51602
51638
|
}
|
|
51603
51639
|
}
|
|
@@ -51705,61 +51741,61 @@ async function connectRemote(args) {
|
|
|
51705
51741
|
}
|
|
51706
51742
|
|
|
51707
51743
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
51708
|
-
var
|
|
51709
|
-
var
|
|
51744
|
+
var fs37 = __toESM(require("fs"), 1);
|
|
51745
|
+
var path38 = __toESM(require("path"), 1);
|
|
51710
51746
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
51711
51747
|
function migrateFlattenSessions(opts) {
|
|
51712
51748
|
const dataDir = opts.dataDir;
|
|
51713
51749
|
const now = opts.now ?? Date.now;
|
|
51714
|
-
const sessionsDir =
|
|
51715
|
-
const flagPath =
|
|
51750
|
+
const sessionsDir = path38.join(dataDir, "sessions");
|
|
51751
|
+
const flagPath = path38.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
51716
51752
|
if (existsSync3(flagPath)) {
|
|
51717
51753
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
51718
51754
|
}
|
|
51719
51755
|
let movedBare = 0;
|
|
51720
51756
|
let movedVmOwner = 0;
|
|
51721
51757
|
let archivedListener = 0;
|
|
51722
|
-
const defaultDir =
|
|
51758
|
+
const defaultDir = path38.join(sessionsDir, "default");
|
|
51723
51759
|
if (existsSync3(defaultDir)) {
|
|
51724
51760
|
for (const entry of readdirSafe(defaultDir)) {
|
|
51725
51761
|
if (!entry.endsWith(".json")) continue;
|
|
51726
|
-
const src =
|
|
51727
|
-
const dst =
|
|
51728
|
-
|
|
51762
|
+
const src = path38.join(defaultDir, entry);
|
|
51763
|
+
const dst = path38.join(sessionsDir, entry);
|
|
51764
|
+
fs37.renameSync(src, dst);
|
|
51729
51765
|
movedBare += 1;
|
|
51730
51766
|
}
|
|
51731
51767
|
rmdirIfEmpty(defaultDir);
|
|
51732
51768
|
}
|
|
51733
51769
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
51734
|
-
const personaDir =
|
|
51770
|
+
const personaDir = path38.join(sessionsDir, pid);
|
|
51735
51771
|
if (!isDir(personaDir)) continue;
|
|
51736
51772
|
if (pid === "default") continue;
|
|
51737
|
-
const ownerSrc =
|
|
51773
|
+
const ownerSrc = path38.join(personaDir, "owner");
|
|
51738
51774
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
51739
|
-
const ownerDst =
|
|
51740
|
-
|
|
51775
|
+
const ownerDst = path38.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
51776
|
+
fs37.mkdirSync(ownerDst, { recursive: true });
|
|
51741
51777
|
for (const file of readdirSafe(ownerSrc)) {
|
|
51742
51778
|
if (!file.endsWith(".json")) continue;
|
|
51743
|
-
|
|
51779
|
+
fs37.renameSync(path38.join(ownerSrc, file), path38.join(ownerDst, file));
|
|
51744
51780
|
movedVmOwner += 1;
|
|
51745
51781
|
}
|
|
51746
51782
|
rmdirIfEmpty(ownerSrc);
|
|
51747
51783
|
}
|
|
51748
|
-
const listenerSrc =
|
|
51784
|
+
const listenerSrc = path38.join(personaDir, "listener");
|
|
51749
51785
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
51750
|
-
const archiveDst =
|
|
51751
|
-
|
|
51786
|
+
const archiveDst = path38.join(dataDir, ".legacy", `listener-${pid}`);
|
|
51787
|
+
fs37.mkdirSync(archiveDst, { recursive: true });
|
|
51752
51788
|
for (const file of readdirSafe(listenerSrc)) {
|
|
51753
51789
|
if (!file.endsWith(".json")) continue;
|
|
51754
|
-
|
|
51790
|
+
fs37.renameSync(path38.join(listenerSrc, file), path38.join(archiveDst, file));
|
|
51755
51791
|
archivedListener += 1;
|
|
51756
51792
|
}
|
|
51757
51793
|
rmdirIfEmpty(listenerSrc);
|
|
51758
51794
|
}
|
|
51759
51795
|
rmdirIfEmpty(personaDir);
|
|
51760
51796
|
}
|
|
51761
|
-
|
|
51762
|
-
|
|
51797
|
+
fs37.mkdirSync(sessionsDir, { recursive: true });
|
|
51798
|
+
fs37.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
51763
51799
|
return {
|
|
51764
51800
|
skipped: false,
|
|
51765
51801
|
flagWritten: true,
|
|
@@ -51770,7 +51806,7 @@ function migrateFlattenSessions(opts) {
|
|
|
51770
51806
|
}
|
|
51771
51807
|
function existsSync3(p2) {
|
|
51772
51808
|
try {
|
|
51773
|
-
|
|
51809
|
+
fs37.statSync(p2);
|
|
51774
51810
|
return true;
|
|
51775
51811
|
} catch {
|
|
51776
51812
|
return false;
|
|
@@ -51778,31 +51814,31 @@ function existsSync3(p2) {
|
|
|
51778
51814
|
}
|
|
51779
51815
|
function isDir(p2) {
|
|
51780
51816
|
try {
|
|
51781
|
-
return
|
|
51817
|
+
return fs37.statSync(p2).isDirectory();
|
|
51782
51818
|
} catch {
|
|
51783
51819
|
return false;
|
|
51784
51820
|
}
|
|
51785
51821
|
}
|
|
51786
51822
|
function readdirSafe(p2) {
|
|
51787
51823
|
try {
|
|
51788
|
-
return
|
|
51824
|
+
return fs37.readdirSync(p2);
|
|
51789
51825
|
} catch {
|
|
51790
51826
|
return [];
|
|
51791
51827
|
}
|
|
51792
51828
|
}
|
|
51793
51829
|
function rmdirIfEmpty(p2) {
|
|
51794
51830
|
try {
|
|
51795
|
-
|
|
51831
|
+
fs37.rmdirSync(p2);
|
|
51796
51832
|
} catch {
|
|
51797
51833
|
}
|
|
51798
51834
|
}
|
|
51799
51835
|
|
|
51800
51836
|
// src/transport/http-router.ts
|
|
51801
|
-
var
|
|
51802
|
-
var
|
|
51837
|
+
var import_node_fs31 = __toESM(require("fs"), 1);
|
|
51838
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
51803
51839
|
|
|
51804
51840
|
// src/attachment/mime.ts
|
|
51805
|
-
var
|
|
51841
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
51806
51842
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
51807
51843
|
var EXT_TO_NATIVE_MIME = {
|
|
51808
51844
|
// 图片
|
|
@@ -51909,7 +51945,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
51909
51945
|
".mk"
|
|
51910
51946
|
]);
|
|
51911
51947
|
function lookupMime(filePathOrName) {
|
|
51912
|
-
const ext =
|
|
51948
|
+
const ext = import_node_path31.default.extname(filePathOrName).toLowerCase();
|
|
51913
51949
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
51914
51950
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
51915
51951
|
return "application/octet-stream";
|
|
@@ -51931,8 +51967,9 @@ function encodeAbsPathForUrl(absPath) {
|
|
|
51931
51967
|
function decodeAbsPathFromUrl(encoded) {
|
|
51932
51968
|
return encoded.split("/").map(decodeURIComponent).join("/");
|
|
51933
51969
|
}
|
|
51970
|
+
var DOMAIN_PREFIX2 = "clawd-attach-v1|";
|
|
51934
51971
|
function computeSig(secret, absPath, e) {
|
|
51935
|
-
const msg = e === null ? absPath : `${absPath}|${e}`;
|
|
51972
|
+
const msg = e === null ? `${DOMAIN_PREFIX2}${absPath}` : `${DOMAIN_PREFIX2}${absPath}|${e}`;
|
|
51936
51973
|
return import_node_crypto7.default.createHmac(HMAC_ALGO, secret).update(msg).digest();
|
|
51937
51974
|
}
|
|
51938
51975
|
function signUrlParts(secret, absPath, ttlSeconds, now = Date.now) {
|
|
@@ -51978,8 +52015,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
51978
52015
|
}
|
|
51979
52016
|
|
|
51980
52017
|
// src/attachment/upload.ts
|
|
51981
|
-
var
|
|
51982
|
-
var
|
|
52018
|
+
var import_node_fs30 = __toESM(require("fs"), 1);
|
|
52019
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
51983
52020
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
51984
52021
|
var import_promises3 = require("stream/promises");
|
|
51985
52022
|
var UploadError = class extends Error {
|
|
@@ -51991,22 +52028,22 @@ var UploadError = class extends Error {
|
|
|
51991
52028
|
code;
|
|
51992
52029
|
};
|
|
51993
52030
|
function assertValidFileName(fileName) {
|
|
51994
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
52031
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path32.default.basename(fileName)) {
|
|
51995
52032
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
51996
52033
|
}
|
|
51997
52034
|
}
|
|
51998
52035
|
var HASH_PREFIX_LEN = 16;
|
|
51999
52036
|
async function writeUploadedAttachment(args) {
|
|
52000
52037
|
assertValidFileName(args.fileName);
|
|
52001
|
-
const attachmentsRoot =
|
|
52038
|
+
const attachmentsRoot = import_node_path32.default.join(args.sessionDir, ".attachments");
|
|
52002
52039
|
try {
|
|
52003
|
-
|
|
52040
|
+
import_node_fs30.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
52004
52041
|
} catch (err) {
|
|
52005
52042
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
52006
52043
|
}
|
|
52007
52044
|
const hasher = import_node_crypto8.default.createHash("sha256");
|
|
52008
52045
|
let actualSize = 0;
|
|
52009
|
-
const tmpPath =
|
|
52046
|
+
const tmpPath = import_node_path32.default.join(
|
|
52010
52047
|
attachmentsRoot,
|
|
52011
52048
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
|
|
52012
52049
|
);
|
|
@@ -52021,18 +52058,18 @@ async function writeUploadedAttachment(args) {
|
|
|
52021
52058
|
yield buf;
|
|
52022
52059
|
}
|
|
52023
52060
|
},
|
|
52024
|
-
|
|
52061
|
+
import_node_fs30.default.createWriteStream(tmpPath, { mode: 384 })
|
|
52025
52062
|
);
|
|
52026
52063
|
} catch (err) {
|
|
52027
52064
|
try {
|
|
52028
|
-
|
|
52065
|
+
import_node_fs30.default.unlinkSync(tmpPath);
|
|
52029
52066
|
} catch {
|
|
52030
52067
|
}
|
|
52031
52068
|
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
52032
52069
|
}
|
|
52033
52070
|
if (actualSize !== args.contentLength) {
|
|
52034
52071
|
try {
|
|
52035
|
-
|
|
52072
|
+
import_node_fs30.default.unlinkSync(tmpPath);
|
|
52036
52073
|
} catch {
|
|
52037
52074
|
}
|
|
52038
52075
|
throw new UploadError(
|
|
@@ -52041,35 +52078,35 @@ async function writeUploadedAttachment(args) {
|
|
|
52041
52078
|
);
|
|
52042
52079
|
}
|
|
52043
52080
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
52044
|
-
const hashDir =
|
|
52081
|
+
const hashDir = import_node_path32.default.join(attachmentsRoot, attachmentId);
|
|
52045
52082
|
let finalFileName;
|
|
52046
52083
|
let hashDirExists = false;
|
|
52047
52084
|
try {
|
|
52048
|
-
hashDirExists =
|
|
52085
|
+
hashDirExists = import_node_fs30.default.statSync(hashDir).isDirectory();
|
|
52049
52086
|
} catch {
|
|
52050
52087
|
}
|
|
52051
52088
|
if (hashDirExists) {
|
|
52052
|
-
const existing =
|
|
52089
|
+
const existing = import_node_fs30.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
|
|
52053
52090
|
finalFileName = existing[0] ?? args.fileName;
|
|
52054
52091
|
try {
|
|
52055
|
-
|
|
52092
|
+
import_node_fs30.default.unlinkSync(tmpPath);
|
|
52056
52093
|
} catch {
|
|
52057
52094
|
}
|
|
52058
52095
|
} else {
|
|
52059
52096
|
try {
|
|
52060
|
-
|
|
52097
|
+
import_node_fs30.default.mkdirSync(hashDir, { recursive: true });
|
|
52061
52098
|
finalFileName = args.fileName;
|
|
52062
|
-
|
|
52099
|
+
import_node_fs30.default.renameSync(tmpPath, import_node_path32.default.join(hashDir, finalFileName));
|
|
52063
52100
|
} catch (err) {
|
|
52064
52101
|
try {
|
|
52065
|
-
|
|
52102
|
+
import_node_fs30.default.unlinkSync(tmpPath);
|
|
52066
52103
|
} catch {
|
|
52067
52104
|
}
|
|
52068
52105
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
52069
52106
|
}
|
|
52070
52107
|
}
|
|
52071
|
-
const absPath =
|
|
52072
|
-
const relPath =
|
|
52108
|
+
const absPath = import_node_path32.default.join(hashDir, finalFileName);
|
|
52109
|
+
const relPath = import_node_path32.default.relative(args.sessionDir, absPath);
|
|
52073
52110
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
52074
52111
|
relPath: absPath,
|
|
52075
52112
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -52083,7 +52120,7 @@ async function writeUploadedAttachment(args) {
|
|
|
52083
52120
|
|
|
52084
52121
|
// src/extension/import.ts
|
|
52085
52122
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
52086
|
-
var
|
|
52123
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
52087
52124
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
52088
52125
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
52089
52126
|
var ImportError = class extends Error {
|
|
@@ -52101,7 +52138,7 @@ async function importZip(buf, root) {
|
|
|
52101
52138
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
52102
52139
|
}
|
|
52103
52140
|
for (const name of Object.keys(zip.files)) {
|
|
52104
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
52141
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path33.default.isAbsolute(name)) {
|
|
52105
52142
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
52106
52143
|
}
|
|
52107
52144
|
}
|
|
@@ -52134,7 +52171,7 @@ async function importZip(buf, root) {
|
|
|
52134
52171
|
);
|
|
52135
52172
|
}
|
|
52136
52173
|
}
|
|
52137
|
-
const destDir =
|
|
52174
|
+
const destDir = import_node_path33.default.join(root, manifest.id);
|
|
52138
52175
|
let destExists = false;
|
|
52139
52176
|
try {
|
|
52140
52177
|
await import_promises4.default.access(destDir);
|
|
@@ -52144,15 +52181,15 @@ async function importZip(buf, root) {
|
|
|
52144
52181
|
if (destExists) {
|
|
52145
52182
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
52146
52183
|
}
|
|
52147
|
-
const stage = await import_promises4.default.mkdtemp(
|
|
52184
|
+
const stage = await import_promises4.default.mkdtemp(import_node_path33.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
52148
52185
|
try {
|
|
52149
52186
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
52150
|
-
const dest =
|
|
52187
|
+
const dest = import_node_path33.default.join(stage, name);
|
|
52151
52188
|
if (entry.dir) {
|
|
52152
52189
|
await import_promises4.default.mkdir(dest, { recursive: true });
|
|
52153
52190
|
continue;
|
|
52154
52191
|
}
|
|
52155
|
-
await import_promises4.default.mkdir(
|
|
52192
|
+
await import_promises4.default.mkdir(import_node_path33.default.dirname(dest), { recursive: true });
|
|
52156
52193
|
const content = await entry.async("nodebuffer");
|
|
52157
52194
|
await import_promises4.default.writeFile(dest, content);
|
|
52158
52195
|
}
|
|
@@ -52167,7 +52204,6 @@ async function importZip(buf, root) {
|
|
|
52167
52204
|
}
|
|
52168
52205
|
|
|
52169
52206
|
// src/transport/http-router.ts
|
|
52170
|
-
var RPC_ROUTE_PREFIX = "/api/rpc/";
|
|
52171
52207
|
var RPC_BODY_MAX_BYTES = 1 * 1024 * 1024;
|
|
52172
52208
|
var SHARE_UI_ASSETS_PREFIX = "/share-ui/assets/";
|
|
52173
52209
|
var SHARE_UI_ASSET_MIME = {
|
|
@@ -52183,11 +52219,9 @@ var SHARE_UI_ASSET_MIME = {
|
|
|
52183
52219
|
".wasm": "application/wasm"
|
|
52184
52220
|
};
|
|
52185
52221
|
function shareUiAssetMime(filePath) {
|
|
52186
|
-
const ext =
|
|
52222
|
+
const ext = import_node_path34.default.extname(filePath).toLowerCase();
|
|
52187
52223
|
return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
|
|
52188
52224
|
}
|
|
52189
|
-
var DISPATCH_HEARTBEAT_MS = 25e3;
|
|
52190
|
-
var DISPATCH_HOLD_METHOD = "personaDispatch:run";
|
|
52191
52225
|
var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
|
|
52192
52226
|
var AUTHED_RPC_CORS_HEADERS = {
|
|
52193
52227
|
"Access-Control-Allow-Origin": "*",
|
|
@@ -52210,10 +52244,6 @@ function authedRpcErrorStatus(code) {
|
|
|
52210
52244
|
return 400;
|
|
52211
52245
|
}
|
|
52212
52246
|
}
|
|
52213
|
-
function isLoopbackAddress(addr) {
|
|
52214
|
-
if (!addr) return false;
|
|
52215
|
-
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1" || addr.startsWith("127.");
|
|
52216
|
-
}
|
|
52217
52247
|
async function readJsonBody(req, max) {
|
|
52218
52248
|
return await new Promise((resolve6, reject) => {
|
|
52219
52249
|
let size = 0;
|
|
@@ -52270,7 +52300,7 @@ function isValidUploadFileName(fileName) {
|
|
|
52270
52300
|
if (fileName === "." || fileName === "..") return false;
|
|
52271
52301
|
if (fileName.startsWith(".")) return false;
|
|
52272
52302
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
52273
|
-
return fileName ===
|
|
52303
|
+
return fileName === import_node_path34.default.basename(fileName);
|
|
52274
52304
|
}
|
|
52275
52305
|
function createHttpRouter(deps) {
|
|
52276
52306
|
return async (req, res) => {
|
|
@@ -52342,7 +52372,7 @@ function createHttpRouter(deps) {
|
|
|
52342
52372
|
}
|
|
52343
52373
|
let buf;
|
|
52344
52374
|
try {
|
|
52345
|
-
buf = await
|
|
52375
|
+
buf = await import_node_fs31.default.promises.readFile(abs);
|
|
52346
52376
|
} catch {
|
|
52347
52377
|
sendJson(res, 404, { code: "NOT_FOUND", message: "asset not found" });
|
|
52348
52378
|
return true;
|
|
@@ -52390,57 +52420,6 @@ function createHttpRouter(deps) {
|
|
|
52390
52420
|
return true;
|
|
52391
52421
|
}
|
|
52392
52422
|
const dispatchArgs = typeof body === "object" && body != null ? body : {};
|
|
52393
|
-
if (method === DISPATCH_HOLD_METHOD) {
|
|
52394
|
-
const heartbeatMs = deps.dispatchHeartbeatMs ?? DISPATCH_HEARTBEAT_MS;
|
|
52395
|
-
let headSent = false;
|
|
52396
|
-
let hbInterval;
|
|
52397
|
-
const startStreaming = () => {
|
|
52398
|
-
headSent = true;
|
|
52399
|
-
req.socket?.setTimeout?.(0);
|
|
52400
|
-
res.socket?.setTimeout?.(0);
|
|
52401
|
-
res.writeHead(200, {
|
|
52402
|
-
"Content-Type": "application/json; charset=utf-8",
|
|
52403
|
-
"Transfer-Encoding": "chunked",
|
|
52404
|
-
// nginx 专用:禁用该响应缓冲,让心跳字节即时 flush 到上游 read(否则被攒着不重置计时)
|
|
52405
|
-
"X-Accel-Buffering": "no",
|
|
52406
|
-
...AUTHED_RPC_CORS_HEADERS
|
|
52407
|
-
});
|
|
52408
|
-
res.write(" ");
|
|
52409
|
-
hbInterval = setInterval(() => {
|
|
52410
|
-
try {
|
|
52411
|
-
res.write(" ");
|
|
52412
|
-
} catch {
|
|
52413
|
-
}
|
|
52414
|
-
}, heartbeatMs);
|
|
52415
|
-
};
|
|
52416
|
-
const graceTimer = setTimeout(startStreaming, heartbeatMs);
|
|
52417
|
-
const cleanup = () => {
|
|
52418
|
-
clearTimeout(graceTimer);
|
|
52419
|
-
if (hbInterval) clearInterval(hbInterval);
|
|
52420
|
-
};
|
|
52421
|
-
const safeEnd = (payload) => {
|
|
52422
|
-
if (res.writableEnded || res.destroyed) return;
|
|
52423
|
-
try {
|
|
52424
|
-
res.end(payload);
|
|
52425
|
-
} catch {
|
|
52426
|
-
}
|
|
52427
|
-
};
|
|
52428
|
-
res.on("close", cleanup);
|
|
52429
|
-
try {
|
|
52430
|
-
const result = await deps.authedRpc.dispatch(method, dispatchArgs, auth.context);
|
|
52431
|
-
cleanup();
|
|
52432
|
-
if (headSent) safeEnd(JSON.stringify({ ok: true, result: result.response }));
|
|
52433
|
-
else sendJson(res, 200, { ok: true, result: result.response }, AUTHED_RPC_CORS_HEADERS);
|
|
52434
|
-
} catch (err) {
|
|
52435
|
-
cleanup();
|
|
52436
|
-
const e = err;
|
|
52437
|
-
const code = e?.code ?? "INTERNAL";
|
|
52438
|
-
const payload = { ok: false, error: code, message: e?.message ?? String(err) };
|
|
52439
|
-
if (headSent) safeEnd(JSON.stringify(payload));
|
|
52440
|
-
else sendJson(res, authedRpcErrorStatus(code), payload, AUTHED_RPC_CORS_HEADERS);
|
|
52441
|
-
}
|
|
52442
|
-
return true;
|
|
52443
|
-
}
|
|
52444
52423
|
try {
|
|
52445
52424
|
const result = await deps.authedRpc.dispatch(method, dispatchArgs, auth.context);
|
|
52446
52425
|
sendJson(res, 200, { ok: true, result: result.response }, AUTHED_RPC_CORS_HEADERS);
|
|
@@ -52451,34 +52430,6 @@ function createHttpRouter(deps) {
|
|
|
52451
52430
|
}
|
|
52452
52431
|
return true;
|
|
52453
52432
|
}
|
|
52454
|
-
if (url.pathname.startsWith(RPC_ROUTE_PREFIX)) {
|
|
52455
|
-
if (!deps.rpcDispatcher) {
|
|
52456
|
-
sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "HTTP RPC adapter not wired" });
|
|
52457
|
-
return true;
|
|
52458
|
-
}
|
|
52459
|
-
if (req.method !== "POST") {
|
|
52460
|
-
sendJson(res, 405, { code: "METHOD_NOT_ALLOWED", message: "POST only" });
|
|
52461
|
-
return true;
|
|
52462
|
-
}
|
|
52463
|
-
if (!isLoopbackAddress(req.socket.remoteAddress)) {
|
|
52464
|
-
sendJson(res, 403, { code: "NOT_LOOPBACK", message: "RPC adapter only accepts loopback connections" });
|
|
52465
|
-
return true;
|
|
52466
|
-
}
|
|
52467
|
-
req.socket.setTimeout(0);
|
|
52468
|
-
res.socket?.setTimeout(0);
|
|
52469
|
-
const method = url.pathname.slice(RPC_ROUTE_PREFIX.length).split("?")[0] ?? "";
|
|
52470
|
-
const sessionId = req.headers["x-clawd-session-id"] ?? void 0;
|
|
52471
|
-
let body;
|
|
52472
|
-
try {
|
|
52473
|
-
body = await readJsonBody(req, RPC_BODY_MAX_BYTES);
|
|
52474
|
-
} catch (err) {
|
|
52475
|
-
sendJson(res, 400, { code: "INVALID_BODY", message: err instanceof Error ? err.message : String(err) });
|
|
52476
|
-
return true;
|
|
52477
|
-
}
|
|
52478
|
-
const result = await handleRpcRequest({ method, body, sessionId, dispatcher: deps.rpcDispatcher });
|
|
52479
|
-
sendJson(res, result.status, result.body);
|
|
52480
|
-
return true;
|
|
52481
|
-
}
|
|
52482
52433
|
if (url.pathname.startsWith("/preview/")) {
|
|
52483
52434
|
const port = matchPreviewPort(url.pathname);
|
|
52484
52435
|
if (port != null && isPreviewPortAllowed(port, { allowedPorts: deps.previewPorts ?? [] })) {
|
|
@@ -52566,7 +52517,7 @@ function createHttpRouter(deps) {
|
|
|
52566
52517
|
sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
|
|
52567
52518
|
return true;
|
|
52568
52519
|
}
|
|
52569
|
-
sendHtml(res, 200, loader.renderViewerHtml(
|
|
52520
|
+
sendHtml(res, 200, loader.renderViewerHtml(import_node_path34.default.basename(r.absPath)));
|
|
52570
52521
|
return true;
|
|
52571
52522
|
}
|
|
52572
52523
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
@@ -52687,7 +52638,7 @@ function createHttpRouter(deps) {
|
|
|
52687
52638
|
return true;
|
|
52688
52639
|
}
|
|
52689
52640
|
let absPath;
|
|
52690
|
-
if (
|
|
52641
|
+
if (import_node_path34.default.isAbsolute(pathParam)) {
|
|
52691
52642
|
absPath = pathParam;
|
|
52692
52643
|
} else if (deps.sessionStore) {
|
|
52693
52644
|
const file = deps.sessionStore.read(sid);
|
|
@@ -52695,7 +52646,7 @@ function createHttpRouter(deps) {
|
|
|
52695
52646
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
52696
52647
|
return true;
|
|
52697
52648
|
}
|
|
52698
|
-
absPath =
|
|
52649
|
+
absPath = import_node_path34.default.join(file.cwd, pathParam);
|
|
52699
52650
|
} else {
|
|
52700
52651
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
52701
52652
|
return true;
|
|
@@ -52782,7 +52733,7 @@ function withCtx(ctx, body) {
|
|
|
52782
52733
|
function streamFile(res, absPath, logger) {
|
|
52783
52734
|
let stat;
|
|
52784
52735
|
try {
|
|
52785
|
-
stat =
|
|
52736
|
+
stat = import_node_fs31.default.statSync(absPath);
|
|
52786
52737
|
} catch (err) {
|
|
52787
52738
|
const code = err?.code;
|
|
52788
52739
|
if (code === "ENOENT") {
|
|
@@ -52797,7 +52748,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52797
52748
|
return;
|
|
52798
52749
|
}
|
|
52799
52750
|
const mime = lookupMime(absPath);
|
|
52800
|
-
const basename =
|
|
52751
|
+
const basename = import_node_path34.default.basename(absPath);
|
|
52801
52752
|
res.writeHead(200, {
|
|
52802
52753
|
"Content-Type": mime,
|
|
52803
52754
|
"Content-Length": String(stat.size),
|
|
@@ -52805,7 +52756,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52805
52756
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
52806
52757
|
"X-Content-Type-Options": "nosniff"
|
|
52807
52758
|
});
|
|
52808
|
-
const stream =
|
|
52759
|
+
const stream = import_node_fs31.default.createReadStream(absPath);
|
|
52809
52760
|
stream.on("error", (err) => {
|
|
52810
52761
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
52811
52762
|
res.destroy();
|
|
@@ -52814,8 +52765,8 @@ function streamFile(res, absPath, logger) {
|
|
|
52814
52765
|
}
|
|
52815
52766
|
|
|
52816
52767
|
// src/attachment/gc.ts
|
|
52817
|
-
var
|
|
52818
|
-
var
|
|
52768
|
+
var import_node_fs32 = __toESM(require("fs"), 1);
|
|
52769
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
52819
52770
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
52820
52771
|
function runAttachmentGc(args) {
|
|
52821
52772
|
const now = (args.now ?? Date.now)();
|
|
@@ -52824,38 +52775,38 @@ function runAttachmentGc(args) {
|
|
|
52824
52775
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52825
52776
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
52826
52777
|
if (entry.stale) continue;
|
|
52827
|
-
if (
|
|
52778
|
+
if (import_node_path35.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
52828
52779
|
}
|
|
52829
52780
|
}
|
|
52830
52781
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52831
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
52782
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path35.default.join(
|
|
52832
52783
|
args.dataDir,
|
|
52833
52784
|
"sessions",
|
|
52834
52785
|
...scopeSubPath(scope).map(safeFileName),
|
|
52835
52786
|
safeFileName(sessionId)
|
|
52836
52787
|
);
|
|
52837
|
-
const attRoot =
|
|
52788
|
+
const attRoot = import_node_path35.default.join(sessionDir, ".attachments");
|
|
52838
52789
|
let hashDirs;
|
|
52839
52790
|
try {
|
|
52840
|
-
hashDirs =
|
|
52791
|
+
hashDirs = import_node_fs32.default.readdirSync(attRoot);
|
|
52841
52792
|
} catch (err) {
|
|
52842
52793
|
if (err.code === "ENOENT") continue;
|
|
52843
52794
|
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
52844
52795
|
continue;
|
|
52845
52796
|
}
|
|
52846
52797
|
for (const hashDir of hashDirs) {
|
|
52847
|
-
const hashDirAbs =
|
|
52798
|
+
const hashDirAbs = import_node_path35.default.join(attRoot, hashDir);
|
|
52848
52799
|
let files;
|
|
52849
52800
|
try {
|
|
52850
|
-
files =
|
|
52801
|
+
files = import_node_fs32.default.readdirSync(hashDirAbs);
|
|
52851
52802
|
} catch {
|
|
52852
52803
|
continue;
|
|
52853
52804
|
}
|
|
52854
52805
|
for (const name of files) {
|
|
52855
|
-
const file =
|
|
52806
|
+
const file = import_node_path35.default.join(hashDirAbs, name);
|
|
52856
52807
|
let stat;
|
|
52857
52808
|
try {
|
|
52858
|
-
stat =
|
|
52809
|
+
stat = import_node_fs32.default.statSync(file);
|
|
52859
52810
|
} catch {
|
|
52860
52811
|
continue;
|
|
52861
52812
|
}
|
|
@@ -52864,26 +52815,26 @@ function runAttachmentGc(args) {
|
|
|
52864
52815
|
if (age < ttlMs) continue;
|
|
52865
52816
|
if (liveAbs.has(file)) continue;
|
|
52866
52817
|
try {
|
|
52867
|
-
|
|
52818
|
+
import_node_fs32.default.unlinkSync(file);
|
|
52868
52819
|
} catch (err) {
|
|
52869
52820
|
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
52870
52821
|
}
|
|
52871
52822
|
}
|
|
52872
52823
|
try {
|
|
52873
|
-
if (
|
|
52824
|
+
if (import_node_fs32.default.readdirSync(hashDirAbs).length === 0) import_node_fs32.default.rmdirSync(hashDirAbs);
|
|
52874
52825
|
} catch {
|
|
52875
52826
|
}
|
|
52876
52827
|
}
|
|
52877
52828
|
try {
|
|
52878
|
-
if (
|
|
52829
|
+
if (import_node_fs32.default.readdirSync(attRoot).length === 0) import_node_fs32.default.rmdirSync(attRoot);
|
|
52879
52830
|
} catch {
|
|
52880
52831
|
}
|
|
52881
52832
|
}
|
|
52882
52833
|
}
|
|
52883
52834
|
|
|
52884
52835
|
// src/attachment/group.ts
|
|
52885
|
-
var
|
|
52886
|
-
var
|
|
52836
|
+
var import_node_fs33 = __toESM(require("fs"), 1);
|
|
52837
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
52887
52838
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
52888
52839
|
init_protocol();
|
|
52889
52840
|
var GroupFileStore = class {
|
|
@@ -52895,11 +52846,11 @@ var GroupFileStore = class {
|
|
|
52895
52846
|
this.logger = opts.logger;
|
|
52896
52847
|
}
|
|
52897
52848
|
rootForScope(scope) {
|
|
52898
|
-
return
|
|
52849
|
+
return import_node_path36.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
52899
52850
|
}
|
|
52900
52851
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
52901
52852
|
filePath(scope, sessionId) {
|
|
52902
|
-
return
|
|
52853
|
+
return import_node_path36.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
52903
52854
|
}
|
|
52904
52855
|
cacheKey(scope, sessionId) {
|
|
52905
52856
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -52908,7 +52859,7 @@ var GroupFileStore = class {
|
|
|
52908
52859
|
readFile(scope, sessionId) {
|
|
52909
52860
|
const file = this.filePath(scope, sessionId);
|
|
52910
52861
|
try {
|
|
52911
|
-
const raw =
|
|
52862
|
+
const raw = import_node_fs33.default.readFileSync(file, "utf8");
|
|
52912
52863
|
const parsed = JSON.parse(raw);
|
|
52913
52864
|
if (!Array.isArray(parsed)) {
|
|
52914
52865
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -52934,10 +52885,10 @@ var GroupFileStore = class {
|
|
|
52934
52885
|
}
|
|
52935
52886
|
writeFile(scope, sessionId, entries) {
|
|
52936
52887
|
const file = this.filePath(scope, sessionId);
|
|
52937
|
-
|
|
52888
|
+
import_node_fs33.default.mkdirSync(import_node_path36.default.dirname(file), { recursive: true });
|
|
52938
52889
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
52939
|
-
|
|
52940
|
-
|
|
52890
|
+
import_node_fs33.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
52891
|
+
import_node_fs33.default.renameSync(tmp, file);
|
|
52941
52892
|
}
|
|
52942
52893
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
52943
52894
|
list(scope, sessionId) {
|
|
@@ -53023,10 +52974,10 @@ var GroupFileStore = class {
|
|
|
53023
52974
|
};
|
|
53024
52975
|
|
|
53025
52976
|
// src/discovery/state-file.ts
|
|
53026
|
-
var
|
|
53027
|
-
var
|
|
52977
|
+
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
52978
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
53028
52979
|
function defaultStateFilePath(dataDir) {
|
|
53029
|
-
return
|
|
52980
|
+
return import_node_path37.default.join(dataDir, "state.json");
|
|
53030
52981
|
}
|
|
53031
52982
|
function isPidAlive(pid) {
|
|
53032
52983
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -53048,7 +52999,7 @@ var StateFileManager = class {
|
|
|
53048
52999
|
}
|
|
53049
53000
|
read() {
|
|
53050
53001
|
try {
|
|
53051
|
-
const raw =
|
|
53002
|
+
const raw = import_node_fs34.default.readFileSync(this.file, "utf8");
|
|
53052
53003
|
const parsed = JSON.parse(raw);
|
|
53053
53004
|
return parsed;
|
|
53054
53005
|
} catch {
|
|
@@ -53062,20 +53013,20 @@ var StateFileManager = class {
|
|
|
53062
53013
|
return { status: "stale", existing };
|
|
53063
53014
|
}
|
|
53064
53015
|
write(state) {
|
|
53065
|
-
|
|
53016
|
+
import_node_fs34.default.mkdirSync(import_node_path37.default.dirname(this.file), { recursive: true });
|
|
53066
53017
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
53067
|
-
|
|
53068
|
-
|
|
53018
|
+
import_node_fs34.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
53019
|
+
import_node_fs34.default.renameSync(tmp, this.file);
|
|
53069
53020
|
if (process.platform !== "win32") {
|
|
53070
53021
|
try {
|
|
53071
|
-
|
|
53022
|
+
import_node_fs34.default.chmodSync(this.file, 384);
|
|
53072
53023
|
} catch {
|
|
53073
53024
|
}
|
|
53074
53025
|
}
|
|
53075
53026
|
}
|
|
53076
53027
|
delete() {
|
|
53077
53028
|
try {
|
|
53078
|
-
|
|
53029
|
+
import_node_fs34.default.unlinkSync(this.file);
|
|
53079
53030
|
} catch {
|
|
53080
53031
|
}
|
|
53081
53032
|
}
|
|
@@ -53089,14 +53040,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
|
|
|
53089
53040
|
}
|
|
53090
53041
|
|
|
53091
53042
|
// src/tunnel/tunnel-manager.ts
|
|
53092
|
-
var
|
|
53093
|
-
var
|
|
53043
|
+
var import_node_fs38 = __toESM(require("fs"), 1);
|
|
53044
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
53094
53045
|
var import_node_crypto10 = __toESM(require("crypto"), 1);
|
|
53095
53046
|
var import_node_child_process10 = require("child_process");
|
|
53096
53047
|
|
|
53097
53048
|
// src/tunnel/tunnel-store.ts
|
|
53098
|
-
var
|
|
53099
|
-
var
|
|
53049
|
+
var import_node_fs35 = __toESM(require("fs"), 1);
|
|
53050
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
53100
53051
|
var TunnelStore = class {
|
|
53101
53052
|
constructor(filePath) {
|
|
53102
53053
|
this.filePath = filePath;
|
|
@@ -53104,7 +53055,7 @@ var TunnelStore = class {
|
|
|
53104
53055
|
filePath;
|
|
53105
53056
|
async get() {
|
|
53106
53057
|
try {
|
|
53107
|
-
const raw = await
|
|
53058
|
+
const raw = await import_node_fs35.default.promises.readFile(this.filePath, "utf8");
|
|
53108
53059
|
const obj = JSON.parse(raw);
|
|
53109
53060
|
if (!isPersistedTunnel(obj)) return null;
|
|
53110
53061
|
return obj;
|
|
@@ -53115,22 +53066,22 @@ var TunnelStore = class {
|
|
|
53115
53066
|
}
|
|
53116
53067
|
}
|
|
53117
53068
|
async set(v2) {
|
|
53118
|
-
const dir =
|
|
53119
|
-
await
|
|
53069
|
+
const dir = import_node_path38.default.dirname(this.filePath);
|
|
53070
|
+
await import_node_fs35.default.promises.mkdir(dir, { recursive: true });
|
|
53120
53071
|
const data = JSON.stringify(v2, null, 2);
|
|
53121
53072
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
53122
|
-
await
|
|
53073
|
+
await import_node_fs35.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
53123
53074
|
if (process.platform !== "win32") {
|
|
53124
53075
|
try {
|
|
53125
|
-
await
|
|
53076
|
+
await import_node_fs35.default.promises.chmod(tmp, 384);
|
|
53126
53077
|
} catch {
|
|
53127
53078
|
}
|
|
53128
53079
|
}
|
|
53129
|
-
await
|
|
53080
|
+
await import_node_fs35.default.promises.rename(tmp, this.filePath);
|
|
53130
53081
|
}
|
|
53131
53082
|
async clear() {
|
|
53132
53083
|
try {
|
|
53133
|
-
await
|
|
53084
|
+
await import_node_fs35.default.promises.unlink(this.filePath);
|
|
53134
53085
|
} catch (err) {
|
|
53135
53086
|
const code = err?.code;
|
|
53136
53087
|
if (code !== "ENOENT") throw err;
|
|
@@ -53225,9 +53176,9 @@ function escape(v2) {
|
|
|
53225
53176
|
}
|
|
53226
53177
|
|
|
53227
53178
|
// src/tunnel/frpc-binary.ts
|
|
53228
|
-
var
|
|
53179
|
+
var import_node_fs36 = __toESM(require("fs"), 1);
|
|
53229
53180
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
53230
|
-
var
|
|
53181
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
53231
53182
|
var import_node_child_process8 = require("child_process");
|
|
53232
53183
|
var import_node_stream3 = require("stream");
|
|
53233
53184
|
var import_promises5 = require("stream/promises");
|
|
@@ -53259,20 +53210,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
53259
53210
|
}
|
|
53260
53211
|
async function ensureFrpcBinary(opts) {
|
|
53261
53212
|
if (opts.override) {
|
|
53262
|
-
if (!
|
|
53213
|
+
if (!import_node_fs36.default.existsSync(opts.override)) {
|
|
53263
53214
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
53264
53215
|
}
|
|
53265
53216
|
return opts.override;
|
|
53266
53217
|
}
|
|
53267
53218
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
53268
53219
|
const platform = opts.platform ?? detectPlatform();
|
|
53269
|
-
const binDir =
|
|
53270
|
-
|
|
53220
|
+
const binDir = import_node_path39.default.join(opts.dataDir, "bin");
|
|
53221
|
+
import_node_fs36.default.mkdirSync(binDir, { recursive: true });
|
|
53271
53222
|
cleanupStaleArtifacts(binDir);
|
|
53272
|
-
const stableBin =
|
|
53273
|
-
if (
|
|
53223
|
+
const stableBin = import_node_path39.default.join(binDir, "frpc");
|
|
53224
|
+
if (import_node_fs36.default.existsSync(stableBin)) return stableBin;
|
|
53274
53225
|
const partialBin = `${stableBin}.partial`;
|
|
53275
|
-
const tarballPath =
|
|
53226
|
+
const tarballPath = import_node_path39.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
53276
53227
|
try {
|
|
53277
53228
|
const url = frpcDownloadUrl(version2, platform);
|
|
53278
53229
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -53281,8 +53232,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
53281
53232
|
} else {
|
|
53282
53233
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
53283
53234
|
}
|
|
53284
|
-
|
|
53285
|
-
|
|
53235
|
+
import_node_fs36.default.chmodSync(partialBin, 493);
|
|
53236
|
+
import_node_fs36.default.renameSync(partialBin, stableBin);
|
|
53286
53237
|
} finally {
|
|
53287
53238
|
safeUnlink(tarballPath);
|
|
53288
53239
|
safeUnlink(partialBin);
|
|
@@ -53292,15 +53243,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
53292
53243
|
function cleanupStaleArtifacts(binDir) {
|
|
53293
53244
|
let entries;
|
|
53294
53245
|
try {
|
|
53295
|
-
entries =
|
|
53246
|
+
entries = import_node_fs36.default.readdirSync(binDir);
|
|
53296
53247
|
} catch {
|
|
53297
53248
|
return;
|
|
53298
53249
|
}
|
|
53299
53250
|
for (const name of entries) {
|
|
53300
53251
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
53301
|
-
const full =
|
|
53252
|
+
const full = import_node_path39.default.join(binDir, name);
|
|
53302
53253
|
try {
|
|
53303
|
-
|
|
53254
|
+
import_node_fs36.default.rmSync(full, { recursive: true, force: true });
|
|
53304
53255
|
} catch {
|
|
53305
53256
|
}
|
|
53306
53257
|
}
|
|
@@ -53308,7 +53259,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
53308
53259
|
}
|
|
53309
53260
|
function safeUnlink(p2) {
|
|
53310
53261
|
try {
|
|
53311
|
-
|
|
53262
|
+
import_node_fs36.default.unlinkSync(p2);
|
|
53312
53263
|
} catch {
|
|
53313
53264
|
}
|
|
53314
53265
|
}
|
|
@@ -53319,13 +53270,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
53319
53270
|
if (!res.ok || !res.body) {
|
|
53320
53271
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
53321
53272
|
}
|
|
53322
|
-
const out =
|
|
53273
|
+
const out = import_node_fs36.default.createWriteStream(dest);
|
|
53323
53274
|
const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
|
|
53324
53275
|
await (0, import_promises5.pipeline)(nodeStream, out);
|
|
53325
53276
|
}
|
|
53326
53277
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
53327
|
-
const work =
|
|
53328
|
-
|
|
53278
|
+
const work = import_node_path39.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
53279
|
+
import_node_fs36.default.mkdirSync(work, { recursive: true });
|
|
53329
53280
|
try {
|
|
53330
53281
|
await new Promise((resolve6, reject) => {
|
|
53331
53282
|
const proc = (0, import_node_child_process8.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -53333,32 +53284,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
53333
53284
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
53334
53285
|
});
|
|
53335
53286
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
53336
|
-
const src =
|
|
53337
|
-
if (!
|
|
53287
|
+
const src = import_node_path39.default.join(work, dirName, "frpc");
|
|
53288
|
+
if (!import_node_fs36.default.existsSync(src)) {
|
|
53338
53289
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
53339
53290
|
}
|
|
53340
|
-
|
|
53291
|
+
import_node_fs36.default.copyFileSync(src, destBin);
|
|
53341
53292
|
} finally {
|
|
53342
|
-
|
|
53293
|
+
import_node_fs36.default.rmSync(work, { recursive: true, force: true });
|
|
53343
53294
|
}
|
|
53344
53295
|
}
|
|
53345
53296
|
|
|
53346
53297
|
// src/tunnel/frpc-process.ts
|
|
53347
|
-
var
|
|
53348
|
-
var
|
|
53298
|
+
var import_node_fs37 = __toESM(require("fs"), 1);
|
|
53299
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
53349
53300
|
var import_node_child_process9 = require("child_process");
|
|
53350
53301
|
function frpcPidFilePath(dataDir) {
|
|
53351
|
-
return
|
|
53302
|
+
return import_node_path40.default.join(dataDir, "frpc.pid");
|
|
53352
53303
|
}
|
|
53353
53304
|
function writeFrpcPid(dataDir, pid) {
|
|
53354
53305
|
try {
|
|
53355
|
-
|
|
53306
|
+
import_node_fs37.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
53356
53307
|
} catch {
|
|
53357
53308
|
}
|
|
53358
53309
|
}
|
|
53359
53310
|
function clearFrpcPid(dataDir) {
|
|
53360
53311
|
try {
|
|
53361
|
-
|
|
53312
|
+
import_node_fs37.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
53362
53313
|
} catch {
|
|
53363
53314
|
}
|
|
53364
53315
|
}
|
|
@@ -53374,7 +53325,7 @@ function defaultIsPidAlive(pid) {
|
|
|
53374
53325
|
}
|
|
53375
53326
|
function defaultReadPidFile(file) {
|
|
53376
53327
|
try {
|
|
53377
|
-
return
|
|
53328
|
+
return import_node_fs37.default.readFileSync(file, "utf8");
|
|
53378
53329
|
} catch {
|
|
53379
53330
|
return null;
|
|
53380
53331
|
}
|
|
@@ -53385,17 +53336,17 @@ function defaultKillPid(pid, signal) {
|
|
|
53385
53336
|
} catch {
|
|
53386
53337
|
}
|
|
53387
53338
|
}
|
|
53388
|
-
function
|
|
53339
|
+
function defaultSleep2(ms) {
|
|
53389
53340
|
return new Promise((r) => setTimeout(r, ms));
|
|
53390
53341
|
}
|
|
53391
53342
|
async function killStaleFrpc(deps) {
|
|
53392
53343
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
53393
|
-
const tomlPath =
|
|
53344
|
+
const tomlPath = import_node_path40.default.join(deps.dataDir, "frpc.toml");
|
|
53394
53345
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
53395
53346
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
53396
53347
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
53397
53348
|
const scanPids = deps.scanFrpcPidsImpl ?? ((tp) => defaultScanFrpcPidsByCmdline(tp, deps.logger));
|
|
53398
|
-
const sleep2 = deps.sleepImpl ??
|
|
53349
|
+
const sleep2 = deps.sleepImpl ?? defaultSleep2;
|
|
53399
53350
|
const victims = /* @__PURE__ */ new Set();
|
|
53400
53351
|
const raw = readPidFile(pidFile);
|
|
53401
53352
|
if (raw) {
|
|
@@ -53414,7 +53365,7 @@ async function killStaleFrpc(deps) {
|
|
|
53414
53365
|
}
|
|
53415
53366
|
if (victims.size === 0) {
|
|
53416
53367
|
try {
|
|
53417
|
-
|
|
53368
|
+
import_node_fs37.default.unlinkSync(pidFile);
|
|
53418
53369
|
} catch {
|
|
53419
53370
|
}
|
|
53420
53371
|
return;
|
|
@@ -53425,7 +53376,7 @@ async function killStaleFrpc(deps) {
|
|
|
53425
53376
|
}
|
|
53426
53377
|
await sleep2(deps.reapWaitMs ?? 300);
|
|
53427
53378
|
try {
|
|
53428
|
-
|
|
53379
|
+
import_node_fs37.default.unlinkSync(pidFile);
|
|
53429
53380
|
} catch {
|
|
53430
53381
|
}
|
|
53431
53382
|
}
|
|
@@ -53462,7 +53413,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
53462
53413
|
var TunnelManager = class {
|
|
53463
53414
|
constructor(deps) {
|
|
53464
53415
|
this.deps = deps;
|
|
53465
|
-
this.store = deps.store ?? new TunnelStore(
|
|
53416
|
+
this.store = deps.store ?? new TunnelStore(import_node_path41.default.join(deps.dataDir, "tunnel.json"));
|
|
53466
53417
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
53467
53418
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
53468
53419
|
}
|
|
@@ -53589,7 +53540,7 @@ var TunnelManager = class {
|
|
|
53589
53540
|
dataDir: this.deps.dataDir,
|
|
53590
53541
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
53591
53542
|
});
|
|
53592
|
-
const tomlPath =
|
|
53543
|
+
const tomlPath = import_node_path41.default.join(this.deps.dataDir, "frpc.toml");
|
|
53593
53544
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
|
|
53594
53545
|
const toml = buildFrpcToml({
|
|
53595
53546
|
serverAddr: t.frpsHost,
|
|
@@ -53600,14 +53551,14 @@ var TunnelManager = class {
|
|
|
53600
53551
|
localPort,
|
|
53601
53552
|
logLevel: "info"
|
|
53602
53553
|
});
|
|
53603
|
-
await
|
|
53554
|
+
await import_node_fs38.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
53604
53555
|
const proc = (this.deps.spawnImpl ?? import_node_child_process10.spawn)(frpcBin, ["-c", tomlPath], {
|
|
53605
53556
|
stdio: ["ignore", "pipe", "pipe"]
|
|
53606
53557
|
});
|
|
53607
|
-
const logDir =
|
|
53608
|
-
|
|
53609
|
-
const logFilePath =
|
|
53610
|
-
const logStream =
|
|
53558
|
+
const logDir = import_node_path41.default.join(this.deps.dataDir, "log");
|
|
53559
|
+
import_node_fs38.default.mkdirSync(logDir, { recursive: true });
|
|
53560
|
+
const logFilePath = import_node_path41.default.join(logDir, "frpc.log");
|
|
53561
|
+
const logStream = import_node_fs38.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
53611
53562
|
logStream.on("error", () => {
|
|
53612
53563
|
});
|
|
53613
53564
|
const tee = (chunk) => {
|
|
@@ -53690,27 +53641,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
53690
53641
|
|
|
53691
53642
|
// src/tunnel/device-key.ts
|
|
53692
53643
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
53693
|
-
var
|
|
53644
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
53694
53645
|
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
53695
53646
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
53696
53647
|
function deriveStableDeviceKey(opts = {}) {
|
|
53697
53648
|
const hostname = opts.hostname ?? import_node_os14.default.hostname();
|
|
53698
53649
|
const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
|
|
53699
53650
|
const home = opts.home ?? import_node_os14.default.homedir();
|
|
53700
|
-
const defaultDataDir =
|
|
53701
|
-
const normalizedDataDir = opts.dataDir ?
|
|
53651
|
+
const defaultDataDir = import_node_path42.default.resolve(import_node_path42.default.join(home, ".clawd"));
|
|
53652
|
+
const normalizedDataDir = opts.dataDir ? import_node_path42.default.resolve(opts.dataDir) : null;
|
|
53702
53653
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
53703
53654
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
53704
53655
|
return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
53705
53656
|
}
|
|
53706
53657
|
|
|
53707
53658
|
// src/auth-store.ts
|
|
53708
|
-
var
|
|
53709
|
-
var
|
|
53659
|
+
var import_node_fs39 = __toESM(require("fs"), 1);
|
|
53660
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
53710
53661
|
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
53711
53662
|
var AUTH_FILE_NAME = "auth.json";
|
|
53712
53663
|
function authFilePath(dataDir) {
|
|
53713
|
-
return
|
|
53664
|
+
return import_node_path43.default.join(dataDir, AUTH_FILE_NAME);
|
|
53714
53665
|
}
|
|
53715
53666
|
function loadOrCreateAuthFile(opts) {
|
|
53716
53667
|
const file = authFilePath(opts.dataDir);
|
|
@@ -53718,23 +53669,19 @@ function loadOrCreateAuthFile(opts) {
|
|
|
53718
53669
|
const genId = opts.genOwnerPrincipalId ?? defaultGenerateOwnerPrincipalId;
|
|
53719
53670
|
const now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
53720
53671
|
const existing = readAuthFile(file);
|
|
53721
|
-
if (existing && existing.token && existing.
|
|
53672
|
+
if (existing && existing.token && existing.ownerPrincipalId && existing.deviceId && existing.deviceId === existing.ownerPrincipalId && !existing.hasLegacySecrets) {
|
|
53722
53673
|
return {
|
|
53723
53674
|
token: existing.token,
|
|
53724
|
-
signSecret: existing.signSecret,
|
|
53725
|
-
visitorTokenSecret: existing.visitorTokenSecret,
|
|
53726
53675
|
ownerPrincipalId: existing.ownerPrincipalId,
|
|
53727
53676
|
deviceId: existing.deviceId,
|
|
53728
53677
|
createdAt: existing.createdAt ?? (/* @__PURE__ */ new Date(0)).toISOString()
|
|
53729
53678
|
};
|
|
53730
53679
|
}
|
|
53731
53680
|
const token = existing?.token || generate();
|
|
53732
|
-
const signSecret = existing?.signSecret || generate();
|
|
53733
|
-
const visitorTokenSecret = existing?.visitorTokenSecret || generate();
|
|
53734
53681
|
const ownerPrincipalId = existing?.ownerPrincipalId || genId();
|
|
53735
53682
|
const deviceId = ownerPrincipalId;
|
|
53736
53683
|
const createdAt = existing?.createdAt || now().toISOString();
|
|
53737
|
-
const next = { token,
|
|
53684
|
+
const next = { token, ownerPrincipalId, deviceId, createdAt };
|
|
53738
53685
|
writeAuthFile(file, next);
|
|
53739
53686
|
return next;
|
|
53740
53687
|
}
|
|
@@ -53746,18 +53693,18 @@ function defaultGenerateOwnerPrincipalId() {
|
|
|
53746
53693
|
}
|
|
53747
53694
|
function readAuthFile(file) {
|
|
53748
53695
|
try {
|
|
53749
|
-
const raw =
|
|
53696
|
+
const raw = import_node_fs39.default.readFileSync(file, "utf8");
|
|
53750
53697
|
const parsed = JSON.parse(raw);
|
|
53751
53698
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
53752
53699
|
return null;
|
|
53753
53700
|
}
|
|
53754
53701
|
return {
|
|
53755
53702
|
token: parsed.token,
|
|
53756
|
-
signSecret: typeof parsed.signSecret === "string" && parsed.signSecret.length > 0 ? parsed.signSecret : void 0,
|
|
53757
|
-
visitorTokenSecret: typeof parsed.visitorTokenSecret === "string" && parsed.visitorTokenSecret.length > 0 ? parsed.visitorTokenSecret : void 0,
|
|
53758
53703
|
ownerPrincipalId: typeof parsed.ownerPrincipalId === "string" && parsed.ownerPrincipalId.length > 0 ? parsed.ownerPrincipalId : void 0,
|
|
53759
53704
|
deviceId: typeof parsed.deviceId === "string" && parsed.deviceId.length > 0 ? parsed.deviceId : void 0,
|
|
53760
|
-
createdAt: typeof parsed.createdAt === "string" ? parsed.createdAt : void 0
|
|
53705
|
+
createdAt: typeof parsed.createdAt === "string" ? parsed.createdAt : void 0,
|
|
53706
|
+
// 单 secret 合并前的旧字段:出现即触发清理写回(值无所谓,硬切不再使用)
|
|
53707
|
+
hasLegacySecrets: "signSecret" in parsed || "visitorTokenSecret" in parsed
|
|
53761
53708
|
};
|
|
53762
53709
|
} catch (err) {
|
|
53763
53710
|
const code = err?.code;
|
|
@@ -53766,25 +53713,25 @@ function readAuthFile(file) {
|
|
|
53766
53713
|
}
|
|
53767
53714
|
}
|
|
53768
53715
|
function writeAuthFile(file, content) {
|
|
53769
|
-
|
|
53770
|
-
|
|
53716
|
+
import_node_fs39.default.mkdirSync(import_node_path43.default.dirname(file), { recursive: true });
|
|
53717
|
+
import_node_fs39.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
53771
53718
|
try {
|
|
53772
|
-
|
|
53719
|
+
import_node_fs39.default.chmodSync(file, 384);
|
|
53773
53720
|
} catch {
|
|
53774
53721
|
}
|
|
53775
53722
|
}
|
|
53776
53723
|
|
|
53777
53724
|
// src/owner-profile.ts
|
|
53778
|
-
var
|
|
53725
|
+
var import_node_fs40 = __toESM(require("fs"), 1);
|
|
53779
53726
|
var import_node_os15 = __toESM(require("os"), 1);
|
|
53780
|
-
var
|
|
53727
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
53781
53728
|
var PROFILE_FILENAME = "profile.json";
|
|
53782
53729
|
function loadOwnerDisplayName(dataDir) {
|
|
53783
53730
|
const fallback = import_node_os15.default.userInfo().username;
|
|
53784
|
-
const profilePath =
|
|
53731
|
+
const profilePath = import_node_path44.default.join(dataDir, PROFILE_FILENAME);
|
|
53785
53732
|
let raw;
|
|
53786
53733
|
try {
|
|
53787
|
-
raw =
|
|
53734
|
+
raw = import_node_fs40.default.readFileSync(profilePath, "utf8");
|
|
53788
53735
|
} catch {
|
|
53789
53736
|
return fallback;
|
|
53790
53737
|
}
|
|
@@ -53807,18 +53754,18 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
53807
53754
|
}
|
|
53808
53755
|
|
|
53809
53756
|
// src/feishu-auth/owner-identity-store.ts
|
|
53810
|
-
var
|
|
53811
|
-
var
|
|
53757
|
+
var import_node_fs41 = __toESM(require("fs"), 1);
|
|
53758
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
53812
53759
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
53813
53760
|
var OwnerIdentityStore = class {
|
|
53814
53761
|
file;
|
|
53815
53762
|
constructor(dataDir) {
|
|
53816
|
-
this.file =
|
|
53763
|
+
this.file = import_node_path45.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
53817
53764
|
}
|
|
53818
53765
|
read() {
|
|
53819
53766
|
let raw;
|
|
53820
53767
|
try {
|
|
53821
|
-
raw =
|
|
53768
|
+
raw = import_node_fs41.default.readFileSync(this.file, "utf8");
|
|
53822
53769
|
} catch {
|
|
53823
53770
|
return null;
|
|
53824
53771
|
}
|
|
@@ -53846,16 +53793,16 @@ var OwnerIdentityStore = class {
|
|
|
53846
53793
|
};
|
|
53847
53794
|
}
|
|
53848
53795
|
write(record) {
|
|
53849
|
-
|
|
53850
|
-
|
|
53796
|
+
import_node_fs41.default.mkdirSync(import_node_path45.default.dirname(this.file), { recursive: true });
|
|
53797
|
+
import_node_fs41.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
53851
53798
|
try {
|
|
53852
|
-
|
|
53799
|
+
import_node_fs41.default.chmodSync(this.file, 384);
|
|
53853
53800
|
} catch {
|
|
53854
53801
|
}
|
|
53855
53802
|
}
|
|
53856
53803
|
clear() {
|
|
53857
53804
|
try {
|
|
53858
|
-
|
|
53805
|
+
import_node_fs41.default.unlinkSync(this.file);
|
|
53859
53806
|
} catch (err) {
|
|
53860
53807
|
const code = err?.code;
|
|
53861
53808
|
if (code !== "ENOENT") throw err;
|
|
@@ -53992,9 +53939,9 @@ var CentralClientError = class extends Error {
|
|
|
53992
53939
|
code;
|
|
53993
53940
|
cause;
|
|
53994
53941
|
};
|
|
53995
|
-
async function centralRequest(opts,
|
|
53942
|
+
async function centralRequest(opts, path75, init) {
|
|
53996
53943
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
53997
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
53944
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path75}`;
|
|
53998
53945
|
const ctrl = new AbortController();
|
|
53999
53946
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
54000
53947
|
let res;
|
|
@@ -54188,8 +54135,8 @@ function verifyConnectToken(args) {
|
|
|
54188
54135
|
}
|
|
54189
54136
|
|
|
54190
54137
|
// src/feishu-auth/server-key.ts
|
|
54191
|
-
var
|
|
54192
|
-
var
|
|
54138
|
+
var fs51 = __toESM(require("fs"), 1);
|
|
54139
|
+
var path54 = __toESM(require("path"), 1);
|
|
54193
54140
|
var FILE_NAME2 = "server-signing-key.json";
|
|
54194
54141
|
var ServerKeyStore = class {
|
|
54195
54142
|
constructor(dataDir) {
|
|
@@ -54197,12 +54144,12 @@ var ServerKeyStore = class {
|
|
|
54197
54144
|
}
|
|
54198
54145
|
dataDir;
|
|
54199
54146
|
filePath() {
|
|
54200
|
-
return
|
|
54147
|
+
return path54.join(this.dataDir, FILE_NAME2);
|
|
54201
54148
|
}
|
|
54202
54149
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
54203
54150
|
read() {
|
|
54204
54151
|
try {
|
|
54205
|
-
const raw =
|
|
54152
|
+
const raw = fs51.readFileSync(this.filePath(), "utf8");
|
|
54206
54153
|
const parsed = JSON.parse(raw);
|
|
54207
54154
|
if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
|
|
54208
54155
|
return parsed.publicKeyPem;
|
|
@@ -54217,12 +54164,12 @@ var ServerKeyStore = class {
|
|
|
54217
54164
|
publicKeyPem,
|
|
54218
54165
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
54219
54166
|
};
|
|
54220
|
-
|
|
54221
|
-
|
|
54167
|
+
fs51.mkdirSync(this.dataDir, { recursive: true });
|
|
54168
|
+
fs51.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
|
|
54222
54169
|
}
|
|
54223
54170
|
clear() {
|
|
54224
54171
|
try {
|
|
54225
|
-
|
|
54172
|
+
fs51.unlinkSync(this.filePath());
|
|
54226
54173
|
} catch {
|
|
54227
54174
|
}
|
|
54228
54175
|
}
|
|
@@ -54235,12 +54182,12 @@ init_protocol();
|
|
|
54235
54182
|
init_protocol();
|
|
54236
54183
|
|
|
54237
54184
|
// src/session/fork.ts
|
|
54238
|
-
var
|
|
54185
|
+
var import_node_fs42 = __toESM(require("fs"), 1);
|
|
54239
54186
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
54240
|
-
var
|
|
54187
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
54241
54188
|
init_claude_history();
|
|
54242
54189
|
function readJsonlEntries(file) {
|
|
54243
|
-
const raw =
|
|
54190
|
+
const raw = import_node_fs42.default.readFileSync(file, "utf8");
|
|
54244
54191
|
const out = [];
|
|
54245
54192
|
for (const line of raw.split("\n")) {
|
|
54246
54193
|
const t = line.trim();
|
|
@@ -54253,19 +54200,19 @@ function readJsonlEntries(file) {
|
|
|
54253
54200
|
return out;
|
|
54254
54201
|
}
|
|
54255
54202
|
function forkSession(input) {
|
|
54256
|
-
const baseDir = input.baseDir ??
|
|
54257
|
-
let projectDir =
|
|
54258
|
-
let sourceFile =
|
|
54259
|
-
if (!
|
|
54203
|
+
const baseDir = input.baseDir ?? import_node_path46.default.join(import_node_os16.default.homedir(), ".claude");
|
|
54204
|
+
let projectDir = import_node_path46.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
54205
|
+
let sourceFile = import_node_path46.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
54206
|
+
if (!import_node_fs42.default.existsSync(sourceFile)) {
|
|
54260
54207
|
const found = findTranscriptByToolSessionId(
|
|
54261
|
-
|
|
54208
|
+
import_node_path46.default.join(baseDir, "projects"),
|
|
54262
54209
|
input.toolSessionId
|
|
54263
54210
|
);
|
|
54264
54211
|
if (!found) {
|
|
54265
54212
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
54266
54213
|
}
|
|
54267
54214
|
sourceFile = found;
|
|
54268
|
-
projectDir =
|
|
54215
|
+
projectDir = import_node_path46.default.dirname(found);
|
|
54269
54216
|
}
|
|
54270
54217
|
const entries = readJsonlEntries(sourceFile);
|
|
54271
54218
|
const mainEntries = entries.filter((e) => e.isSidechain !== true);
|
|
@@ -54294,9 +54241,9 @@ function forkSession(input) {
|
|
|
54294
54241
|
}
|
|
54295
54242
|
forkedLines.push(JSON.stringify(forked));
|
|
54296
54243
|
}
|
|
54297
|
-
const forkedFilePath =
|
|
54298
|
-
|
|
54299
|
-
|
|
54244
|
+
const forkedFilePath = import_node_path46.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
54245
|
+
import_node_fs42.default.mkdirSync(projectDir, { recursive: true });
|
|
54246
|
+
import_node_fs42.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
54300
54247
|
return { forkedToolSessionId, forkedFilePath };
|
|
54301
54248
|
}
|
|
54302
54249
|
|
|
@@ -54708,7 +54655,7 @@ function buildPermissionHandlers(deps) {
|
|
|
54708
54655
|
}
|
|
54709
54656
|
|
|
54710
54657
|
// src/handlers/history.ts
|
|
54711
|
-
var
|
|
54658
|
+
var path57 = __toESM(require("path"), 1);
|
|
54712
54659
|
init_protocol();
|
|
54713
54660
|
|
|
54714
54661
|
// src/session/recent-dirs.ts
|
|
@@ -54726,7 +54673,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
54726
54673
|
}
|
|
54727
54674
|
|
|
54728
54675
|
// src/permission/persona-paths.ts
|
|
54729
|
-
var
|
|
54676
|
+
var path56 = __toESM(require("path"), 1);
|
|
54730
54677
|
function getAllowedPersonaIds(grants, action) {
|
|
54731
54678
|
const ids = /* @__PURE__ */ new Set();
|
|
54732
54679
|
for (const g2 of grants) {
|
|
@@ -54739,42 +54686,42 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
54739
54686
|
return ids;
|
|
54740
54687
|
}
|
|
54741
54688
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
54742
|
-
const target =
|
|
54689
|
+
const target = path56.resolve(absPath);
|
|
54743
54690
|
if (userWorkDir) {
|
|
54744
|
-
const u =
|
|
54745
|
-
const usep = u.endsWith(
|
|
54691
|
+
const u = path56.resolve(userWorkDir);
|
|
54692
|
+
const usep = u.endsWith(path56.sep) ? "" : path56.sep;
|
|
54746
54693
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
54747
54694
|
}
|
|
54748
|
-
const root =
|
|
54749
|
-
const sep3 = root.endsWith(
|
|
54695
|
+
const root = path56.resolve(personaRoot);
|
|
54696
|
+
const sep3 = root.endsWith(path56.sep) ? "" : path56.sep;
|
|
54750
54697
|
if (!target.startsWith(root + sep3)) return false;
|
|
54751
|
-
const rel =
|
|
54698
|
+
const rel = path56.relative(root, target);
|
|
54752
54699
|
if (!rel || rel.startsWith("..")) return false;
|
|
54753
|
-
const personaId = rel.split(
|
|
54700
|
+
const personaId = rel.split(path56.sep)[0];
|
|
54754
54701
|
if (!personaId) return false;
|
|
54755
54702
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
54756
54703
|
if (allowed === "*") return true;
|
|
54757
54704
|
return allowed.has(personaId);
|
|
54758
54705
|
}
|
|
54759
54706
|
function personaIdFromPath(absPath, personaRoot) {
|
|
54760
|
-
const root =
|
|
54761
|
-
const target =
|
|
54762
|
-
const sep3 = root.endsWith(
|
|
54707
|
+
const root = path56.resolve(personaRoot);
|
|
54708
|
+
const target = path56.resolve(absPath);
|
|
54709
|
+
const sep3 = root.endsWith(path56.sep) ? "" : path56.sep;
|
|
54763
54710
|
if (!target.startsWith(root + sep3)) return null;
|
|
54764
|
-
const rel =
|
|
54711
|
+
const rel = path56.relative(root, target);
|
|
54765
54712
|
if (!rel || rel.startsWith("..")) return null;
|
|
54766
|
-
const id = rel.split(
|
|
54713
|
+
const id = rel.split(path56.sep)[0];
|
|
54767
54714
|
return id || null;
|
|
54768
54715
|
}
|
|
54769
54716
|
function isPathWithin(dir, absPath) {
|
|
54770
|
-
const d =
|
|
54771
|
-
const t =
|
|
54772
|
-
const sep3 = d.endsWith(
|
|
54717
|
+
const d = path56.resolve(dir);
|
|
54718
|
+
const t = path56.resolve(absPath);
|
|
54719
|
+
const sep3 = d.endsWith(path56.sep) ? "" : path56.sep;
|
|
54773
54720
|
return t === d || t.startsWith(d + sep3);
|
|
54774
54721
|
}
|
|
54775
54722
|
function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
|
|
54776
54723
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
54777
|
-
return personaIdFromPath(
|
|
54724
|
+
return personaIdFromPath(path56.resolve(absPath), personaRoot) === personaId;
|
|
54778
54725
|
}
|
|
54779
54726
|
|
|
54780
54727
|
// src/handlers/history.ts
|
|
@@ -54826,7 +54773,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54826
54773
|
if (!pid) return false;
|
|
54827
54774
|
return isGuestPathAllowed(
|
|
54828
54775
|
ctx.grants,
|
|
54829
|
-
|
|
54776
|
+
path57.join(personaRoot, pid),
|
|
54830
54777
|
personaRoot,
|
|
54831
54778
|
"read",
|
|
54832
54779
|
userWorkDir
|
|
@@ -54838,7 +54785,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54838
54785
|
};
|
|
54839
54786
|
const list = async (frame, _client, ctx) => {
|
|
54840
54787
|
const args = HistoryListArgs.parse(frame);
|
|
54841
|
-
assertGuestPath(ctx,
|
|
54788
|
+
assertGuestPath(ctx, path57.resolve(args.projectPath), personaRoot, "history:list");
|
|
54842
54789
|
const sessions = await history.listSessions(args);
|
|
54843
54790
|
return { response: { type: "history:list", sessions } };
|
|
54844
54791
|
};
|
|
@@ -54871,13 +54818,13 @@ function buildHistoryHandlers(deps) {
|
|
|
54871
54818
|
};
|
|
54872
54819
|
const subagents = async (frame, _client, ctx) => {
|
|
54873
54820
|
const args = HistorySubagentsArgs.parse(frame);
|
|
54874
|
-
assertGuestPath(ctx,
|
|
54821
|
+
assertGuestPath(ctx, path57.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
54875
54822
|
const subs = await history.listSubagents(args);
|
|
54876
54823
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
54877
54824
|
};
|
|
54878
54825
|
const subagentRead = async (frame, _client, ctx) => {
|
|
54879
54826
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
54880
|
-
assertGuestPath(ctx,
|
|
54827
|
+
assertGuestPath(ctx, path57.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
54881
54828
|
const res = await history.readSubagent(args);
|
|
54882
54829
|
return { response: { type: "history:subagent-read", ...res } };
|
|
54883
54830
|
};
|
|
@@ -54886,7 +54833,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54886
54833
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
54887
54834
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
54888
54835
|
const filtered = dirs.filter(
|
|
54889
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
54836
|
+
(d) => isGuestPathAllowed(ctx.grants, path57.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
54890
54837
|
);
|
|
54891
54838
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
54892
54839
|
}
|
|
@@ -54903,7 +54850,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54903
54850
|
}
|
|
54904
54851
|
|
|
54905
54852
|
// src/handlers/workspace.ts
|
|
54906
|
-
var
|
|
54853
|
+
var path58 = __toESM(require("path"), 1);
|
|
54907
54854
|
var os16 = __toESM(require("os"), 1);
|
|
54908
54855
|
init_protocol();
|
|
54909
54856
|
init_protocol();
|
|
@@ -54945,22 +54892,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54945
54892
|
const args = WorkspaceListArgs.parse(frame);
|
|
54946
54893
|
const isGuest = ctx?.principal.kind === "guest";
|
|
54947
54894
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
|
|
54948
|
-
const resolvedCwd =
|
|
54949
|
-
const target = args.path ?
|
|
54895
|
+
const resolvedCwd = path58.resolve(args.cwd ?? fallbackCwd);
|
|
54896
|
+
const target = args.path ? path58.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
54950
54897
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
54951
54898
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
54952
54899
|
return { response: { type: "workspace:list", ...res } };
|
|
54953
54900
|
};
|
|
54954
54901
|
const read = async (frame, _client, ctx) => {
|
|
54955
54902
|
const args = WorkspaceReadArgs.parse(frame);
|
|
54956
|
-
const target =
|
|
54903
|
+
const target = path58.isAbsolute(args.path) ? path58.resolve(args.path) : path58.resolve(args.cwd, args.path);
|
|
54957
54904
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
54958
54905
|
const res = workspace.read(args);
|
|
54959
54906
|
return { response: { type: "workspace:read", ...res } };
|
|
54960
54907
|
};
|
|
54961
54908
|
const skillsList = async (frame, _client, ctx) => {
|
|
54962
54909
|
const args = SkillsListArgs.parse(frame);
|
|
54963
|
-
const cwdAbs =
|
|
54910
|
+
const cwdAbs = path58.resolve(args.cwd);
|
|
54964
54911
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
54965
54912
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
54966
54913
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -54972,7 +54919,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54972
54919
|
};
|
|
54973
54920
|
const agentsList = async (frame, _client, ctx) => {
|
|
54974
54921
|
const args = AgentsListArgs.parse(frame);
|
|
54975
|
-
const cwdAbs =
|
|
54922
|
+
const cwdAbs = path58.resolve(args.cwd);
|
|
54976
54923
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
54977
54924
|
if (args.tool === "codex") {
|
|
54978
54925
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -54994,20 +54941,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54994
54941
|
}
|
|
54995
54942
|
|
|
54996
54943
|
// src/handlers/git.ts
|
|
54997
|
-
var
|
|
54944
|
+
var path60 = __toESM(require("path"), 1);
|
|
54998
54945
|
init_protocol();
|
|
54999
54946
|
init_protocol();
|
|
55000
54947
|
|
|
55001
54948
|
// src/workspace/git.ts
|
|
55002
54949
|
var import_node_child_process11 = require("child_process");
|
|
55003
|
-
var
|
|
55004
|
-
var
|
|
54950
|
+
var import_node_fs43 = __toESM(require("fs"), 1);
|
|
54951
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
55005
54952
|
var import_node_util = require("util");
|
|
55006
54953
|
var pexec = (0, import_node_util.promisify)(import_node_child_process11.execFile);
|
|
55007
54954
|
function normalizePath(p2) {
|
|
55008
|
-
const resolved =
|
|
54955
|
+
const resolved = import_node_path47.default.resolve(p2);
|
|
55009
54956
|
try {
|
|
55010
|
-
return
|
|
54957
|
+
return import_node_fs43.default.realpathSync(resolved);
|
|
55011
54958
|
} catch {
|
|
55012
54959
|
return resolved;
|
|
55013
54960
|
}
|
|
@@ -55081,7 +55028,7 @@ async function listGitBranches(cwd) {
|
|
|
55081
55028
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
55082
55029
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
55083
55030
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
55084
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
55031
|
+
if (!isGuestPathAllowed(ctx.grants, path60.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
55085
55032
|
throw new ClawdError(
|
|
55086
55033
|
ERROR_CODES.UNAUTHORIZED,
|
|
55087
55034
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -55826,7 +55773,7 @@ function buildPersonaHandlers(deps) {
|
|
|
55826
55773
|
}
|
|
55827
55774
|
|
|
55828
55775
|
// src/handlers/attachment.ts
|
|
55829
|
-
var
|
|
55776
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
55830
55777
|
init_protocol();
|
|
55831
55778
|
init_protocol();
|
|
55832
55779
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -55842,10 +55789,8 @@ function assertGuestAttachmentPath(ctx, absPath, personaRoot, method, usersRoot)
|
|
|
55842
55789
|
}
|
|
55843
55790
|
function buildAttachmentHandlers(deps) {
|
|
55844
55791
|
function guardAttachmentPath(ctx, sessionId, candidateAbs, method, nonGuestPolicy) {
|
|
55845
|
-
if (ctx?.principal.kind === "owner") return;
|
|
55846
55792
|
const scope = deps.getSessionScope?.(sessionId);
|
|
55847
|
-
if (
|
|
55848
|
-
if (scope.kind === "persona" && scope.mode === "guest") {
|
|
55793
|
+
if (scope?.kind === "persona" && scope.mode === "guest") {
|
|
55849
55794
|
if (!deps.personaRoot) return;
|
|
55850
55795
|
const userWorkDir = deps.usersRoot ? deriveUserWorkDir(scope.capId, deps.usersRoot) : void 0;
|
|
55851
55796
|
if (!isPathInGuestBoundary(deps.personaRoot, scope.personaId, userWorkDir, candidateAbs)) {
|
|
@@ -55856,6 +55801,8 @@ function buildAttachmentHandlers(deps) {
|
|
|
55856
55801
|
}
|
|
55857
55802
|
return;
|
|
55858
55803
|
}
|
|
55804
|
+
if (ctx?.principal.kind === "owner") return;
|
|
55805
|
+
if (!scope) return;
|
|
55859
55806
|
if (nonGuestPolicy === "group-acl") return;
|
|
55860
55807
|
const cwd = deps.sessionStore?.read(sessionId)?.cwd;
|
|
55861
55808
|
if (!cwd) return;
|
|
@@ -55906,12 +55853,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
55906
55853
|
`session ${args.sessionId} scope unresolved`
|
|
55907
55854
|
);
|
|
55908
55855
|
}
|
|
55909
|
-
const cwdAbs =
|
|
55910
|
-
const candidateAbs =
|
|
55856
|
+
const cwdAbs = import_node_path48.default.resolve(sessionFile.cwd);
|
|
55857
|
+
const candidateAbs = import_node_path48.default.isAbsolute(args.relPath) ? import_node_path48.default.resolve(args.relPath) : import_node_path48.default.resolve(cwdAbs, args.relPath);
|
|
55911
55858
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
|
|
55912
55859
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
55913
55860
|
const entry = entries.find((e) => {
|
|
55914
|
-
const storedAbs =
|
|
55861
|
+
const storedAbs = import_node_path48.default.isAbsolute(e.relPath) ? import_node_path48.default.resolve(e.relPath) : import_node_path48.default.resolve(cwdAbs, e.relPath);
|
|
55915
55862
|
return storedAbs === candidateAbs && !e.stale;
|
|
55916
55863
|
});
|
|
55917
55864
|
if (!entry) {
|
|
@@ -55936,7 +55883,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
55936
55883
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
55937
55884
|
const f = deps.sessionStore.read(sessionId);
|
|
55938
55885
|
if (!f) return;
|
|
55939
|
-
assertGuestAttachmentPath(ctx,
|
|
55886
|
+
assertGuestAttachmentPath(ctx, import_node_path48.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
55940
55887
|
}
|
|
55941
55888
|
const groupAdd = async (frame, _client, ctx) => {
|
|
55942
55889
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -55951,10 +55898,10 @@ function buildAttachmentHandlers(deps) {
|
|
|
55951
55898
|
if (!scope) {
|
|
55952
55899
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
|
|
55953
55900
|
}
|
|
55954
|
-
const cwdAbs =
|
|
55955
|
-
const candidateAbs =
|
|
55901
|
+
const cwdAbs = import_node_path48.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
|
|
55902
|
+
const candidateAbs = import_node_path48.default.isAbsolute(args.relPath) ? import_node_path48.default.resolve(args.relPath) : import_node_path48.default.resolve(cwdAbs, args.relPath);
|
|
55956
55903
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
|
|
55957
|
-
const from = ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
55904
|
+
const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
55958
55905
|
const size = 0;
|
|
55959
55906
|
const entry = deps.groupFileStore.upsert(scope, args.sessionId, {
|
|
55960
55907
|
relPath: args.relPath,
|
|
@@ -56011,19 +55958,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
56011
55958
|
|
|
56012
55959
|
// src/handlers/extension.ts
|
|
56013
55960
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
56014
|
-
var
|
|
55961
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
56015
55962
|
init_protocol();
|
|
56016
55963
|
|
|
56017
55964
|
// src/extension/bundle-zip.ts
|
|
56018
55965
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
56019
|
-
var
|
|
55966
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
56020
55967
|
var import_node_crypto14 = __toESM(require("crypto"), 1);
|
|
56021
55968
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
56022
55969
|
async function bundleExtensionDir(dir) {
|
|
56023
55970
|
const entries = await listFilesSorted(dir);
|
|
56024
55971
|
const zip = new import_jszip2.default();
|
|
56025
55972
|
for (const rel of entries) {
|
|
56026
|
-
const abs =
|
|
55973
|
+
const abs = import_node_path49.default.join(dir, rel);
|
|
56027
55974
|
const content = await import_promises6.default.readFile(abs);
|
|
56028
55975
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
56029
55976
|
}
|
|
@@ -56044,7 +55991,7 @@ async function listFilesSorted(rootDir) {
|
|
|
56044
55991
|
return out;
|
|
56045
55992
|
}
|
|
56046
55993
|
async function walk(absRoot, relPrefix, out) {
|
|
56047
|
-
const dirAbs =
|
|
55994
|
+
const dirAbs = import_node_path49.default.join(absRoot, relPrefix);
|
|
56048
55995
|
const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
|
|
56049
55996
|
for (const e of entries) {
|
|
56050
55997
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -56098,25 +56045,25 @@ function computePublishCheck(args) {
|
|
|
56098
56045
|
|
|
56099
56046
|
// src/extension/install-flow.ts
|
|
56100
56047
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
56101
|
-
var
|
|
56048
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
56102
56049
|
var import_node_os19 = __toESM(require("os"), 1);
|
|
56103
56050
|
var import_node_crypto15 = __toESM(require("crypto"), 1);
|
|
56104
56051
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
56105
56052
|
|
|
56106
56053
|
// src/extension/paths.ts
|
|
56107
56054
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
56108
|
-
var
|
|
56055
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
56109
56056
|
function clawdHomeRoot(override) {
|
|
56110
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
56057
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path50.default.join(import_node_os18.default.homedir(), ".clawd");
|
|
56111
56058
|
}
|
|
56112
56059
|
function extensionsRoot(override) {
|
|
56113
|
-
return
|
|
56060
|
+
return import_node_path50.default.join(clawdHomeRoot(override), "extensions");
|
|
56114
56061
|
}
|
|
56115
56062
|
function publishedChannelsFile(override) {
|
|
56116
|
-
return
|
|
56063
|
+
return import_node_path50.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
56117
56064
|
}
|
|
56118
56065
|
function bundleCacheRoot(override) {
|
|
56119
|
-
return
|
|
56066
|
+
return import_node_path50.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
56120
56067
|
}
|
|
56121
56068
|
|
|
56122
56069
|
// src/extension/install-flow.ts
|
|
@@ -56143,7 +56090,7 @@ async function installFromChannel(args, deps) {
|
|
|
56143
56090
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
56144
56091
|
}
|
|
56145
56092
|
for (const name of Object.keys(zip.files)) {
|
|
56146
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
56093
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path51.default.isAbsolute(name)) {
|
|
56147
56094
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
56148
56095
|
}
|
|
56149
56096
|
}
|
|
@@ -56175,7 +56122,7 @@ async function installFromChannel(args, deps) {
|
|
|
56175
56122
|
);
|
|
56176
56123
|
}
|
|
56177
56124
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
56178
|
-
const destDir =
|
|
56125
|
+
const destDir = import_node_path51.default.join(deps.extensionsRoot, localExtId);
|
|
56179
56126
|
let destExists = false;
|
|
56180
56127
|
try {
|
|
56181
56128
|
await import_promises7.default.access(destDir);
|
|
@@ -56189,16 +56136,16 @@ async function installFromChannel(args, deps) {
|
|
|
56189
56136
|
);
|
|
56190
56137
|
}
|
|
56191
56138
|
const stage = await import_promises7.default.mkdtemp(
|
|
56192
|
-
|
|
56139
|
+
import_node_path51.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
56193
56140
|
);
|
|
56194
56141
|
try {
|
|
56195
56142
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
56196
|
-
const dest =
|
|
56143
|
+
const dest = import_node_path51.default.join(stage, name);
|
|
56197
56144
|
if (entry.dir) {
|
|
56198
56145
|
await import_promises7.default.mkdir(dest, { recursive: true });
|
|
56199
56146
|
continue;
|
|
56200
56147
|
}
|
|
56201
|
-
await import_promises7.default.mkdir(
|
|
56148
|
+
await import_promises7.default.mkdir(import_node_path51.default.dirname(dest), { recursive: true });
|
|
56202
56149
|
if (name === "manifest.json") {
|
|
56203
56150
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
56204
56151
|
await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -56219,7 +56166,7 @@ async function installFromChannel(args, deps) {
|
|
|
56219
56166
|
|
|
56220
56167
|
// src/extension/update-flow.ts
|
|
56221
56168
|
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
56222
|
-
var
|
|
56169
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
56223
56170
|
var import_node_os20 = __toESM(require("os"), 1);
|
|
56224
56171
|
var import_node_crypto16 = __toESM(require("crypto"), 1);
|
|
56225
56172
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
@@ -56236,11 +56183,11 @@ async function updateFromChannel(args, deps) {
|
|
|
56236
56183
|
channelRef.extId,
|
|
56237
56184
|
channelRef.ownerPrincipalId
|
|
56238
56185
|
);
|
|
56239
|
-
const liveDir =
|
|
56186
|
+
const liveDir = import_node_path52.default.join(deps.extensionsRoot, localExtId);
|
|
56240
56187
|
const prevDir = `${liveDir}.prev`;
|
|
56241
56188
|
let existingVersion;
|
|
56242
56189
|
try {
|
|
56243
|
-
const raw = await import_promises8.default.readFile(
|
|
56190
|
+
const raw = await import_promises8.default.readFile(import_node_path52.default.join(liveDir, "manifest.json"), "utf8");
|
|
56244
56191
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
56245
56192
|
if (!parsed2.success) {
|
|
56246
56193
|
throw new UpdateError(
|
|
@@ -56273,7 +56220,7 @@ async function updateFromChannel(args, deps) {
|
|
|
56273
56220
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
56274
56221
|
}
|
|
56275
56222
|
for (const name of Object.keys(zip.files)) {
|
|
56276
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
56223
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path52.default.isAbsolute(name)) {
|
|
56277
56224
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
56278
56225
|
}
|
|
56279
56226
|
}
|
|
@@ -56308,16 +56255,16 @@ async function updateFromChannel(args, deps) {
|
|
|
56308
56255
|
await import_promises8.default.rm(prevDir, { recursive: true, force: true });
|
|
56309
56256
|
await import_promises8.default.rename(liveDir, prevDir);
|
|
56310
56257
|
const stage = await import_promises8.default.mkdtemp(
|
|
56311
|
-
|
|
56258
|
+
import_node_path52.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
56312
56259
|
);
|
|
56313
56260
|
try {
|
|
56314
56261
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
56315
|
-
const dest =
|
|
56262
|
+
const dest = import_node_path52.default.join(stage, name);
|
|
56316
56263
|
if (entry.dir) {
|
|
56317
56264
|
await import_promises8.default.mkdir(dest, { recursive: true });
|
|
56318
56265
|
continue;
|
|
56319
56266
|
}
|
|
56320
|
-
await import_promises8.default.mkdir(
|
|
56267
|
+
await import_promises8.default.mkdir(import_node_path52.default.dirname(dest), { recursive: true });
|
|
56321
56268
|
if (name === "manifest.json") {
|
|
56322
56269
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
56323
56270
|
await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -56410,7 +56357,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
56410
56357
|
);
|
|
56411
56358
|
}
|
|
56412
56359
|
}
|
|
56413
|
-
const manifestPath =
|
|
56360
|
+
const manifestPath = import_node_path53.default.join(root, extId, "manifest.json");
|
|
56414
56361
|
const manifest = await readManifest(root, extId);
|
|
56415
56362
|
const next = { ...manifest, version: newVersion };
|
|
56416
56363
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -56418,7 +56365,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
56418
56365
|
await import_promises9.default.rename(tmp, manifestPath);
|
|
56419
56366
|
}
|
|
56420
56367
|
async function readManifest(root, extId) {
|
|
56421
|
-
const file =
|
|
56368
|
+
const file = import_node_path53.default.join(root, extId, "manifest.json");
|
|
56422
56369
|
let raw;
|
|
56423
56370
|
try {
|
|
56424
56371
|
raw = await import_promises9.default.readFile(file, "utf8");
|
|
@@ -56509,7 +56456,7 @@ function buildExtensionHandlers(deps) {
|
|
|
56509
56456
|
};
|
|
56510
56457
|
async function buildSnapshotMeta(extId) {
|
|
56511
56458
|
const manifest = await readManifest(deps.root, extId);
|
|
56512
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
56459
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path53.default.join(deps.root, extId));
|
|
56513
56460
|
return { manifest, contentHash: sha256, buffer };
|
|
56514
56461
|
}
|
|
56515
56462
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -56690,9 +56637,9 @@ function buildExtensionHandlers(deps) {
|
|
|
56690
56637
|
}
|
|
56691
56638
|
|
|
56692
56639
|
// src/app-builder/project-store.ts
|
|
56693
|
-
var
|
|
56640
|
+
var import_node_fs44 = require("fs");
|
|
56694
56641
|
var import_node_child_process12 = require("child_process");
|
|
56695
|
-
var
|
|
56642
|
+
var import_node_path54 = require("path");
|
|
56696
56643
|
init_protocol();
|
|
56697
56644
|
var PROJECTS_DIR = "projects";
|
|
56698
56645
|
var META_FILE = ".clawd-project.json";
|
|
@@ -56706,19 +56653,19 @@ var ProjectStore = class {
|
|
|
56706
56653
|
root;
|
|
56707
56654
|
/** projects/<name>/.clawd-project.json 路径 */
|
|
56708
56655
|
metaPath(name) {
|
|
56709
|
-
return (0,
|
|
56656
|
+
return (0, import_node_path54.join)(this.projectsRoot(), name, META_FILE);
|
|
56710
56657
|
}
|
|
56711
56658
|
/** projects/<name>/ 目录路径(cwd 用) */
|
|
56712
56659
|
projectDir(name) {
|
|
56713
|
-
return (0,
|
|
56660
|
+
return (0, import_node_path54.join)(this.projectsRoot(), name);
|
|
56714
56661
|
}
|
|
56715
56662
|
projectsRoot() {
|
|
56716
|
-
return (0,
|
|
56663
|
+
return (0, import_node_path54.join)(this.root, PROJECTS_DIR);
|
|
56717
56664
|
}
|
|
56718
56665
|
async list() {
|
|
56719
56666
|
let entries;
|
|
56720
56667
|
try {
|
|
56721
|
-
entries = await
|
|
56668
|
+
entries = await import_node_fs44.promises.readdir(this.projectsRoot());
|
|
56722
56669
|
} catch (err) {
|
|
56723
56670
|
if (err.code === "ENOENT") return [];
|
|
56724
56671
|
throw err;
|
|
@@ -56726,7 +56673,7 @@ var ProjectStore = class {
|
|
|
56726
56673
|
const out = [];
|
|
56727
56674
|
for (const name of entries) {
|
|
56728
56675
|
try {
|
|
56729
|
-
const raw = await
|
|
56676
|
+
const raw = await import_node_fs44.promises.readFile(this.metaPath(name), "utf8");
|
|
56730
56677
|
const json = JSON.parse(raw);
|
|
56731
56678
|
let migrated = false;
|
|
56732
56679
|
if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
|
|
@@ -56737,7 +56684,7 @@ var ProjectStore = class {
|
|
|
56737
56684
|
if (parsed.success) {
|
|
56738
56685
|
out.push(parsed.data);
|
|
56739
56686
|
if (migrated) {
|
|
56740
|
-
void
|
|
56687
|
+
void import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
|
|
56741
56688
|
});
|
|
56742
56689
|
}
|
|
56743
56690
|
}
|
|
@@ -56781,8 +56728,8 @@ var ProjectStore = class {
|
|
|
56781
56728
|
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
56782
56729
|
}
|
|
56783
56730
|
const dir = this.projectDir(name);
|
|
56784
|
-
await
|
|
56785
|
-
await
|
|
56731
|
+
await import_node_fs44.promises.mkdir(dir, { recursive: true });
|
|
56732
|
+
await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
56786
56733
|
return meta;
|
|
56787
56734
|
}
|
|
56788
56735
|
/**
|
|
@@ -56825,7 +56772,7 @@ var ProjectStore = class {
|
|
|
56825
56772
|
}
|
|
56826
56773
|
async delete(name) {
|
|
56827
56774
|
const dir = this.projectDir(name);
|
|
56828
|
-
await
|
|
56775
|
+
await import_node_fs44.promises.rm(dir, { recursive: true, force: true });
|
|
56829
56776
|
}
|
|
56830
56777
|
async updatePort(name, newPort) {
|
|
56831
56778
|
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
@@ -56841,7 +56788,7 @@ var ProjectStore = class {
|
|
|
56841
56788
|
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
56842
56789
|
}
|
|
56843
56790
|
const updated = { ...target, port: newPort };
|
|
56844
|
-
await
|
|
56791
|
+
await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
56845
56792
|
return updated;
|
|
56846
56793
|
}
|
|
56847
56794
|
/**
|
|
@@ -56858,7 +56805,7 @@ var ProjectStore = class {
|
|
|
56858
56805
|
if (!validated.success) {
|
|
56859
56806
|
throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
|
|
56860
56807
|
}
|
|
56861
|
-
await
|
|
56808
|
+
await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
56862
56809
|
return validated.data;
|
|
56863
56810
|
}
|
|
56864
56811
|
/**
|
|
@@ -56879,7 +56826,7 @@ var ProjectStore = class {
|
|
|
56879
56826
|
if (!validated.success) {
|
|
56880
56827
|
throw new Error(`invalid publishJob: ${validated.error.message}`);
|
|
56881
56828
|
}
|
|
56882
|
-
await
|
|
56829
|
+
await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
56883
56830
|
return validated.data;
|
|
56884
56831
|
}
|
|
56885
56832
|
/** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
|
|
@@ -56894,7 +56841,7 @@ var ProjectStore = class {
|
|
|
56894
56841
|
if (!validated.success) {
|
|
56895
56842
|
throw new Error(`failed to clear publishJob: ${validated.error.message}`);
|
|
56896
56843
|
}
|
|
56897
|
-
await
|
|
56844
|
+
await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
56898
56845
|
return validated.data;
|
|
56899
56846
|
}
|
|
56900
56847
|
};
|
|
@@ -57015,8 +56962,8 @@ var PublishJobRegistry = class {
|
|
|
57015
56962
|
|
|
57016
56963
|
// src/app-builder/publish-job-runner.ts
|
|
57017
56964
|
var import_node_child_process14 = require("child_process");
|
|
57018
|
-
var
|
|
57019
|
-
var
|
|
56965
|
+
var import_node_fs45 = require("fs");
|
|
56966
|
+
var import_node_path55 = require("path");
|
|
57020
56967
|
|
|
57021
56968
|
// src/app-builder/publish-stage-parser.ts
|
|
57022
56969
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -57048,10 +56995,10 @@ async function startPublishJob(deps, args) {
|
|
|
57048
56995
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
57049
56996
|
}
|
|
57050
56997
|
const projDir = projectDir(args.name);
|
|
57051
|
-
const logPath = (0,
|
|
56998
|
+
const logPath = (0, import_node_path55.join)(projDir, ".publish.log");
|
|
57052
56999
|
let logStream = null;
|
|
57053
57000
|
try {
|
|
57054
|
-
logStream = (0,
|
|
57001
|
+
logStream = (0, import_node_fs45.createWriteStream)(logPath, { flags: "w" });
|
|
57055
57002
|
} catch {
|
|
57056
57003
|
logStream = null;
|
|
57057
57004
|
}
|
|
@@ -57308,8 +57255,8 @@ async function recoverInterruptedJobs(deps) {
|
|
|
57308
57255
|
|
|
57309
57256
|
// src/handlers/app-builder.ts
|
|
57310
57257
|
init_protocol();
|
|
57311
|
-
var
|
|
57312
|
-
var
|
|
57258
|
+
var import_node_path56 = require("path");
|
|
57259
|
+
var import_node_fs46 = require("fs");
|
|
57313
57260
|
var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
|
|
57314
57261
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
57315
57262
|
async function recoverInterruptedPublishJobs(store, logger) {
|
|
@@ -57390,7 +57337,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57390
57337
|
async function listAllUsersProjects() {
|
|
57391
57338
|
if (!deps.usersRoot || !deps.getStore) return [];
|
|
57392
57339
|
const getStore = deps.getStore;
|
|
57393
|
-
const userIds = await
|
|
57340
|
+
const userIds = await import_node_fs46.promises.readdir(deps.usersRoot).catch(() => []);
|
|
57394
57341
|
const perUser = await Promise.all(
|
|
57395
57342
|
userIds.map((uid) => getStore(uid).list().catch(() => []))
|
|
57396
57343
|
);
|
|
@@ -57409,12 +57356,14 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57409
57356
|
}
|
|
57410
57357
|
const listProjects = async (frame, _client, ctx) => {
|
|
57411
57358
|
const f = frame;
|
|
57359
|
+
const sessionId = typeof f.sessionId === "string" ? f.sessionId : void 0;
|
|
57412
57360
|
let metas;
|
|
57413
|
-
if (
|
|
57361
|
+
if (sessionId) {
|
|
57362
|
+
metas = await resolveStore({ ctx, sessionId }).list();
|
|
57363
|
+
} else if (ctx?.principal.kind === "owner" && deps.usersRoot && deps.getStore) {
|
|
57414
57364
|
metas = await listAllUsersProjects();
|
|
57415
57365
|
} else {
|
|
57416
|
-
|
|
57417
|
-
metas = await resolveStore({ ctx, sessionId }).list();
|
|
57366
|
+
metas = await resolveStore({ ctx }).list();
|
|
57418
57367
|
}
|
|
57419
57368
|
return { response: { projects: metas.map(toProjectWithStatus) } };
|
|
57420
57369
|
};
|
|
@@ -57466,8 +57415,8 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57466
57415
|
const project = await userStore.create(f.name, reservedPorts);
|
|
57467
57416
|
try {
|
|
57468
57417
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
|
|
57469
|
-
const templateSrcDir = (0,
|
|
57470
|
-
const scaffoldScript = (0,
|
|
57418
|
+
const templateSrcDir = (0, import_node_path56.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
|
|
57419
|
+
const scaffoldScript = (0, import_node_path56.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
|
|
57471
57420
|
const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
|
|
57472
57421
|
deps.logger?.info("app-builder.scaffold.done", {
|
|
57473
57422
|
name: project.name,
|
|
@@ -57688,7 +57637,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57688
57637
|
await userStore.clearPublishJob(args.name);
|
|
57689
57638
|
}
|
|
57690
57639
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
|
|
57691
|
-
const scriptPath = (0,
|
|
57640
|
+
const scriptPath = (0, import_node_path56.join)(deps.deployKitRoot, "scripts", "publish.sh");
|
|
57692
57641
|
deps.logger?.info("app-builder.publish.start", {
|
|
57693
57642
|
name: args.name,
|
|
57694
57643
|
sessionId: boundSession.sessionId,
|
|
@@ -57864,7 +57813,7 @@ function buildVisitorHandlers(deps) {
|
|
|
57864
57813
|
|
|
57865
57814
|
// src/extension/registry.ts
|
|
57866
57815
|
var import_promises10 = __toESM(require("fs/promises"), 1);
|
|
57867
|
-
var
|
|
57816
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
57868
57817
|
async function loadAll(root) {
|
|
57869
57818
|
let entries;
|
|
57870
57819
|
try {
|
|
@@ -57877,13 +57826,13 @@ async function loadAll(root) {
|
|
|
57877
57826
|
for (const ent of entries) {
|
|
57878
57827
|
if (!ent.isDirectory()) continue;
|
|
57879
57828
|
if (ent.name.startsWith(".")) continue;
|
|
57880
|
-
records.push(await loadOne(
|
|
57829
|
+
records.push(await loadOne(import_node_path57.default.join(root, ent.name), ent.name));
|
|
57881
57830
|
}
|
|
57882
57831
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
57883
57832
|
return records;
|
|
57884
57833
|
}
|
|
57885
57834
|
async function loadOne(dir, dirName) {
|
|
57886
|
-
const manifestPath =
|
|
57835
|
+
const manifestPath = import_node_path57.default.join(dir, "manifest.json");
|
|
57887
57836
|
let raw;
|
|
57888
57837
|
try {
|
|
57889
57838
|
raw = await import_promises10.default.readFile(manifestPath, "utf8");
|
|
@@ -57928,7 +57877,7 @@ async function loadOne(dir, dirName) {
|
|
|
57928
57877
|
|
|
57929
57878
|
// src/extension/uninstall.ts
|
|
57930
57879
|
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
57931
|
-
var
|
|
57880
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
57932
57881
|
var UninstallError = class extends Error {
|
|
57933
57882
|
constructor(code, message) {
|
|
57934
57883
|
super(message);
|
|
@@ -57937,7 +57886,7 @@ var UninstallError = class extends Error {
|
|
|
57937
57886
|
code;
|
|
57938
57887
|
};
|
|
57939
57888
|
async function uninstall(deps) {
|
|
57940
|
-
const dir =
|
|
57889
|
+
const dir = import_node_path58.default.join(deps.root, deps.extId);
|
|
57941
57890
|
try {
|
|
57942
57891
|
await import_promises11.default.access(dir);
|
|
57943
57892
|
} catch {
|
|
@@ -58524,6 +58473,21 @@ var METHOD_GRANT_MAP = {
|
|
|
58524
58473
|
// ---- shift:* (排班 mock,owner-only 读) ----
|
|
58525
58474
|
// mock 阶段只 owner 用;接 guest 后再考虑分级
|
|
58526
58475
|
"shift:list": ADMIN_ANY,
|
|
58476
|
+
// ---- shift-internal:* + inbox:sendDm + personaDispatch complete/list ----
|
|
58477
|
+
// 统一 RPC 鉴权(spec 2026-07-28):原 /api/rpc 白名单 method 收编。调用方 = 本机
|
|
58478
|
+
// MCP server 持 owner token → ADMIN_ANY 即「owner token 即可」;业务归因(sendDm 的
|
|
58479
|
+
// sender、shift 的 personaId)在 handler 内按 body 字段处理,与鉴权无关。
|
|
58480
|
+
"shift-internal:add": ADMIN_ANY,
|
|
58481
|
+
"shift-internal:list": ADMIN_ANY,
|
|
58482
|
+
"shift-internal:cancel": ADMIN_ANY,
|
|
58483
|
+
"shift-internal:update": ADMIN_ANY,
|
|
58484
|
+
"shift-internal:history": ADMIN_ANY,
|
|
58485
|
+
"inbox:sendDm": ADMIN_ANY,
|
|
58486
|
+
"personaDispatch:complete": ADMIN_ANY,
|
|
58487
|
+
"personaDispatch:list": ADMIN_ANY,
|
|
58488
|
+
// 跨设备轮询(spec §5):A 端 daemon 凭 connect token 查 outcome;handler 内校验
|
|
58489
|
+
// 台账行 sourceSessionId === ctx.principal.id,防 guest 查别人的 dispatch。
|
|
58490
|
+
"personaDispatch:get": CAPABILITY_SCOPED,
|
|
58527
58491
|
"skills:list": CAPABILITY_SCOPED,
|
|
58528
58492
|
"agents:list": CAPABILITY_SCOPED,
|
|
58529
58493
|
"git:root": CAPABILITY_SCOPED,
|
|
@@ -58543,7 +58507,7 @@ var METHOD_GRANT_MAP = {
|
|
|
58543
58507
|
"persona:delete": ADMIN_ANY,
|
|
58544
58508
|
// 跨设备 dispatch:A 的 peer daemon 凭 connect token 经 /rpc 调进来;dispatcher 放行,
|
|
58545
58509
|
// run handler 内做 persona.public + assertGrant(send) 双重校验(guest grants 是 wildcard,
|
|
58546
|
-
// 单 assertGrant 不够)。本地
|
|
58510
|
+
// 单 assertGrant 不够)。本地 MCP server 经 /rpc + Bearer 进来,同过此表(owner 恒过)。
|
|
58547
58511
|
"personaDispatch:run": CAPABILITY_SCOPED,
|
|
58548
58512
|
// 跨设备 exec(spec 2026-07-16):public——"能连上=有 auth",业务在 handler 校
|
|
58549
58513
|
// (ensureGuest + remoteAccessAllowed),跟 inbox:postMessage 同模式。
|
|
@@ -58655,7 +58619,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
|
|
|
58655
58619
|
|
|
58656
58620
|
// src/extension/runtime.ts
|
|
58657
58621
|
var import_node_child_process17 = require("child_process");
|
|
58658
|
-
var
|
|
58622
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
58659
58623
|
var import_promises12 = require("timers/promises");
|
|
58660
58624
|
|
|
58661
58625
|
// src/extension/port-allocator.ts
|
|
@@ -58756,7 +58720,7 @@ var Runtime = class {
|
|
|
58756
58720
|
/\$CLAWOS_EXT_PORT/g,
|
|
58757
58721
|
String(port)
|
|
58758
58722
|
);
|
|
58759
|
-
const dir =
|
|
58723
|
+
const dir = import_node_path59.default.join(this.root, extId);
|
|
58760
58724
|
const env = {
|
|
58761
58725
|
...process.env,
|
|
58762
58726
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -58868,7 +58832,7 @@ ${handle.stderrTail}`
|
|
|
58868
58832
|
|
|
58869
58833
|
// src/extension/published-channels.ts
|
|
58870
58834
|
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
58871
|
-
var
|
|
58835
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
58872
58836
|
init_zod();
|
|
58873
58837
|
var PublishedChannelsError = class extends Error {
|
|
58874
58838
|
constructor(code, message) {
|
|
@@ -58967,7 +58931,7 @@ var PublishedChannelStore = class {
|
|
|
58967
58931
|
)
|
|
58968
58932
|
};
|
|
58969
58933
|
const tmp = `${this.filePath}.tmp`;
|
|
58970
|
-
await import_promises13.default.mkdir(
|
|
58934
|
+
await import_promises13.default.mkdir(import_node_path60.default.dirname(this.filePath), { recursive: true });
|
|
58971
58935
|
await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
58972
58936
|
await import_promises13.default.rename(tmp, this.filePath);
|
|
58973
58937
|
}
|
|
@@ -58975,7 +58939,7 @@ var PublishedChannelStore = class {
|
|
|
58975
58939
|
|
|
58976
58940
|
// src/extension/bundle-cache.ts
|
|
58977
58941
|
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
58978
|
-
var
|
|
58942
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
58979
58943
|
var BundleCache = class {
|
|
58980
58944
|
constructor(rootDir) {
|
|
58981
58945
|
this.rootDir = rootDir;
|
|
@@ -58984,14 +58948,14 @@ var BundleCache = class {
|
|
|
58984
58948
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
58985
58949
|
async write(snapshotHash, buffer) {
|
|
58986
58950
|
await import_promises14.default.mkdir(this.rootDir, { recursive: true });
|
|
58987
|
-
const file =
|
|
58951
|
+
const file = import_node_path61.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58988
58952
|
const tmp = `${file}.tmp`;
|
|
58989
58953
|
await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
|
|
58990
58954
|
await import_promises14.default.rename(tmp, file);
|
|
58991
58955
|
}
|
|
58992
58956
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
58993
58957
|
async read(snapshotHash) {
|
|
58994
|
-
const file =
|
|
58958
|
+
const file = import_node_path61.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58995
58959
|
try {
|
|
58996
58960
|
return await import_promises14.default.readFile(file);
|
|
58997
58961
|
} catch (e) {
|
|
@@ -59001,7 +58965,7 @@ var BundleCache = class {
|
|
|
59001
58965
|
}
|
|
59002
58966
|
/** Idempotent — missing file is not an error. */
|
|
59003
58967
|
async delete(snapshotHash) {
|
|
59004
|
-
const file =
|
|
58968
|
+
const file = import_node_path61.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
59005
58969
|
await import_promises14.default.rm(file, { force: true });
|
|
59006
58970
|
}
|
|
59007
58971
|
};
|
|
@@ -59024,24 +58988,24 @@ async function startDaemon(config) {
|
|
|
59024
58988
|
sampling: logShippingCfg.sampling,
|
|
59025
58989
|
homeDir: import_node_os22.default.homedir()
|
|
59026
58990
|
});
|
|
59027
|
-
const logDir =
|
|
59028
|
-
|
|
58991
|
+
const logDir = import_node_path62.default.join(config.dataDir, "log");
|
|
58992
|
+
import_node_fs47.default.mkdirSync(logDir, { recursive: true });
|
|
59029
58993
|
const logger = createLogger({
|
|
59030
58994
|
level: config.logLevel,
|
|
59031
|
-
file:
|
|
58995
|
+
file: import_node_path62.default.join(logDir, "clawd.log"),
|
|
59032
58996
|
logClient
|
|
59033
58997
|
});
|
|
59034
58998
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
59035
58999
|
const screenIdleProbeLogger = createFileOnlyLogger({
|
|
59036
|
-
file:
|
|
59000
|
+
file: import_node_path62.default.join(logDir, "screen-idle-probe.log"),
|
|
59037
59001
|
level: "debug"
|
|
59038
59002
|
});
|
|
59039
59003
|
logger.info("screen-idle probe logger enabled", {
|
|
59040
|
-
file:
|
|
59004
|
+
file: import_node_path62.default.join(logDir, "screen-idle-probe.log")
|
|
59041
59005
|
});
|
|
59042
59006
|
const CAP_TARGETS = [
|
|
59043
|
-
|
|
59044
|
-
|
|
59007
|
+
import_node_path62.default.join(logDir, "clawd.log"),
|
|
59008
|
+
import_node_path62.default.join(logDir, "screen-idle-probe.log")
|
|
59045
59009
|
];
|
|
59046
59010
|
const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
|
|
59047
59011
|
const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
|
|
@@ -59065,12 +59029,7 @@ async function startDaemon(config) {
|
|
|
59065
59029
|
if (pre.status === "stale") {
|
|
59066
59030
|
logger.warn("stale state file detected, overwriting", { pid: pre.existing.pid });
|
|
59067
59031
|
}
|
|
59068
|
-
|
|
59069
|
-
if (config.authToken && config.authToken.trim()) {
|
|
59070
|
-
resolvedAuthToken = config.authToken.trim();
|
|
59071
|
-
} else if (config.tunnel) {
|
|
59072
|
-
resolvedAuthToken = authFile.token;
|
|
59073
|
-
}
|
|
59032
|
+
const resolvedAuthToken = config.authToken && config.authToken.trim() ? config.authToken.trim() : authFile.token;
|
|
59074
59033
|
const ownerIdentityStore = new OwnerIdentityStore(config.dataDir);
|
|
59075
59034
|
const feishuIdentity = ownerIdentityStore.read();
|
|
59076
59035
|
let feishuActive = feishuIdentity !== null;
|
|
@@ -59079,7 +59038,7 @@ async function startDaemon(config) {
|
|
|
59079
59038
|
let ownerProvider = feishuIdentity?.identity.provider ?? "";
|
|
59080
59039
|
let ownerDisplayName = feishuIdentity?.identity.displayName ?? loadOwnerDisplayName(config.dataDir);
|
|
59081
59040
|
let ownerFeishuUnionId = feishuIdentity?.identity.unionId;
|
|
59082
|
-
const authMode =
|
|
59041
|
+
const authMode = "first-message";
|
|
59083
59042
|
const inboxStore = new InboxStore(config.dataDir);
|
|
59084
59043
|
const inboxManager = new InboxManager(inboxStore, (_peerDeviceId, frame) => {
|
|
59085
59044
|
wsServer?.broadcastToOwners(frame);
|
|
@@ -59095,7 +59054,7 @@ async function startDaemon(config) {
|
|
|
59095
59054
|
// persona web 分享:访客 visitor token = daemon 自签 HMAC(无 aud),独立于飞书 connect token
|
|
59096
59055
|
// 基建——secret 恒存在(auth-store backfill),故无条件注入。验签 ok → guest ctx(persona wildcard)。
|
|
59097
59056
|
verifyVisitorToken: (t) => {
|
|
59098
|
-
const r = verifyVisitorToken(authFile.
|
|
59057
|
+
const r = verifyVisitorToken(authFile.token, t, Math.floor(Date.now() / 1e3));
|
|
59099
59058
|
return r.ok ? { ok: true, payload: r.payload } : { ok: false };
|
|
59100
59059
|
},
|
|
59101
59060
|
...feishuActive ? {
|
|
@@ -59143,8 +59102,8 @@ async function startDaemon(config) {
|
|
|
59143
59102
|
const agents = new AgentsScanner();
|
|
59144
59103
|
const history = new ClaudeHistoryReader();
|
|
59145
59104
|
let transport = null;
|
|
59146
|
-
const personaStore = new PersonaStore(
|
|
59147
|
-
const usersRoot =
|
|
59105
|
+
const personaStore = new PersonaStore(import_node_path62.default.join(config.dataDir, "personas"));
|
|
59106
|
+
const usersRoot = import_node_path62.default.join(config.dataDir, "users");
|
|
59148
59107
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
59149
59108
|
if (defaultsRoot) {
|
|
59150
59109
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -59164,7 +59123,7 @@ async function startDaemon(config) {
|
|
|
59164
59123
|
migrateCodexSandbox({ store: personaStore, logger });
|
|
59165
59124
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
59166
59125
|
const dispatchStore = createDispatchStore({
|
|
59167
|
-
filePath:
|
|
59126
|
+
filePath: import_node_path62.default.join(config.dataDir, "dispatch.json"),
|
|
59168
59127
|
now: () => Date.now(),
|
|
59169
59128
|
onFlushError: (err) => logger.error("dispatch store flush failed", {
|
|
59170
59129
|
reason: err instanceof Error ? err.message : String(err)
|
|
@@ -59179,20 +59138,23 @@ async function startDaemon(config) {
|
|
|
59179
59138
|
now: () => Date.now(),
|
|
59180
59139
|
onCompleted: (sid) => deliverPendingRef?.(sid)
|
|
59181
59140
|
});
|
|
59182
|
-
const here = typeof __dirname === "string" ? __dirname :
|
|
59141
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path62.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
|
|
59183
59142
|
const mcpConfigs = [];
|
|
59143
|
+
const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
|
|
59184
59144
|
const dispatchServerCandidates = [
|
|
59185
|
-
|
|
59145
|
+
import_node_path62.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
59186
59146
|
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
59187
|
-
|
|
59147
|
+
import_node_path62.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
59188
59148
|
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
59189
59149
|
];
|
|
59190
|
-
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) =>
|
|
59150
|
+
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59191
59151
|
if (dispatchServerScriptPath) {
|
|
59192
|
-
const dispatchLogPath =
|
|
59152
|
+
const dispatchLogPath = import_node_path62.default.join(logDir, "dispatch-mcp-server.log");
|
|
59193
59153
|
const dispatchCfgPath = writeDispatchMcpConfig({
|
|
59194
59154
|
dataDir: config.dataDir,
|
|
59195
59155
|
serverScriptPath: dispatchServerScriptPath,
|
|
59156
|
+
daemonToken: resolvedAuthToken,
|
|
59157
|
+
daemonUrl: mcpDaemonUrl,
|
|
59196
59158
|
logPath: dispatchLogPath
|
|
59197
59159
|
});
|
|
59198
59160
|
mcpConfigs.push({ id: DISPATCH_MCP_ID, path: dispatchCfgPath });
|
|
@@ -59207,17 +59169,19 @@ async function startDaemon(config) {
|
|
|
59207
59169
|
});
|
|
59208
59170
|
}
|
|
59209
59171
|
const ticketServerCandidates = [
|
|
59210
|
-
|
|
59211
|
-
|
|
59172
|
+
import_node_path62.default.join(here, "ticket", "mcp-server.cjs"),
|
|
59173
|
+
import_node_path62.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
59212
59174
|
];
|
|
59213
|
-
const ticketServerScriptPath = ticketServerCandidates.find((p2) =>
|
|
59175
|
+
const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59214
59176
|
if (ticketServerScriptPath) {
|
|
59215
|
-
const ticketLogPath =
|
|
59177
|
+
const ticketLogPath = import_node_path62.default.join(logDir, "ticket-mcp-server.log");
|
|
59216
59178
|
const ticketCfgPath = writeTicketMcpConfig({
|
|
59217
59179
|
dataDir: config.dataDir,
|
|
59218
59180
|
serverScriptPath: ticketServerScriptPath,
|
|
59219
59181
|
apiBaseUrl: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
59220
59182
|
apiKey: resolveClawdTicketsApiKey(),
|
|
59183
|
+
daemonToken: resolvedAuthToken,
|
|
59184
|
+
daemonUrl: mcpDaemonUrl,
|
|
59221
59185
|
logPath: ticketLogPath
|
|
59222
59186
|
});
|
|
59223
59187
|
mcpConfigs.push({ id: "ticket", path: ticketCfgPath });
|
|
@@ -59232,15 +59196,17 @@ async function startDaemon(config) {
|
|
|
59232
59196
|
});
|
|
59233
59197
|
}
|
|
59234
59198
|
const shiftServerCandidates = [
|
|
59235
|
-
|
|
59236
|
-
|
|
59199
|
+
import_node_path62.default.join(here, "shift", "mcp-server.cjs"),
|
|
59200
|
+
import_node_path62.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
|
|
59237
59201
|
];
|
|
59238
|
-
const shiftServerScriptPath = shiftServerCandidates.find((p2) =>
|
|
59202
|
+
const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59239
59203
|
if (shiftServerScriptPath) {
|
|
59240
|
-
const shiftLogPath =
|
|
59204
|
+
const shiftLogPath = import_node_path62.default.join(logDir, "shift-mcp-server.log");
|
|
59241
59205
|
const shiftCfgPath = await writeShiftMcpConfig({
|
|
59242
59206
|
dataDir: config.dataDir,
|
|
59243
59207
|
serverScriptPath: shiftServerScriptPath,
|
|
59208
|
+
daemonToken: resolvedAuthToken,
|
|
59209
|
+
daemonUrl: mcpDaemonUrl,
|
|
59244
59210
|
logPath: shiftLogPath
|
|
59245
59211
|
});
|
|
59246
59212
|
mcpConfigs.push({ id: "shift", path: shiftCfgPath });
|
|
@@ -59256,15 +59222,17 @@ async function startDaemon(config) {
|
|
|
59256
59222
|
);
|
|
59257
59223
|
}
|
|
59258
59224
|
const inboxServerCandidates = [
|
|
59259
|
-
|
|
59260
|
-
|
|
59225
|
+
import_node_path62.default.join(here, "inbox", "mcp-server.cjs"),
|
|
59226
|
+
import_node_path62.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
|
|
59261
59227
|
];
|
|
59262
|
-
const inboxServerScriptPath = inboxServerCandidates.find((p2) =>
|
|
59228
|
+
const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59263
59229
|
if (inboxServerScriptPath) {
|
|
59264
|
-
const inboxLogPath =
|
|
59230
|
+
const inboxLogPath = import_node_path62.default.join(logDir, "inbox-mcp-server.log");
|
|
59265
59231
|
const inboxCfgPath = await writeInboxMcpConfig({
|
|
59266
59232
|
dataDir: config.dataDir,
|
|
59267
59233
|
serverScriptPath: inboxServerScriptPath,
|
|
59234
|
+
daemonToken: resolvedAuthToken,
|
|
59235
|
+
daemonUrl: mcpDaemonUrl,
|
|
59268
59236
|
logPath: inboxLogPath
|
|
59269
59237
|
});
|
|
59270
59238
|
mcpConfigs.push({ id: "inbox", path: inboxCfgPath });
|
|
@@ -59280,14 +59248,16 @@ async function startDaemon(config) {
|
|
|
59280
59248
|
);
|
|
59281
59249
|
}
|
|
59282
59250
|
const peerOpsServerCandidates = [
|
|
59283
|
-
|
|
59284
|
-
|
|
59251
|
+
import_node_path62.default.join(here, "peer-ops", "mcp-server.cjs"),
|
|
59252
|
+
import_node_path62.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
|
|
59285
59253
|
];
|
|
59286
|
-
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) =>
|
|
59254
|
+
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59287
59255
|
if (peerOpsServerScriptPath) {
|
|
59288
59256
|
const peerOpsCfgPath = writePeerOpsMcpConfig({
|
|
59289
59257
|
dataDir: config.dataDir,
|
|
59290
|
-
serverScriptPath: peerOpsServerScriptPath
|
|
59258
|
+
serverScriptPath: peerOpsServerScriptPath,
|
|
59259
|
+
daemonToken: resolvedAuthToken,
|
|
59260
|
+
daemonUrl: mcpDaemonUrl
|
|
59291
59261
|
});
|
|
59292
59262
|
mcpConfigs.push({ id: "peer-ops", path: peerOpsCfgPath });
|
|
59293
59263
|
logger.info("peer-ops.mcp.json written", {
|
|
@@ -59300,8 +59270,34 @@ async function startDaemon(config) {
|
|
|
59300
59270
|
{ tried: peerOpsServerCandidates }
|
|
59301
59271
|
);
|
|
59302
59272
|
}
|
|
59273
|
+
const rpcToolServerCandidates = [
|
|
59274
|
+
import_node_path62.default.join(here, "rpc-tool", "mcp-server.cjs"),
|
|
59275
|
+
import_node_path62.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
|
|
59276
|
+
];
|
|
59277
|
+
const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59278
|
+
if (rpcToolServerScriptPath) {
|
|
59279
|
+
const rpcToolLogPath = import_node_path62.default.join(logDir, "rpc-tool-mcp-server.log");
|
|
59280
|
+
const rpcToolCfgPath = writeRpcToolMcpConfig({
|
|
59281
|
+
dataDir: config.dataDir,
|
|
59282
|
+
serverScriptPath: rpcToolServerScriptPath,
|
|
59283
|
+
daemonToken: resolvedAuthToken,
|
|
59284
|
+
daemonUrl: mcpDaemonUrl,
|
|
59285
|
+
logPath: rpcToolLogPath
|
|
59286
|
+
});
|
|
59287
|
+
mcpConfigs.push({ id: "rpc-tool", path: rpcToolCfgPath });
|
|
59288
|
+
logger.info("rpc-tool.mcp.json written", {
|
|
59289
|
+
path: rpcToolCfgPath,
|
|
59290
|
+
server: rpcToolServerScriptPath,
|
|
59291
|
+
serverLog: rpcToolLogPath
|
|
59292
|
+
});
|
|
59293
|
+
} else {
|
|
59294
|
+
logger.warn(
|
|
59295
|
+
"rpc-tool-mcp-server.cjs not found; clawd-rpc call tool disabled (dev tsx \u6A21\u5F0F\u4E0B\u9700\u5148\u8DD1\u8FC7 build)",
|
|
59296
|
+
{ tried: rpcToolServerCandidates }
|
|
59297
|
+
);
|
|
59298
|
+
}
|
|
59303
59299
|
const shiftStore = createShiftStore({
|
|
59304
|
-
filePath:
|
|
59300
|
+
filePath: import_node_path62.default.join(config.dataDir, "shift.json"),
|
|
59305
59301
|
ownerIdProvider: () => ownerPrincipalId,
|
|
59306
59302
|
now: () => Date.now()
|
|
59307
59303
|
});
|
|
@@ -59323,7 +59319,7 @@ async function startDaemon(config) {
|
|
|
59323
59319
|
getAdapter,
|
|
59324
59320
|
historyReader: history,
|
|
59325
59321
|
dataDir: config.dataDir,
|
|
59326
|
-
personaRoot:
|
|
59322
|
+
personaRoot: import_node_path62.default.join(config.dataDir, "personas"),
|
|
59327
59323
|
// dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
|
|
59328
59324
|
// personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
|
|
59329
59325
|
getPersonaTool: (personaId) => personaRegistry.get(personaId)?.tool,
|
|
@@ -59338,7 +59334,7 @@ async function startDaemon(config) {
|
|
|
59338
59334
|
contactStore,
|
|
59339
59335
|
mode: config.mode,
|
|
59340
59336
|
// 单栏 refactor (spec 2026-06-02 §5.1):cc 子进程 env CLAWD_DAEMON_URL 闭包来源。
|
|
59341
|
-
//
|
|
59337
|
+
// MCP server 用它拼 /rpc/<method>(Bearer CLAWD_DAEMON_TOKEN)调本机 daemon。
|
|
59342
59338
|
// 127.0.0.1(不是 config.host)—— cc 跑在本机,loopback 最稳;外部访问限制 + http-router
|
|
59343
59339
|
// 的 isLoopback 兜底已确保安全。
|
|
59344
59340
|
getDaemonUrl: () => `http://127.0.0.1:${config.port}`,
|
|
@@ -59374,10 +59370,10 @@ async function startDaemon(config) {
|
|
|
59374
59370
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
59375
59371
|
attachmentGroup: {
|
|
59376
59372
|
onFileEdit: (input) => {
|
|
59377
|
-
const absPath =
|
|
59373
|
+
const absPath = import_node_path62.default.isAbsolute(input.relPath) ? input.relPath : import_node_path62.default.join(input.cwd, input.relPath);
|
|
59378
59374
|
let size = 0;
|
|
59379
59375
|
try {
|
|
59380
|
-
size =
|
|
59376
|
+
size = import_node_fs47.default.statSync(absPath).size;
|
|
59381
59377
|
} catch (err) {
|
|
59382
59378
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
59383
59379
|
sessionId: input.sessionId,
|
|
@@ -59545,7 +59541,7 @@ async function startDaemon(config) {
|
|
|
59545
59541
|
});
|
|
59546
59542
|
const visitorStore = createVisitorStore({ dir: config.dataDir });
|
|
59547
59543
|
const exchangeVisitorToken = buildVisitorLogin({
|
|
59548
|
-
getSecret: () => authFile.
|
|
59544
|
+
getSecret: () => authFile.token,
|
|
59549
59545
|
fetchUserInfo: (ttcToken) => fetchTtcUserInfo({ apiBase: TTC_HOSTS.api, token: ttcToken }),
|
|
59550
59546
|
visitorStore,
|
|
59551
59547
|
now: () => Date.now(),
|
|
@@ -59601,18 +59597,17 @@ async function startDaemon(config) {
|
|
|
59601
59597
|
groupFileStore,
|
|
59602
59598
|
sessionStore: { read: (sid) => manager.findOwnedSession(sid) },
|
|
59603
59599
|
getHttpBaseUrl,
|
|
59604
|
-
// HMAC sign secret
|
|
59605
|
-
|
|
59606
|
-
getSignSecret: () => authFile?.signSecret ?? "",
|
|
59600
|
+
// HMAC sign secret = auth.json 唯一 token(authFile 恒非空,startDaemon 开头加载)。
|
|
59601
|
+
getSignSecret: () => authFile.token,
|
|
59607
59602
|
// group RPC + sign 都用:根据 sessionId 反查 scope。owner-mode persona session 走
|
|
59608
59603
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
59609
59604
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
59610
59605
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
59611
|
-
personaRoot:
|
|
59606
|
+
personaRoot: import_node_path62.default.join(config.dataDir, "personas"),
|
|
59612
59607
|
usersRoot
|
|
59613
59608
|
},
|
|
59614
59609
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
59615
|
-
personaRoot:
|
|
59610
|
+
personaRoot: import_node_path62.default.join(config.dataDir, "personas"),
|
|
59616
59611
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
59617
59612
|
usersRoot,
|
|
59618
59613
|
// v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
|
|
@@ -59741,11 +59736,11 @@ async function startDaemon(config) {
|
|
|
59741
59736
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
59742
59737
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
59743
59738
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
59744
|
-
appBuilderPersonaRoot:
|
|
59739
|
+
appBuilderPersonaRoot: import_node_path62.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
59745
59740
|
// 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
|
|
59746
|
-
deployKitRoot:
|
|
59741
|
+
deployKitRoot: import_node_path62.default.join(config.dataDir, "deploy-kit"),
|
|
59747
59742
|
// scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
|
|
59748
|
-
resolvePersonaRoot: (personaId) =>
|
|
59743
|
+
resolvePersonaRoot: (personaId) => import_node_path62.default.join(config.dataDir, "personas", personaId),
|
|
59749
59744
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
59750
59745
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
59751
59746
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -59791,7 +59786,7 @@ async function startDaemon(config) {
|
|
|
59791
59786
|
}
|
|
59792
59787
|
let sourceJsonlPath = "(no transcript yet \u2014 operate from the task description alone)";
|
|
59793
59788
|
if (sourceFile && sourceFile.toolSessionId) {
|
|
59794
|
-
sourceJsonlPath =
|
|
59789
|
+
sourceJsonlPath = import_node_path62.default.join(
|
|
59795
59790
|
import_node_os22.default.homedir(),
|
|
59796
59791
|
".claude",
|
|
59797
59792
|
"projects",
|
|
@@ -59861,17 +59856,6 @@ async function startDaemon(config) {
|
|
|
59861
59856
|
const authResolver = new AuthContextResolver({
|
|
59862
59857
|
ownerToken: resolvedAuthToken
|
|
59863
59858
|
});
|
|
59864
|
-
const rpcDispatcher = {
|
|
59865
|
-
async dispatch(method, args, _ctx) {
|
|
59866
|
-
const handler = resolveExposedHandler(handlers, method);
|
|
59867
|
-
if (!handler) {
|
|
59868
|
-
throw Object.assign(new Error(`unknown RPC method "${method}"`), { code: "METHOD_NOT_IMPLEMENTED" });
|
|
59869
|
-
}
|
|
59870
|
-
const emptyClient = {};
|
|
59871
|
-
const result = await handler(args, emptyClient);
|
|
59872
|
-
return result.response;
|
|
59873
|
-
}
|
|
59874
|
-
};
|
|
59875
59859
|
const authedRpc = {
|
|
59876
59860
|
authenticate: (token) => authenticate(token, buildConnectAuthDeps()),
|
|
59877
59861
|
dispatch: (method, body, ctx) => {
|
|
@@ -59896,17 +59880,15 @@ async function startDaemon(config) {
|
|
|
59896
59880
|
daemonVersion: version,
|
|
59897
59881
|
logger,
|
|
59898
59882
|
sessionStore: store,
|
|
59899
|
-
rpcDispatcher,
|
|
59900
59883
|
authedRpc,
|
|
59901
59884
|
...viewerAssetLoader ? { viewerAssetLoader } : {},
|
|
59902
59885
|
// persona web 分享:访客换 token(POST /share/exchange)+ guest SPA serve(GET /s)
|
|
59903
59886
|
visitorExchange: exchangeVisitorToken,
|
|
59904
59887
|
...shareUiAssetLoader ? { shareUiAssetLoader } : {},
|
|
59905
|
-
// /files HMAC verify 用 auth.json
|
|
59906
|
-
|
|
59907
|
-
getSignSecret: () => authFile?.signSecret ?? null,
|
|
59888
|
+
// /files HMAC verify 用 auth.json token(与 attachment.signUrl 同源)。
|
|
59889
|
+
getSignSecret: () => authFile.token,
|
|
59908
59890
|
// chatinput 附件上传(POST /attachments/upload,spec §6.1)。upload pipeline
|
|
59909
|
-
// 在 session.cwd 下的 .attachments/
|
|
59891
|
+
// 在 session.cwd 下的 .attachments/ 落盘;签名 secret 与 /files HMAC 同源;
|
|
59910
59892
|
// tunnel 未启时返 503 TUNNEL_NOT_READY 让前端显式提示。
|
|
59911
59893
|
attachmentUpload: {
|
|
59912
59894
|
groupFileStore,
|
|
@@ -59987,7 +59969,7 @@ async function startDaemon(config) {
|
|
|
59987
59969
|
// (非 persona-web 场景静默 return null;tunnel 模式走 AuthGate 不经此路)。参数名
|
|
59988
59970
|
// tryVerifyCapabilityToken 不再准确,跨 local-ws-server 改名属 followup 清理。
|
|
59989
59971
|
tryVerifyCapabilityToken: (token) => {
|
|
59990
|
-
const vis = verifyVisitorToken(authFile.
|
|
59972
|
+
const vis = verifyVisitorToken(authFile.token, token, Math.floor(Date.now() / 1e3));
|
|
59991
59973
|
if (vis.ok) return visitorGuestContext(vis.payload);
|
|
59992
59974
|
return null;
|
|
59993
59975
|
},
|
|
@@ -60106,8 +60088,8 @@ async function startDaemon(config) {
|
|
|
60106
60088
|
const lines = [
|
|
60107
60089
|
`Tunnel: ${r.url}`,
|
|
60108
60090
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
60109
|
-
`Frpc config: ${
|
|
60110
|
-
`Frpc log: ${
|
|
60091
|
+
`Frpc config: ${import_node_path62.default.join(config.dataDir, "frpc.toml")}`,
|
|
60092
|
+
`Frpc log: ${import_node_path62.default.join(logDir, "frpc.log")}`
|
|
60111
60093
|
];
|
|
60112
60094
|
const width = Math.max(...lines.map((l) => l.length));
|
|
60113
60095
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -60120,8 +60102,8 @@ ${bar}
|
|
|
60120
60102
|
|
|
60121
60103
|
`);
|
|
60122
60104
|
try {
|
|
60123
|
-
const connectPath =
|
|
60124
|
-
|
|
60105
|
+
const connectPath = import_node_path62.default.join(config.dataDir, "connect.txt");
|
|
60106
|
+
import_node_fs47.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
60125
60107
|
} catch {
|
|
60126
60108
|
}
|
|
60127
60109
|
} catch (err) {
|
|
@@ -60193,9 +60175,9 @@ ${bar}
|
|
|
60193
60175
|
};
|
|
60194
60176
|
}
|
|
60195
60177
|
function migrateDropPersonsDir(dataDir) {
|
|
60196
|
-
const dir =
|
|
60178
|
+
const dir = import_node_path62.default.join(dataDir, "persons");
|
|
60197
60179
|
try {
|
|
60198
|
-
|
|
60180
|
+
import_node_fs47.default.rmSync(dir, { recursive: true, force: true });
|
|
60199
60181
|
} catch {
|
|
60200
60182
|
}
|
|
60201
60183
|
}
|