@clawos-dev/clawd 0.2.256 → 0.2.258
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 +796 -786
- 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-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/{guest-kK-Ir45s.css → guest-DTAqwGDc.css} +1 -1
- package/dist/share-ui/assets/{guest-hgeG05IO.js → guest-SFe_5tKr.js} +65 -65
- package/dist/share-ui/guest.html +2 -2
- 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();
|
|
@@ -40774,6 +40804,7 @@ init_protocol();
|
|
|
40774
40804
|
var DEFAULT_PORT = 18790;
|
|
40775
40805
|
var DEFAULT_HOST = "127.0.0.1";
|
|
40776
40806
|
var DEFAULT_CLAWOS_API = "https://api.clawos.chat";
|
|
40807
|
+
var DEFAULT_OWNER_IDLE_KILL_DELAY_MS = 6 * 60 * 60 * 1e3;
|
|
40777
40808
|
var DEFAULT_LOG_ENDPOINT = "https://clawd-prod.cn-hangzhou.log.aliyuncs.com/logstores/app-logs/track";
|
|
40778
40809
|
function resolveLogShipping(raw, cliNoShipping) {
|
|
40779
40810
|
if (cliNoShipping) {
|
|
@@ -40788,6 +40819,12 @@ function resolveLogShipping(raw, cliNoShipping) {
|
|
|
40788
40819
|
const sampling = mode === "errors-only" ? { debug: 0, info: 0, warn: 1, error: 1 } : isPlainSamplingMap(raw?.sampling) ? raw.sampling : {};
|
|
40789
40820
|
return { mode, endpoint, sampling };
|
|
40790
40821
|
}
|
|
40822
|
+
function resolveIdleKillMs(raw) {
|
|
40823
|
+
if (raw === void 0 || raw === null || raw === "") return null;
|
|
40824
|
+
const n = typeof raw === "number" ? raw : Number(raw);
|
|
40825
|
+
if (!Number.isFinite(n) || n < 0) return null;
|
|
40826
|
+
return n;
|
|
40827
|
+
}
|
|
40791
40828
|
function isPlainSamplingMap(v2) {
|
|
40792
40829
|
if (!v2 || typeof v2 !== "object") return false;
|
|
40793
40830
|
return Object.values(v2).every((n) => typeof n === "number");
|
|
@@ -40885,6 +40922,7 @@ function resolveConfig(opts) {
|
|
|
40885
40922
|
const mode = DAEMON_MODE_VALUES.includes(rawMode ?? "") ? rawMode : "sdk";
|
|
40886
40923
|
const filePreviewPorts = Array.isArray(fileCfg.previewPorts) ? fileCfg.previewPorts.map((n) => Number(n)).filter((n) => Number.isInteger(n) && n > 0) : null;
|
|
40887
40924
|
const previewPorts = env.CLAWD_PREVIEW_PORTS ? env.CLAWD_PREVIEW_PORTS.split(",").map((s) => Number(s.trim())).filter((n) => Number.isInteger(n) && n > 0) : filePreviewPorts && filePreviewPorts.length > 0 ? filePreviewPorts : null;
|
|
40925
|
+
const ownerIdleKillDelayMs = resolveIdleKillMs(env.CLAWD_OWNER_IDLE_KILL_DELAY_MS) ?? resolveIdleKillMs(fileCfg.ownerIdleKillDelayMs) ?? DEFAULT_OWNER_IDLE_KILL_DELAY_MS;
|
|
40888
40926
|
const logShipping = resolveLogShipping(
|
|
40889
40927
|
fileCfg.logShipping,
|
|
40890
40928
|
args.noLogShipping ?? false
|
|
@@ -40902,7 +40940,8 @@ function resolveConfig(opts) {
|
|
|
40902
40940
|
frpcBinary,
|
|
40903
40941
|
mode,
|
|
40904
40942
|
previewPorts,
|
|
40905
|
-
logShipping
|
|
40943
|
+
logShipping,
|
|
40944
|
+
ownerIdleKillDelayMs
|
|
40906
40945
|
};
|
|
40907
40946
|
}
|
|
40908
40947
|
var HELP_TEXT = `clawd [options]
|
|
@@ -40929,11 +40968,15 @@ Env (advanced):
|
|
|
40929
40968
|
CLAWD_CC_MODE CC \u5B50\u8FDB\u7A0B\u4EA4\u4E92\u6A21\u5F0F\uFF1A'sdk'\uFF08\u9ED8\u8BA4\uFF0C--print stream-json\uFF09/ 'tui'\uFF08pty \u4EA4\u4E92\u5F0F\uFF09\uFF1B
|
|
40930
40969
|
\u503C\u975E\u5408\u6CD5\u5B57\u9762\u91CF\u65F6\u9759\u9ED8\u56DE\u9000 'sdk'\u3002ready \u5E27 mode \u5B57\u6BB5\u900F\u4F20\u7ED9 UI\uFF1B
|
|
40931
40970
|
'tui' \u6A21\u5F0F\u989D\u5916\u63A8 session:control + session:pty \u4E24\u4E2A\u5E27\uFF08\u4E1A\u52A1\u5E27\u540D\u4E0D\u53D8\uFF09
|
|
40971
|
+
CLAWD_OWNER_IDLE_KILL_DELAY_MS
|
|
40972
|
+
owner persona session \u95F2\u7F6E\u56DE\u6536\u515C\u5E95\u4E0A\u9650\uFF08ms\uFF0C\u9ED8\u8BA4 21600000 = 6h\uFF09\uFF1B
|
|
40973
|
+
\u8BBE 0 \u5173\u95ED\u56DE\u6536\u3002\u4E5F\u53EF\u5199 config.json \u7684 ownerIdleKillDelayMs\u3002
|
|
40974
|
+
guest session \u7684 10min \u662F\u72EC\u7ACB\u5EF6\u8FDF\uFF0C\u4E0D\u53D7\u6B64\u9879\u5F71\u54CD
|
|
40932
40975
|
`;
|
|
40933
40976
|
|
|
40934
40977
|
// src/index.ts
|
|
40935
|
-
var
|
|
40936
|
-
var
|
|
40978
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
40979
|
+
var import_node_fs47 = __toESM(require("fs"), 1);
|
|
40937
40980
|
var import_node_os22 = __toESM(require("os"), 1);
|
|
40938
40981
|
|
|
40939
40982
|
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
@@ -41412,12 +41455,14 @@ function scopeSubPath(scope) {
|
|
|
41412
41455
|
if (scope.mode === "guest") return [scope.personaId, "guests", scope.capId];
|
|
41413
41456
|
return [scope.personaId, scope.mode];
|
|
41414
41457
|
}
|
|
41415
|
-
|
|
41458
|
+
var GUEST_IDLE_KILL_DELAY_MS = 6e5;
|
|
41459
|
+
function metaFromScope(scope, personaRoot, usersRoot, ownerPrincipalId, callerDisplayName, callerFeishuUnionId, opts) {
|
|
41416
41460
|
if (scope.kind === "default") return void 0;
|
|
41461
|
+
const ownerDelay = opts?.ownerIdleKillDelayMs !== void 0 && opts.ownerIdleKillDelayMs > 0 ? opts.ownerIdleKillDelayMs : void 0;
|
|
41417
41462
|
if (scope.mode === "owner") {
|
|
41418
41463
|
if (!ownerPrincipalId || !usersRoot) {
|
|
41419
41464
|
return {
|
|
41420
|
-
|
|
41465
|
+
idleKillDelayMs: ownerDelay,
|
|
41421
41466
|
personaMode: "owner",
|
|
41422
41467
|
callerDisplayName,
|
|
41423
41468
|
callerDeviceId: ownerPrincipalId,
|
|
@@ -41426,7 +41471,7 @@ function metaFromScope(scope, personaRoot, usersRoot, ownerPrincipalId, callerDi
|
|
|
41426
41471
|
}
|
|
41427
41472
|
const userWorkDir2 = deriveUserWorkDir(ownerPrincipalId, usersRoot);
|
|
41428
41473
|
return {
|
|
41429
|
-
|
|
41474
|
+
idleKillDelayMs: ownerDelay,
|
|
41430
41475
|
personaMode: "owner",
|
|
41431
41476
|
userWorkDir: userWorkDir2,
|
|
41432
41477
|
addDirs: [userWorkDir2],
|
|
@@ -41437,7 +41482,7 @@ function metaFromScope(scope, personaRoot, usersRoot, ownerPrincipalId, callerDi
|
|
|
41437
41482
|
}
|
|
41438
41483
|
const userWorkDir = deriveUserWorkDir(scope.capId, usersRoot);
|
|
41439
41484
|
return {
|
|
41440
|
-
|
|
41485
|
+
idleKillDelayMs: GUEST_IDLE_KILL_DELAY_MS,
|
|
41441
41486
|
personaMode: "guest",
|
|
41442
41487
|
userWorkDir,
|
|
41443
41488
|
addDirs: [userWorkDir],
|
|
@@ -41918,24 +41963,16 @@ function buildConnectionPrompt(args) {
|
|
|
41918
41963
|
// src/persona/sharing-prompt.ts
|
|
41919
41964
|
var ATTACHMENT_SHARING_HINT = `## \u628A\u4EA7\u51FA\u6587\u4EF6\u5206\u4EAB\u7ED9\u5BF9\u65B9\uFF08attachment\uFF09
|
|
41920
41965
|
|
|
41921
|
-
\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
|
|
41922
41967
|
|
|
41923
41968
|
1. \u5165\u7FA4\uFF08\u767B\u8BB0\u5230\u672C session \u7684\u5171\u4EAB\u6E05\u5355\uFF09\uFF1A
|
|
41924
|
-
|
|
41925
|
-
curl -sS -X POST "$CLAWD_DAEMON_URL/api/rpc/attachment.groupAdd" \\
|
|
41926
|
-
-H "X-Clawd-Session-Id: $CLAWD_SESSION_ID" -H 'Content-Type: application/json' \\
|
|
41927
|
-
-d '{"relPath":"<\u6587\u4EF6\u7684\u7EDD\u5BF9\u8DEF\u5F84>"}'
|
|
41928
|
-
\`\`\`
|
|
41969
|
+
call({ method: "attachment.groupAdd", args: { relPath: "<\u6587\u4EF6\u7684\u7EDD\u5BF9\u8DEF\u5F84>", origin: "agent" } })
|
|
41929
41970
|
2. \u7B7E\u540D\u62FF URL\uFF1A
|
|
41930
|
-
|
|
41931
|
-
curl -sS -X POST "$CLAWD_DAEMON_URL/api/rpc/attachment.signUrl" \\
|
|
41932
|
-
-H "X-Clawd-Session-Id: $CLAWD_SESSION_ID" -H 'Content-Type: application/json' \\
|
|
41933
|
-
-d '{"relPath":"<\u540C\u4E00\u4E2A\u7EDD\u5BF9\u8DEF\u5F84>"}'
|
|
41934
|
-
\`\`\`
|
|
41971
|
+
call({ method: "attachment.signUrl", args: { relPath: "<\u540C\u4E00\u4E2A\u7EDD\u5BF9\u8DEF\u5F84>" } })
|
|
41935
41972
|
\u8FD4\u56DE\u7684 \`url\` \u5C31\u662F\u5BF9\u65B9\u53EF\u76F4\u63A5\u6253\u5F00/\u4E0B\u8F7D\u7684\u94FE\u63A5\u3002
|
|
41936
41973
|
|
|
41937
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
|
|
41938
|
-
- \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
|
|
41939
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`;
|
|
41940
41977
|
|
|
41941
41978
|
// src/persona/no-ask-user-question-prompt.ts
|
|
@@ -42021,7 +42058,10 @@ function cloneState(s) {
|
|
|
42021
42058
|
currentTurnSender: s.currentTurnSender
|
|
42022
42059
|
};
|
|
42023
42060
|
}
|
|
42024
|
-
|
|
42061
|
+
function idleKillDelayOf(state) {
|
|
42062
|
+
const ms = state.subSessionMeta?.idleKillDelayMs;
|
|
42063
|
+
return ms !== void 0 && ms > 0 ? ms : void 0;
|
|
42064
|
+
}
|
|
42025
42065
|
function tryFlushPending(state, deps) {
|
|
42026
42066
|
if (!state.readyForSend || state.pendingSend.length === 0) return [];
|
|
42027
42067
|
const text = state.pendingSend.shift();
|
|
@@ -42296,11 +42336,12 @@ function pushEventToBuffer(state, event, deps) {
|
|
|
42296
42336
|
status: "running-idle"
|
|
42297
42337
|
}
|
|
42298
42338
|
});
|
|
42299
|
-
|
|
42339
|
+
const idleKillMs = idleKillDelayOf(next);
|
|
42340
|
+
if (idleKillMs !== void 0) {
|
|
42300
42341
|
effects.push({
|
|
42301
42342
|
kind: "schedule-idle-kill",
|
|
42302
42343
|
sessionId: next.file.sessionId,
|
|
42303
|
-
ms:
|
|
42344
|
+
ms: idleKillMs
|
|
42304
42345
|
});
|
|
42305
42346
|
}
|
|
42306
42347
|
}
|
|
@@ -42737,14 +42778,15 @@ function reduceSessionInner(state, input, deps) {
|
|
|
42737
42778
|
if (state.status !== "running-idle") {
|
|
42738
42779
|
return { state, effects: [] };
|
|
42739
42780
|
}
|
|
42740
|
-
|
|
42781
|
+
const rescheduleMs = idleKillDelayOf(state);
|
|
42782
|
+
if (input.subagentActive && rescheduleMs !== void 0) {
|
|
42741
42783
|
return {
|
|
42742
42784
|
state,
|
|
42743
42785
|
effects: [
|
|
42744
42786
|
{
|
|
42745
42787
|
kind: "schedule-idle-kill",
|
|
42746
42788
|
sessionId: state.file.sessionId,
|
|
42747
|
-
ms:
|
|
42789
|
+
ms: rescheduleMs
|
|
42748
42790
|
}
|
|
42749
42791
|
]
|
|
42750
42792
|
};
|
|
@@ -42930,7 +42972,7 @@ var SessionRunner = class {
|
|
|
42930
42972
|
ownerFeishuUnionId: this.hooks.ownerFeishuUnionId,
|
|
42931
42973
|
personaRoot: this.hooks.personaRoot,
|
|
42932
42974
|
// 单栏 refactor (spec 2026-06-02 §5.1): cc 子进程 env 注入 CLAWD_DAEMON_URL,让 assistant
|
|
42933
|
-
//
|
|
42975
|
+
// MCP server 拼 /rpc/<method>(Bearer)调 daemon。null = HTTP RPC 未启。
|
|
42934
42976
|
getDaemonUrl: this.hooks.getDaemonUrl,
|
|
42935
42977
|
// clawd 管家 (spec 2026-07-22-clawd-butler-persona §3.1): cc 子进程 env 注入 CLAWOS_API,
|
|
42936
42978
|
// 让 clawd 管家 skill fetch `${CLAWOS_API}/docs/**` 线上文档。
|
|
@@ -43664,8 +43706,8 @@ var SessionManager = class {
|
|
|
43664
43706
|
// 经过 compressFrameForWire 后决定是 push collector 还是走 deps.broadcastFrame。
|
|
43665
43707
|
// scope 决定两件事:SessionStore 路由 + SubSessionMeta 派生(metaFromScope)。
|
|
43666
43708
|
// - default → 复用 deps.store,无 subSessionMeta(普通 session)
|
|
43667
|
-
// - persona/owner → personas/<pid>/.clawd/sessions/owner/,meta={
|
|
43668
|
-
// - persona/guest → personas/<pid>/.clawd/sessions/guests/<capId>/,meta={
|
|
43709
|
+
// - persona/owner → personas/<pid>/.clawd/sessions/owner/,meta={idleKillDelayMs:<config 默认 6h>, personaMode:'owner'}
|
|
43710
|
+
// - persona/guest → personas/<pid>/.clawd/sessions/guests/<capId>/,meta={idleKillDelayMs:10min, personaMode:'guest', extraSettings:<sandbox>}
|
|
43669
43711
|
newRunner(file, scope) {
|
|
43670
43712
|
const adapter = this.deps.getAdapter(file.tool ?? "claude");
|
|
43671
43713
|
const store = this.storeFor(scope);
|
|
@@ -43677,7 +43719,8 @@ var SessionManager = class {
|
|
|
43677
43719
|
this.deps.usersRoot ?? "",
|
|
43678
43720
|
this.deps.ownerPrincipalId,
|
|
43679
43721
|
callerDisplayName,
|
|
43680
|
-
callerFeishuUnionId
|
|
43722
|
+
callerFeishuUnionId,
|
|
43723
|
+
{ ownerIdleKillDelayMs: this.deps.ownerIdleKillDelayMs }
|
|
43681
43724
|
);
|
|
43682
43725
|
if (subSessionMeta?.userWorkDir) {
|
|
43683
43726
|
import_node_fs9.default.mkdirSync(subSessionMeta.userWorkDir, { recursive: true });
|
|
@@ -44515,8 +44558,8 @@ var SessionManager = class {
|
|
|
44515
44558
|
//
|
|
44516
44559
|
// 区别于 owner / default 单 sessionId 入口,这些 API 接 SessionScope 参数 ——
|
|
44517
44560
|
// 调用方(PersonaManager / observer 等)明确传 scope,由 storeFor 路由到正确目录:
|
|
44518
|
-
// - {kind:'persona', personaId, mode:'guest', capId} → guests/<capId>/,meta={idleKill:
|
|
44519
|
-
// - {kind:'persona', personaId, mode:'owner'} → owner/,meta={idleKill
|
|
44561
|
+
// - {kind:'persona', personaId, mode:'guest', capId} → guests/<capId>/,meta={idleKill:10min, sandbox}
|
|
44562
|
+
// - {kind:'persona', personaId, mode:'owner'} → owner/,meta={idleKill:<config 默认 6h>}
|
|
44520
44563
|
//
|
|
44521
44564
|
// SubSessionMeta 由 scope → metaFromScope 派生,不进 SessionFile schema。
|
|
44522
44565
|
/** 按 scope 读取 SessionFile;不存在返回 null */
|
|
@@ -46859,8 +46902,8 @@ function turnStartInput(text) {
|
|
|
46859
46902
|
const items = [];
|
|
46860
46903
|
let leftover = text;
|
|
46861
46904
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
46862
|
-
const [marker, name,
|
|
46863
|
-
items.push({ type: "skill", name, path:
|
|
46905
|
+
const [marker, name, path75] = m2;
|
|
46906
|
+
items.push({ type: "skill", name, path: path75 });
|
|
46864
46907
|
leftover = leftover.replace(marker, "");
|
|
46865
46908
|
}
|
|
46866
46909
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -48449,13 +48492,6 @@ function jsonlExistsForCtx(ctx) {
|
|
|
48449
48492
|
init_claude_history();
|
|
48450
48493
|
|
|
48451
48494
|
// src/dispatch/manager.ts
|
|
48452
|
-
function defer() {
|
|
48453
|
-
let resolve6;
|
|
48454
|
-
const promise = new Promise((r) => {
|
|
48455
|
-
resolve6 = r;
|
|
48456
|
-
});
|
|
48457
|
-
return { promise, resolve: resolve6 };
|
|
48458
|
-
}
|
|
48459
48495
|
var PersonaDispatchManager = class {
|
|
48460
48496
|
constructor(deps) {
|
|
48461
48497
|
this.deps = deps;
|
|
@@ -48467,8 +48503,7 @@ var PersonaDispatchManager = class {
|
|
|
48467
48503
|
this.map.set(dispatchId, {
|
|
48468
48504
|
dispatchId,
|
|
48469
48505
|
sourceSessionId: args.sourceSessionId,
|
|
48470
|
-
targetPersona: args.targetPersona
|
|
48471
|
-
waiters: []
|
|
48506
|
+
targetPersona: args.targetPersona
|
|
48472
48507
|
});
|
|
48473
48508
|
this.deps.store.add({
|
|
48474
48509
|
dispatchId,
|
|
@@ -48490,45 +48525,21 @@ var PersonaDispatchManager = class {
|
|
|
48490
48525
|
outcome,
|
|
48491
48526
|
completedAt: new Date(this.deps.now()).toISOString()
|
|
48492
48527
|
});
|
|
48493
|
-
if (state)
|
|
48494
|
-
const waiters = state.waiters;
|
|
48495
|
-
state.waiters = [];
|
|
48496
|
-
for (const w2 of waiters) w2.resolve(outcome);
|
|
48497
|
-
this.map.delete(dispatchId);
|
|
48498
|
-
}
|
|
48528
|
+
if (state) this.map.delete(dispatchId);
|
|
48499
48529
|
const sourceSessionId = updated?.sourceSessionId ?? state?.sourceSessionId;
|
|
48500
48530
|
if (sourceSessionId) this.deps.onCompleted?.(sourceSessionId);
|
|
48501
48531
|
}
|
|
48502
|
-
/**
|
|
48503
|
-
* mesh B 角色 hold 专用(跨设备 dispatch 的 peer 侧):guest B-role handler 用它
|
|
48504
|
-
* 挂住 /rpc HTTP 响应直到 complete,把 outcome 回传给 A 侧 daemon 的 forwardToPeer
|
|
48505
|
-
* (A 侧后台 await,A 的 tool call 不受影响照样秒回)。
|
|
48506
|
-
* 本地 dispatch 链路**不用**这个——本地 outcome 只走台账 + deliverPending。
|
|
48507
|
-
*/
|
|
48508
|
-
async waitForOutcome(dispatchId) {
|
|
48509
|
-
const state = this.map.get(dispatchId);
|
|
48510
|
-
if (!state) {
|
|
48511
|
-
const rec3 = this.deps.store.get(dispatchId);
|
|
48512
|
-
if (rec3?.outcome) return rec3.outcome;
|
|
48513
|
-
throw new Error(`unknown dispatchId: ${dispatchId}`);
|
|
48514
|
-
}
|
|
48515
|
-
const d = defer();
|
|
48516
|
-
state.waiters.push(d);
|
|
48517
|
-
return d.promise;
|
|
48518
|
-
}
|
|
48519
48532
|
/**
|
|
48520
48533
|
* 续派(spec 2026-07-21):complete 已清掉 map 条目,续派前重建——bSessionId 映射
|
|
48521
48534
|
* 保证 worker 进程死后 respawn 时 reducer lookupDispatchByBSessionId 仍注回同一
|
|
48522
48535
|
* CLAWD_DISPATCH_ID env。台账行的复位由 handler 直接走 store(本方法只管内存态)。
|
|
48523
48536
|
*/
|
|
48524
48537
|
reopen(dispatchId, args) {
|
|
48525
|
-
const existing = this.map.get(dispatchId);
|
|
48526
48538
|
this.map.set(dispatchId, {
|
|
48527
48539
|
dispatchId,
|
|
48528
48540
|
sourceSessionId: args.sourceSessionId,
|
|
48529
48541
|
targetPersona: args.targetPersona,
|
|
48530
|
-
bSessionId: args.workerSessionId
|
|
48531
|
-
waiters: existing?.waiters ?? []
|
|
48542
|
+
bSessionId: args.workerSessionId
|
|
48532
48543
|
});
|
|
48533
48544
|
}
|
|
48534
48545
|
/** SessionManager 在 createDispatchedSession 时调,建立 dispatchId → B sessionId 映射 */
|
|
@@ -48657,13 +48668,17 @@ function dispatchMcpConfigPath(dataDir) {
|
|
|
48657
48668
|
function writeDispatchMcpConfig(args) {
|
|
48658
48669
|
const cfgPath = dispatchMcpConfigPath(args.dataDir);
|
|
48659
48670
|
const content = {
|
|
48660
|
-
_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",
|
|
48671
|
+
_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",
|
|
48661
48672
|
mcpServers: {
|
|
48662
48673
|
"clawd-dispatch": {
|
|
48663
48674
|
type: "stdio",
|
|
48664
48675
|
command: "node",
|
|
48665
48676
|
args: [args.serverScriptPath],
|
|
48666
|
-
|
|
48677
|
+
env: {
|
|
48678
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48679
|
+
CLAWD_DAEMON_URL: args.daemonUrl,
|
|
48680
|
+
...args.logPath ? { CLAWD_DISPATCH_LOG: args.logPath } : {}
|
|
48681
|
+
}
|
|
48667
48682
|
}
|
|
48668
48683
|
}
|
|
48669
48684
|
};
|
|
@@ -48681,7 +48696,7 @@ function ticketMcpConfigPath(dataDir) {
|
|
|
48681
48696
|
function writeTicketMcpConfig(args) {
|
|
48682
48697
|
const cfgPath = ticketMcpConfigPath(args.dataDir);
|
|
48683
48698
|
const content = {
|
|
48684
|
-
_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
|
|
48699
|
+
_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",
|
|
48685
48700
|
mcpServers: {
|
|
48686
48701
|
"clawd-ticket": {
|
|
48687
48702
|
type: "stdio",
|
|
@@ -48691,6 +48706,8 @@ function writeTicketMcpConfig(args) {
|
|
|
48691
48706
|
CLAWD_TICKET_API_URL: args.apiBaseUrl,
|
|
48692
48707
|
CLAWD_TICKET_API_KEY: args.apiKey,
|
|
48693
48708
|
CLAWD_TICKET_SCENE: "persona",
|
|
48709
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48710
|
+
CLAWD_DAEMON_URL: args.daemonUrl,
|
|
48694
48711
|
...args.logPath ? { CLAWD_TICKET_LOG: args.logPath } : {}
|
|
48695
48712
|
}
|
|
48696
48713
|
}
|
|
@@ -48716,7 +48733,11 @@ async function writeShiftMcpConfig(args) {
|
|
|
48716
48733
|
type: "stdio",
|
|
48717
48734
|
command: "node",
|
|
48718
48735
|
args: [args.serverScriptPath],
|
|
48719
|
-
|
|
48736
|
+
env: {
|
|
48737
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48738
|
+
CLAWD_DAEMON_URL: args.daemonUrl,
|
|
48739
|
+
...args.logPath ? { CLAWD_SHIFT_LOG: args.logPath } : {}
|
|
48740
|
+
}
|
|
48720
48741
|
}
|
|
48721
48742
|
}
|
|
48722
48743
|
};
|
|
@@ -48740,7 +48761,11 @@ async function writeInboxMcpConfig(args) {
|
|
|
48740
48761
|
type: "stdio",
|
|
48741
48762
|
command: "node",
|
|
48742
48763
|
args: [args.serverScriptPath],
|
|
48743
|
-
|
|
48764
|
+
env: {
|
|
48765
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48766
|
+
CLAWD_DAEMON_URL: args.daemonUrl,
|
|
48767
|
+
...args.logPath ? { CLAWD_INBOX_LOG: args.logPath } : {}
|
|
48768
|
+
}
|
|
48744
48769
|
}
|
|
48745
48770
|
}
|
|
48746
48771
|
};
|
|
@@ -48758,11 +48783,15 @@ function peerOpsMcpConfigPath(dataDir) {
|
|
|
48758
48783
|
function writePeerOpsMcpConfig(args) {
|
|
48759
48784
|
const cfgPath = peerOpsMcpConfigPath(args.dataDir);
|
|
48760
48785
|
const cfg = {
|
|
48761
|
-
_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",
|
|
48786
|
+
_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",
|
|
48762
48787
|
mcpServers: {
|
|
48763
48788
|
"peer-ops": {
|
|
48764
48789
|
command: "node",
|
|
48765
|
-
args: [args.serverScriptPath]
|
|
48790
|
+
args: [args.serverScriptPath],
|
|
48791
|
+
env: {
|
|
48792
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48793
|
+
CLAWD_DAEMON_URL: args.daemonUrl
|
|
48794
|
+
}
|
|
48766
48795
|
}
|
|
48767
48796
|
}
|
|
48768
48797
|
};
|
|
@@ -48771,9 +48800,37 @@ function writePeerOpsMcpConfig(args) {
|
|
|
48771
48800
|
return cfgPath;
|
|
48772
48801
|
}
|
|
48773
48802
|
|
|
48803
|
+
// src/rpc-tool/mcp-config.ts
|
|
48804
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
48805
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
48806
|
+
function rpcToolMcpConfigPath(dataDir) {
|
|
48807
|
+
return import_node_path24.default.join(dataDir, "rpc-tool.mcp.json");
|
|
48808
|
+
}
|
|
48809
|
+
function writeRpcToolMcpConfig(args) {
|
|
48810
|
+
const cfgPath = rpcToolMcpConfigPath(args.dataDir);
|
|
48811
|
+
const content = {
|
|
48812
|
+
_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",
|
|
48813
|
+
mcpServers: {
|
|
48814
|
+
"clawd-rpc": {
|
|
48815
|
+
type: "stdio",
|
|
48816
|
+
command: "node",
|
|
48817
|
+
args: [args.serverScriptPath],
|
|
48818
|
+
env: {
|
|
48819
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
48820
|
+
CLAWD_DAEMON_URL: args.daemonUrl,
|
|
48821
|
+
...args.logPath ? { CLAWD_RPC_LOG: args.logPath } : {}
|
|
48822
|
+
}
|
|
48823
|
+
}
|
|
48824
|
+
}
|
|
48825
|
+
};
|
|
48826
|
+
import_node_fs25.default.mkdirSync(args.dataDir, { recursive: true });
|
|
48827
|
+
import_node_fs25.default.writeFileSync(cfgPath, JSON.stringify(content, null, 2), "utf8");
|
|
48828
|
+
return cfgPath;
|
|
48829
|
+
}
|
|
48830
|
+
|
|
48774
48831
|
// src/shift/store.ts
|
|
48775
48832
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
48776
|
-
var
|
|
48833
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
48777
48834
|
var import_node_crypto6 = require("crypto");
|
|
48778
48835
|
|
|
48779
48836
|
// src/shift/schedule.ts
|
|
@@ -48848,7 +48905,7 @@ function createShiftStore(deps) {
|
|
|
48848
48905
|
flushTimer = null;
|
|
48849
48906
|
}
|
|
48850
48907
|
const content = { version: 1, shifts };
|
|
48851
|
-
await import_promises2.default.mkdir(
|
|
48908
|
+
await import_promises2.default.mkdir(import_node_path25.default.dirname(deps.filePath), { recursive: true });
|
|
48852
48909
|
const tmp = `${deps.filePath}.tmp-${deps.now()}-${Math.floor(Math.random() * 1e6)}`;
|
|
48853
48910
|
await import_promises2.default.writeFile(tmp, JSON.stringify(content, null, 2), "utf8");
|
|
48854
48911
|
await import_promises2.default.rename(tmp, deps.filePath);
|
|
@@ -49301,7 +49358,7 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
49301
49358
|
}
|
|
49302
49359
|
if (!sourceSessionId) {
|
|
49303
49360
|
throw new Error(
|
|
49304
|
-
"personaDispatch:run requires sessionId
|
|
49361
|
+
"personaDispatch:run requires sessionId in the request body"
|
|
49305
49362
|
);
|
|
49306
49363
|
}
|
|
49307
49364
|
const rec3 = deps.store.get(args.dispatchId);
|
|
@@ -49374,7 +49431,7 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
49374
49431
|
}
|
|
49375
49432
|
if (!sourceSessionId) {
|
|
49376
49433
|
throw new Error(
|
|
49377
|
-
"personaDispatch:run requires sessionId
|
|
49434
|
+
"personaDispatch:run requires sessionId in the request body"
|
|
49378
49435
|
);
|
|
49379
49436
|
}
|
|
49380
49437
|
const { dispatchId: dispatchId2 } = mgr.start({
|
|
@@ -49441,14 +49498,13 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
49441
49498
|
reason: `failed to spawn B: ${reason}`
|
|
49442
49499
|
});
|
|
49443
49500
|
});
|
|
49444
|
-
const outcome = await mgr.waitForOutcome(dispatchId2);
|
|
49445
49501
|
return {
|
|
49446
|
-
response: { type: "personaDispatch:run:ok",
|
|
49502
|
+
response: { type: "personaDispatch:run:ok", dispatchId: dispatchId2 }
|
|
49447
49503
|
};
|
|
49448
49504
|
}
|
|
49449
49505
|
if (!sourceSessionId) {
|
|
49450
49506
|
throw new Error(
|
|
49451
|
-
"personaDispatch:run requires sessionId
|
|
49507
|
+
"personaDispatch:run requires sessionId in the request body"
|
|
49452
49508
|
);
|
|
49453
49509
|
}
|
|
49454
49510
|
const { dispatchId } = mgr.start({
|
|
@@ -49496,6 +49552,22 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
49496
49552
|
response: { type: "personaDispatch:complete:ok" }
|
|
49497
49553
|
};
|
|
49498
49554
|
};
|
|
49555
|
+
const get = async (frame, _client, ctx) => {
|
|
49556
|
+
const { type: _t, requestId: _r, ...rest } = frame;
|
|
49557
|
+
const args = DispatchGetArgsSchema.parse(rest);
|
|
49558
|
+
const rec3 = deps.store.get(args.dispatchId);
|
|
49559
|
+
const denied = ctx?.principal.kind === "guest" && rec3?.sourceSessionId !== ctx.principal.id;
|
|
49560
|
+
if (!rec3 || denied) {
|
|
49561
|
+
throw new ClawdError(ERROR_CODES.DISPATCH_NOT_FOUND, `unknown dispatchId: ${args.dispatchId}`);
|
|
49562
|
+
}
|
|
49563
|
+
return {
|
|
49564
|
+
response: {
|
|
49565
|
+
type: "personaDispatch:get:ok",
|
|
49566
|
+
status: rec3.status,
|
|
49567
|
+
...rec3.outcome ? { outcome: rec3.outcome } : {}
|
|
49568
|
+
}
|
|
49569
|
+
};
|
|
49570
|
+
};
|
|
49499
49571
|
const list = async (frame) => {
|
|
49500
49572
|
const { type: _t, requestId: _r, ...rest } = frame;
|
|
49501
49573
|
const args = DispatchListArgsSchema.parse(rest);
|
|
@@ -49509,7 +49581,8 @@ function buildPersonaDispatchHandlers(deps) {
|
|
|
49509
49581
|
return {
|
|
49510
49582
|
"personaDispatch:run": run,
|
|
49511
49583
|
"personaDispatch:complete": complete,
|
|
49512
|
-
"personaDispatch:list": list
|
|
49584
|
+
"personaDispatch:list": list,
|
|
49585
|
+
"personaDispatch:get": get
|
|
49513
49586
|
};
|
|
49514
49587
|
}
|
|
49515
49588
|
|
|
@@ -49520,8 +49593,13 @@ function wsUrlToHttp(url) {
|
|
|
49520
49593
|
if (url.startsWith("ws://")) return "http://" + url.slice("ws://".length);
|
|
49521
49594
|
return url;
|
|
49522
49595
|
}
|
|
49596
|
+
var DISPATCH_POLL_INTERVAL_MS = 5e3;
|
|
49597
|
+
var DISPATCH_POLL_UNREACHABLE_MS = 6e5;
|
|
49598
|
+
var DISPATCH_POLL_TOTAL_MS = 864e5;
|
|
49599
|
+
var defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
49523
49600
|
async function forwardDispatchToPeer(args) {
|
|
49524
49601
|
const f = args.fetchImpl ?? fetch;
|
|
49602
|
+
const sleep2 = args.sleepImpl ?? defaultSleep;
|
|
49525
49603
|
const base = wsUrlToHttp(args.contact.remoteUrl).replace(/\/+$/, "");
|
|
49526
49604
|
const url = `${base}/rpc/personaDispatch:run`;
|
|
49527
49605
|
let res;
|
|
@@ -49556,7 +49634,58 @@ async function forwardDispatchToPeer(args) {
|
|
|
49556
49634
|
if (json.ok === false) {
|
|
49557
49635
|
return { kind: "failure", reason: `peer rejected: ${json.error}: ${json.message}` };
|
|
49558
49636
|
}
|
|
49559
|
-
return json.result.outcome;
|
|
49637
|
+
if ("outcome" in json.result) return json.result.outcome;
|
|
49638
|
+
const dispatchId = json.result.dispatchId;
|
|
49639
|
+
let elapsed = 0;
|
|
49640
|
+
let unreachableFor = 0;
|
|
49641
|
+
while (elapsed < DISPATCH_POLL_TOTAL_MS) {
|
|
49642
|
+
await sleep2(DISPATCH_POLL_INTERVAL_MS);
|
|
49643
|
+
elapsed += DISPATCH_POLL_INTERVAL_MS;
|
|
49644
|
+
const markUnreachable = () => {
|
|
49645
|
+
unreachableFor += DISPATCH_POLL_INTERVAL_MS;
|
|
49646
|
+
return unreachableFor >= DISPATCH_POLL_UNREACHABLE_MS ? {
|
|
49647
|
+
kind: "failure",
|
|
49648
|
+
reason: "peer unreachable while polling dispatch outcome (TARGET_UNREACHABLE)"
|
|
49649
|
+
} : null;
|
|
49650
|
+
};
|
|
49651
|
+
let getRes;
|
|
49652
|
+
try {
|
|
49653
|
+
getRes = await f(`${base}/rpc/personaDispatch:get`, {
|
|
49654
|
+
method: "POST",
|
|
49655
|
+
headers: {
|
|
49656
|
+
"content-type": "application/json",
|
|
49657
|
+
authorization: `Bearer ${args.contact.connectToken}`
|
|
49658
|
+
},
|
|
49659
|
+
body: JSON.stringify({ dispatchId })
|
|
49660
|
+
});
|
|
49661
|
+
} catch {
|
|
49662
|
+
const dead = markUnreachable();
|
|
49663
|
+
if (dead) return dead;
|
|
49664
|
+
continue;
|
|
49665
|
+
}
|
|
49666
|
+
let getJson;
|
|
49667
|
+
try {
|
|
49668
|
+
getJson = await getRes.json();
|
|
49669
|
+
} catch {
|
|
49670
|
+
const dead = markUnreachable();
|
|
49671
|
+
if (dead) return dead;
|
|
49672
|
+
continue;
|
|
49673
|
+
}
|
|
49674
|
+
if (getJson.ok === false) {
|
|
49675
|
+
if (getJson.error === ERROR_CODES.DISPATCH_NOT_FOUND) {
|
|
49676
|
+
return { kind: "failure", reason: `peer lost dispatch ${dispatchId} (daemon restarted?)` };
|
|
49677
|
+
}
|
|
49678
|
+
const dead = markUnreachable();
|
|
49679
|
+
if (dead) return dead;
|
|
49680
|
+
continue;
|
|
49681
|
+
}
|
|
49682
|
+
unreachableFor = 0;
|
|
49683
|
+
const { status, outcome } = getJson.result;
|
|
49684
|
+
if (status === "completed" || status === "failed") {
|
|
49685
|
+
return outcome ?? { kind: "failure", reason: "peer returned terminal status without outcome" };
|
|
49686
|
+
}
|
|
49687
|
+
}
|
|
49688
|
+
return { kind: "failure", reason: "dispatch polling exceeded 24h (TIMEOUT)" };
|
|
49560
49689
|
}
|
|
49561
49690
|
async function forwardInboxPostToPeer(args) {
|
|
49562
49691
|
const f = args.fetchImpl ?? fetch;
|
|
@@ -49800,7 +49929,7 @@ var CodexHistoryReader = class {
|
|
|
49800
49929
|
|
|
49801
49930
|
// src/tools/codex-skills.ts
|
|
49802
49931
|
var import_node_child_process7 = require("child_process");
|
|
49803
|
-
var
|
|
49932
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
49804
49933
|
var DEFAULT_TIMEOUT_MS3 = 8e3;
|
|
49805
49934
|
function str3(v2) {
|
|
49806
49935
|
return typeof v2 === "string" ? v2 : void 0;
|
|
@@ -49816,13 +49945,13 @@ function mapSkillsListResponse(res) {
|
|
|
49816
49945
|
const r = s ?? {};
|
|
49817
49946
|
const name = str3(r.name);
|
|
49818
49947
|
if (!name) continue;
|
|
49819
|
-
const
|
|
49948
|
+
const path75 = str3(r.path);
|
|
49820
49949
|
const description = str3(r.description);
|
|
49821
49950
|
const isPlugin = name.includes(":");
|
|
49822
49951
|
out.push({
|
|
49823
49952
|
name,
|
|
49824
49953
|
source: isPlugin ? "plugin" : "project",
|
|
49825
|
-
...
|
|
49954
|
+
...path75 ? { path: path75 } : {},
|
|
49826
49955
|
...description ? { description } : {},
|
|
49827
49956
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
49828
49957
|
});
|
|
@@ -49852,7 +49981,7 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
49852
49981
|
})(),
|
|
49853
49982
|
timeout
|
|
49854
49983
|
]);
|
|
49855
|
-
void client.request("skills/extraRoots/set", { extraRoots: [
|
|
49984
|
+
void client.request("skills/extraRoots/set", { extraRoots: [import_node_path26.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
|
|
49856
49985
|
const res = await Promise.race([client.request("skills/list", { cwds: [cwd] }), timeout]);
|
|
49857
49986
|
return mapSkillsListResponse(res);
|
|
49858
49987
|
} finally {
|
|
@@ -49862,23 +49991,23 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
49862
49991
|
}
|
|
49863
49992
|
|
|
49864
49993
|
// src/workspace/browser.ts
|
|
49865
|
-
var
|
|
49994
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
49866
49995
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
49867
|
-
var
|
|
49996
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
49868
49997
|
init_protocol();
|
|
49869
49998
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
49870
49999
|
function resolveInsideCwd(cwd, subpath) {
|
|
49871
|
-
const absCwd =
|
|
49872
|
-
const joined =
|
|
49873
|
-
const rel =
|
|
49874
|
-
if (rel.startsWith("..") ||
|
|
50000
|
+
const absCwd = import_node_path27.default.resolve(cwd);
|
|
50001
|
+
const joined = import_node_path27.default.resolve(absCwd, subpath ?? ".");
|
|
50002
|
+
const rel = import_node_path27.default.relative(absCwd, joined);
|
|
50003
|
+
if (rel.startsWith("..") || import_node_path27.default.isAbsolute(rel)) {
|
|
49875
50004
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
49876
50005
|
}
|
|
49877
50006
|
return joined;
|
|
49878
50007
|
}
|
|
49879
50008
|
function ensureCwd(cwd) {
|
|
49880
50009
|
try {
|
|
49881
|
-
const stat =
|
|
50010
|
+
const stat = import_node_fs26.default.statSync(cwd);
|
|
49882
50011
|
if (!stat.isDirectory()) {
|
|
49883
50012
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
|
|
49884
50013
|
}
|
|
@@ -49892,7 +50021,7 @@ var WorkspaceBrowser = class {
|
|
|
49892
50021
|
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os8.default.homedir();
|
|
49893
50022
|
ensureCwd(cwd);
|
|
49894
50023
|
const full = resolveInsideCwd(cwd, args.path);
|
|
49895
|
-
const dirents =
|
|
50024
|
+
const dirents = import_node_fs26.default.readdirSync(full, { withFileTypes: true });
|
|
49896
50025
|
const entries = [];
|
|
49897
50026
|
for (const d of dirents) {
|
|
49898
50027
|
if (!args.showHidden && d.name.startsWith(".")) continue;
|
|
@@ -49902,7 +50031,7 @@ var WorkspaceBrowser = class {
|
|
|
49902
50031
|
mtime: ""
|
|
49903
50032
|
};
|
|
49904
50033
|
try {
|
|
49905
|
-
const st =
|
|
50034
|
+
const st = import_node_fs26.default.statSync(import_node_path27.default.join(full, d.name));
|
|
49906
50035
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
49907
50036
|
if (d.isFile()) entry.size = st.size;
|
|
49908
50037
|
} catch {
|
|
@@ -49918,14 +50047,14 @@ var WorkspaceBrowser = class {
|
|
|
49918
50047
|
read(args) {
|
|
49919
50048
|
ensureCwd(args.cwd);
|
|
49920
50049
|
const full = resolveInsideCwd(args.cwd, args.path);
|
|
49921
|
-
const st =
|
|
50050
|
+
const st = import_node_fs26.default.statSync(full);
|
|
49922
50051
|
if (!st.isFile()) {
|
|
49923
50052
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
|
|
49924
50053
|
}
|
|
49925
50054
|
if (st.size > MAX_FILE_BYTES) {
|
|
49926
50055
|
throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
|
|
49927
50056
|
}
|
|
49928
|
-
const buf =
|
|
50057
|
+
const buf = import_node_fs26.default.readFileSync(full);
|
|
49929
50058
|
const isBinary = buf.includes(0);
|
|
49930
50059
|
if (isBinary) {
|
|
49931
50060
|
return {
|
|
@@ -49947,20 +50076,20 @@ var WorkspaceBrowser = class {
|
|
|
49947
50076
|
};
|
|
49948
50077
|
|
|
49949
50078
|
// src/skills/agents-scanner.ts
|
|
49950
|
-
var
|
|
50079
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
49951
50080
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
49952
|
-
var
|
|
50081
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
49953
50082
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
49954
50083
|
function isDirLikeSync2(p2) {
|
|
49955
50084
|
try {
|
|
49956
|
-
return
|
|
50085
|
+
return import_node_fs27.default.statSync(p2).isDirectory();
|
|
49957
50086
|
} catch {
|
|
49958
50087
|
return false;
|
|
49959
50088
|
}
|
|
49960
50089
|
}
|
|
49961
50090
|
function fileExistsSync(p2) {
|
|
49962
50091
|
try {
|
|
49963
|
-
return
|
|
50092
|
+
return import_node_fs27.default.statSync(p2).isFile();
|
|
49964
50093
|
} catch {
|
|
49965
50094
|
return false;
|
|
49966
50095
|
}
|
|
@@ -49968,7 +50097,7 @@ function fileExistsSync(p2) {
|
|
|
49968
50097
|
function parseAgentFile(filePath) {
|
|
49969
50098
|
let content;
|
|
49970
50099
|
try {
|
|
49971
|
-
content =
|
|
50100
|
+
content = import_node_fs27.default.readFileSync(filePath, "utf8");
|
|
49972
50101
|
} catch {
|
|
49973
50102
|
return {};
|
|
49974
50103
|
}
|
|
@@ -49981,16 +50110,16 @@ function parseAgentFile(filePath) {
|
|
|
49981
50110
|
function scanAgentsDir(dir, source, seen, out) {
|
|
49982
50111
|
let entries;
|
|
49983
50112
|
try {
|
|
49984
|
-
entries =
|
|
50113
|
+
entries = import_node_fs27.default.readdirSync(dir, { withFileTypes: true });
|
|
49985
50114
|
} catch {
|
|
49986
50115
|
return;
|
|
49987
50116
|
}
|
|
49988
50117
|
for (const ent of entries) {
|
|
49989
50118
|
if (!ent.name.endsWith(".md")) continue;
|
|
49990
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
50119
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path28.default.join(dir, ent.name)))) {
|
|
49991
50120
|
continue;
|
|
49992
50121
|
}
|
|
49993
|
-
const filePath =
|
|
50122
|
+
const filePath = import_node_path28.default.join(dir, ent.name);
|
|
49994
50123
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
49995
50124
|
if (seen.has(baseName)) continue;
|
|
49996
50125
|
seen.add(baseName);
|
|
@@ -50008,12 +50137,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
50008
50137
|
function walk2(dir, namespaces) {
|
|
50009
50138
|
let entries;
|
|
50010
50139
|
try {
|
|
50011
|
-
entries =
|
|
50140
|
+
entries = import_node_fs27.default.readdirSync(dir, { withFileTypes: true });
|
|
50012
50141
|
} catch {
|
|
50013
50142
|
return;
|
|
50014
50143
|
}
|
|
50015
50144
|
for (const ent of entries) {
|
|
50016
|
-
const childPath =
|
|
50145
|
+
const childPath = import_node_path28.default.join(dir, ent.name);
|
|
50017
50146
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
50018
50147
|
walk2(childPath, [...namespaces, ent.name]);
|
|
50019
50148
|
continue;
|
|
@@ -50038,13 +50167,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
50038
50167
|
walk2(root, []);
|
|
50039
50168
|
}
|
|
50040
50169
|
function readInstalledPlugins2(home) {
|
|
50041
|
-
const pluginsDir =
|
|
50042
|
-
const v2 =
|
|
50043
|
-
const v1 =
|
|
50170
|
+
const pluginsDir = import_node_path28.default.join(home, ".claude", "plugins");
|
|
50171
|
+
const v2 = import_node_path28.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
50172
|
+
const v1 = import_node_path28.default.join(pluginsDir, "installed_plugins.json");
|
|
50044
50173
|
let raw = null;
|
|
50045
50174
|
for (const candidate of [v2, v1]) {
|
|
50046
50175
|
try {
|
|
50047
|
-
raw =
|
|
50176
|
+
raw = import_node_fs27.default.readFileSync(candidate, "utf8");
|
|
50048
50177
|
break;
|
|
50049
50178
|
} catch {
|
|
50050
50179
|
}
|
|
@@ -50069,19 +50198,19 @@ function readInstalledPlugins2(home) {
|
|
|
50069
50198
|
return out;
|
|
50070
50199
|
}
|
|
50071
50200
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
50072
|
-
let cur =
|
|
50073
|
-
const fsRoot =
|
|
50201
|
+
let cur = import_node_path28.default.resolve(startCwd);
|
|
50202
|
+
const fsRoot = import_node_path28.default.parse(cur).root;
|
|
50074
50203
|
while (true) {
|
|
50075
|
-
scanAgentsDir(
|
|
50204
|
+
scanAgentsDir(import_node_path28.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
50076
50205
|
let hasGit = false;
|
|
50077
50206
|
try {
|
|
50078
|
-
hasGit =
|
|
50207
|
+
hasGit = import_node_fs27.default.existsSync(import_node_path28.default.join(cur, ".git"));
|
|
50079
50208
|
} catch {
|
|
50080
50209
|
}
|
|
50081
50210
|
if (hasGit) return;
|
|
50082
50211
|
if (cur === home) return;
|
|
50083
50212
|
if (cur === fsRoot) return;
|
|
50084
|
-
const parent =
|
|
50213
|
+
const parent = import_node_path28.default.dirname(cur);
|
|
50085
50214
|
if (parent === cur) return;
|
|
50086
50215
|
cur = parent;
|
|
50087
50216
|
}
|
|
@@ -50116,7 +50245,7 @@ var AgentsScanner = class {
|
|
|
50116
50245
|
}
|
|
50117
50246
|
const fsBlock = [];
|
|
50118
50247
|
scanAgentsDir(
|
|
50119
|
-
|
|
50248
|
+
import_node_path28.default.join(this.home, ".claude", "agents"),
|
|
50120
50249
|
"global",
|
|
50121
50250
|
seen,
|
|
50122
50251
|
fsBlock
|
|
@@ -50130,7 +50259,7 @@ var AgentsScanner = class {
|
|
|
50130
50259
|
...this.extraPluginRoots
|
|
50131
50260
|
];
|
|
50132
50261
|
for (const { name, root } of plugins) {
|
|
50133
|
-
const agentsRoot =
|
|
50262
|
+
const agentsRoot = import_node_path28.default.join(root, "agents");
|
|
50134
50263
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
50135
50264
|
}
|
|
50136
50265
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -50138,15 +50267,15 @@ var AgentsScanner = class {
|
|
|
50138
50267
|
};
|
|
50139
50268
|
|
|
50140
50269
|
// src/observer/session-observer.ts
|
|
50141
|
-
var
|
|
50270
|
+
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
50142
50271
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
50143
|
-
var
|
|
50272
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
50144
50273
|
init_claude_history();
|
|
50145
50274
|
|
|
50146
50275
|
// src/observer/subagent-meta-observer.ts
|
|
50147
|
-
var
|
|
50276
|
+
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
50148
50277
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
50149
|
-
var
|
|
50278
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
50150
50279
|
init_claude_history();
|
|
50151
50280
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
50152
50281
|
var SubagentMetaObserver = class {
|
|
@@ -50159,7 +50288,7 @@ var SubagentMetaObserver = class {
|
|
|
50159
50288
|
watches = /* @__PURE__ */ new Map();
|
|
50160
50289
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
50161
50290
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
50162
|
-
return
|
|
50291
|
+
return import_node_path29.default.join(
|
|
50163
50292
|
this.home,
|
|
50164
50293
|
".claude",
|
|
50165
50294
|
"projects",
|
|
@@ -50189,7 +50318,7 @@ var SubagentMetaObserver = class {
|
|
|
50189
50318
|
attachWatcher(w2) {
|
|
50190
50319
|
if (w2.watcher) return;
|
|
50191
50320
|
try {
|
|
50192
|
-
w2.watcher =
|
|
50321
|
+
w2.watcher = import_node_fs28.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
|
|
50193
50322
|
if (!name) return;
|
|
50194
50323
|
const m2 = META_RE.exec(String(name));
|
|
50195
50324
|
if (!m2) return;
|
|
@@ -50201,7 +50330,7 @@ var SubagentMetaObserver = class {
|
|
|
50201
50330
|
scan(w2) {
|
|
50202
50331
|
let entries;
|
|
50203
50332
|
try {
|
|
50204
|
-
entries =
|
|
50333
|
+
entries = import_node_fs28.default.readdirSync(w2.dirPath);
|
|
50205
50334
|
} catch {
|
|
50206
50335
|
return;
|
|
50207
50336
|
}
|
|
@@ -50215,10 +50344,10 @@ var SubagentMetaObserver = class {
|
|
|
50215
50344
|
if (!m2) return;
|
|
50216
50345
|
const agentId = m2[1];
|
|
50217
50346
|
if (w2.emitted.has(agentId)) return;
|
|
50218
|
-
const file =
|
|
50347
|
+
const file = import_node_path29.default.join(w2.dirPath, name);
|
|
50219
50348
|
let raw;
|
|
50220
50349
|
try {
|
|
50221
|
-
raw =
|
|
50350
|
+
raw = import_node_fs28.default.readFileSync(file, "utf8");
|
|
50222
50351
|
} catch {
|
|
50223
50352
|
return;
|
|
50224
50353
|
}
|
|
@@ -50275,14 +50404,14 @@ var SessionObserver = class {
|
|
|
50275
50404
|
metaObserver;
|
|
50276
50405
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
50277
50406
|
if (override) return override;
|
|
50278
|
-
return
|
|
50407
|
+
return import_node_path30.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
50279
50408
|
}
|
|
50280
50409
|
start(args) {
|
|
50281
50410
|
this.stop(args.sessionId);
|
|
50282
50411
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
50283
50412
|
let size = 0;
|
|
50284
50413
|
try {
|
|
50285
|
-
size =
|
|
50414
|
+
size = import_node_fs29.default.statSync(filePath).size;
|
|
50286
50415
|
} catch {
|
|
50287
50416
|
}
|
|
50288
50417
|
const w2 = {
|
|
@@ -50295,16 +50424,16 @@ var SessionObserver = class {
|
|
|
50295
50424
|
adapter: args.adapter,
|
|
50296
50425
|
prevIsRejectSentinel: false,
|
|
50297
50426
|
toolSessionId: args.toolSessionId,
|
|
50298
|
-
sawFile:
|
|
50427
|
+
sawFile: import_node_fs29.default.existsSync(filePath),
|
|
50299
50428
|
lastRelocateScanMs: 0,
|
|
50300
50429
|
pendingCwdDerive: false,
|
|
50301
50430
|
lastDeriveMs: 0
|
|
50302
50431
|
};
|
|
50303
50432
|
try {
|
|
50304
|
-
|
|
50433
|
+
import_node_fs29.default.mkdirSync(import_node_path30.default.dirname(filePath), { recursive: true });
|
|
50305
50434
|
} catch {
|
|
50306
50435
|
}
|
|
50307
|
-
w2.watcher =
|
|
50436
|
+
w2.watcher = import_node_fs29.default.watch(import_node_path30.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
50308
50437
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
50309
50438
|
this.poll(w2);
|
|
50310
50439
|
});
|
|
@@ -50327,7 +50456,7 @@ var SessionObserver = class {
|
|
|
50327
50456
|
// 异常静默吞,不阻塞 watcher 启动
|
|
50328
50457
|
hydrateMetaTail(w2, maxLines = 200) {
|
|
50329
50458
|
try {
|
|
50330
|
-
const raw =
|
|
50459
|
+
const raw = import_node_fs29.default.readFileSync(w2.filePath, "utf8");
|
|
50331
50460
|
if (!raw) return;
|
|
50332
50461
|
const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
50333
50462
|
if (allLines.length === 0) return;
|
|
@@ -50351,7 +50480,7 @@ var SessionObserver = class {
|
|
|
50351
50480
|
poll(w2) {
|
|
50352
50481
|
let size = 0;
|
|
50353
50482
|
try {
|
|
50354
|
-
size =
|
|
50483
|
+
size = import_node_fs29.default.statSync(w2.filePath).size;
|
|
50355
50484
|
} catch {
|
|
50356
50485
|
if (w2.sawFile) this.maybeRelocate(w2);
|
|
50357
50486
|
return;
|
|
@@ -50362,11 +50491,11 @@ var SessionObserver = class {
|
|
|
50362
50491
|
w2.buf = "";
|
|
50363
50492
|
}
|
|
50364
50493
|
if (size === w2.lastSize) return;
|
|
50365
|
-
const fd =
|
|
50494
|
+
const fd = import_node_fs29.default.openSync(w2.filePath, "r");
|
|
50366
50495
|
try {
|
|
50367
50496
|
const len = size - w2.lastSize;
|
|
50368
50497
|
const buf = Buffer.alloc(len);
|
|
50369
|
-
|
|
50498
|
+
import_node_fs29.default.readSync(fd, buf, 0, len, w2.lastSize);
|
|
50370
50499
|
w2.lastSize = size;
|
|
50371
50500
|
w2.buf += buf.toString("utf8");
|
|
50372
50501
|
let newlineIndex;
|
|
@@ -50389,7 +50518,7 @@ var SessionObserver = class {
|
|
|
50389
50518
|
}
|
|
50390
50519
|
}
|
|
50391
50520
|
} finally {
|
|
50392
|
-
|
|
50521
|
+
import_node_fs29.default.closeSync(fd);
|
|
50393
50522
|
}
|
|
50394
50523
|
if (w2.pendingCwdDerive) this.maybeDeriveCwd(w2);
|
|
50395
50524
|
}
|
|
@@ -50401,7 +50530,7 @@ var SessionObserver = class {
|
|
|
50401
50530
|
const now = Date.now();
|
|
50402
50531
|
if (now - w2.lastRelocateScanMs < 1e3) return;
|
|
50403
50532
|
w2.lastRelocateScanMs = now;
|
|
50404
|
-
const projectsRoot =
|
|
50533
|
+
const projectsRoot = import_node_path30.default.join(this.home, ".claude", "projects");
|
|
50405
50534
|
const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
|
|
50406
50535
|
if (!found || found === w2.filePath) return;
|
|
50407
50536
|
try {
|
|
@@ -50410,7 +50539,7 @@ var SessionObserver = class {
|
|
|
50410
50539
|
}
|
|
50411
50540
|
w2.filePath = found;
|
|
50412
50541
|
try {
|
|
50413
|
-
w2.watcher =
|
|
50542
|
+
w2.watcher = import_node_fs29.default.watch(import_node_path30.default.dirname(found), { persistent: false }, (_event, changedName) => {
|
|
50414
50543
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
50415
50544
|
this.poll(w2);
|
|
50416
50545
|
});
|
|
@@ -50977,79 +51106,6 @@ function removeSubscription(client, sessionId) {
|
|
|
50977
51106
|
else client.subscribedSessions.set(sessionId, next);
|
|
50978
51107
|
}
|
|
50979
51108
|
|
|
50980
|
-
// src/transport/rpc-adapter.ts
|
|
50981
|
-
var EXPOSED_RPC_METHODS = [
|
|
50982
|
-
"appBuilder.createProject",
|
|
50983
|
-
"appBuilder.listProjects",
|
|
50984
|
-
"appBuilder.updateProjectPort",
|
|
50985
|
-
"appBuilder.setProdUrl",
|
|
50986
|
-
// 单栏 refactor §5.6.2 stage fix:scaffold + install 完成调 startDevServer 起 dev server;
|
|
50987
|
-
// 中间用 reportStage 上报阶段(scaffolding / installing / failed),UI 据 stage 推帧切 PreviewPane。
|
|
50988
|
-
"appBuilder.startDevServer",
|
|
50989
|
-
"appBuilder.reportStage",
|
|
50990
|
-
// 单栏 §5.6.5 fix: UI 切 session 时调(assistant 不需要主动调,但暴露白名单避免误猜成 forbidden)
|
|
50991
|
-
"appBuilder.setActiveSession",
|
|
50992
|
-
// dataclaw-builder:persona 建页时取建页人身份(含 union_id)写进生成 app 的配置。
|
|
50993
|
-
// 路由到 handlers['auth:getIdentity'],只返 identity、绝不带 ttcToken(见 handlers/feishu-auth.ts)。
|
|
50994
|
-
"auth.getIdentity",
|
|
50995
|
-
// Persona dispatch(异步,spec 2026-07-20):A 端 dispatch MCP server 调 run(秒回 dispatchId);
|
|
50996
|
-
// B 端调 complete(带 outcome → 台账 + 投递);发起方调 list 查台账。详见 protocol/src/dispatch.ts。
|
|
50997
|
-
"personaDispatch.run",
|
|
50998
|
-
// 跨设备 exec(spec 2026-07-16):A 侧本地 cc 经 /api/rpc 调,带 peerDeviceId → daemon forward。
|
|
50999
|
-
"peerExec.run",
|
|
51000
|
-
"personaDispatch.complete",
|
|
51001
|
-
"personaDispatch.list",
|
|
51002
|
-
// persona 清单(spec 2026-07-21):两级路由第一级——发起方 cc(loopback owner 语义)
|
|
51003
|
-
// 用 curl 拿全量 personaId+label 紧凑清单,再按需读候选 CLAUDE.md 首段做终选。
|
|
51004
|
-
"persona.list",
|
|
51005
|
-
// clawd-shift v1 (spec 2026-06-24-clawd-shift):cc 子进程内的 shift MCP server 调
|
|
51006
|
-
// 这 5 个 method 管理 owner 的 shift(fire-and-forget 排班)。鉴权靠 body.personaId
|
|
51007
|
-
// (mcp-server 从 process.env.CLAWD_PERSONA_ID 读,源 = SessionFile.ownerPersonaId)。
|
|
51008
|
-
// handler 内 cancel/update/history 校验 createdByPersona === personaId 防越权。
|
|
51009
|
-
"shift-internal.add",
|
|
51010
|
-
"shift-internal.list",
|
|
51011
|
-
"shift-internal.cancel",
|
|
51012
|
-
"shift-internal.update",
|
|
51013
|
-
"shift-internal.history",
|
|
51014
|
-
// file-sharing:persona guest agent 把自己工作目录内的产物入群+签名分享。
|
|
51015
|
-
// 路径越界由 handlers/attachment.ts guardAttachmentPath(scope-based)拦截。
|
|
51016
|
-
"attachment.groupAdd",
|
|
51017
|
-
"attachment.signUrl",
|
|
51018
|
-
// persona 受控发 P2P IM DM(sender 由 session scope 推,driver 分级授权见 handlers/inbox.ts)
|
|
51019
|
-
"inbox.sendDm",
|
|
51020
|
-
// per-turn sender 2026-07-08 spec §4.1:MCP servers (ticket / inbox / ...) 每 tool call
|
|
51021
|
-
// 查当前 turn caller —— cc 长驻 + owner/guest 交替驱动同一 session 时不能靠启动时 env
|
|
51022
|
-
// 写死身份,必须运行时 fetch。header X-Clawd-Session-Id 作 session 定位,handler 内查
|
|
51023
|
-
// manager.tryGetState(sid).currentTurnSender 返 SenderInfo | null。
|
|
51024
|
-
"session.currentTurnSender"
|
|
51025
|
-
];
|
|
51026
|
-
async function handleRpcRequest(input) {
|
|
51027
|
-
const { method, body, sessionId, dispatcher } = input;
|
|
51028
|
-
if (!sessionId) {
|
|
51029
|
-
return { status: 400, body: { ok: false, error: "MISSING_SESSION_ID", message: "X-Clawd-Session-Id header required" } };
|
|
51030
|
-
}
|
|
51031
|
-
if (!EXPOSED_RPC_METHODS.includes(method)) {
|
|
51032
|
-
return { status: 403, body: { ok: false, error: "METHOD_NOT_EXPOSED", message: `method "${method}" not exposed via HTTP RPC` } };
|
|
51033
|
-
}
|
|
51034
|
-
const internalMethod = method.replace(".", ":");
|
|
51035
|
-
const augmentedBody = {
|
|
51036
|
-
...typeof body === "object" && body != null ? body : {},
|
|
51037
|
-
sessionId
|
|
51038
|
-
};
|
|
51039
|
-
try {
|
|
51040
|
-
const result = await dispatcher.dispatch(internalMethod, augmentedBody, { sessionId });
|
|
51041
|
-
return { status: 200, body: { ok: true, result } };
|
|
51042
|
-
} catch (err) {
|
|
51043
|
-
const e = err;
|
|
51044
|
-
const code = e?.code ?? "INTERNAL";
|
|
51045
|
-
const message = e?.message ?? String(err);
|
|
51046
|
-
return { status: 400, body: { ok: false, error: code, message } };
|
|
51047
|
-
}
|
|
51048
|
-
}
|
|
51049
|
-
function resolveExposedHandler(handlers, internalMethod) {
|
|
51050
|
-
return handlers[internalMethod] ?? handlers[internalMethod.replace(":", ".")];
|
|
51051
|
-
}
|
|
51052
|
-
|
|
51053
51109
|
// src/transport/auth.ts
|
|
51054
51110
|
init_protocol();
|
|
51055
51111
|
var AuthGate = class {
|
|
@@ -51266,8 +51322,8 @@ async function authenticate(token, deps) {
|
|
|
51266
51322
|
}
|
|
51267
51323
|
|
|
51268
51324
|
// src/legacy-cleanup.ts
|
|
51269
|
-
var
|
|
51270
|
-
var
|
|
51325
|
+
var fs34 = __toESM(require("fs/promises"), 1);
|
|
51326
|
+
var path35 = __toESM(require("path"), 1);
|
|
51271
51327
|
var LEGACY_FILES = [
|
|
51272
51328
|
"personal-capability.json",
|
|
51273
51329
|
"received-capabilities.json",
|
|
@@ -51276,9 +51332,9 @@ var LEGACY_FILES = [
|
|
|
51276
51332
|
async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
51277
51333
|
const removed = [];
|
|
51278
51334
|
for (const name of LEGACY_FILES) {
|
|
51279
|
-
const p2 =
|
|
51335
|
+
const p2 = path35.join(dataDir, name);
|
|
51280
51336
|
try {
|
|
51281
|
-
await
|
|
51337
|
+
await fs34.unlink(p2);
|
|
51282
51338
|
removed.push(name);
|
|
51283
51339
|
logger.debug("legacy capability file removed", { file: name });
|
|
51284
51340
|
} catch (err) {
|
|
@@ -51290,13 +51346,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
|
51290
51346
|
}
|
|
51291
51347
|
|
|
51292
51348
|
// src/inbox/inbox-store.ts
|
|
51293
|
-
var
|
|
51294
|
-
var
|
|
51349
|
+
var fs35 = __toESM(require("fs"), 1);
|
|
51350
|
+
var path36 = __toESM(require("path"), 1);
|
|
51295
51351
|
var INBOX_SUBDIR = "inbox";
|
|
51296
51352
|
var InboxStore = class {
|
|
51297
51353
|
constructor(dataDir) {
|
|
51298
51354
|
this.dataDir = dataDir;
|
|
51299
|
-
|
|
51355
|
+
fs35.mkdirSync(this.dirPath(), { recursive: true });
|
|
51300
51356
|
}
|
|
51301
51357
|
dataDir;
|
|
51302
51358
|
/**
|
|
@@ -51308,7 +51364,7 @@ var InboxStore = class {
|
|
|
51308
51364
|
const file = this.filePath(peerDeviceId);
|
|
51309
51365
|
let raw;
|
|
51310
51366
|
try {
|
|
51311
|
-
raw =
|
|
51367
|
+
raw = fs35.readFileSync(file, "utf8");
|
|
51312
51368
|
} catch (err) {
|
|
51313
51369
|
if (err?.code === "ENOENT") return [];
|
|
51314
51370
|
return [];
|
|
@@ -51324,7 +51380,7 @@ var InboxStore = class {
|
|
|
51324
51380
|
const dir = this.dirPath();
|
|
51325
51381
|
let entries;
|
|
51326
51382
|
try {
|
|
51327
|
-
entries =
|
|
51383
|
+
entries = fs35.readdirSync(dir);
|
|
51328
51384
|
} catch (err) {
|
|
51329
51385
|
if (err?.code === "ENOENT") return [];
|
|
51330
51386
|
return [];
|
|
@@ -51340,9 +51396,9 @@ var InboxStore = class {
|
|
|
51340
51396
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
51341
51397
|
const file = this.filePath(message.peerDeviceId);
|
|
51342
51398
|
const line = JSON.stringify(message) + "\n";
|
|
51343
|
-
|
|
51399
|
+
fs35.appendFileSync(file, line, { mode: 384 });
|
|
51344
51400
|
try {
|
|
51345
|
-
|
|
51401
|
+
fs35.chmodSync(file, 384);
|
|
51346
51402
|
} catch {
|
|
51347
51403
|
}
|
|
51348
51404
|
}
|
|
@@ -51372,7 +51428,7 @@ var InboxStore = class {
|
|
|
51372
51428
|
removeByPeerDeviceId(peerDeviceId) {
|
|
51373
51429
|
const file = this.filePath(peerDeviceId);
|
|
51374
51430
|
try {
|
|
51375
|
-
|
|
51431
|
+
fs35.unlinkSync(file);
|
|
51376
51432
|
} catch (err) {
|
|
51377
51433
|
if (err?.code === "ENOENT") return;
|
|
51378
51434
|
}
|
|
@@ -51381,18 +51437,18 @@ var InboxStore = class {
|
|
|
51381
51437
|
const file = this.filePath(peerDeviceId);
|
|
51382
51438
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
51383
51439
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
51384
|
-
|
|
51385
|
-
|
|
51440
|
+
fs35.writeFileSync(tmp, content, { mode: 384 });
|
|
51441
|
+
fs35.renameSync(tmp, file);
|
|
51386
51442
|
try {
|
|
51387
|
-
|
|
51443
|
+
fs35.chmodSync(file, 384);
|
|
51388
51444
|
} catch {
|
|
51389
51445
|
}
|
|
51390
51446
|
}
|
|
51391
51447
|
dirPath() {
|
|
51392
|
-
return
|
|
51448
|
+
return path36.join(this.dataDir, INBOX_SUBDIR);
|
|
51393
51449
|
}
|
|
51394
51450
|
filePath(peerDeviceId) {
|
|
51395
|
-
return
|
|
51451
|
+
return path36.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
51396
51452
|
}
|
|
51397
51453
|
};
|
|
51398
51454
|
function parseAllLines(raw) {
|
|
@@ -51480,8 +51536,8 @@ var InboxManager = class {
|
|
|
51480
51536
|
};
|
|
51481
51537
|
|
|
51482
51538
|
// src/state/contact-store.ts
|
|
51483
|
-
var
|
|
51484
|
-
var
|
|
51539
|
+
var fs36 = __toESM(require("fs"), 1);
|
|
51540
|
+
var path37 = __toESM(require("path"), 1);
|
|
51485
51541
|
var FILE_NAME = "contacts.json";
|
|
51486
51542
|
var ContactStore = class {
|
|
51487
51543
|
constructor(dataDir) {
|
|
@@ -51491,10 +51547,10 @@ var ContactStore = class {
|
|
|
51491
51547
|
contacts = /* @__PURE__ */ new Map();
|
|
51492
51548
|
load() {
|
|
51493
51549
|
this.contacts.clear();
|
|
51494
|
-
const file =
|
|
51550
|
+
const file = path37.join(this.dataDir, FILE_NAME);
|
|
51495
51551
|
let raw;
|
|
51496
51552
|
try {
|
|
51497
|
-
raw =
|
|
51553
|
+
raw = fs36.readFileSync(file, "utf8");
|
|
51498
51554
|
} catch (err) {
|
|
51499
51555
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
51500
51556
|
return;
|
|
@@ -51563,20 +51619,20 @@ var ContactStore = class {
|
|
|
51563
51619
|
return true;
|
|
51564
51620
|
}
|
|
51565
51621
|
flush() {
|
|
51566
|
-
const file =
|
|
51622
|
+
const file = path37.join(this.dataDir, FILE_NAME);
|
|
51567
51623
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
51568
51624
|
const content = JSON.stringify(
|
|
51569
51625
|
{ contacts: Array.from(this.contacts.values()) },
|
|
51570
51626
|
null,
|
|
51571
51627
|
2
|
|
51572
51628
|
);
|
|
51573
|
-
|
|
51574
|
-
|
|
51575
|
-
|
|
51629
|
+
fs36.mkdirSync(this.dataDir, { recursive: true });
|
|
51630
|
+
fs36.writeFileSync(tmp, content, { mode: 384 });
|
|
51631
|
+
fs36.renameSync(tmp, file);
|
|
51576
51632
|
}
|
|
51577
51633
|
renameBak(file) {
|
|
51578
51634
|
try {
|
|
51579
|
-
|
|
51635
|
+
fs36.renameSync(file, `${file}.bak`);
|
|
51580
51636
|
} catch {
|
|
51581
51637
|
}
|
|
51582
51638
|
}
|
|
@@ -51684,61 +51740,61 @@ async function connectRemote(args) {
|
|
|
51684
51740
|
}
|
|
51685
51741
|
|
|
51686
51742
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
51687
|
-
var
|
|
51688
|
-
var
|
|
51743
|
+
var fs37 = __toESM(require("fs"), 1);
|
|
51744
|
+
var path38 = __toESM(require("path"), 1);
|
|
51689
51745
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
51690
51746
|
function migrateFlattenSessions(opts) {
|
|
51691
51747
|
const dataDir = opts.dataDir;
|
|
51692
51748
|
const now = opts.now ?? Date.now;
|
|
51693
|
-
const sessionsDir =
|
|
51694
|
-
const flagPath =
|
|
51749
|
+
const sessionsDir = path38.join(dataDir, "sessions");
|
|
51750
|
+
const flagPath = path38.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
51695
51751
|
if (existsSync3(flagPath)) {
|
|
51696
51752
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
51697
51753
|
}
|
|
51698
51754
|
let movedBare = 0;
|
|
51699
51755
|
let movedVmOwner = 0;
|
|
51700
51756
|
let archivedListener = 0;
|
|
51701
|
-
const defaultDir =
|
|
51757
|
+
const defaultDir = path38.join(sessionsDir, "default");
|
|
51702
51758
|
if (existsSync3(defaultDir)) {
|
|
51703
51759
|
for (const entry of readdirSafe(defaultDir)) {
|
|
51704
51760
|
if (!entry.endsWith(".json")) continue;
|
|
51705
|
-
const src =
|
|
51706
|
-
const dst =
|
|
51707
|
-
|
|
51761
|
+
const src = path38.join(defaultDir, entry);
|
|
51762
|
+
const dst = path38.join(sessionsDir, entry);
|
|
51763
|
+
fs37.renameSync(src, dst);
|
|
51708
51764
|
movedBare += 1;
|
|
51709
51765
|
}
|
|
51710
51766
|
rmdirIfEmpty(defaultDir);
|
|
51711
51767
|
}
|
|
51712
51768
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
51713
|
-
const personaDir =
|
|
51769
|
+
const personaDir = path38.join(sessionsDir, pid);
|
|
51714
51770
|
if (!isDir(personaDir)) continue;
|
|
51715
51771
|
if (pid === "default") continue;
|
|
51716
|
-
const ownerSrc =
|
|
51772
|
+
const ownerSrc = path38.join(personaDir, "owner");
|
|
51717
51773
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
51718
|
-
const ownerDst =
|
|
51719
|
-
|
|
51774
|
+
const ownerDst = path38.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
51775
|
+
fs37.mkdirSync(ownerDst, { recursive: true });
|
|
51720
51776
|
for (const file of readdirSafe(ownerSrc)) {
|
|
51721
51777
|
if (!file.endsWith(".json")) continue;
|
|
51722
|
-
|
|
51778
|
+
fs37.renameSync(path38.join(ownerSrc, file), path38.join(ownerDst, file));
|
|
51723
51779
|
movedVmOwner += 1;
|
|
51724
51780
|
}
|
|
51725
51781
|
rmdirIfEmpty(ownerSrc);
|
|
51726
51782
|
}
|
|
51727
|
-
const listenerSrc =
|
|
51783
|
+
const listenerSrc = path38.join(personaDir, "listener");
|
|
51728
51784
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
51729
|
-
const archiveDst =
|
|
51730
|
-
|
|
51785
|
+
const archiveDst = path38.join(dataDir, ".legacy", `listener-${pid}`);
|
|
51786
|
+
fs37.mkdirSync(archiveDst, { recursive: true });
|
|
51731
51787
|
for (const file of readdirSafe(listenerSrc)) {
|
|
51732
51788
|
if (!file.endsWith(".json")) continue;
|
|
51733
|
-
|
|
51789
|
+
fs37.renameSync(path38.join(listenerSrc, file), path38.join(archiveDst, file));
|
|
51734
51790
|
archivedListener += 1;
|
|
51735
51791
|
}
|
|
51736
51792
|
rmdirIfEmpty(listenerSrc);
|
|
51737
51793
|
}
|
|
51738
51794
|
rmdirIfEmpty(personaDir);
|
|
51739
51795
|
}
|
|
51740
|
-
|
|
51741
|
-
|
|
51796
|
+
fs37.mkdirSync(sessionsDir, { recursive: true });
|
|
51797
|
+
fs37.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
51742
51798
|
return {
|
|
51743
51799
|
skipped: false,
|
|
51744
51800
|
flagWritten: true,
|
|
@@ -51749,7 +51805,7 @@ function migrateFlattenSessions(opts) {
|
|
|
51749
51805
|
}
|
|
51750
51806
|
function existsSync3(p2) {
|
|
51751
51807
|
try {
|
|
51752
|
-
|
|
51808
|
+
fs37.statSync(p2);
|
|
51753
51809
|
return true;
|
|
51754
51810
|
} catch {
|
|
51755
51811
|
return false;
|
|
@@ -51757,31 +51813,31 @@ function existsSync3(p2) {
|
|
|
51757
51813
|
}
|
|
51758
51814
|
function isDir(p2) {
|
|
51759
51815
|
try {
|
|
51760
|
-
return
|
|
51816
|
+
return fs37.statSync(p2).isDirectory();
|
|
51761
51817
|
} catch {
|
|
51762
51818
|
return false;
|
|
51763
51819
|
}
|
|
51764
51820
|
}
|
|
51765
51821
|
function readdirSafe(p2) {
|
|
51766
51822
|
try {
|
|
51767
|
-
return
|
|
51823
|
+
return fs37.readdirSync(p2);
|
|
51768
51824
|
} catch {
|
|
51769
51825
|
return [];
|
|
51770
51826
|
}
|
|
51771
51827
|
}
|
|
51772
51828
|
function rmdirIfEmpty(p2) {
|
|
51773
51829
|
try {
|
|
51774
|
-
|
|
51830
|
+
fs37.rmdirSync(p2);
|
|
51775
51831
|
} catch {
|
|
51776
51832
|
}
|
|
51777
51833
|
}
|
|
51778
51834
|
|
|
51779
51835
|
// src/transport/http-router.ts
|
|
51780
|
-
var
|
|
51781
|
-
var
|
|
51836
|
+
var import_node_fs31 = __toESM(require("fs"), 1);
|
|
51837
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
51782
51838
|
|
|
51783
51839
|
// src/attachment/mime.ts
|
|
51784
|
-
var
|
|
51840
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
51785
51841
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
51786
51842
|
var EXT_TO_NATIVE_MIME = {
|
|
51787
51843
|
// 图片
|
|
@@ -51888,7 +51944,7 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
51888
51944
|
".mk"
|
|
51889
51945
|
]);
|
|
51890
51946
|
function lookupMime(filePathOrName) {
|
|
51891
|
-
const ext =
|
|
51947
|
+
const ext = import_node_path31.default.extname(filePathOrName).toLowerCase();
|
|
51892
51948
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
51893
51949
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
51894
51950
|
return "application/octet-stream";
|
|
@@ -51957,8 +52013,8 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
51957
52013
|
}
|
|
51958
52014
|
|
|
51959
52015
|
// src/attachment/upload.ts
|
|
51960
|
-
var
|
|
51961
|
-
var
|
|
52016
|
+
var import_node_fs30 = __toESM(require("fs"), 1);
|
|
52017
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
51962
52018
|
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
51963
52019
|
var import_promises3 = require("stream/promises");
|
|
51964
52020
|
var UploadError = class extends Error {
|
|
@@ -51970,22 +52026,22 @@ var UploadError = class extends Error {
|
|
|
51970
52026
|
code;
|
|
51971
52027
|
};
|
|
51972
52028
|
function assertValidFileName(fileName) {
|
|
51973
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
52029
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path32.default.basename(fileName)) {
|
|
51974
52030
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
51975
52031
|
}
|
|
51976
52032
|
}
|
|
51977
52033
|
var HASH_PREFIX_LEN = 16;
|
|
51978
52034
|
async function writeUploadedAttachment(args) {
|
|
51979
52035
|
assertValidFileName(args.fileName);
|
|
51980
|
-
const attachmentsRoot =
|
|
52036
|
+
const attachmentsRoot = import_node_path32.default.join(args.sessionDir, ".attachments");
|
|
51981
52037
|
try {
|
|
51982
|
-
|
|
52038
|
+
import_node_fs30.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
51983
52039
|
} catch (err) {
|
|
51984
52040
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
51985
52041
|
}
|
|
51986
52042
|
const hasher = import_node_crypto8.default.createHash("sha256");
|
|
51987
52043
|
let actualSize = 0;
|
|
51988
|
-
const tmpPath =
|
|
52044
|
+
const tmpPath = import_node_path32.default.join(
|
|
51989
52045
|
attachmentsRoot,
|
|
51990
52046
|
`.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
|
|
51991
52047
|
);
|
|
@@ -52000,18 +52056,18 @@ async function writeUploadedAttachment(args) {
|
|
|
52000
52056
|
yield buf;
|
|
52001
52057
|
}
|
|
52002
52058
|
},
|
|
52003
|
-
|
|
52059
|
+
import_node_fs30.default.createWriteStream(tmpPath, { mode: 384 })
|
|
52004
52060
|
);
|
|
52005
52061
|
} catch (err) {
|
|
52006
52062
|
try {
|
|
52007
|
-
|
|
52063
|
+
import_node_fs30.default.unlinkSync(tmpPath);
|
|
52008
52064
|
} catch {
|
|
52009
52065
|
}
|
|
52010
52066
|
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
52011
52067
|
}
|
|
52012
52068
|
if (actualSize !== args.contentLength) {
|
|
52013
52069
|
try {
|
|
52014
|
-
|
|
52070
|
+
import_node_fs30.default.unlinkSync(tmpPath);
|
|
52015
52071
|
} catch {
|
|
52016
52072
|
}
|
|
52017
52073
|
throw new UploadError(
|
|
@@ -52020,35 +52076,35 @@ async function writeUploadedAttachment(args) {
|
|
|
52020
52076
|
);
|
|
52021
52077
|
}
|
|
52022
52078
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
52023
|
-
const hashDir =
|
|
52079
|
+
const hashDir = import_node_path32.default.join(attachmentsRoot, attachmentId);
|
|
52024
52080
|
let finalFileName;
|
|
52025
52081
|
let hashDirExists = false;
|
|
52026
52082
|
try {
|
|
52027
|
-
hashDirExists =
|
|
52083
|
+
hashDirExists = import_node_fs30.default.statSync(hashDir).isDirectory();
|
|
52028
52084
|
} catch {
|
|
52029
52085
|
}
|
|
52030
52086
|
if (hashDirExists) {
|
|
52031
|
-
const existing =
|
|
52087
|
+
const existing = import_node_fs30.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
|
|
52032
52088
|
finalFileName = existing[0] ?? args.fileName;
|
|
52033
52089
|
try {
|
|
52034
|
-
|
|
52090
|
+
import_node_fs30.default.unlinkSync(tmpPath);
|
|
52035
52091
|
} catch {
|
|
52036
52092
|
}
|
|
52037
52093
|
} else {
|
|
52038
52094
|
try {
|
|
52039
|
-
|
|
52095
|
+
import_node_fs30.default.mkdirSync(hashDir, { recursive: true });
|
|
52040
52096
|
finalFileName = args.fileName;
|
|
52041
|
-
|
|
52097
|
+
import_node_fs30.default.renameSync(tmpPath, import_node_path32.default.join(hashDir, finalFileName));
|
|
52042
52098
|
} catch (err) {
|
|
52043
52099
|
try {
|
|
52044
|
-
|
|
52100
|
+
import_node_fs30.default.unlinkSync(tmpPath);
|
|
52045
52101
|
} catch {
|
|
52046
52102
|
}
|
|
52047
52103
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
52048
52104
|
}
|
|
52049
52105
|
}
|
|
52050
|
-
const absPath =
|
|
52051
|
-
const relPath =
|
|
52106
|
+
const absPath = import_node_path32.default.join(hashDir, finalFileName);
|
|
52107
|
+
const relPath = import_node_path32.default.relative(args.sessionDir, absPath);
|
|
52052
52108
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
52053
52109
|
relPath: absPath,
|
|
52054
52110
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -52062,7 +52118,7 @@ async function writeUploadedAttachment(args) {
|
|
|
52062
52118
|
|
|
52063
52119
|
// src/extension/import.ts
|
|
52064
52120
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
52065
|
-
var
|
|
52121
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
52066
52122
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
52067
52123
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
52068
52124
|
var ImportError = class extends Error {
|
|
@@ -52080,7 +52136,7 @@ async function importZip(buf, root) {
|
|
|
52080
52136
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
52081
52137
|
}
|
|
52082
52138
|
for (const name of Object.keys(zip.files)) {
|
|
52083
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
52139
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path33.default.isAbsolute(name)) {
|
|
52084
52140
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
52085
52141
|
}
|
|
52086
52142
|
}
|
|
@@ -52113,7 +52169,7 @@ async function importZip(buf, root) {
|
|
|
52113
52169
|
);
|
|
52114
52170
|
}
|
|
52115
52171
|
}
|
|
52116
|
-
const destDir =
|
|
52172
|
+
const destDir = import_node_path33.default.join(root, manifest.id);
|
|
52117
52173
|
let destExists = false;
|
|
52118
52174
|
try {
|
|
52119
52175
|
await import_promises4.default.access(destDir);
|
|
@@ -52123,15 +52179,15 @@ async function importZip(buf, root) {
|
|
|
52123
52179
|
if (destExists) {
|
|
52124
52180
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
52125
52181
|
}
|
|
52126
|
-
const stage = await import_promises4.default.mkdtemp(
|
|
52182
|
+
const stage = await import_promises4.default.mkdtemp(import_node_path33.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
52127
52183
|
try {
|
|
52128
52184
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
52129
|
-
const dest =
|
|
52185
|
+
const dest = import_node_path33.default.join(stage, name);
|
|
52130
52186
|
if (entry.dir) {
|
|
52131
52187
|
await import_promises4.default.mkdir(dest, { recursive: true });
|
|
52132
52188
|
continue;
|
|
52133
52189
|
}
|
|
52134
|
-
await import_promises4.default.mkdir(
|
|
52190
|
+
await import_promises4.default.mkdir(import_node_path33.default.dirname(dest), { recursive: true });
|
|
52135
52191
|
const content = await entry.async("nodebuffer");
|
|
52136
52192
|
await import_promises4.default.writeFile(dest, content);
|
|
52137
52193
|
}
|
|
@@ -52146,7 +52202,6 @@ async function importZip(buf, root) {
|
|
|
52146
52202
|
}
|
|
52147
52203
|
|
|
52148
52204
|
// src/transport/http-router.ts
|
|
52149
|
-
var RPC_ROUTE_PREFIX = "/api/rpc/";
|
|
52150
52205
|
var RPC_BODY_MAX_BYTES = 1 * 1024 * 1024;
|
|
52151
52206
|
var SHARE_UI_ASSETS_PREFIX = "/share-ui/assets/";
|
|
52152
52207
|
var SHARE_UI_ASSET_MIME = {
|
|
@@ -52162,11 +52217,9 @@ var SHARE_UI_ASSET_MIME = {
|
|
|
52162
52217
|
".wasm": "application/wasm"
|
|
52163
52218
|
};
|
|
52164
52219
|
function shareUiAssetMime(filePath) {
|
|
52165
|
-
const ext =
|
|
52220
|
+
const ext = import_node_path34.default.extname(filePath).toLowerCase();
|
|
52166
52221
|
return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
|
|
52167
52222
|
}
|
|
52168
|
-
var DISPATCH_HEARTBEAT_MS = 25e3;
|
|
52169
|
-
var DISPATCH_HOLD_METHOD = "personaDispatch:run";
|
|
52170
52223
|
var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
|
|
52171
52224
|
var AUTHED_RPC_CORS_HEADERS = {
|
|
52172
52225
|
"Access-Control-Allow-Origin": "*",
|
|
@@ -52189,10 +52242,6 @@ function authedRpcErrorStatus(code) {
|
|
|
52189
52242
|
return 400;
|
|
52190
52243
|
}
|
|
52191
52244
|
}
|
|
52192
|
-
function isLoopbackAddress(addr) {
|
|
52193
|
-
if (!addr) return false;
|
|
52194
|
-
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1" || addr.startsWith("127.");
|
|
52195
|
-
}
|
|
52196
52245
|
async function readJsonBody(req, max) {
|
|
52197
52246
|
return await new Promise((resolve6, reject) => {
|
|
52198
52247
|
let size = 0;
|
|
@@ -52249,7 +52298,7 @@ function isValidUploadFileName(fileName) {
|
|
|
52249
52298
|
if (fileName === "." || fileName === "..") return false;
|
|
52250
52299
|
if (fileName.startsWith(".")) return false;
|
|
52251
52300
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
52252
|
-
return fileName ===
|
|
52301
|
+
return fileName === import_node_path34.default.basename(fileName);
|
|
52253
52302
|
}
|
|
52254
52303
|
function createHttpRouter(deps) {
|
|
52255
52304
|
return async (req, res) => {
|
|
@@ -52321,7 +52370,7 @@ function createHttpRouter(deps) {
|
|
|
52321
52370
|
}
|
|
52322
52371
|
let buf;
|
|
52323
52372
|
try {
|
|
52324
|
-
buf = await
|
|
52373
|
+
buf = await import_node_fs31.default.promises.readFile(abs);
|
|
52325
52374
|
} catch {
|
|
52326
52375
|
sendJson(res, 404, { code: "NOT_FOUND", message: "asset not found" });
|
|
52327
52376
|
return true;
|
|
@@ -52369,57 +52418,6 @@ function createHttpRouter(deps) {
|
|
|
52369
52418
|
return true;
|
|
52370
52419
|
}
|
|
52371
52420
|
const dispatchArgs = typeof body === "object" && body != null ? body : {};
|
|
52372
|
-
if (method === DISPATCH_HOLD_METHOD) {
|
|
52373
|
-
const heartbeatMs = deps.dispatchHeartbeatMs ?? DISPATCH_HEARTBEAT_MS;
|
|
52374
|
-
let headSent = false;
|
|
52375
|
-
let hbInterval;
|
|
52376
|
-
const startStreaming = () => {
|
|
52377
|
-
headSent = true;
|
|
52378
|
-
req.socket?.setTimeout?.(0);
|
|
52379
|
-
res.socket?.setTimeout?.(0);
|
|
52380
|
-
res.writeHead(200, {
|
|
52381
|
-
"Content-Type": "application/json; charset=utf-8",
|
|
52382
|
-
"Transfer-Encoding": "chunked",
|
|
52383
|
-
// nginx 专用:禁用该响应缓冲,让心跳字节即时 flush 到上游 read(否则被攒着不重置计时)
|
|
52384
|
-
"X-Accel-Buffering": "no",
|
|
52385
|
-
...AUTHED_RPC_CORS_HEADERS
|
|
52386
|
-
});
|
|
52387
|
-
res.write(" ");
|
|
52388
|
-
hbInterval = setInterval(() => {
|
|
52389
|
-
try {
|
|
52390
|
-
res.write(" ");
|
|
52391
|
-
} catch {
|
|
52392
|
-
}
|
|
52393
|
-
}, heartbeatMs);
|
|
52394
|
-
};
|
|
52395
|
-
const graceTimer = setTimeout(startStreaming, heartbeatMs);
|
|
52396
|
-
const cleanup = () => {
|
|
52397
|
-
clearTimeout(graceTimer);
|
|
52398
|
-
if (hbInterval) clearInterval(hbInterval);
|
|
52399
|
-
};
|
|
52400
|
-
const safeEnd = (payload) => {
|
|
52401
|
-
if (res.writableEnded || res.destroyed) return;
|
|
52402
|
-
try {
|
|
52403
|
-
res.end(payload);
|
|
52404
|
-
} catch {
|
|
52405
|
-
}
|
|
52406
|
-
};
|
|
52407
|
-
res.on("close", cleanup);
|
|
52408
|
-
try {
|
|
52409
|
-
const result = await deps.authedRpc.dispatch(method, dispatchArgs, auth.context);
|
|
52410
|
-
cleanup();
|
|
52411
|
-
if (headSent) safeEnd(JSON.stringify({ ok: true, result: result.response }));
|
|
52412
|
-
else sendJson(res, 200, { ok: true, result: result.response }, AUTHED_RPC_CORS_HEADERS);
|
|
52413
|
-
} catch (err) {
|
|
52414
|
-
cleanup();
|
|
52415
|
-
const e = err;
|
|
52416
|
-
const code = e?.code ?? "INTERNAL";
|
|
52417
|
-
const payload = { ok: false, error: code, message: e?.message ?? String(err) };
|
|
52418
|
-
if (headSent) safeEnd(JSON.stringify(payload));
|
|
52419
|
-
else sendJson(res, authedRpcErrorStatus(code), payload, AUTHED_RPC_CORS_HEADERS);
|
|
52420
|
-
}
|
|
52421
|
-
return true;
|
|
52422
|
-
}
|
|
52423
52421
|
try {
|
|
52424
52422
|
const result = await deps.authedRpc.dispatch(method, dispatchArgs, auth.context);
|
|
52425
52423
|
sendJson(res, 200, { ok: true, result: result.response }, AUTHED_RPC_CORS_HEADERS);
|
|
@@ -52430,34 +52428,6 @@ function createHttpRouter(deps) {
|
|
|
52430
52428
|
}
|
|
52431
52429
|
return true;
|
|
52432
52430
|
}
|
|
52433
|
-
if (url.pathname.startsWith(RPC_ROUTE_PREFIX)) {
|
|
52434
|
-
if (!deps.rpcDispatcher) {
|
|
52435
|
-
sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "HTTP RPC adapter not wired" });
|
|
52436
|
-
return true;
|
|
52437
|
-
}
|
|
52438
|
-
if (req.method !== "POST") {
|
|
52439
|
-
sendJson(res, 405, { code: "METHOD_NOT_ALLOWED", message: "POST only" });
|
|
52440
|
-
return true;
|
|
52441
|
-
}
|
|
52442
|
-
if (!isLoopbackAddress(req.socket.remoteAddress)) {
|
|
52443
|
-
sendJson(res, 403, { code: "NOT_LOOPBACK", message: "RPC adapter only accepts loopback connections" });
|
|
52444
|
-
return true;
|
|
52445
|
-
}
|
|
52446
|
-
req.socket.setTimeout(0);
|
|
52447
|
-
res.socket?.setTimeout(0);
|
|
52448
|
-
const method = url.pathname.slice(RPC_ROUTE_PREFIX.length).split("?")[0] ?? "";
|
|
52449
|
-
const sessionId = req.headers["x-clawd-session-id"] ?? void 0;
|
|
52450
|
-
let body;
|
|
52451
|
-
try {
|
|
52452
|
-
body = await readJsonBody(req, RPC_BODY_MAX_BYTES);
|
|
52453
|
-
} catch (err) {
|
|
52454
|
-
sendJson(res, 400, { code: "INVALID_BODY", message: err instanceof Error ? err.message : String(err) });
|
|
52455
|
-
return true;
|
|
52456
|
-
}
|
|
52457
|
-
const result = await handleRpcRequest({ method, body, sessionId, dispatcher: deps.rpcDispatcher });
|
|
52458
|
-
sendJson(res, result.status, result.body);
|
|
52459
|
-
return true;
|
|
52460
|
-
}
|
|
52461
52431
|
if (url.pathname.startsWith("/preview/")) {
|
|
52462
52432
|
const port = matchPreviewPort(url.pathname);
|
|
52463
52433
|
if (port != null && isPreviewPortAllowed(port, { allowedPorts: deps.previewPorts ?? [] })) {
|
|
@@ -52545,7 +52515,7 @@ function createHttpRouter(deps) {
|
|
|
52545
52515
|
sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
|
|
52546
52516
|
return true;
|
|
52547
52517
|
}
|
|
52548
|
-
sendHtml(res, 200, loader.renderViewerHtml(
|
|
52518
|
+
sendHtml(res, 200, loader.renderViewerHtml(import_node_path34.default.basename(r.absPath)));
|
|
52549
52519
|
return true;
|
|
52550
52520
|
}
|
|
52551
52521
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
@@ -52666,7 +52636,7 @@ function createHttpRouter(deps) {
|
|
|
52666
52636
|
return true;
|
|
52667
52637
|
}
|
|
52668
52638
|
let absPath;
|
|
52669
|
-
if (
|
|
52639
|
+
if (import_node_path34.default.isAbsolute(pathParam)) {
|
|
52670
52640
|
absPath = pathParam;
|
|
52671
52641
|
} else if (deps.sessionStore) {
|
|
52672
52642
|
const file = deps.sessionStore.read(sid);
|
|
@@ -52674,7 +52644,7 @@ function createHttpRouter(deps) {
|
|
|
52674
52644
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
52675
52645
|
return true;
|
|
52676
52646
|
}
|
|
52677
|
-
absPath =
|
|
52647
|
+
absPath = import_node_path34.default.join(file.cwd, pathParam);
|
|
52678
52648
|
} else {
|
|
52679
52649
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
52680
52650
|
return true;
|
|
@@ -52761,7 +52731,7 @@ function withCtx(ctx, body) {
|
|
|
52761
52731
|
function streamFile(res, absPath, logger) {
|
|
52762
52732
|
let stat;
|
|
52763
52733
|
try {
|
|
52764
|
-
stat =
|
|
52734
|
+
stat = import_node_fs31.default.statSync(absPath);
|
|
52765
52735
|
} catch (err) {
|
|
52766
52736
|
const code = err?.code;
|
|
52767
52737
|
if (code === "ENOENT") {
|
|
@@ -52776,7 +52746,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52776
52746
|
return;
|
|
52777
52747
|
}
|
|
52778
52748
|
const mime = lookupMime(absPath);
|
|
52779
|
-
const basename =
|
|
52749
|
+
const basename = import_node_path34.default.basename(absPath);
|
|
52780
52750
|
res.writeHead(200, {
|
|
52781
52751
|
"Content-Type": mime,
|
|
52782
52752
|
"Content-Length": String(stat.size),
|
|
@@ -52784,7 +52754,7 @@ function streamFile(res, absPath, logger) {
|
|
|
52784
52754
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
52785
52755
|
"X-Content-Type-Options": "nosniff"
|
|
52786
52756
|
});
|
|
52787
|
-
const stream =
|
|
52757
|
+
const stream = import_node_fs31.default.createReadStream(absPath);
|
|
52788
52758
|
stream.on("error", (err) => {
|
|
52789
52759
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
52790
52760
|
res.destroy();
|
|
@@ -52793,8 +52763,8 @@ function streamFile(res, absPath, logger) {
|
|
|
52793
52763
|
}
|
|
52794
52764
|
|
|
52795
52765
|
// src/attachment/gc.ts
|
|
52796
|
-
var
|
|
52797
|
-
var
|
|
52766
|
+
var import_node_fs32 = __toESM(require("fs"), 1);
|
|
52767
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
52798
52768
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
52799
52769
|
function runAttachmentGc(args) {
|
|
52800
52770
|
const now = (args.now ?? Date.now)();
|
|
@@ -52803,38 +52773,38 @@ function runAttachmentGc(args) {
|
|
|
52803
52773
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52804
52774
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
52805
52775
|
if (entry.stale) continue;
|
|
52806
|
-
if (
|
|
52776
|
+
if (import_node_path35.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
52807
52777
|
}
|
|
52808
52778
|
}
|
|
52809
52779
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
52810
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
52780
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path35.default.join(
|
|
52811
52781
|
args.dataDir,
|
|
52812
52782
|
"sessions",
|
|
52813
52783
|
...scopeSubPath(scope).map(safeFileName),
|
|
52814
52784
|
safeFileName(sessionId)
|
|
52815
52785
|
);
|
|
52816
|
-
const attRoot =
|
|
52786
|
+
const attRoot = import_node_path35.default.join(sessionDir, ".attachments");
|
|
52817
52787
|
let hashDirs;
|
|
52818
52788
|
try {
|
|
52819
|
-
hashDirs =
|
|
52789
|
+
hashDirs = import_node_fs32.default.readdirSync(attRoot);
|
|
52820
52790
|
} catch (err) {
|
|
52821
52791
|
if (err.code === "ENOENT") continue;
|
|
52822
52792
|
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
52823
52793
|
continue;
|
|
52824
52794
|
}
|
|
52825
52795
|
for (const hashDir of hashDirs) {
|
|
52826
|
-
const hashDirAbs =
|
|
52796
|
+
const hashDirAbs = import_node_path35.default.join(attRoot, hashDir);
|
|
52827
52797
|
let files;
|
|
52828
52798
|
try {
|
|
52829
|
-
files =
|
|
52799
|
+
files = import_node_fs32.default.readdirSync(hashDirAbs);
|
|
52830
52800
|
} catch {
|
|
52831
52801
|
continue;
|
|
52832
52802
|
}
|
|
52833
52803
|
for (const name of files) {
|
|
52834
|
-
const file =
|
|
52804
|
+
const file = import_node_path35.default.join(hashDirAbs, name);
|
|
52835
52805
|
let stat;
|
|
52836
52806
|
try {
|
|
52837
|
-
stat =
|
|
52807
|
+
stat = import_node_fs32.default.statSync(file);
|
|
52838
52808
|
} catch {
|
|
52839
52809
|
continue;
|
|
52840
52810
|
}
|
|
@@ -52843,26 +52813,26 @@ function runAttachmentGc(args) {
|
|
|
52843
52813
|
if (age < ttlMs) continue;
|
|
52844
52814
|
if (liveAbs.has(file)) continue;
|
|
52845
52815
|
try {
|
|
52846
|
-
|
|
52816
|
+
import_node_fs32.default.unlinkSync(file);
|
|
52847
52817
|
} catch (err) {
|
|
52848
52818
|
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
52849
52819
|
}
|
|
52850
52820
|
}
|
|
52851
52821
|
try {
|
|
52852
|
-
if (
|
|
52822
|
+
if (import_node_fs32.default.readdirSync(hashDirAbs).length === 0) import_node_fs32.default.rmdirSync(hashDirAbs);
|
|
52853
52823
|
} catch {
|
|
52854
52824
|
}
|
|
52855
52825
|
}
|
|
52856
52826
|
try {
|
|
52857
|
-
if (
|
|
52827
|
+
if (import_node_fs32.default.readdirSync(attRoot).length === 0) import_node_fs32.default.rmdirSync(attRoot);
|
|
52858
52828
|
} catch {
|
|
52859
52829
|
}
|
|
52860
52830
|
}
|
|
52861
52831
|
}
|
|
52862
52832
|
|
|
52863
52833
|
// src/attachment/group.ts
|
|
52864
|
-
var
|
|
52865
|
-
var
|
|
52834
|
+
var import_node_fs33 = __toESM(require("fs"), 1);
|
|
52835
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
52866
52836
|
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
52867
52837
|
init_protocol();
|
|
52868
52838
|
var GroupFileStore = class {
|
|
@@ -52874,11 +52844,11 @@ var GroupFileStore = class {
|
|
|
52874
52844
|
this.logger = opts.logger;
|
|
52875
52845
|
}
|
|
52876
52846
|
rootForScope(scope) {
|
|
52877
|
-
return
|
|
52847
|
+
return import_node_path36.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
52878
52848
|
}
|
|
52879
52849
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
52880
52850
|
filePath(scope, sessionId) {
|
|
52881
|
-
return
|
|
52851
|
+
return import_node_path36.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
52882
52852
|
}
|
|
52883
52853
|
cacheKey(scope, sessionId) {
|
|
52884
52854
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -52887,7 +52857,7 @@ var GroupFileStore = class {
|
|
|
52887
52857
|
readFile(scope, sessionId) {
|
|
52888
52858
|
const file = this.filePath(scope, sessionId);
|
|
52889
52859
|
try {
|
|
52890
|
-
const raw =
|
|
52860
|
+
const raw = import_node_fs33.default.readFileSync(file, "utf8");
|
|
52891
52861
|
const parsed = JSON.parse(raw);
|
|
52892
52862
|
if (!Array.isArray(parsed)) {
|
|
52893
52863
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -52913,10 +52883,10 @@ var GroupFileStore = class {
|
|
|
52913
52883
|
}
|
|
52914
52884
|
writeFile(scope, sessionId, entries) {
|
|
52915
52885
|
const file = this.filePath(scope, sessionId);
|
|
52916
|
-
|
|
52886
|
+
import_node_fs33.default.mkdirSync(import_node_path36.default.dirname(file), { recursive: true });
|
|
52917
52887
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
52918
|
-
|
|
52919
|
-
|
|
52888
|
+
import_node_fs33.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
52889
|
+
import_node_fs33.default.renameSync(tmp, file);
|
|
52920
52890
|
}
|
|
52921
52891
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
52922
52892
|
list(scope, sessionId) {
|
|
@@ -53002,10 +52972,10 @@ var GroupFileStore = class {
|
|
|
53002
52972
|
};
|
|
53003
52973
|
|
|
53004
52974
|
// src/discovery/state-file.ts
|
|
53005
|
-
var
|
|
53006
|
-
var
|
|
52975
|
+
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
52976
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
53007
52977
|
function defaultStateFilePath(dataDir) {
|
|
53008
|
-
return
|
|
52978
|
+
return import_node_path37.default.join(dataDir, "state.json");
|
|
53009
52979
|
}
|
|
53010
52980
|
function isPidAlive(pid) {
|
|
53011
52981
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -53027,7 +52997,7 @@ var StateFileManager = class {
|
|
|
53027
52997
|
}
|
|
53028
52998
|
read() {
|
|
53029
52999
|
try {
|
|
53030
|
-
const raw =
|
|
53000
|
+
const raw = import_node_fs34.default.readFileSync(this.file, "utf8");
|
|
53031
53001
|
const parsed = JSON.parse(raw);
|
|
53032
53002
|
return parsed;
|
|
53033
53003
|
} catch {
|
|
@@ -53041,20 +53011,20 @@ var StateFileManager = class {
|
|
|
53041
53011
|
return { status: "stale", existing };
|
|
53042
53012
|
}
|
|
53043
53013
|
write(state) {
|
|
53044
|
-
|
|
53014
|
+
import_node_fs34.default.mkdirSync(import_node_path37.default.dirname(this.file), { recursive: true });
|
|
53045
53015
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
53046
|
-
|
|
53047
|
-
|
|
53016
|
+
import_node_fs34.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
53017
|
+
import_node_fs34.default.renameSync(tmp, this.file);
|
|
53048
53018
|
if (process.platform !== "win32") {
|
|
53049
53019
|
try {
|
|
53050
|
-
|
|
53020
|
+
import_node_fs34.default.chmodSync(this.file, 384);
|
|
53051
53021
|
} catch {
|
|
53052
53022
|
}
|
|
53053
53023
|
}
|
|
53054
53024
|
}
|
|
53055
53025
|
delete() {
|
|
53056
53026
|
try {
|
|
53057
|
-
|
|
53027
|
+
import_node_fs34.default.unlinkSync(this.file);
|
|
53058
53028
|
} catch {
|
|
53059
53029
|
}
|
|
53060
53030
|
}
|
|
@@ -53068,14 +53038,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
|
|
|
53068
53038
|
}
|
|
53069
53039
|
|
|
53070
53040
|
// src/tunnel/tunnel-manager.ts
|
|
53071
|
-
var
|
|
53072
|
-
var
|
|
53041
|
+
var import_node_fs38 = __toESM(require("fs"), 1);
|
|
53042
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
53073
53043
|
var import_node_crypto10 = __toESM(require("crypto"), 1);
|
|
53074
53044
|
var import_node_child_process10 = require("child_process");
|
|
53075
53045
|
|
|
53076
53046
|
// src/tunnel/tunnel-store.ts
|
|
53077
|
-
var
|
|
53078
|
-
var
|
|
53047
|
+
var import_node_fs35 = __toESM(require("fs"), 1);
|
|
53048
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
53079
53049
|
var TunnelStore = class {
|
|
53080
53050
|
constructor(filePath) {
|
|
53081
53051
|
this.filePath = filePath;
|
|
@@ -53083,7 +53053,7 @@ var TunnelStore = class {
|
|
|
53083
53053
|
filePath;
|
|
53084
53054
|
async get() {
|
|
53085
53055
|
try {
|
|
53086
|
-
const raw = await
|
|
53056
|
+
const raw = await import_node_fs35.default.promises.readFile(this.filePath, "utf8");
|
|
53087
53057
|
const obj = JSON.parse(raw);
|
|
53088
53058
|
if (!isPersistedTunnel(obj)) return null;
|
|
53089
53059
|
return obj;
|
|
@@ -53094,22 +53064,22 @@ var TunnelStore = class {
|
|
|
53094
53064
|
}
|
|
53095
53065
|
}
|
|
53096
53066
|
async set(v2) {
|
|
53097
|
-
const dir =
|
|
53098
|
-
await
|
|
53067
|
+
const dir = import_node_path38.default.dirname(this.filePath);
|
|
53068
|
+
await import_node_fs35.default.promises.mkdir(dir, { recursive: true });
|
|
53099
53069
|
const data = JSON.stringify(v2, null, 2);
|
|
53100
53070
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
53101
|
-
await
|
|
53071
|
+
await import_node_fs35.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
53102
53072
|
if (process.platform !== "win32") {
|
|
53103
53073
|
try {
|
|
53104
|
-
await
|
|
53074
|
+
await import_node_fs35.default.promises.chmod(tmp, 384);
|
|
53105
53075
|
} catch {
|
|
53106
53076
|
}
|
|
53107
53077
|
}
|
|
53108
|
-
await
|
|
53078
|
+
await import_node_fs35.default.promises.rename(tmp, this.filePath);
|
|
53109
53079
|
}
|
|
53110
53080
|
async clear() {
|
|
53111
53081
|
try {
|
|
53112
|
-
await
|
|
53082
|
+
await import_node_fs35.default.promises.unlink(this.filePath);
|
|
53113
53083
|
} catch (err) {
|
|
53114
53084
|
const code = err?.code;
|
|
53115
53085
|
if (code !== "ENOENT") throw err;
|
|
@@ -53204,9 +53174,9 @@ function escape(v2) {
|
|
|
53204
53174
|
}
|
|
53205
53175
|
|
|
53206
53176
|
// src/tunnel/frpc-binary.ts
|
|
53207
|
-
var
|
|
53177
|
+
var import_node_fs36 = __toESM(require("fs"), 1);
|
|
53208
53178
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
53209
|
-
var
|
|
53179
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
53210
53180
|
var import_node_child_process8 = require("child_process");
|
|
53211
53181
|
var import_node_stream3 = require("stream");
|
|
53212
53182
|
var import_promises5 = require("stream/promises");
|
|
@@ -53238,20 +53208,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
53238
53208
|
}
|
|
53239
53209
|
async function ensureFrpcBinary(opts) {
|
|
53240
53210
|
if (opts.override) {
|
|
53241
|
-
if (!
|
|
53211
|
+
if (!import_node_fs36.default.existsSync(opts.override)) {
|
|
53242
53212
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
53243
53213
|
}
|
|
53244
53214
|
return opts.override;
|
|
53245
53215
|
}
|
|
53246
53216
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
53247
53217
|
const platform = opts.platform ?? detectPlatform();
|
|
53248
|
-
const binDir =
|
|
53249
|
-
|
|
53218
|
+
const binDir = import_node_path39.default.join(opts.dataDir, "bin");
|
|
53219
|
+
import_node_fs36.default.mkdirSync(binDir, { recursive: true });
|
|
53250
53220
|
cleanupStaleArtifacts(binDir);
|
|
53251
|
-
const stableBin =
|
|
53252
|
-
if (
|
|
53221
|
+
const stableBin = import_node_path39.default.join(binDir, "frpc");
|
|
53222
|
+
if (import_node_fs36.default.existsSync(stableBin)) return stableBin;
|
|
53253
53223
|
const partialBin = `${stableBin}.partial`;
|
|
53254
|
-
const tarballPath =
|
|
53224
|
+
const tarballPath = import_node_path39.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
53255
53225
|
try {
|
|
53256
53226
|
const url = frpcDownloadUrl(version2, platform);
|
|
53257
53227
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -53260,8 +53230,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
53260
53230
|
} else {
|
|
53261
53231
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
53262
53232
|
}
|
|
53263
|
-
|
|
53264
|
-
|
|
53233
|
+
import_node_fs36.default.chmodSync(partialBin, 493);
|
|
53234
|
+
import_node_fs36.default.renameSync(partialBin, stableBin);
|
|
53265
53235
|
} finally {
|
|
53266
53236
|
safeUnlink(tarballPath);
|
|
53267
53237
|
safeUnlink(partialBin);
|
|
@@ -53271,15 +53241,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
53271
53241
|
function cleanupStaleArtifacts(binDir) {
|
|
53272
53242
|
let entries;
|
|
53273
53243
|
try {
|
|
53274
|
-
entries =
|
|
53244
|
+
entries = import_node_fs36.default.readdirSync(binDir);
|
|
53275
53245
|
} catch {
|
|
53276
53246
|
return;
|
|
53277
53247
|
}
|
|
53278
53248
|
for (const name of entries) {
|
|
53279
53249
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
53280
|
-
const full =
|
|
53250
|
+
const full = import_node_path39.default.join(binDir, name);
|
|
53281
53251
|
try {
|
|
53282
|
-
|
|
53252
|
+
import_node_fs36.default.rmSync(full, { recursive: true, force: true });
|
|
53283
53253
|
} catch {
|
|
53284
53254
|
}
|
|
53285
53255
|
}
|
|
@@ -53287,7 +53257,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
53287
53257
|
}
|
|
53288
53258
|
function safeUnlink(p2) {
|
|
53289
53259
|
try {
|
|
53290
|
-
|
|
53260
|
+
import_node_fs36.default.unlinkSync(p2);
|
|
53291
53261
|
} catch {
|
|
53292
53262
|
}
|
|
53293
53263
|
}
|
|
@@ -53298,13 +53268,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
53298
53268
|
if (!res.ok || !res.body) {
|
|
53299
53269
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
53300
53270
|
}
|
|
53301
|
-
const out =
|
|
53271
|
+
const out = import_node_fs36.default.createWriteStream(dest);
|
|
53302
53272
|
const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
|
|
53303
53273
|
await (0, import_promises5.pipeline)(nodeStream, out);
|
|
53304
53274
|
}
|
|
53305
53275
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
53306
|
-
const work =
|
|
53307
|
-
|
|
53276
|
+
const work = import_node_path39.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
53277
|
+
import_node_fs36.default.mkdirSync(work, { recursive: true });
|
|
53308
53278
|
try {
|
|
53309
53279
|
await new Promise((resolve6, reject) => {
|
|
53310
53280
|
const proc = (0, import_node_child_process8.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -53312,32 +53282,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
53312
53282
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
53313
53283
|
});
|
|
53314
53284
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
53315
|
-
const src =
|
|
53316
|
-
if (!
|
|
53285
|
+
const src = import_node_path39.default.join(work, dirName, "frpc");
|
|
53286
|
+
if (!import_node_fs36.default.existsSync(src)) {
|
|
53317
53287
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
53318
53288
|
}
|
|
53319
|
-
|
|
53289
|
+
import_node_fs36.default.copyFileSync(src, destBin);
|
|
53320
53290
|
} finally {
|
|
53321
|
-
|
|
53291
|
+
import_node_fs36.default.rmSync(work, { recursive: true, force: true });
|
|
53322
53292
|
}
|
|
53323
53293
|
}
|
|
53324
53294
|
|
|
53325
53295
|
// src/tunnel/frpc-process.ts
|
|
53326
|
-
var
|
|
53327
|
-
var
|
|
53296
|
+
var import_node_fs37 = __toESM(require("fs"), 1);
|
|
53297
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
53328
53298
|
var import_node_child_process9 = require("child_process");
|
|
53329
53299
|
function frpcPidFilePath(dataDir) {
|
|
53330
|
-
return
|
|
53300
|
+
return import_node_path40.default.join(dataDir, "frpc.pid");
|
|
53331
53301
|
}
|
|
53332
53302
|
function writeFrpcPid(dataDir, pid) {
|
|
53333
53303
|
try {
|
|
53334
|
-
|
|
53304
|
+
import_node_fs37.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
53335
53305
|
} catch {
|
|
53336
53306
|
}
|
|
53337
53307
|
}
|
|
53338
53308
|
function clearFrpcPid(dataDir) {
|
|
53339
53309
|
try {
|
|
53340
|
-
|
|
53310
|
+
import_node_fs37.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
53341
53311
|
} catch {
|
|
53342
53312
|
}
|
|
53343
53313
|
}
|
|
@@ -53353,7 +53323,7 @@ function defaultIsPidAlive(pid) {
|
|
|
53353
53323
|
}
|
|
53354
53324
|
function defaultReadPidFile(file) {
|
|
53355
53325
|
try {
|
|
53356
|
-
return
|
|
53326
|
+
return import_node_fs37.default.readFileSync(file, "utf8");
|
|
53357
53327
|
} catch {
|
|
53358
53328
|
return null;
|
|
53359
53329
|
}
|
|
@@ -53364,17 +53334,17 @@ function defaultKillPid(pid, signal) {
|
|
|
53364
53334
|
} catch {
|
|
53365
53335
|
}
|
|
53366
53336
|
}
|
|
53367
|
-
function
|
|
53337
|
+
function defaultSleep2(ms) {
|
|
53368
53338
|
return new Promise((r) => setTimeout(r, ms));
|
|
53369
53339
|
}
|
|
53370
53340
|
async function killStaleFrpc(deps) {
|
|
53371
53341
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
53372
|
-
const tomlPath =
|
|
53342
|
+
const tomlPath = import_node_path40.default.join(deps.dataDir, "frpc.toml");
|
|
53373
53343
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
53374
53344
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
53375
53345
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
53376
53346
|
const scanPids = deps.scanFrpcPidsImpl ?? ((tp) => defaultScanFrpcPidsByCmdline(tp, deps.logger));
|
|
53377
|
-
const sleep2 = deps.sleepImpl ??
|
|
53347
|
+
const sleep2 = deps.sleepImpl ?? defaultSleep2;
|
|
53378
53348
|
const victims = /* @__PURE__ */ new Set();
|
|
53379
53349
|
const raw = readPidFile(pidFile);
|
|
53380
53350
|
if (raw) {
|
|
@@ -53393,7 +53363,7 @@ async function killStaleFrpc(deps) {
|
|
|
53393
53363
|
}
|
|
53394
53364
|
if (victims.size === 0) {
|
|
53395
53365
|
try {
|
|
53396
|
-
|
|
53366
|
+
import_node_fs37.default.unlinkSync(pidFile);
|
|
53397
53367
|
} catch {
|
|
53398
53368
|
}
|
|
53399
53369
|
return;
|
|
@@ -53404,7 +53374,7 @@ async function killStaleFrpc(deps) {
|
|
|
53404
53374
|
}
|
|
53405
53375
|
await sleep2(deps.reapWaitMs ?? 300);
|
|
53406
53376
|
try {
|
|
53407
|
-
|
|
53377
|
+
import_node_fs37.default.unlinkSync(pidFile);
|
|
53408
53378
|
} catch {
|
|
53409
53379
|
}
|
|
53410
53380
|
}
|
|
@@ -53441,7 +53411,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
53441
53411
|
var TunnelManager = class {
|
|
53442
53412
|
constructor(deps) {
|
|
53443
53413
|
this.deps = deps;
|
|
53444
|
-
this.store = deps.store ?? new TunnelStore(
|
|
53414
|
+
this.store = deps.store ?? new TunnelStore(import_node_path41.default.join(deps.dataDir, "tunnel.json"));
|
|
53445
53415
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
53446
53416
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
53447
53417
|
}
|
|
@@ -53568,7 +53538,7 @@ var TunnelManager = class {
|
|
|
53568
53538
|
dataDir: this.deps.dataDir,
|
|
53569
53539
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
53570
53540
|
});
|
|
53571
|
-
const tomlPath =
|
|
53541
|
+
const tomlPath = import_node_path41.default.join(this.deps.dataDir, "frpc.toml");
|
|
53572
53542
|
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
|
|
53573
53543
|
const toml = buildFrpcToml({
|
|
53574
53544
|
serverAddr: t.frpsHost,
|
|
@@ -53579,14 +53549,14 @@ var TunnelManager = class {
|
|
|
53579
53549
|
localPort,
|
|
53580
53550
|
logLevel: "info"
|
|
53581
53551
|
});
|
|
53582
|
-
await
|
|
53552
|
+
await import_node_fs38.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
53583
53553
|
const proc = (this.deps.spawnImpl ?? import_node_child_process10.spawn)(frpcBin, ["-c", tomlPath], {
|
|
53584
53554
|
stdio: ["ignore", "pipe", "pipe"]
|
|
53585
53555
|
});
|
|
53586
|
-
const logDir =
|
|
53587
|
-
|
|
53588
|
-
const logFilePath =
|
|
53589
|
-
const logStream =
|
|
53556
|
+
const logDir = import_node_path41.default.join(this.deps.dataDir, "log");
|
|
53557
|
+
import_node_fs38.default.mkdirSync(logDir, { recursive: true });
|
|
53558
|
+
const logFilePath = import_node_path41.default.join(logDir, "frpc.log");
|
|
53559
|
+
const logStream = import_node_fs38.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
53590
53560
|
logStream.on("error", () => {
|
|
53591
53561
|
});
|
|
53592
53562
|
const tee = (chunk) => {
|
|
@@ -53669,27 +53639,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
53669
53639
|
|
|
53670
53640
|
// src/tunnel/device-key.ts
|
|
53671
53641
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
53672
|
-
var
|
|
53642
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
53673
53643
|
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
53674
53644
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
53675
53645
|
function deriveStableDeviceKey(opts = {}) {
|
|
53676
53646
|
const hostname = opts.hostname ?? import_node_os14.default.hostname();
|
|
53677
53647
|
const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
|
|
53678
53648
|
const home = opts.home ?? import_node_os14.default.homedir();
|
|
53679
|
-
const defaultDataDir =
|
|
53680
|
-
const normalizedDataDir = opts.dataDir ?
|
|
53649
|
+
const defaultDataDir = import_node_path42.default.resolve(import_node_path42.default.join(home, ".clawd"));
|
|
53650
|
+
const normalizedDataDir = opts.dataDir ? import_node_path42.default.resolve(opts.dataDir) : null;
|
|
53681
53651
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
53682
53652
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
53683
53653
|
return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
53684
53654
|
}
|
|
53685
53655
|
|
|
53686
53656
|
// src/auth-store.ts
|
|
53687
|
-
var
|
|
53688
|
-
var
|
|
53657
|
+
var import_node_fs39 = __toESM(require("fs"), 1);
|
|
53658
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
53689
53659
|
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
53690
53660
|
var AUTH_FILE_NAME = "auth.json";
|
|
53691
53661
|
function authFilePath(dataDir) {
|
|
53692
|
-
return
|
|
53662
|
+
return import_node_path43.default.join(dataDir, AUTH_FILE_NAME);
|
|
53693
53663
|
}
|
|
53694
53664
|
function loadOrCreateAuthFile(opts) {
|
|
53695
53665
|
const file = authFilePath(opts.dataDir);
|
|
@@ -53725,7 +53695,7 @@ function defaultGenerateOwnerPrincipalId() {
|
|
|
53725
53695
|
}
|
|
53726
53696
|
function readAuthFile(file) {
|
|
53727
53697
|
try {
|
|
53728
|
-
const raw =
|
|
53698
|
+
const raw = import_node_fs39.default.readFileSync(file, "utf8");
|
|
53729
53699
|
const parsed = JSON.parse(raw);
|
|
53730
53700
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
53731
53701
|
return null;
|
|
@@ -53745,25 +53715,25 @@ function readAuthFile(file) {
|
|
|
53745
53715
|
}
|
|
53746
53716
|
}
|
|
53747
53717
|
function writeAuthFile(file, content) {
|
|
53748
|
-
|
|
53749
|
-
|
|
53718
|
+
import_node_fs39.default.mkdirSync(import_node_path43.default.dirname(file), { recursive: true });
|
|
53719
|
+
import_node_fs39.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
53750
53720
|
try {
|
|
53751
|
-
|
|
53721
|
+
import_node_fs39.default.chmodSync(file, 384);
|
|
53752
53722
|
} catch {
|
|
53753
53723
|
}
|
|
53754
53724
|
}
|
|
53755
53725
|
|
|
53756
53726
|
// src/owner-profile.ts
|
|
53757
|
-
var
|
|
53727
|
+
var import_node_fs40 = __toESM(require("fs"), 1);
|
|
53758
53728
|
var import_node_os15 = __toESM(require("os"), 1);
|
|
53759
|
-
var
|
|
53729
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
53760
53730
|
var PROFILE_FILENAME = "profile.json";
|
|
53761
53731
|
function loadOwnerDisplayName(dataDir) {
|
|
53762
53732
|
const fallback = import_node_os15.default.userInfo().username;
|
|
53763
|
-
const profilePath =
|
|
53733
|
+
const profilePath = import_node_path44.default.join(dataDir, PROFILE_FILENAME);
|
|
53764
53734
|
let raw;
|
|
53765
53735
|
try {
|
|
53766
|
-
raw =
|
|
53736
|
+
raw = import_node_fs40.default.readFileSync(profilePath, "utf8");
|
|
53767
53737
|
} catch {
|
|
53768
53738
|
return fallback;
|
|
53769
53739
|
}
|
|
@@ -53786,18 +53756,18 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
53786
53756
|
}
|
|
53787
53757
|
|
|
53788
53758
|
// src/feishu-auth/owner-identity-store.ts
|
|
53789
|
-
var
|
|
53790
|
-
var
|
|
53759
|
+
var import_node_fs41 = __toESM(require("fs"), 1);
|
|
53760
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
53791
53761
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
53792
53762
|
var OwnerIdentityStore = class {
|
|
53793
53763
|
file;
|
|
53794
53764
|
constructor(dataDir) {
|
|
53795
|
-
this.file =
|
|
53765
|
+
this.file = import_node_path45.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
53796
53766
|
}
|
|
53797
53767
|
read() {
|
|
53798
53768
|
let raw;
|
|
53799
53769
|
try {
|
|
53800
|
-
raw =
|
|
53770
|
+
raw = import_node_fs41.default.readFileSync(this.file, "utf8");
|
|
53801
53771
|
} catch {
|
|
53802
53772
|
return null;
|
|
53803
53773
|
}
|
|
@@ -53825,16 +53795,16 @@ var OwnerIdentityStore = class {
|
|
|
53825
53795
|
};
|
|
53826
53796
|
}
|
|
53827
53797
|
write(record) {
|
|
53828
|
-
|
|
53829
|
-
|
|
53798
|
+
import_node_fs41.default.mkdirSync(import_node_path45.default.dirname(this.file), { recursive: true });
|
|
53799
|
+
import_node_fs41.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
53830
53800
|
try {
|
|
53831
|
-
|
|
53801
|
+
import_node_fs41.default.chmodSync(this.file, 384);
|
|
53832
53802
|
} catch {
|
|
53833
53803
|
}
|
|
53834
53804
|
}
|
|
53835
53805
|
clear() {
|
|
53836
53806
|
try {
|
|
53837
|
-
|
|
53807
|
+
import_node_fs41.default.unlinkSync(this.file);
|
|
53838
53808
|
} catch (err) {
|
|
53839
53809
|
const code = err?.code;
|
|
53840
53810
|
if (code !== "ENOENT") throw err;
|
|
@@ -53971,9 +53941,9 @@ var CentralClientError = class extends Error {
|
|
|
53971
53941
|
code;
|
|
53972
53942
|
cause;
|
|
53973
53943
|
};
|
|
53974
|
-
async function centralRequest(opts,
|
|
53944
|
+
async function centralRequest(opts, path75, init) {
|
|
53975
53945
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
53976
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
53946
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path75}`;
|
|
53977
53947
|
const ctrl = new AbortController();
|
|
53978
53948
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
53979
53949
|
let res;
|
|
@@ -54167,8 +54137,8 @@ function verifyConnectToken(args) {
|
|
|
54167
54137
|
}
|
|
54168
54138
|
|
|
54169
54139
|
// src/feishu-auth/server-key.ts
|
|
54170
|
-
var
|
|
54171
|
-
var
|
|
54140
|
+
var fs51 = __toESM(require("fs"), 1);
|
|
54141
|
+
var path54 = __toESM(require("path"), 1);
|
|
54172
54142
|
var FILE_NAME2 = "server-signing-key.json";
|
|
54173
54143
|
var ServerKeyStore = class {
|
|
54174
54144
|
constructor(dataDir) {
|
|
@@ -54176,12 +54146,12 @@ var ServerKeyStore = class {
|
|
|
54176
54146
|
}
|
|
54177
54147
|
dataDir;
|
|
54178
54148
|
filePath() {
|
|
54179
|
-
return
|
|
54149
|
+
return path54.join(this.dataDir, FILE_NAME2);
|
|
54180
54150
|
}
|
|
54181
54151
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
54182
54152
|
read() {
|
|
54183
54153
|
try {
|
|
54184
|
-
const raw =
|
|
54154
|
+
const raw = fs51.readFileSync(this.filePath(), "utf8");
|
|
54185
54155
|
const parsed = JSON.parse(raw);
|
|
54186
54156
|
if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
|
|
54187
54157
|
return parsed.publicKeyPem;
|
|
@@ -54196,12 +54166,12 @@ var ServerKeyStore = class {
|
|
|
54196
54166
|
publicKeyPem,
|
|
54197
54167
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
54198
54168
|
};
|
|
54199
|
-
|
|
54200
|
-
|
|
54169
|
+
fs51.mkdirSync(this.dataDir, { recursive: true });
|
|
54170
|
+
fs51.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
|
|
54201
54171
|
}
|
|
54202
54172
|
clear() {
|
|
54203
54173
|
try {
|
|
54204
|
-
|
|
54174
|
+
fs51.unlinkSync(this.filePath());
|
|
54205
54175
|
} catch {
|
|
54206
54176
|
}
|
|
54207
54177
|
}
|
|
@@ -54214,12 +54184,12 @@ init_protocol();
|
|
|
54214
54184
|
init_protocol();
|
|
54215
54185
|
|
|
54216
54186
|
// src/session/fork.ts
|
|
54217
|
-
var
|
|
54187
|
+
var import_node_fs42 = __toESM(require("fs"), 1);
|
|
54218
54188
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
54219
|
-
var
|
|
54189
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
54220
54190
|
init_claude_history();
|
|
54221
54191
|
function readJsonlEntries(file) {
|
|
54222
|
-
const raw =
|
|
54192
|
+
const raw = import_node_fs42.default.readFileSync(file, "utf8");
|
|
54223
54193
|
const out = [];
|
|
54224
54194
|
for (const line of raw.split("\n")) {
|
|
54225
54195
|
const t = line.trim();
|
|
@@ -54232,19 +54202,19 @@ function readJsonlEntries(file) {
|
|
|
54232
54202
|
return out;
|
|
54233
54203
|
}
|
|
54234
54204
|
function forkSession(input) {
|
|
54235
|
-
const baseDir = input.baseDir ??
|
|
54236
|
-
let projectDir =
|
|
54237
|
-
let sourceFile =
|
|
54238
|
-
if (!
|
|
54205
|
+
const baseDir = input.baseDir ?? import_node_path46.default.join(import_node_os16.default.homedir(), ".claude");
|
|
54206
|
+
let projectDir = import_node_path46.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
54207
|
+
let sourceFile = import_node_path46.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
54208
|
+
if (!import_node_fs42.default.existsSync(sourceFile)) {
|
|
54239
54209
|
const found = findTranscriptByToolSessionId(
|
|
54240
|
-
|
|
54210
|
+
import_node_path46.default.join(baseDir, "projects"),
|
|
54241
54211
|
input.toolSessionId
|
|
54242
54212
|
);
|
|
54243
54213
|
if (!found) {
|
|
54244
54214
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
54245
54215
|
}
|
|
54246
54216
|
sourceFile = found;
|
|
54247
|
-
projectDir =
|
|
54217
|
+
projectDir = import_node_path46.default.dirname(found);
|
|
54248
54218
|
}
|
|
54249
54219
|
const entries = readJsonlEntries(sourceFile);
|
|
54250
54220
|
const mainEntries = entries.filter((e) => e.isSidechain !== true);
|
|
@@ -54273,9 +54243,9 @@ function forkSession(input) {
|
|
|
54273
54243
|
}
|
|
54274
54244
|
forkedLines.push(JSON.stringify(forked));
|
|
54275
54245
|
}
|
|
54276
|
-
const forkedFilePath =
|
|
54277
|
-
|
|
54278
|
-
|
|
54246
|
+
const forkedFilePath = import_node_path46.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
54247
|
+
import_node_fs42.default.mkdirSync(projectDir, { recursive: true });
|
|
54248
|
+
import_node_fs42.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
54279
54249
|
return { forkedToolSessionId, forkedFilePath };
|
|
54280
54250
|
}
|
|
54281
54251
|
|
|
@@ -54687,7 +54657,7 @@ function buildPermissionHandlers(deps) {
|
|
|
54687
54657
|
}
|
|
54688
54658
|
|
|
54689
54659
|
// src/handlers/history.ts
|
|
54690
|
-
var
|
|
54660
|
+
var path57 = __toESM(require("path"), 1);
|
|
54691
54661
|
init_protocol();
|
|
54692
54662
|
|
|
54693
54663
|
// src/session/recent-dirs.ts
|
|
@@ -54705,7 +54675,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
54705
54675
|
}
|
|
54706
54676
|
|
|
54707
54677
|
// src/permission/persona-paths.ts
|
|
54708
|
-
var
|
|
54678
|
+
var path56 = __toESM(require("path"), 1);
|
|
54709
54679
|
function getAllowedPersonaIds(grants, action) {
|
|
54710
54680
|
const ids = /* @__PURE__ */ new Set();
|
|
54711
54681
|
for (const g2 of grants) {
|
|
@@ -54718,42 +54688,42 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
54718
54688
|
return ids;
|
|
54719
54689
|
}
|
|
54720
54690
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
54721
|
-
const target =
|
|
54691
|
+
const target = path56.resolve(absPath);
|
|
54722
54692
|
if (userWorkDir) {
|
|
54723
|
-
const u =
|
|
54724
|
-
const usep = u.endsWith(
|
|
54693
|
+
const u = path56.resolve(userWorkDir);
|
|
54694
|
+
const usep = u.endsWith(path56.sep) ? "" : path56.sep;
|
|
54725
54695
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
54726
54696
|
}
|
|
54727
|
-
const root =
|
|
54728
|
-
const sep3 = root.endsWith(
|
|
54697
|
+
const root = path56.resolve(personaRoot);
|
|
54698
|
+
const sep3 = root.endsWith(path56.sep) ? "" : path56.sep;
|
|
54729
54699
|
if (!target.startsWith(root + sep3)) return false;
|
|
54730
|
-
const rel =
|
|
54700
|
+
const rel = path56.relative(root, target);
|
|
54731
54701
|
if (!rel || rel.startsWith("..")) return false;
|
|
54732
|
-
const personaId = rel.split(
|
|
54702
|
+
const personaId = rel.split(path56.sep)[0];
|
|
54733
54703
|
if (!personaId) return false;
|
|
54734
54704
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
54735
54705
|
if (allowed === "*") return true;
|
|
54736
54706
|
return allowed.has(personaId);
|
|
54737
54707
|
}
|
|
54738
54708
|
function personaIdFromPath(absPath, personaRoot) {
|
|
54739
|
-
const root =
|
|
54740
|
-
const target =
|
|
54741
|
-
const sep3 = root.endsWith(
|
|
54709
|
+
const root = path56.resolve(personaRoot);
|
|
54710
|
+
const target = path56.resolve(absPath);
|
|
54711
|
+
const sep3 = root.endsWith(path56.sep) ? "" : path56.sep;
|
|
54742
54712
|
if (!target.startsWith(root + sep3)) return null;
|
|
54743
|
-
const rel =
|
|
54713
|
+
const rel = path56.relative(root, target);
|
|
54744
54714
|
if (!rel || rel.startsWith("..")) return null;
|
|
54745
|
-
const id = rel.split(
|
|
54715
|
+
const id = rel.split(path56.sep)[0];
|
|
54746
54716
|
return id || null;
|
|
54747
54717
|
}
|
|
54748
54718
|
function isPathWithin(dir, absPath) {
|
|
54749
|
-
const d =
|
|
54750
|
-
const t =
|
|
54751
|
-
const sep3 = d.endsWith(
|
|
54719
|
+
const d = path56.resolve(dir);
|
|
54720
|
+
const t = path56.resolve(absPath);
|
|
54721
|
+
const sep3 = d.endsWith(path56.sep) ? "" : path56.sep;
|
|
54752
54722
|
return t === d || t.startsWith(d + sep3);
|
|
54753
54723
|
}
|
|
54754
54724
|
function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
|
|
54755
54725
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
54756
|
-
return personaIdFromPath(
|
|
54726
|
+
return personaIdFromPath(path56.resolve(absPath), personaRoot) === personaId;
|
|
54757
54727
|
}
|
|
54758
54728
|
|
|
54759
54729
|
// src/handlers/history.ts
|
|
@@ -54805,7 +54775,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54805
54775
|
if (!pid) return false;
|
|
54806
54776
|
return isGuestPathAllowed(
|
|
54807
54777
|
ctx.grants,
|
|
54808
|
-
|
|
54778
|
+
path57.join(personaRoot, pid),
|
|
54809
54779
|
personaRoot,
|
|
54810
54780
|
"read",
|
|
54811
54781
|
userWorkDir
|
|
@@ -54817,7 +54787,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54817
54787
|
};
|
|
54818
54788
|
const list = async (frame, _client, ctx) => {
|
|
54819
54789
|
const args = HistoryListArgs.parse(frame);
|
|
54820
|
-
assertGuestPath(ctx,
|
|
54790
|
+
assertGuestPath(ctx, path57.resolve(args.projectPath), personaRoot, "history:list");
|
|
54821
54791
|
const sessions = await history.listSessions(args);
|
|
54822
54792
|
return { response: { type: "history:list", sessions } };
|
|
54823
54793
|
};
|
|
@@ -54850,13 +54820,13 @@ function buildHistoryHandlers(deps) {
|
|
|
54850
54820
|
};
|
|
54851
54821
|
const subagents = async (frame, _client, ctx) => {
|
|
54852
54822
|
const args = HistorySubagentsArgs.parse(frame);
|
|
54853
|
-
assertGuestPath(ctx,
|
|
54823
|
+
assertGuestPath(ctx, path57.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
54854
54824
|
const subs = await history.listSubagents(args);
|
|
54855
54825
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
54856
54826
|
};
|
|
54857
54827
|
const subagentRead = async (frame, _client, ctx) => {
|
|
54858
54828
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
54859
|
-
assertGuestPath(ctx,
|
|
54829
|
+
assertGuestPath(ctx, path57.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
54860
54830
|
const res = await history.readSubagent(args);
|
|
54861
54831
|
return { response: { type: "history:subagent-read", ...res } };
|
|
54862
54832
|
};
|
|
@@ -54865,7 +54835,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54865
54835
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
54866
54836
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
54867
54837
|
const filtered = dirs.filter(
|
|
54868
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
54838
|
+
(d) => isGuestPathAllowed(ctx.grants, path57.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
54869
54839
|
);
|
|
54870
54840
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
54871
54841
|
}
|
|
@@ -54882,7 +54852,7 @@ function buildHistoryHandlers(deps) {
|
|
|
54882
54852
|
}
|
|
54883
54853
|
|
|
54884
54854
|
// src/handlers/workspace.ts
|
|
54885
|
-
var
|
|
54855
|
+
var path58 = __toESM(require("path"), 1);
|
|
54886
54856
|
var os16 = __toESM(require("os"), 1);
|
|
54887
54857
|
init_protocol();
|
|
54888
54858
|
init_protocol();
|
|
@@ -54924,22 +54894,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54924
54894
|
const args = WorkspaceListArgs.parse(frame);
|
|
54925
54895
|
const isGuest = ctx?.principal.kind === "guest";
|
|
54926
54896
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
|
|
54927
|
-
const resolvedCwd =
|
|
54928
|
-
const target = args.path ?
|
|
54897
|
+
const resolvedCwd = path58.resolve(args.cwd ?? fallbackCwd);
|
|
54898
|
+
const target = args.path ? path58.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
54929
54899
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
54930
54900
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
54931
54901
|
return { response: { type: "workspace:list", ...res } };
|
|
54932
54902
|
};
|
|
54933
54903
|
const read = async (frame, _client, ctx) => {
|
|
54934
54904
|
const args = WorkspaceReadArgs.parse(frame);
|
|
54935
|
-
const target =
|
|
54905
|
+
const target = path58.isAbsolute(args.path) ? path58.resolve(args.path) : path58.resolve(args.cwd, args.path);
|
|
54936
54906
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
54937
54907
|
const res = workspace.read(args);
|
|
54938
54908
|
return { response: { type: "workspace:read", ...res } };
|
|
54939
54909
|
};
|
|
54940
54910
|
const skillsList = async (frame, _client, ctx) => {
|
|
54941
54911
|
const args = SkillsListArgs.parse(frame);
|
|
54942
|
-
const cwdAbs =
|
|
54912
|
+
const cwdAbs = path58.resolve(args.cwd);
|
|
54943
54913
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
54944
54914
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
54945
54915
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -54951,7 +54921,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54951
54921
|
};
|
|
54952
54922
|
const agentsList = async (frame, _client, ctx) => {
|
|
54953
54923
|
const args = AgentsListArgs.parse(frame);
|
|
54954
|
-
const cwdAbs =
|
|
54924
|
+
const cwdAbs = path58.resolve(args.cwd);
|
|
54955
54925
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
54956
54926
|
if (args.tool === "codex") {
|
|
54957
54927
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -54973,20 +54943,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
54973
54943
|
}
|
|
54974
54944
|
|
|
54975
54945
|
// src/handlers/git.ts
|
|
54976
|
-
var
|
|
54946
|
+
var path60 = __toESM(require("path"), 1);
|
|
54977
54947
|
init_protocol();
|
|
54978
54948
|
init_protocol();
|
|
54979
54949
|
|
|
54980
54950
|
// src/workspace/git.ts
|
|
54981
54951
|
var import_node_child_process11 = require("child_process");
|
|
54982
|
-
var
|
|
54983
|
-
var
|
|
54952
|
+
var import_node_fs43 = __toESM(require("fs"), 1);
|
|
54953
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
54984
54954
|
var import_node_util = require("util");
|
|
54985
54955
|
var pexec = (0, import_node_util.promisify)(import_node_child_process11.execFile);
|
|
54986
54956
|
function normalizePath(p2) {
|
|
54987
|
-
const resolved =
|
|
54957
|
+
const resolved = import_node_path47.default.resolve(p2);
|
|
54988
54958
|
try {
|
|
54989
|
-
return
|
|
54959
|
+
return import_node_fs43.default.realpathSync(resolved);
|
|
54990
54960
|
} catch {
|
|
54991
54961
|
return resolved;
|
|
54992
54962
|
}
|
|
@@ -55060,7 +55030,7 @@ async function listGitBranches(cwd) {
|
|
|
55060
55030
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
55061
55031
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
55062
55032
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
55063
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
55033
|
+
if (!isGuestPathAllowed(ctx.grants, path60.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
55064
55034
|
throw new ClawdError(
|
|
55065
55035
|
ERROR_CODES.UNAUTHORIZED,
|
|
55066
55036
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -55805,7 +55775,7 @@ function buildPersonaHandlers(deps) {
|
|
|
55805
55775
|
}
|
|
55806
55776
|
|
|
55807
55777
|
// src/handlers/attachment.ts
|
|
55808
|
-
var
|
|
55778
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
55809
55779
|
init_protocol();
|
|
55810
55780
|
init_protocol();
|
|
55811
55781
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -55821,10 +55791,8 @@ function assertGuestAttachmentPath(ctx, absPath, personaRoot, method, usersRoot)
|
|
|
55821
55791
|
}
|
|
55822
55792
|
function buildAttachmentHandlers(deps) {
|
|
55823
55793
|
function guardAttachmentPath(ctx, sessionId, candidateAbs, method, nonGuestPolicy) {
|
|
55824
|
-
if (ctx?.principal.kind === "owner") return;
|
|
55825
55794
|
const scope = deps.getSessionScope?.(sessionId);
|
|
55826
|
-
if (
|
|
55827
|
-
if (scope.kind === "persona" && scope.mode === "guest") {
|
|
55795
|
+
if (scope?.kind === "persona" && scope.mode === "guest") {
|
|
55828
55796
|
if (!deps.personaRoot) return;
|
|
55829
55797
|
const userWorkDir = deps.usersRoot ? deriveUserWorkDir(scope.capId, deps.usersRoot) : void 0;
|
|
55830
55798
|
if (!isPathInGuestBoundary(deps.personaRoot, scope.personaId, userWorkDir, candidateAbs)) {
|
|
@@ -55835,6 +55803,8 @@ function buildAttachmentHandlers(deps) {
|
|
|
55835
55803
|
}
|
|
55836
55804
|
return;
|
|
55837
55805
|
}
|
|
55806
|
+
if (ctx?.principal.kind === "owner") return;
|
|
55807
|
+
if (!scope) return;
|
|
55838
55808
|
if (nonGuestPolicy === "group-acl") return;
|
|
55839
55809
|
const cwd = deps.sessionStore?.read(sessionId)?.cwd;
|
|
55840
55810
|
if (!cwd) return;
|
|
@@ -55885,12 +55855,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
55885
55855
|
`session ${args.sessionId} scope unresolved`
|
|
55886
55856
|
);
|
|
55887
55857
|
}
|
|
55888
|
-
const cwdAbs =
|
|
55889
|
-
const candidateAbs =
|
|
55858
|
+
const cwdAbs = import_node_path48.default.resolve(sessionFile.cwd);
|
|
55859
|
+
const candidateAbs = import_node_path48.default.isAbsolute(args.relPath) ? import_node_path48.default.resolve(args.relPath) : import_node_path48.default.resolve(cwdAbs, args.relPath);
|
|
55890
55860
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
|
|
55891
55861
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
55892
55862
|
const entry = entries.find((e) => {
|
|
55893
|
-
const storedAbs =
|
|
55863
|
+
const storedAbs = import_node_path48.default.isAbsolute(e.relPath) ? import_node_path48.default.resolve(e.relPath) : import_node_path48.default.resolve(cwdAbs, e.relPath);
|
|
55894
55864
|
return storedAbs === candidateAbs && !e.stale;
|
|
55895
55865
|
});
|
|
55896
55866
|
if (!entry) {
|
|
@@ -55915,7 +55885,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
55915
55885
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
55916
55886
|
const f = deps.sessionStore.read(sessionId);
|
|
55917
55887
|
if (!f) return;
|
|
55918
|
-
assertGuestAttachmentPath(ctx,
|
|
55888
|
+
assertGuestAttachmentPath(ctx, import_node_path48.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
55919
55889
|
}
|
|
55920
55890
|
const groupAdd = async (frame, _client, ctx) => {
|
|
55921
55891
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -55930,10 +55900,10 @@ function buildAttachmentHandlers(deps) {
|
|
|
55930
55900
|
if (!scope) {
|
|
55931
55901
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
|
|
55932
55902
|
}
|
|
55933
|
-
const cwdAbs =
|
|
55934
|
-
const candidateAbs =
|
|
55903
|
+
const cwdAbs = import_node_path48.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
|
|
55904
|
+
const candidateAbs = import_node_path48.default.isAbsolute(args.relPath) ? import_node_path48.default.resolve(args.relPath) : import_node_path48.default.resolve(cwdAbs, args.relPath);
|
|
55935
55905
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
|
|
55936
|
-
const from = ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
55906
|
+
const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
55937
55907
|
const size = 0;
|
|
55938
55908
|
const entry = deps.groupFileStore.upsert(scope, args.sessionId, {
|
|
55939
55909
|
relPath: args.relPath,
|
|
@@ -55990,19 +55960,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
55990
55960
|
|
|
55991
55961
|
// src/handlers/extension.ts
|
|
55992
55962
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
55993
|
-
var
|
|
55963
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
55994
55964
|
init_protocol();
|
|
55995
55965
|
|
|
55996
55966
|
// src/extension/bundle-zip.ts
|
|
55997
55967
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
55998
|
-
var
|
|
55968
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
55999
55969
|
var import_node_crypto14 = __toESM(require("crypto"), 1);
|
|
56000
55970
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
56001
55971
|
async function bundleExtensionDir(dir) {
|
|
56002
55972
|
const entries = await listFilesSorted(dir);
|
|
56003
55973
|
const zip = new import_jszip2.default();
|
|
56004
55974
|
for (const rel of entries) {
|
|
56005
|
-
const abs =
|
|
55975
|
+
const abs = import_node_path49.default.join(dir, rel);
|
|
56006
55976
|
const content = await import_promises6.default.readFile(abs);
|
|
56007
55977
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
56008
55978
|
}
|
|
@@ -56023,7 +55993,7 @@ async function listFilesSorted(rootDir) {
|
|
|
56023
55993
|
return out;
|
|
56024
55994
|
}
|
|
56025
55995
|
async function walk(absRoot, relPrefix, out) {
|
|
56026
|
-
const dirAbs =
|
|
55996
|
+
const dirAbs = import_node_path49.default.join(absRoot, relPrefix);
|
|
56027
55997
|
const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
|
|
56028
55998
|
for (const e of entries) {
|
|
56029
55999
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -56077,25 +56047,25 @@ function computePublishCheck(args) {
|
|
|
56077
56047
|
|
|
56078
56048
|
// src/extension/install-flow.ts
|
|
56079
56049
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
56080
|
-
var
|
|
56050
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
56081
56051
|
var import_node_os19 = __toESM(require("os"), 1);
|
|
56082
56052
|
var import_node_crypto15 = __toESM(require("crypto"), 1);
|
|
56083
56053
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
56084
56054
|
|
|
56085
56055
|
// src/extension/paths.ts
|
|
56086
56056
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
56087
|
-
var
|
|
56057
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
56088
56058
|
function clawdHomeRoot(override) {
|
|
56089
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
56059
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path50.default.join(import_node_os18.default.homedir(), ".clawd");
|
|
56090
56060
|
}
|
|
56091
56061
|
function extensionsRoot(override) {
|
|
56092
|
-
return
|
|
56062
|
+
return import_node_path50.default.join(clawdHomeRoot(override), "extensions");
|
|
56093
56063
|
}
|
|
56094
56064
|
function publishedChannelsFile(override) {
|
|
56095
|
-
return
|
|
56065
|
+
return import_node_path50.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
56096
56066
|
}
|
|
56097
56067
|
function bundleCacheRoot(override) {
|
|
56098
|
-
return
|
|
56068
|
+
return import_node_path50.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
56099
56069
|
}
|
|
56100
56070
|
|
|
56101
56071
|
// src/extension/install-flow.ts
|
|
@@ -56122,7 +56092,7 @@ async function installFromChannel(args, deps) {
|
|
|
56122
56092
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
56123
56093
|
}
|
|
56124
56094
|
for (const name of Object.keys(zip.files)) {
|
|
56125
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
56095
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path51.default.isAbsolute(name)) {
|
|
56126
56096
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
56127
56097
|
}
|
|
56128
56098
|
}
|
|
@@ -56154,7 +56124,7 @@ async function installFromChannel(args, deps) {
|
|
|
56154
56124
|
);
|
|
56155
56125
|
}
|
|
56156
56126
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
56157
|
-
const destDir =
|
|
56127
|
+
const destDir = import_node_path51.default.join(deps.extensionsRoot, localExtId);
|
|
56158
56128
|
let destExists = false;
|
|
56159
56129
|
try {
|
|
56160
56130
|
await import_promises7.default.access(destDir);
|
|
@@ -56168,16 +56138,16 @@ async function installFromChannel(args, deps) {
|
|
|
56168
56138
|
);
|
|
56169
56139
|
}
|
|
56170
56140
|
const stage = await import_promises7.default.mkdtemp(
|
|
56171
|
-
|
|
56141
|
+
import_node_path51.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
56172
56142
|
);
|
|
56173
56143
|
try {
|
|
56174
56144
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
56175
|
-
const dest =
|
|
56145
|
+
const dest = import_node_path51.default.join(stage, name);
|
|
56176
56146
|
if (entry.dir) {
|
|
56177
56147
|
await import_promises7.default.mkdir(dest, { recursive: true });
|
|
56178
56148
|
continue;
|
|
56179
56149
|
}
|
|
56180
|
-
await import_promises7.default.mkdir(
|
|
56150
|
+
await import_promises7.default.mkdir(import_node_path51.default.dirname(dest), { recursive: true });
|
|
56181
56151
|
if (name === "manifest.json") {
|
|
56182
56152
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
56183
56153
|
await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -56198,7 +56168,7 @@ async function installFromChannel(args, deps) {
|
|
|
56198
56168
|
|
|
56199
56169
|
// src/extension/update-flow.ts
|
|
56200
56170
|
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
56201
|
-
var
|
|
56171
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
56202
56172
|
var import_node_os20 = __toESM(require("os"), 1);
|
|
56203
56173
|
var import_node_crypto16 = __toESM(require("crypto"), 1);
|
|
56204
56174
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
@@ -56215,11 +56185,11 @@ async function updateFromChannel(args, deps) {
|
|
|
56215
56185
|
channelRef.extId,
|
|
56216
56186
|
channelRef.ownerPrincipalId
|
|
56217
56187
|
);
|
|
56218
|
-
const liveDir =
|
|
56188
|
+
const liveDir = import_node_path52.default.join(deps.extensionsRoot, localExtId);
|
|
56219
56189
|
const prevDir = `${liveDir}.prev`;
|
|
56220
56190
|
let existingVersion;
|
|
56221
56191
|
try {
|
|
56222
|
-
const raw = await import_promises8.default.readFile(
|
|
56192
|
+
const raw = await import_promises8.default.readFile(import_node_path52.default.join(liveDir, "manifest.json"), "utf8");
|
|
56223
56193
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
56224
56194
|
if (!parsed2.success) {
|
|
56225
56195
|
throw new UpdateError(
|
|
@@ -56252,7 +56222,7 @@ async function updateFromChannel(args, deps) {
|
|
|
56252
56222
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
56253
56223
|
}
|
|
56254
56224
|
for (const name of Object.keys(zip.files)) {
|
|
56255
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
56225
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path52.default.isAbsolute(name)) {
|
|
56256
56226
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
56257
56227
|
}
|
|
56258
56228
|
}
|
|
@@ -56287,16 +56257,16 @@ async function updateFromChannel(args, deps) {
|
|
|
56287
56257
|
await import_promises8.default.rm(prevDir, { recursive: true, force: true });
|
|
56288
56258
|
await import_promises8.default.rename(liveDir, prevDir);
|
|
56289
56259
|
const stage = await import_promises8.default.mkdtemp(
|
|
56290
|
-
|
|
56260
|
+
import_node_path52.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
56291
56261
|
);
|
|
56292
56262
|
try {
|
|
56293
56263
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
56294
|
-
const dest =
|
|
56264
|
+
const dest = import_node_path52.default.join(stage, name);
|
|
56295
56265
|
if (entry.dir) {
|
|
56296
56266
|
await import_promises8.default.mkdir(dest, { recursive: true });
|
|
56297
56267
|
continue;
|
|
56298
56268
|
}
|
|
56299
|
-
await import_promises8.default.mkdir(
|
|
56269
|
+
await import_promises8.default.mkdir(import_node_path52.default.dirname(dest), { recursive: true });
|
|
56300
56270
|
if (name === "manifest.json") {
|
|
56301
56271
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
56302
56272
|
await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -56389,7 +56359,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
56389
56359
|
);
|
|
56390
56360
|
}
|
|
56391
56361
|
}
|
|
56392
|
-
const manifestPath =
|
|
56362
|
+
const manifestPath = import_node_path53.default.join(root, extId, "manifest.json");
|
|
56393
56363
|
const manifest = await readManifest(root, extId);
|
|
56394
56364
|
const next = { ...manifest, version: newVersion };
|
|
56395
56365
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -56397,7 +56367,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
56397
56367
|
await import_promises9.default.rename(tmp, manifestPath);
|
|
56398
56368
|
}
|
|
56399
56369
|
async function readManifest(root, extId) {
|
|
56400
|
-
const file =
|
|
56370
|
+
const file = import_node_path53.default.join(root, extId, "manifest.json");
|
|
56401
56371
|
let raw;
|
|
56402
56372
|
try {
|
|
56403
56373
|
raw = await import_promises9.default.readFile(file, "utf8");
|
|
@@ -56488,7 +56458,7 @@ function buildExtensionHandlers(deps) {
|
|
|
56488
56458
|
};
|
|
56489
56459
|
async function buildSnapshotMeta(extId) {
|
|
56490
56460
|
const manifest = await readManifest(deps.root, extId);
|
|
56491
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
56461
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path53.default.join(deps.root, extId));
|
|
56492
56462
|
return { manifest, contentHash: sha256, buffer };
|
|
56493
56463
|
}
|
|
56494
56464
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -56669,9 +56639,9 @@ function buildExtensionHandlers(deps) {
|
|
|
56669
56639
|
}
|
|
56670
56640
|
|
|
56671
56641
|
// src/app-builder/project-store.ts
|
|
56672
|
-
var
|
|
56642
|
+
var import_node_fs44 = require("fs");
|
|
56673
56643
|
var import_node_child_process12 = require("child_process");
|
|
56674
|
-
var
|
|
56644
|
+
var import_node_path54 = require("path");
|
|
56675
56645
|
init_protocol();
|
|
56676
56646
|
var PROJECTS_DIR = "projects";
|
|
56677
56647
|
var META_FILE = ".clawd-project.json";
|
|
@@ -56685,19 +56655,19 @@ var ProjectStore = class {
|
|
|
56685
56655
|
root;
|
|
56686
56656
|
/** projects/<name>/.clawd-project.json 路径 */
|
|
56687
56657
|
metaPath(name) {
|
|
56688
|
-
return (0,
|
|
56658
|
+
return (0, import_node_path54.join)(this.projectsRoot(), name, META_FILE);
|
|
56689
56659
|
}
|
|
56690
56660
|
/** projects/<name>/ 目录路径(cwd 用) */
|
|
56691
56661
|
projectDir(name) {
|
|
56692
|
-
return (0,
|
|
56662
|
+
return (0, import_node_path54.join)(this.projectsRoot(), name);
|
|
56693
56663
|
}
|
|
56694
56664
|
projectsRoot() {
|
|
56695
|
-
return (0,
|
|
56665
|
+
return (0, import_node_path54.join)(this.root, PROJECTS_DIR);
|
|
56696
56666
|
}
|
|
56697
56667
|
async list() {
|
|
56698
56668
|
let entries;
|
|
56699
56669
|
try {
|
|
56700
|
-
entries = await
|
|
56670
|
+
entries = await import_node_fs44.promises.readdir(this.projectsRoot());
|
|
56701
56671
|
} catch (err) {
|
|
56702
56672
|
if (err.code === "ENOENT") return [];
|
|
56703
56673
|
throw err;
|
|
@@ -56705,7 +56675,7 @@ var ProjectStore = class {
|
|
|
56705
56675
|
const out = [];
|
|
56706
56676
|
for (const name of entries) {
|
|
56707
56677
|
try {
|
|
56708
|
-
const raw = await
|
|
56678
|
+
const raw = await import_node_fs44.promises.readFile(this.metaPath(name), "utf8");
|
|
56709
56679
|
const json = JSON.parse(raw);
|
|
56710
56680
|
let migrated = false;
|
|
56711
56681
|
if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
|
|
@@ -56716,7 +56686,7 @@ var ProjectStore = class {
|
|
|
56716
56686
|
if (parsed.success) {
|
|
56717
56687
|
out.push(parsed.data);
|
|
56718
56688
|
if (migrated) {
|
|
56719
|
-
void
|
|
56689
|
+
void import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
|
|
56720
56690
|
});
|
|
56721
56691
|
}
|
|
56722
56692
|
}
|
|
@@ -56760,8 +56730,8 @@ var ProjectStore = class {
|
|
|
56760
56730
|
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
56761
56731
|
}
|
|
56762
56732
|
const dir = this.projectDir(name);
|
|
56763
|
-
await
|
|
56764
|
-
await
|
|
56733
|
+
await import_node_fs44.promises.mkdir(dir, { recursive: true });
|
|
56734
|
+
await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
56765
56735
|
return meta;
|
|
56766
56736
|
}
|
|
56767
56737
|
/**
|
|
@@ -56804,7 +56774,7 @@ var ProjectStore = class {
|
|
|
56804
56774
|
}
|
|
56805
56775
|
async delete(name) {
|
|
56806
56776
|
const dir = this.projectDir(name);
|
|
56807
|
-
await
|
|
56777
|
+
await import_node_fs44.promises.rm(dir, { recursive: true, force: true });
|
|
56808
56778
|
}
|
|
56809
56779
|
async updatePort(name, newPort) {
|
|
56810
56780
|
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
@@ -56820,7 +56790,7 @@ var ProjectStore = class {
|
|
|
56820
56790
|
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
56821
56791
|
}
|
|
56822
56792
|
const updated = { ...target, port: newPort };
|
|
56823
|
-
await
|
|
56793
|
+
await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
56824
56794
|
return updated;
|
|
56825
56795
|
}
|
|
56826
56796
|
/**
|
|
@@ -56837,7 +56807,7 @@ var ProjectStore = class {
|
|
|
56837
56807
|
if (!validated.success) {
|
|
56838
56808
|
throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
|
|
56839
56809
|
}
|
|
56840
|
-
await
|
|
56810
|
+
await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
56841
56811
|
return validated.data;
|
|
56842
56812
|
}
|
|
56843
56813
|
/**
|
|
@@ -56858,7 +56828,7 @@ var ProjectStore = class {
|
|
|
56858
56828
|
if (!validated.success) {
|
|
56859
56829
|
throw new Error(`invalid publishJob: ${validated.error.message}`);
|
|
56860
56830
|
}
|
|
56861
|
-
await
|
|
56831
|
+
await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
56862
56832
|
return validated.data;
|
|
56863
56833
|
}
|
|
56864
56834
|
/** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
|
|
@@ -56873,7 +56843,7 @@ var ProjectStore = class {
|
|
|
56873
56843
|
if (!validated.success) {
|
|
56874
56844
|
throw new Error(`failed to clear publishJob: ${validated.error.message}`);
|
|
56875
56845
|
}
|
|
56876
|
-
await
|
|
56846
|
+
await import_node_fs44.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
56877
56847
|
return validated.data;
|
|
56878
56848
|
}
|
|
56879
56849
|
};
|
|
@@ -56994,8 +56964,8 @@ var PublishJobRegistry = class {
|
|
|
56994
56964
|
|
|
56995
56965
|
// src/app-builder/publish-job-runner.ts
|
|
56996
56966
|
var import_node_child_process14 = require("child_process");
|
|
56997
|
-
var
|
|
56998
|
-
var
|
|
56967
|
+
var import_node_fs45 = require("fs");
|
|
56968
|
+
var import_node_path55 = require("path");
|
|
56999
56969
|
|
|
57000
56970
|
// src/app-builder/publish-stage-parser.ts
|
|
57001
56971
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -57027,10 +56997,10 @@ async function startPublishJob(deps, args) {
|
|
|
57027
56997
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
57028
56998
|
}
|
|
57029
56999
|
const projDir = projectDir(args.name);
|
|
57030
|
-
const logPath = (0,
|
|
57000
|
+
const logPath = (0, import_node_path55.join)(projDir, ".publish.log");
|
|
57031
57001
|
let logStream = null;
|
|
57032
57002
|
try {
|
|
57033
|
-
logStream = (0,
|
|
57003
|
+
logStream = (0, import_node_fs45.createWriteStream)(logPath, { flags: "w" });
|
|
57034
57004
|
} catch {
|
|
57035
57005
|
logStream = null;
|
|
57036
57006
|
}
|
|
@@ -57287,8 +57257,8 @@ async function recoverInterruptedJobs(deps) {
|
|
|
57287
57257
|
|
|
57288
57258
|
// src/handlers/app-builder.ts
|
|
57289
57259
|
init_protocol();
|
|
57290
|
-
var
|
|
57291
|
-
var
|
|
57260
|
+
var import_node_path56 = require("path");
|
|
57261
|
+
var import_node_fs46 = require("fs");
|
|
57292
57262
|
var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
|
|
57293
57263
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
57294
57264
|
async function recoverInterruptedPublishJobs(store, logger) {
|
|
@@ -57369,7 +57339,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57369
57339
|
async function listAllUsersProjects() {
|
|
57370
57340
|
if (!deps.usersRoot || !deps.getStore) return [];
|
|
57371
57341
|
const getStore = deps.getStore;
|
|
57372
|
-
const userIds = await
|
|
57342
|
+
const userIds = await import_node_fs46.promises.readdir(deps.usersRoot).catch(() => []);
|
|
57373
57343
|
const perUser = await Promise.all(
|
|
57374
57344
|
userIds.map((uid) => getStore(uid).list().catch(() => []))
|
|
57375
57345
|
);
|
|
@@ -57388,12 +57358,14 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57388
57358
|
}
|
|
57389
57359
|
const listProjects = async (frame, _client, ctx) => {
|
|
57390
57360
|
const f = frame;
|
|
57361
|
+
const sessionId = typeof f.sessionId === "string" ? f.sessionId : void 0;
|
|
57391
57362
|
let metas;
|
|
57392
|
-
if (
|
|
57363
|
+
if (sessionId) {
|
|
57364
|
+
metas = await resolveStore({ ctx, sessionId }).list();
|
|
57365
|
+
} else if (ctx?.principal.kind === "owner" && deps.usersRoot && deps.getStore) {
|
|
57393
57366
|
metas = await listAllUsersProjects();
|
|
57394
57367
|
} else {
|
|
57395
|
-
|
|
57396
|
-
metas = await resolveStore({ ctx, sessionId }).list();
|
|
57368
|
+
metas = await resolveStore({ ctx }).list();
|
|
57397
57369
|
}
|
|
57398
57370
|
return { response: { projects: metas.map(toProjectWithStatus) } };
|
|
57399
57371
|
};
|
|
@@ -57445,8 +57417,8 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57445
57417
|
const project = await userStore.create(f.name, reservedPorts);
|
|
57446
57418
|
try {
|
|
57447
57419
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
|
|
57448
|
-
const templateSrcDir = (0,
|
|
57449
|
-
const scaffoldScript = (0,
|
|
57420
|
+
const templateSrcDir = (0, import_node_path56.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
|
|
57421
|
+
const scaffoldScript = (0, import_node_path56.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
|
|
57450
57422
|
const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
|
|
57451
57423
|
deps.logger?.info("app-builder.scaffold.done", {
|
|
57452
57424
|
name: project.name,
|
|
@@ -57667,7 +57639,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57667
57639
|
await userStore.clearPublishJob(args.name);
|
|
57668
57640
|
}
|
|
57669
57641
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
|
|
57670
|
-
const scriptPath = (0,
|
|
57642
|
+
const scriptPath = (0, import_node_path56.join)(deps.deployKitRoot, "scripts", "publish.sh");
|
|
57671
57643
|
deps.logger?.info("app-builder.publish.start", {
|
|
57672
57644
|
name: args.name,
|
|
57673
57645
|
sessionId: boundSession.sessionId,
|
|
@@ -57843,7 +57815,7 @@ function buildVisitorHandlers(deps) {
|
|
|
57843
57815
|
|
|
57844
57816
|
// src/extension/registry.ts
|
|
57845
57817
|
var import_promises10 = __toESM(require("fs/promises"), 1);
|
|
57846
|
-
var
|
|
57818
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
57847
57819
|
async function loadAll(root) {
|
|
57848
57820
|
let entries;
|
|
57849
57821
|
try {
|
|
@@ -57856,13 +57828,13 @@ async function loadAll(root) {
|
|
|
57856
57828
|
for (const ent of entries) {
|
|
57857
57829
|
if (!ent.isDirectory()) continue;
|
|
57858
57830
|
if (ent.name.startsWith(".")) continue;
|
|
57859
|
-
records.push(await loadOne(
|
|
57831
|
+
records.push(await loadOne(import_node_path57.default.join(root, ent.name), ent.name));
|
|
57860
57832
|
}
|
|
57861
57833
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
57862
57834
|
return records;
|
|
57863
57835
|
}
|
|
57864
57836
|
async function loadOne(dir, dirName) {
|
|
57865
|
-
const manifestPath =
|
|
57837
|
+
const manifestPath = import_node_path57.default.join(dir, "manifest.json");
|
|
57866
57838
|
let raw;
|
|
57867
57839
|
try {
|
|
57868
57840
|
raw = await import_promises10.default.readFile(manifestPath, "utf8");
|
|
@@ -57907,7 +57879,7 @@ async function loadOne(dir, dirName) {
|
|
|
57907
57879
|
|
|
57908
57880
|
// src/extension/uninstall.ts
|
|
57909
57881
|
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
57910
|
-
var
|
|
57882
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
57911
57883
|
var UninstallError = class extends Error {
|
|
57912
57884
|
constructor(code, message) {
|
|
57913
57885
|
super(message);
|
|
@@ -57916,7 +57888,7 @@ var UninstallError = class extends Error {
|
|
|
57916
57888
|
code;
|
|
57917
57889
|
};
|
|
57918
57890
|
async function uninstall(deps) {
|
|
57919
|
-
const dir =
|
|
57891
|
+
const dir = import_node_path58.default.join(deps.root, deps.extId);
|
|
57920
57892
|
try {
|
|
57921
57893
|
await import_promises11.default.access(dir);
|
|
57922
57894
|
} catch {
|
|
@@ -58503,6 +58475,21 @@ var METHOD_GRANT_MAP = {
|
|
|
58503
58475
|
// ---- shift:* (排班 mock,owner-only 读) ----
|
|
58504
58476
|
// mock 阶段只 owner 用;接 guest 后再考虑分级
|
|
58505
58477
|
"shift:list": ADMIN_ANY,
|
|
58478
|
+
// ---- shift-internal:* + inbox:sendDm + personaDispatch complete/list ----
|
|
58479
|
+
// 统一 RPC 鉴权(spec 2026-07-28):原 /api/rpc 白名单 method 收编。调用方 = 本机
|
|
58480
|
+
// MCP server 持 owner token → ADMIN_ANY 即「owner token 即可」;业务归因(sendDm 的
|
|
58481
|
+
// sender、shift 的 personaId)在 handler 内按 body 字段处理,与鉴权无关。
|
|
58482
|
+
"shift-internal:add": ADMIN_ANY,
|
|
58483
|
+
"shift-internal:list": ADMIN_ANY,
|
|
58484
|
+
"shift-internal:cancel": ADMIN_ANY,
|
|
58485
|
+
"shift-internal:update": ADMIN_ANY,
|
|
58486
|
+
"shift-internal:history": ADMIN_ANY,
|
|
58487
|
+
"inbox:sendDm": ADMIN_ANY,
|
|
58488
|
+
"personaDispatch:complete": ADMIN_ANY,
|
|
58489
|
+
"personaDispatch:list": ADMIN_ANY,
|
|
58490
|
+
// 跨设备轮询(spec §5):A 端 daemon 凭 connect token 查 outcome;handler 内校验
|
|
58491
|
+
// 台账行 sourceSessionId === ctx.principal.id,防 guest 查别人的 dispatch。
|
|
58492
|
+
"personaDispatch:get": CAPABILITY_SCOPED,
|
|
58506
58493
|
"skills:list": CAPABILITY_SCOPED,
|
|
58507
58494
|
"agents:list": CAPABILITY_SCOPED,
|
|
58508
58495
|
"git:root": CAPABILITY_SCOPED,
|
|
@@ -58522,7 +58509,7 @@ var METHOD_GRANT_MAP = {
|
|
|
58522
58509
|
"persona:delete": ADMIN_ANY,
|
|
58523
58510
|
// 跨设备 dispatch:A 的 peer daemon 凭 connect token 经 /rpc 调进来;dispatcher 放行,
|
|
58524
58511
|
// run handler 内做 persona.public + assertGrant(send) 双重校验(guest grants 是 wildcard,
|
|
58525
|
-
// 单 assertGrant 不够)。本地
|
|
58512
|
+
// 单 assertGrant 不够)。本地 MCP server 经 /rpc + Bearer 进来,同过此表(owner 恒过)。
|
|
58526
58513
|
"personaDispatch:run": CAPABILITY_SCOPED,
|
|
58527
58514
|
// 跨设备 exec(spec 2026-07-16):public——"能连上=有 auth",业务在 handler 校
|
|
58528
58515
|
// (ensureGuest + remoteAccessAllowed),跟 inbox:postMessage 同模式。
|
|
@@ -58634,7 +58621,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
|
|
|
58634
58621
|
|
|
58635
58622
|
// src/extension/runtime.ts
|
|
58636
58623
|
var import_node_child_process17 = require("child_process");
|
|
58637
|
-
var
|
|
58624
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
58638
58625
|
var import_promises12 = require("timers/promises");
|
|
58639
58626
|
|
|
58640
58627
|
// src/extension/port-allocator.ts
|
|
@@ -58735,7 +58722,7 @@ var Runtime = class {
|
|
|
58735
58722
|
/\$CLAWOS_EXT_PORT/g,
|
|
58736
58723
|
String(port)
|
|
58737
58724
|
);
|
|
58738
|
-
const dir =
|
|
58725
|
+
const dir = import_node_path59.default.join(this.root, extId);
|
|
58739
58726
|
const env = {
|
|
58740
58727
|
...process.env,
|
|
58741
58728
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -58847,7 +58834,7 @@ ${handle.stderrTail}`
|
|
|
58847
58834
|
|
|
58848
58835
|
// src/extension/published-channels.ts
|
|
58849
58836
|
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
58850
|
-
var
|
|
58837
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
58851
58838
|
init_zod();
|
|
58852
58839
|
var PublishedChannelsError = class extends Error {
|
|
58853
58840
|
constructor(code, message) {
|
|
@@ -58946,7 +58933,7 @@ var PublishedChannelStore = class {
|
|
|
58946
58933
|
)
|
|
58947
58934
|
};
|
|
58948
58935
|
const tmp = `${this.filePath}.tmp`;
|
|
58949
|
-
await import_promises13.default.mkdir(
|
|
58936
|
+
await import_promises13.default.mkdir(import_node_path60.default.dirname(this.filePath), { recursive: true });
|
|
58950
58937
|
await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
58951
58938
|
await import_promises13.default.rename(tmp, this.filePath);
|
|
58952
58939
|
}
|
|
@@ -58954,7 +58941,7 @@ var PublishedChannelStore = class {
|
|
|
58954
58941
|
|
|
58955
58942
|
// src/extension/bundle-cache.ts
|
|
58956
58943
|
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
58957
|
-
var
|
|
58944
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
58958
58945
|
var BundleCache = class {
|
|
58959
58946
|
constructor(rootDir) {
|
|
58960
58947
|
this.rootDir = rootDir;
|
|
@@ -58963,14 +58950,14 @@ var BundleCache = class {
|
|
|
58963
58950
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
58964
58951
|
async write(snapshotHash, buffer) {
|
|
58965
58952
|
await import_promises14.default.mkdir(this.rootDir, { recursive: true });
|
|
58966
|
-
const file =
|
|
58953
|
+
const file = import_node_path61.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58967
58954
|
const tmp = `${file}.tmp`;
|
|
58968
58955
|
await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
|
|
58969
58956
|
await import_promises14.default.rename(tmp, file);
|
|
58970
58957
|
}
|
|
58971
58958
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
58972
58959
|
async read(snapshotHash) {
|
|
58973
|
-
const file =
|
|
58960
|
+
const file = import_node_path61.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58974
58961
|
try {
|
|
58975
58962
|
return await import_promises14.default.readFile(file);
|
|
58976
58963
|
} catch (e) {
|
|
@@ -58980,7 +58967,7 @@ var BundleCache = class {
|
|
|
58980
58967
|
}
|
|
58981
58968
|
/** Idempotent — missing file is not an error. */
|
|
58982
58969
|
async delete(snapshotHash) {
|
|
58983
|
-
const file =
|
|
58970
|
+
const file = import_node_path61.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
58984
58971
|
await import_promises14.default.rm(file, { force: true });
|
|
58985
58972
|
}
|
|
58986
58973
|
};
|
|
@@ -59003,24 +58990,24 @@ async function startDaemon(config) {
|
|
|
59003
58990
|
sampling: logShippingCfg.sampling,
|
|
59004
58991
|
homeDir: import_node_os22.default.homedir()
|
|
59005
58992
|
});
|
|
59006
|
-
const logDir =
|
|
59007
|
-
|
|
58993
|
+
const logDir = import_node_path62.default.join(config.dataDir, "log");
|
|
58994
|
+
import_node_fs47.default.mkdirSync(logDir, { recursive: true });
|
|
59008
58995
|
const logger = createLogger({
|
|
59009
58996
|
level: config.logLevel,
|
|
59010
|
-
file:
|
|
58997
|
+
file: import_node_path62.default.join(logDir, "clawd.log"),
|
|
59011
58998
|
logClient
|
|
59012
58999
|
});
|
|
59013
59000
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
59014
59001
|
const screenIdleProbeLogger = createFileOnlyLogger({
|
|
59015
|
-
file:
|
|
59002
|
+
file: import_node_path62.default.join(logDir, "screen-idle-probe.log"),
|
|
59016
59003
|
level: "debug"
|
|
59017
59004
|
});
|
|
59018
59005
|
logger.info("screen-idle probe logger enabled", {
|
|
59019
|
-
file:
|
|
59006
|
+
file: import_node_path62.default.join(logDir, "screen-idle-probe.log")
|
|
59020
59007
|
});
|
|
59021
59008
|
const CAP_TARGETS = [
|
|
59022
|
-
|
|
59023
|
-
|
|
59009
|
+
import_node_path62.default.join(logDir, "clawd.log"),
|
|
59010
|
+
import_node_path62.default.join(logDir, "screen-idle-probe.log")
|
|
59024
59011
|
];
|
|
59025
59012
|
const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
|
|
59026
59013
|
const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
|
|
@@ -59044,12 +59031,7 @@ async function startDaemon(config) {
|
|
|
59044
59031
|
if (pre.status === "stale") {
|
|
59045
59032
|
logger.warn("stale state file detected, overwriting", { pid: pre.existing.pid });
|
|
59046
59033
|
}
|
|
59047
|
-
|
|
59048
|
-
if (config.authToken && config.authToken.trim()) {
|
|
59049
|
-
resolvedAuthToken = config.authToken.trim();
|
|
59050
|
-
} else if (config.tunnel) {
|
|
59051
|
-
resolvedAuthToken = authFile.token;
|
|
59052
|
-
}
|
|
59034
|
+
const resolvedAuthToken = config.authToken && config.authToken.trim() ? config.authToken.trim() : authFile.token;
|
|
59053
59035
|
const ownerIdentityStore = new OwnerIdentityStore(config.dataDir);
|
|
59054
59036
|
const feishuIdentity = ownerIdentityStore.read();
|
|
59055
59037
|
let feishuActive = feishuIdentity !== null;
|
|
@@ -59058,7 +59040,7 @@ async function startDaemon(config) {
|
|
|
59058
59040
|
let ownerProvider = feishuIdentity?.identity.provider ?? "";
|
|
59059
59041
|
let ownerDisplayName = feishuIdentity?.identity.displayName ?? loadOwnerDisplayName(config.dataDir);
|
|
59060
59042
|
let ownerFeishuUnionId = feishuIdentity?.identity.unionId;
|
|
59061
|
-
const authMode =
|
|
59043
|
+
const authMode = "first-message";
|
|
59062
59044
|
const inboxStore = new InboxStore(config.dataDir);
|
|
59063
59045
|
const inboxManager = new InboxManager(inboxStore, (_peerDeviceId, frame) => {
|
|
59064
59046
|
wsServer?.broadcastToOwners(frame);
|
|
@@ -59122,8 +59104,8 @@ async function startDaemon(config) {
|
|
|
59122
59104
|
const agents = new AgentsScanner();
|
|
59123
59105
|
const history = new ClaudeHistoryReader();
|
|
59124
59106
|
let transport = null;
|
|
59125
|
-
const personaStore = new PersonaStore(
|
|
59126
|
-
const usersRoot =
|
|
59107
|
+
const personaStore = new PersonaStore(import_node_path62.default.join(config.dataDir, "personas"));
|
|
59108
|
+
const usersRoot = import_node_path62.default.join(config.dataDir, "users");
|
|
59127
59109
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
59128
59110
|
if (defaultsRoot) {
|
|
59129
59111
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -59143,7 +59125,7 @@ async function startDaemon(config) {
|
|
|
59143
59125
|
migrateCodexSandbox({ store: personaStore, logger });
|
|
59144
59126
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
59145
59127
|
const dispatchStore = createDispatchStore({
|
|
59146
|
-
filePath:
|
|
59128
|
+
filePath: import_node_path62.default.join(config.dataDir, "dispatch.json"),
|
|
59147
59129
|
now: () => Date.now(),
|
|
59148
59130
|
onFlushError: (err) => logger.error("dispatch store flush failed", {
|
|
59149
59131
|
reason: err instanceof Error ? err.message : String(err)
|
|
@@ -59158,20 +59140,23 @@ async function startDaemon(config) {
|
|
|
59158
59140
|
now: () => Date.now(),
|
|
59159
59141
|
onCompleted: (sid) => deliverPendingRef?.(sid)
|
|
59160
59142
|
});
|
|
59161
|
-
const here = typeof __dirname === "string" ? __dirname :
|
|
59143
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path62.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
|
|
59162
59144
|
const mcpConfigs = [];
|
|
59145
|
+
const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
|
|
59163
59146
|
const dispatchServerCandidates = [
|
|
59164
|
-
|
|
59147
|
+
import_node_path62.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
59165
59148
|
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
59166
|
-
|
|
59149
|
+
import_node_path62.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
59167
59150
|
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
59168
59151
|
];
|
|
59169
|
-
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) =>
|
|
59152
|
+
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59170
59153
|
if (dispatchServerScriptPath) {
|
|
59171
|
-
const dispatchLogPath =
|
|
59154
|
+
const dispatchLogPath = import_node_path62.default.join(logDir, "dispatch-mcp-server.log");
|
|
59172
59155
|
const dispatchCfgPath = writeDispatchMcpConfig({
|
|
59173
59156
|
dataDir: config.dataDir,
|
|
59174
59157
|
serverScriptPath: dispatchServerScriptPath,
|
|
59158
|
+
daemonToken: resolvedAuthToken,
|
|
59159
|
+
daemonUrl: mcpDaemonUrl,
|
|
59175
59160
|
logPath: dispatchLogPath
|
|
59176
59161
|
});
|
|
59177
59162
|
mcpConfigs.push({ id: DISPATCH_MCP_ID, path: dispatchCfgPath });
|
|
@@ -59186,17 +59171,19 @@ async function startDaemon(config) {
|
|
|
59186
59171
|
});
|
|
59187
59172
|
}
|
|
59188
59173
|
const ticketServerCandidates = [
|
|
59189
|
-
|
|
59190
|
-
|
|
59174
|
+
import_node_path62.default.join(here, "ticket", "mcp-server.cjs"),
|
|
59175
|
+
import_node_path62.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
59191
59176
|
];
|
|
59192
|
-
const ticketServerScriptPath = ticketServerCandidates.find((p2) =>
|
|
59177
|
+
const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59193
59178
|
if (ticketServerScriptPath) {
|
|
59194
|
-
const ticketLogPath =
|
|
59179
|
+
const ticketLogPath = import_node_path62.default.join(logDir, "ticket-mcp-server.log");
|
|
59195
59180
|
const ticketCfgPath = writeTicketMcpConfig({
|
|
59196
59181
|
dataDir: config.dataDir,
|
|
59197
59182
|
serverScriptPath: ticketServerScriptPath,
|
|
59198
59183
|
apiBaseUrl: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
59199
59184
|
apiKey: resolveClawdTicketsApiKey(),
|
|
59185
|
+
daemonToken: resolvedAuthToken,
|
|
59186
|
+
daemonUrl: mcpDaemonUrl,
|
|
59200
59187
|
logPath: ticketLogPath
|
|
59201
59188
|
});
|
|
59202
59189
|
mcpConfigs.push({ id: "ticket", path: ticketCfgPath });
|
|
@@ -59211,15 +59198,17 @@ async function startDaemon(config) {
|
|
|
59211
59198
|
});
|
|
59212
59199
|
}
|
|
59213
59200
|
const shiftServerCandidates = [
|
|
59214
|
-
|
|
59215
|
-
|
|
59201
|
+
import_node_path62.default.join(here, "shift", "mcp-server.cjs"),
|
|
59202
|
+
import_node_path62.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
|
|
59216
59203
|
];
|
|
59217
|
-
const shiftServerScriptPath = shiftServerCandidates.find((p2) =>
|
|
59204
|
+
const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59218
59205
|
if (shiftServerScriptPath) {
|
|
59219
|
-
const shiftLogPath =
|
|
59206
|
+
const shiftLogPath = import_node_path62.default.join(logDir, "shift-mcp-server.log");
|
|
59220
59207
|
const shiftCfgPath = await writeShiftMcpConfig({
|
|
59221
59208
|
dataDir: config.dataDir,
|
|
59222
59209
|
serverScriptPath: shiftServerScriptPath,
|
|
59210
|
+
daemonToken: resolvedAuthToken,
|
|
59211
|
+
daemonUrl: mcpDaemonUrl,
|
|
59223
59212
|
logPath: shiftLogPath
|
|
59224
59213
|
});
|
|
59225
59214
|
mcpConfigs.push({ id: "shift", path: shiftCfgPath });
|
|
@@ -59235,15 +59224,17 @@ async function startDaemon(config) {
|
|
|
59235
59224
|
);
|
|
59236
59225
|
}
|
|
59237
59226
|
const inboxServerCandidates = [
|
|
59238
|
-
|
|
59239
|
-
|
|
59227
|
+
import_node_path62.default.join(here, "inbox", "mcp-server.cjs"),
|
|
59228
|
+
import_node_path62.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
|
|
59240
59229
|
];
|
|
59241
|
-
const inboxServerScriptPath = inboxServerCandidates.find((p2) =>
|
|
59230
|
+
const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59242
59231
|
if (inboxServerScriptPath) {
|
|
59243
|
-
const inboxLogPath =
|
|
59232
|
+
const inboxLogPath = import_node_path62.default.join(logDir, "inbox-mcp-server.log");
|
|
59244
59233
|
const inboxCfgPath = await writeInboxMcpConfig({
|
|
59245
59234
|
dataDir: config.dataDir,
|
|
59246
59235
|
serverScriptPath: inboxServerScriptPath,
|
|
59236
|
+
daemonToken: resolvedAuthToken,
|
|
59237
|
+
daemonUrl: mcpDaemonUrl,
|
|
59247
59238
|
logPath: inboxLogPath
|
|
59248
59239
|
});
|
|
59249
59240
|
mcpConfigs.push({ id: "inbox", path: inboxCfgPath });
|
|
@@ -59259,14 +59250,16 @@ async function startDaemon(config) {
|
|
|
59259
59250
|
);
|
|
59260
59251
|
}
|
|
59261
59252
|
const peerOpsServerCandidates = [
|
|
59262
|
-
|
|
59263
|
-
|
|
59253
|
+
import_node_path62.default.join(here, "peer-ops", "mcp-server.cjs"),
|
|
59254
|
+
import_node_path62.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
|
|
59264
59255
|
];
|
|
59265
|
-
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) =>
|
|
59256
|
+
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59266
59257
|
if (peerOpsServerScriptPath) {
|
|
59267
59258
|
const peerOpsCfgPath = writePeerOpsMcpConfig({
|
|
59268
59259
|
dataDir: config.dataDir,
|
|
59269
|
-
serverScriptPath: peerOpsServerScriptPath
|
|
59260
|
+
serverScriptPath: peerOpsServerScriptPath,
|
|
59261
|
+
daemonToken: resolvedAuthToken,
|
|
59262
|
+
daemonUrl: mcpDaemonUrl
|
|
59270
59263
|
});
|
|
59271
59264
|
mcpConfigs.push({ id: "peer-ops", path: peerOpsCfgPath });
|
|
59272
59265
|
logger.info("peer-ops.mcp.json written", {
|
|
@@ -59279,8 +59272,34 @@ async function startDaemon(config) {
|
|
|
59279
59272
|
{ tried: peerOpsServerCandidates }
|
|
59280
59273
|
);
|
|
59281
59274
|
}
|
|
59275
|
+
const rpcToolServerCandidates = [
|
|
59276
|
+
import_node_path62.default.join(here, "rpc-tool", "mcp-server.cjs"),
|
|
59277
|
+
import_node_path62.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
|
|
59278
|
+
];
|
|
59279
|
+
const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs47.default.existsSync(p2));
|
|
59280
|
+
if (rpcToolServerScriptPath) {
|
|
59281
|
+
const rpcToolLogPath = import_node_path62.default.join(logDir, "rpc-tool-mcp-server.log");
|
|
59282
|
+
const rpcToolCfgPath = writeRpcToolMcpConfig({
|
|
59283
|
+
dataDir: config.dataDir,
|
|
59284
|
+
serverScriptPath: rpcToolServerScriptPath,
|
|
59285
|
+
daemonToken: resolvedAuthToken,
|
|
59286
|
+
daemonUrl: mcpDaemonUrl,
|
|
59287
|
+
logPath: rpcToolLogPath
|
|
59288
|
+
});
|
|
59289
|
+
mcpConfigs.push({ id: "rpc-tool", path: rpcToolCfgPath });
|
|
59290
|
+
logger.info("rpc-tool.mcp.json written", {
|
|
59291
|
+
path: rpcToolCfgPath,
|
|
59292
|
+
server: rpcToolServerScriptPath,
|
|
59293
|
+
serverLog: rpcToolLogPath
|
|
59294
|
+
});
|
|
59295
|
+
} else {
|
|
59296
|
+
logger.warn(
|
|
59297
|
+
"rpc-tool-mcp-server.cjs not found; clawd-rpc call tool disabled (dev tsx \u6A21\u5F0F\u4E0B\u9700\u5148\u8DD1\u8FC7 build)",
|
|
59298
|
+
{ tried: rpcToolServerCandidates }
|
|
59299
|
+
);
|
|
59300
|
+
}
|
|
59282
59301
|
const shiftStore = createShiftStore({
|
|
59283
|
-
filePath:
|
|
59302
|
+
filePath: import_node_path62.default.join(config.dataDir, "shift.json"),
|
|
59284
59303
|
ownerIdProvider: () => ownerPrincipalId,
|
|
59285
59304
|
now: () => Date.now()
|
|
59286
59305
|
});
|
|
@@ -59302,7 +59321,7 @@ async function startDaemon(config) {
|
|
|
59302
59321
|
getAdapter,
|
|
59303
59322
|
historyReader: history,
|
|
59304
59323
|
dataDir: config.dataDir,
|
|
59305
|
-
personaRoot:
|
|
59324
|
+
personaRoot: import_node_path62.default.join(config.dataDir, "personas"),
|
|
59306
59325
|
// dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
|
|
59307
59326
|
// personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
|
|
59308
59327
|
getPersonaTool: (personaId) => personaRegistry.get(personaId)?.tool,
|
|
@@ -59311,10 +59330,13 @@ async function startDaemon(config) {
|
|
|
59311
59330
|
ownerDisplayName,
|
|
59312
59331
|
ownerPrincipalId,
|
|
59313
59332
|
ownerFeishuUnionId,
|
|
59333
|
+
// T-37 owner session 闲置回收兜底上限(默认 6h,config.json / env 可调,设 0 关闭)。
|
|
59334
|
+
// guest 的 10min 不走这条——它是 session/scope.ts 的固定常量。
|
|
59335
|
+
ownerIdleKillDelayMs: config.ownerIdleKillDelayMs,
|
|
59314
59336
|
contactStore,
|
|
59315
59337
|
mode: config.mode,
|
|
59316
59338
|
// 单栏 refactor (spec 2026-06-02 §5.1):cc 子进程 env CLAWD_DAEMON_URL 闭包来源。
|
|
59317
|
-
//
|
|
59339
|
+
// MCP server 用它拼 /rpc/<method>(Bearer CLAWD_DAEMON_TOKEN)调本机 daemon。
|
|
59318
59340
|
// 127.0.0.1(不是 config.host)—— cc 跑在本机,loopback 最稳;外部访问限制 + http-router
|
|
59319
59341
|
// 的 isLoopback 兜底已确保安全。
|
|
59320
59342
|
getDaemonUrl: () => `http://127.0.0.1:${config.port}`,
|
|
@@ -59350,10 +59372,10 @@ async function startDaemon(config) {
|
|
|
59350
59372
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
59351
59373
|
attachmentGroup: {
|
|
59352
59374
|
onFileEdit: (input) => {
|
|
59353
|
-
const absPath =
|
|
59375
|
+
const absPath = import_node_path62.default.isAbsolute(input.relPath) ? input.relPath : import_node_path62.default.join(input.cwd, input.relPath);
|
|
59354
59376
|
let size = 0;
|
|
59355
59377
|
try {
|
|
59356
|
-
size =
|
|
59378
|
+
size = import_node_fs47.default.statSync(absPath).size;
|
|
59357
59379
|
} catch (err) {
|
|
59358
59380
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
59359
59381
|
sessionId: input.sessionId,
|
|
@@ -59584,11 +59606,11 @@ async function startDaemon(config) {
|
|
|
59584
59606
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
59585
59607
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
59586
59608
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
59587
|
-
personaRoot:
|
|
59609
|
+
personaRoot: import_node_path62.default.join(config.dataDir, "personas"),
|
|
59588
59610
|
usersRoot
|
|
59589
59611
|
},
|
|
59590
59612
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
59591
|
-
personaRoot:
|
|
59613
|
+
personaRoot: import_node_path62.default.join(config.dataDir, "personas"),
|
|
59592
59614
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
59593
59615
|
usersRoot,
|
|
59594
59616
|
// v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
|
|
@@ -59717,11 +59739,11 @@ async function startDaemon(config) {
|
|
|
59717
59739
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
59718
59740
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
59719
59741
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
59720
|
-
appBuilderPersonaRoot:
|
|
59742
|
+
appBuilderPersonaRoot: import_node_path62.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
59721
59743
|
// 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
|
|
59722
|
-
deployKitRoot:
|
|
59744
|
+
deployKitRoot: import_node_path62.default.join(config.dataDir, "deploy-kit"),
|
|
59723
59745
|
// scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
|
|
59724
|
-
resolvePersonaRoot: (personaId) =>
|
|
59746
|
+
resolvePersonaRoot: (personaId) => import_node_path62.default.join(config.dataDir, "personas", personaId),
|
|
59725
59747
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
59726
59748
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
59727
59749
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -59767,7 +59789,7 @@ async function startDaemon(config) {
|
|
|
59767
59789
|
}
|
|
59768
59790
|
let sourceJsonlPath = "(no transcript yet \u2014 operate from the task description alone)";
|
|
59769
59791
|
if (sourceFile && sourceFile.toolSessionId) {
|
|
59770
|
-
sourceJsonlPath =
|
|
59792
|
+
sourceJsonlPath = import_node_path62.default.join(
|
|
59771
59793
|
import_node_os22.default.homedir(),
|
|
59772
59794
|
".claude",
|
|
59773
59795
|
"projects",
|
|
@@ -59837,17 +59859,6 @@ async function startDaemon(config) {
|
|
|
59837
59859
|
const authResolver = new AuthContextResolver({
|
|
59838
59860
|
ownerToken: resolvedAuthToken
|
|
59839
59861
|
});
|
|
59840
|
-
const rpcDispatcher = {
|
|
59841
|
-
async dispatch(method, args, _ctx) {
|
|
59842
|
-
const handler = resolveExposedHandler(handlers, method);
|
|
59843
|
-
if (!handler) {
|
|
59844
|
-
throw Object.assign(new Error(`unknown RPC method "${method}"`), { code: "METHOD_NOT_IMPLEMENTED" });
|
|
59845
|
-
}
|
|
59846
|
-
const emptyClient = {};
|
|
59847
|
-
const result = await handler(args, emptyClient);
|
|
59848
|
-
return result.response;
|
|
59849
|
-
}
|
|
59850
|
-
};
|
|
59851
59862
|
const authedRpc = {
|
|
59852
59863
|
authenticate: (token) => authenticate(token, buildConnectAuthDeps()),
|
|
59853
59864
|
dispatch: (method, body, ctx) => {
|
|
@@ -59872,7 +59883,6 @@ async function startDaemon(config) {
|
|
|
59872
59883
|
daemonVersion: version,
|
|
59873
59884
|
logger,
|
|
59874
59885
|
sessionStore: store,
|
|
59875
|
-
rpcDispatcher,
|
|
59876
59886
|
authedRpc,
|
|
59877
59887
|
...viewerAssetLoader ? { viewerAssetLoader } : {},
|
|
59878
59888
|
// persona web 分享:访客换 token(POST /share/exchange)+ guest SPA serve(GET /s)
|
|
@@ -60082,8 +60092,8 @@ async function startDaemon(config) {
|
|
|
60082
60092
|
const lines = [
|
|
60083
60093
|
`Tunnel: ${r.url}`,
|
|
60084
60094
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
60085
|
-
`Frpc config: ${
|
|
60086
|
-
`Frpc log: ${
|
|
60095
|
+
`Frpc config: ${import_node_path62.default.join(config.dataDir, "frpc.toml")}`,
|
|
60096
|
+
`Frpc log: ${import_node_path62.default.join(logDir, "frpc.log")}`
|
|
60087
60097
|
];
|
|
60088
60098
|
const width = Math.max(...lines.map((l) => l.length));
|
|
60089
60099
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -60096,8 +60106,8 @@ ${bar}
|
|
|
60096
60106
|
|
|
60097
60107
|
`);
|
|
60098
60108
|
try {
|
|
60099
|
-
const connectPath =
|
|
60100
|
-
|
|
60109
|
+
const connectPath = import_node_path62.default.join(config.dataDir, "connect.txt");
|
|
60110
|
+
import_node_fs47.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
60101
60111
|
} catch {
|
|
60102
60112
|
}
|
|
60103
60113
|
} catch (err) {
|
|
@@ -60169,9 +60179,9 @@ ${bar}
|
|
|
60169
60179
|
};
|
|
60170
60180
|
}
|
|
60171
60181
|
function migrateDropPersonsDir(dataDir) {
|
|
60172
|
-
const dir =
|
|
60182
|
+
const dir = import_node_path62.default.join(dataDir, "persons");
|
|
60173
60183
|
try {
|
|
60174
|
-
|
|
60184
|
+
import_node_fs47.default.rmSync(dir, { recursive: true, force: true });
|
|
60175
60185
|
} catch {
|
|
60176
60186
|
}
|
|
60177
60187
|
}
|