@clawos-dev/clawd 0.2.285 → 0.2.287
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 +1185 -545
- package/dist/dispatch/mcp-server.cjs +47 -0
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/{guest-DLjILuHk.js → guest-DAhWzKdp.js} +123 -123
- package/dist/share-ui/assets/guest-DdHtcqVc.css +32 -0
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-m8PUkvHw.css +0 -32
package/dist/cli.cjs
CHANGED
|
@@ -450,8 +450,8 @@ var init_parseUtil = __esm({
|
|
|
450
450
|
init_errors();
|
|
451
451
|
init_en();
|
|
452
452
|
makeIssue = (params) => {
|
|
453
|
-
const { data, path:
|
|
454
|
-
const fullPath = [...
|
|
453
|
+
const { data, path: path78, errorMaps, issueData } = params;
|
|
454
|
+
const fullPath = [...path78, ...issueData.path || []];
|
|
455
455
|
const fullIssue = {
|
|
456
456
|
...issueData,
|
|
457
457
|
path: fullPath
|
|
@@ -762,11 +762,11 @@ var init_types = __esm({
|
|
|
762
762
|
init_parseUtil();
|
|
763
763
|
init_util();
|
|
764
764
|
ParseInputLazyPath = class {
|
|
765
|
-
constructor(parent, value,
|
|
765
|
+
constructor(parent, value, path78, key) {
|
|
766
766
|
this._cachedPath = [];
|
|
767
767
|
this.parent = parent;
|
|
768
768
|
this.data = value;
|
|
769
|
-
this._path =
|
|
769
|
+
this._path = path78;
|
|
770
770
|
this._key = key;
|
|
771
771
|
}
|
|
772
772
|
get path() {
|
|
@@ -6584,6 +6584,40 @@ var init_shift_internal = __esm({
|
|
|
6584
6584
|
}
|
|
6585
6585
|
});
|
|
6586
6586
|
|
|
6587
|
+
// ../protocol/src/lark-bot-schemas.ts
|
|
6588
|
+
var LarkBotPersonaArgs, LarkBotUnbindArgs, LarkBotStatusArgs, LarkBotBindManualArgs, LarkBotGroupSchema, LarkBotStatusResultSchema, LarkBotStateFrameSchema;
|
|
6589
|
+
var init_lark_bot_schemas = __esm({
|
|
6590
|
+
"../protocol/src/lark-bot-schemas.ts"() {
|
|
6591
|
+
"use strict";
|
|
6592
|
+
init_zod();
|
|
6593
|
+
LarkBotPersonaArgs = external_exports.object({ personaId: external_exports.string().min(1) });
|
|
6594
|
+
LarkBotUnbindArgs = LarkBotPersonaArgs;
|
|
6595
|
+
LarkBotStatusArgs = LarkBotPersonaArgs;
|
|
6596
|
+
LarkBotBindManualArgs = external_exports.object({
|
|
6597
|
+
personaId: external_exports.string().min(1),
|
|
6598
|
+
appId: external_exports.string().min(1),
|
|
6599
|
+
appSecret: external_exports.string().min(1),
|
|
6600
|
+
botName: external_exports.string().min(1).optional()
|
|
6601
|
+
});
|
|
6602
|
+
LarkBotGroupSchema = external_exports.object({
|
|
6603
|
+
chatId: external_exports.string().min(1),
|
|
6604
|
+
chatName: external_exports.string().optional(),
|
|
6605
|
+
/** epoch ms,该群 session 最近一次活跃时间 */
|
|
6606
|
+
lastActiveAt: external_exports.number().int().optional()
|
|
6607
|
+
});
|
|
6608
|
+
LarkBotStatusResultSchema = external_exports.object({
|
|
6609
|
+
state: external_exports.enum(["unbound", "bound", "broken"]),
|
|
6610
|
+
appId: external_exports.string().optional(),
|
|
6611
|
+
botName: external_exports.string().optional(),
|
|
6612
|
+
brokenReason: external_exports.string().optional(),
|
|
6613
|
+
groups: external_exports.array(LarkBotGroupSchema)
|
|
6614
|
+
});
|
|
6615
|
+
LarkBotStateFrameSchema = LarkBotStatusResultSchema.extend({
|
|
6616
|
+
personaId: external_exports.string().min(1)
|
|
6617
|
+
});
|
|
6618
|
+
}
|
|
6619
|
+
});
|
|
6620
|
+
|
|
6587
6621
|
// ../protocol/src/persona-schemas.ts
|
|
6588
6622
|
var PersonaFileSchema, PersonaSkillSummarySchema, PersonaPluginSummarySchema, PersonaSandboxSettingsSchema, PersonaInfoResponseSchema, PersonaCreateArgsSchema, PersonaIdArgsSchema, PersonaUpdateArgsSchema, CodexSandboxSettingsSchema;
|
|
6589
6623
|
var init_persona_schemas = __esm({
|
|
@@ -6994,6 +7028,14 @@ var init_schemas = __esm({
|
|
|
6994
7028
|
* mirror,留 strip 防御)。
|
|
6995
7029
|
*/
|
|
6996
7030
|
shiftFiredFromSessionId: external_exports.string().min(1).optional(),
|
|
7031
|
+
/**
|
|
7032
|
+
* LarkBotConnector(spec 2026-08-05):该 session 是某飞书群的专属会话。
|
|
7033
|
+
* larkChatId = 飞书群 chat_id(oc_ 前缀),与 persona-guest scope 的 capId `lark-<chat_id>` 对应;
|
|
7034
|
+
* 由 daemon lark-bot-connector 模块写入,UI 只读(sidebar 按此字段隐藏,Drawer 群清单按此聚合)。
|
|
7035
|
+
*/
|
|
7036
|
+
larkChatId: external_exports.string().min(1).optional(),
|
|
7037
|
+
/** 飞书群名快照(展示用,随事件里的群名更新,可能滞后于飞书侧改名) */
|
|
7038
|
+
larkChatName: external_exports.string().min(1).optional(),
|
|
6997
7039
|
createdAt: external_exports.string().min(1),
|
|
6998
7040
|
updatedAt: external_exports.string().min(1)
|
|
6999
7041
|
});
|
|
@@ -7801,6 +7843,7 @@ var init_methods = __esm({
|
|
|
7801
7843
|
init_inbox();
|
|
7802
7844
|
init_peer_exec();
|
|
7803
7845
|
init_shift_internal();
|
|
7846
|
+
init_lark_bot_schemas();
|
|
7804
7847
|
init_persona_schemas();
|
|
7805
7848
|
init_schemas();
|
|
7806
7849
|
NO_ARGS = external_exports.object({});
|
|
@@ -7979,6 +8022,18 @@ var init_methods = __esm({
|
|
|
7979
8022
|
summary: "\u67E5 shift \u7684\u6267\u884C\u5386\u53F2\uFF08\u4EC5\u521B\u5EFA\u8005\uFF09",
|
|
7980
8023
|
args: ShiftInternalHistoryArgs
|
|
7981
8024
|
},
|
|
8025
|
+
"larkBot:bindManual": {
|
|
8026
|
+
summary: "\u624B\u586B app_id/app_secret \u7ED1\u5B9A\u73B0\u6709\u98DE\u4E66 bot\uFF08\u552F\u4E00\u7ED1\u5B9A\u5165\u53E3\uFF09\uFF1Bowner-only",
|
|
8027
|
+
args: LarkBotBindManualArgs
|
|
8028
|
+
},
|
|
8029
|
+
"larkBot:unbind": {
|
|
8030
|
+
summary: "\u89E3\u7ED1 persona \u7684\u98DE\u4E66 bot\uFF08\u5220\u4E91\u7AEF\u7ED1\u5B9A + \u65AD\u957F\u8FDE\u63A5\uFF0C\u98DE\u4E66\u4FA7 app \u4FDD\u7559\uFF09\uFF1Bowner-only",
|
|
8031
|
+
args: LarkBotUnbindArgs
|
|
8032
|
+
},
|
|
8033
|
+
"larkBot:status": {
|
|
8034
|
+
summary: "\u67E5 persona \u7684\u98DE\u4E66 bot \u72B6\u6001\uFF08unbound/bound/broken + \u670D\u52A1\u4E2D\u7FA4\u6E05\u5355\uFF09\uFF1Bowner-only",
|
|
8035
|
+
args: LarkBotStatusArgs
|
|
8036
|
+
},
|
|
7982
8037
|
"skills:list": {
|
|
7983
8038
|
summary: "\u626B\u63CF\u5E76\u5217\u51FA\u8BE5\u76EE\u5F55\u53EF\u7528\u7684 skill",
|
|
7984
8039
|
args: SkillsListArgs
|
|
@@ -8418,6 +8473,7 @@ var init_runtime = __esm({
|
|
|
8418
8473
|
init_log();
|
|
8419
8474
|
init_visitor_schemas();
|
|
8420
8475
|
init_shift_internal();
|
|
8476
|
+
init_lark_bot_schemas();
|
|
8421
8477
|
}
|
|
8422
8478
|
});
|
|
8423
8479
|
|
|
@@ -8692,8 +8748,8 @@ var require_req = __commonJS({
|
|
|
8692
8748
|
if (req.originalUrl) {
|
|
8693
8749
|
_req.url = req.originalUrl;
|
|
8694
8750
|
} else {
|
|
8695
|
-
const
|
|
8696
|
-
_req.url = typeof
|
|
8751
|
+
const path78 = req.path;
|
|
8752
|
+
_req.url = typeof path78 === "string" ? path78 : req.url ? req.url.path || req.url : void 0;
|
|
8697
8753
|
}
|
|
8698
8754
|
if (req.query) {
|
|
8699
8755
|
_req.query = req.query;
|
|
@@ -8858,14 +8914,14 @@ var require_redact = __commonJS({
|
|
|
8858
8914
|
}
|
|
8859
8915
|
return obj;
|
|
8860
8916
|
}
|
|
8861
|
-
function parsePath(
|
|
8917
|
+
function parsePath(path78) {
|
|
8862
8918
|
const parts = [];
|
|
8863
8919
|
let current = "";
|
|
8864
8920
|
let inBrackets = false;
|
|
8865
8921
|
let inQuotes = false;
|
|
8866
8922
|
let quoteChar = "";
|
|
8867
|
-
for (let i = 0; i <
|
|
8868
|
-
const char =
|
|
8923
|
+
for (let i = 0; i < path78.length; i++) {
|
|
8924
|
+
const char = path78[i];
|
|
8869
8925
|
if (!inBrackets && char === ".") {
|
|
8870
8926
|
if (current) {
|
|
8871
8927
|
parts.push(current);
|
|
@@ -8996,10 +9052,10 @@ var require_redact = __commonJS({
|
|
|
8996
9052
|
return current;
|
|
8997
9053
|
}
|
|
8998
9054
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
8999
|
-
for (const
|
|
9000
|
-
const parts = parsePath(
|
|
9055
|
+
for (const path78 of paths) {
|
|
9056
|
+
const parts = parsePath(path78);
|
|
9001
9057
|
if (parts.includes("*")) {
|
|
9002
|
-
redactWildcardPath(obj, parts, censor,
|
|
9058
|
+
redactWildcardPath(obj, parts, censor, path78, remove);
|
|
9003
9059
|
} else {
|
|
9004
9060
|
if (remove) {
|
|
9005
9061
|
removeKey(obj, parts);
|
|
@@ -9084,8 +9140,8 @@ var require_redact = __commonJS({
|
|
|
9084
9140
|
}
|
|
9085
9141
|
} else {
|
|
9086
9142
|
if (afterWildcard.includes("*")) {
|
|
9087
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
9088
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
9143
|
+
const wrappedCensor = typeof censor === "function" ? (value, path78) => {
|
|
9144
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path78];
|
|
9089
9145
|
return censor(value, fullPath);
|
|
9090
9146
|
} : censor;
|
|
9091
9147
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -9120,8 +9176,8 @@ var require_redact = __commonJS({
|
|
|
9120
9176
|
return null;
|
|
9121
9177
|
}
|
|
9122
9178
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
9123
|
-
for (const
|
|
9124
|
-
const parts = parsePath(
|
|
9179
|
+
for (const path78 of pathsToClone) {
|
|
9180
|
+
const parts = parsePath(path78);
|
|
9125
9181
|
let current = pathStructure;
|
|
9126
9182
|
for (let i = 0; i < parts.length; i++) {
|
|
9127
9183
|
const part = parts[i];
|
|
@@ -9173,24 +9229,24 @@ var require_redact = __commonJS({
|
|
|
9173
9229
|
}
|
|
9174
9230
|
return cloneSelectively(obj, pathStructure);
|
|
9175
9231
|
}
|
|
9176
|
-
function validatePath(
|
|
9177
|
-
if (typeof
|
|
9232
|
+
function validatePath(path78) {
|
|
9233
|
+
if (typeof path78 !== "string") {
|
|
9178
9234
|
throw new Error("Paths must be (non-empty) strings");
|
|
9179
9235
|
}
|
|
9180
|
-
if (
|
|
9236
|
+
if (path78 === "") {
|
|
9181
9237
|
throw new Error("Invalid redaction path ()");
|
|
9182
9238
|
}
|
|
9183
|
-
if (
|
|
9184
|
-
throw new Error(`Invalid redaction path (${
|
|
9239
|
+
if (path78.includes("..")) {
|
|
9240
|
+
throw new Error(`Invalid redaction path (${path78})`);
|
|
9185
9241
|
}
|
|
9186
|
-
if (
|
|
9187
|
-
throw new Error(`Invalid redaction path (${
|
|
9242
|
+
if (path78.includes(",")) {
|
|
9243
|
+
throw new Error(`Invalid redaction path (${path78})`);
|
|
9188
9244
|
}
|
|
9189
9245
|
let bracketCount = 0;
|
|
9190
9246
|
let inQuotes = false;
|
|
9191
9247
|
let quoteChar = "";
|
|
9192
|
-
for (let i = 0; i <
|
|
9193
|
-
const char =
|
|
9248
|
+
for (let i = 0; i < path78.length; i++) {
|
|
9249
|
+
const char = path78[i];
|
|
9194
9250
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
9195
9251
|
if (!inQuotes) {
|
|
9196
9252
|
inQuotes = true;
|
|
@@ -9204,20 +9260,20 @@ var require_redact = __commonJS({
|
|
|
9204
9260
|
} else if (char === "]" && !inQuotes) {
|
|
9205
9261
|
bracketCount--;
|
|
9206
9262
|
if (bracketCount < 0) {
|
|
9207
|
-
throw new Error(`Invalid redaction path (${
|
|
9263
|
+
throw new Error(`Invalid redaction path (${path78})`);
|
|
9208
9264
|
}
|
|
9209
9265
|
}
|
|
9210
9266
|
}
|
|
9211
9267
|
if (bracketCount !== 0) {
|
|
9212
|
-
throw new Error(`Invalid redaction path (${
|
|
9268
|
+
throw new Error(`Invalid redaction path (${path78})`);
|
|
9213
9269
|
}
|
|
9214
9270
|
}
|
|
9215
9271
|
function validatePaths(paths) {
|
|
9216
9272
|
if (!Array.isArray(paths)) {
|
|
9217
9273
|
throw new TypeError("paths must be an array");
|
|
9218
9274
|
}
|
|
9219
|
-
for (const
|
|
9220
|
-
validatePath(
|
|
9275
|
+
for (const path78 of paths) {
|
|
9276
|
+
validatePath(path78);
|
|
9221
9277
|
}
|
|
9222
9278
|
}
|
|
9223
9279
|
function slowRedact(options = {}) {
|
|
@@ -9385,8 +9441,8 @@ var require_redaction = __commonJS({
|
|
|
9385
9441
|
if (shape[k2] === null) {
|
|
9386
9442
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
9387
9443
|
} else {
|
|
9388
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
9389
|
-
return censor(value, [k2, ...
|
|
9444
|
+
const wrappedCensor = typeof censor === "function" ? (value, path78) => {
|
|
9445
|
+
return censor(value, [k2, ...path78]);
|
|
9390
9446
|
} : censor;
|
|
9391
9447
|
o[k2] = Redact({
|
|
9392
9448
|
paths: shape[k2],
|
|
@@ -9604,10 +9660,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
9604
9660
|
var require_sonic_boom = __commonJS({
|
|
9605
9661
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
9606
9662
|
"use strict";
|
|
9607
|
-
var
|
|
9663
|
+
var fs68 = require("fs");
|
|
9608
9664
|
var EventEmitter3 = require("events");
|
|
9609
9665
|
var inherits = require("util").inherits;
|
|
9610
|
-
var
|
|
9666
|
+
var path78 = require("path");
|
|
9611
9667
|
var sleep2 = require_atomic_sleep();
|
|
9612
9668
|
var assert = require("assert");
|
|
9613
9669
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -9661,20 +9717,20 @@ var require_sonic_boom = __commonJS({
|
|
|
9661
9717
|
const mode = sonic.mode;
|
|
9662
9718
|
if (sonic.sync) {
|
|
9663
9719
|
try {
|
|
9664
|
-
if (sonic.mkdir)
|
|
9665
|
-
const fd =
|
|
9720
|
+
if (sonic.mkdir) fs68.mkdirSync(path78.dirname(file), { recursive: true });
|
|
9721
|
+
const fd = fs68.openSync(file, flags, mode);
|
|
9666
9722
|
fileOpened(null, fd);
|
|
9667
9723
|
} catch (err) {
|
|
9668
9724
|
fileOpened(err);
|
|
9669
9725
|
throw err;
|
|
9670
9726
|
}
|
|
9671
9727
|
} else if (sonic.mkdir) {
|
|
9672
|
-
|
|
9728
|
+
fs68.mkdir(path78.dirname(file), { recursive: true }, (err) => {
|
|
9673
9729
|
if (err) return fileOpened(err);
|
|
9674
|
-
|
|
9730
|
+
fs68.open(file, flags, mode, fileOpened);
|
|
9675
9731
|
});
|
|
9676
9732
|
} else {
|
|
9677
|
-
|
|
9733
|
+
fs68.open(file, flags, mode, fileOpened);
|
|
9678
9734
|
}
|
|
9679
9735
|
}
|
|
9680
9736
|
function SonicBoom(opts) {
|
|
@@ -9715,8 +9771,8 @@ var require_sonic_boom = __commonJS({
|
|
|
9715
9771
|
this.flush = flushBuffer;
|
|
9716
9772
|
this.flushSync = flushBufferSync;
|
|
9717
9773
|
this._actualWrite = actualWriteBuffer;
|
|
9718
|
-
fsWriteSync = () =>
|
|
9719
|
-
fsWrite = () =>
|
|
9774
|
+
fsWriteSync = () => fs68.writeSync(this.fd, this._writingBuf);
|
|
9775
|
+
fsWrite = () => fs68.write(this.fd, this._writingBuf, this.release);
|
|
9720
9776
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
9721
9777
|
this._writingBuf = "";
|
|
9722
9778
|
this.write = write;
|
|
@@ -9725,15 +9781,15 @@ var require_sonic_boom = __commonJS({
|
|
|
9725
9781
|
this._actualWrite = actualWrite;
|
|
9726
9782
|
fsWriteSync = () => {
|
|
9727
9783
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
9728
|
-
return
|
|
9784
|
+
return fs68.writeSync(this.fd, this._writingBuf);
|
|
9729
9785
|
}
|
|
9730
|
-
return
|
|
9786
|
+
return fs68.writeSync(this.fd, this._writingBuf, "utf8");
|
|
9731
9787
|
};
|
|
9732
9788
|
fsWrite = () => {
|
|
9733
9789
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
9734
|
-
return
|
|
9790
|
+
return fs68.write(this.fd, this._writingBuf, this.release);
|
|
9735
9791
|
}
|
|
9736
|
-
return
|
|
9792
|
+
return fs68.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
9737
9793
|
};
|
|
9738
9794
|
} else {
|
|
9739
9795
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -9790,7 +9846,7 @@ var require_sonic_boom = __commonJS({
|
|
|
9790
9846
|
}
|
|
9791
9847
|
}
|
|
9792
9848
|
if (this._fsync) {
|
|
9793
|
-
|
|
9849
|
+
fs68.fsyncSync(this.fd);
|
|
9794
9850
|
}
|
|
9795
9851
|
const len = this._len;
|
|
9796
9852
|
if (this._reopening) {
|
|
@@ -9904,7 +9960,7 @@ var require_sonic_boom = __commonJS({
|
|
|
9904
9960
|
const onDrain = () => {
|
|
9905
9961
|
if (!this._fsync) {
|
|
9906
9962
|
try {
|
|
9907
|
-
|
|
9963
|
+
fs68.fsync(this.fd, (err) => {
|
|
9908
9964
|
this._flushPending = false;
|
|
9909
9965
|
cb(err);
|
|
9910
9966
|
});
|
|
@@ -10006,7 +10062,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10006
10062
|
const fd = this.fd;
|
|
10007
10063
|
this.once("ready", () => {
|
|
10008
10064
|
if (fd !== this.fd) {
|
|
10009
|
-
|
|
10065
|
+
fs68.close(fd, (err) => {
|
|
10010
10066
|
if (err) {
|
|
10011
10067
|
return this.emit("error", err);
|
|
10012
10068
|
}
|
|
@@ -10055,7 +10111,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10055
10111
|
buf = this._bufs[0];
|
|
10056
10112
|
}
|
|
10057
10113
|
try {
|
|
10058
|
-
const n = Buffer.isBuffer(buf) ?
|
|
10114
|
+
const n = Buffer.isBuffer(buf) ? fs68.writeSync(this.fd, buf) : fs68.writeSync(this.fd, buf, "utf8");
|
|
10059
10115
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
10060
10116
|
buf = releasedBufObj.writingBuf;
|
|
10061
10117
|
this._len = releasedBufObj.len;
|
|
@@ -10071,7 +10127,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10071
10127
|
}
|
|
10072
10128
|
}
|
|
10073
10129
|
try {
|
|
10074
|
-
|
|
10130
|
+
fs68.fsyncSync(this.fd);
|
|
10075
10131
|
} catch {
|
|
10076
10132
|
}
|
|
10077
10133
|
}
|
|
@@ -10092,7 +10148,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10092
10148
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
10093
10149
|
}
|
|
10094
10150
|
try {
|
|
10095
|
-
const n =
|
|
10151
|
+
const n = fs68.writeSync(this.fd, buf);
|
|
10096
10152
|
buf = buf.subarray(n);
|
|
10097
10153
|
this._len = Math.max(this._len - n, 0);
|
|
10098
10154
|
if (buf.length <= 0) {
|
|
@@ -10120,13 +10176,13 @@ var require_sonic_boom = __commonJS({
|
|
|
10120
10176
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
10121
10177
|
if (this.sync) {
|
|
10122
10178
|
try {
|
|
10123
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
10179
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs68.writeSync(this.fd, this._writingBuf) : fs68.writeSync(this.fd, this._writingBuf, "utf8");
|
|
10124
10180
|
release(null, written);
|
|
10125
10181
|
} catch (err) {
|
|
10126
10182
|
release(err);
|
|
10127
10183
|
}
|
|
10128
10184
|
} else {
|
|
10129
|
-
|
|
10185
|
+
fs68.write(this.fd, this._writingBuf, release);
|
|
10130
10186
|
}
|
|
10131
10187
|
}
|
|
10132
10188
|
function actualWriteBuffer() {
|
|
@@ -10135,7 +10191,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10135
10191
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
10136
10192
|
if (this.sync) {
|
|
10137
10193
|
try {
|
|
10138
|
-
const written =
|
|
10194
|
+
const written = fs68.writeSync(this.fd, this._writingBuf);
|
|
10139
10195
|
release(null, written);
|
|
10140
10196
|
} catch (err) {
|
|
10141
10197
|
release(err);
|
|
@@ -10144,7 +10200,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10144
10200
|
if (kCopyBuffer) {
|
|
10145
10201
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
10146
10202
|
}
|
|
10147
|
-
|
|
10203
|
+
fs68.write(this.fd, this._writingBuf, release);
|
|
10148
10204
|
}
|
|
10149
10205
|
}
|
|
10150
10206
|
function actualClose(sonic) {
|
|
@@ -10160,12 +10216,12 @@ var require_sonic_boom = __commonJS({
|
|
|
10160
10216
|
sonic._lens = [];
|
|
10161
10217
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
10162
10218
|
try {
|
|
10163
|
-
|
|
10219
|
+
fs68.fsync(sonic.fd, closeWrapped);
|
|
10164
10220
|
} catch {
|
|
10165
10221
|
}
|
|
10166
10222
|
function closeWrapped() {
|
|
10167
10223
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
10168
|
-
|
|
10224
|
+
fs68.close(sonic.fd, done);
|
|
10169
10225
|
} else {
|
|
10170
10226
|
done();
|
|
10171
10227
|
}
|
|
@@ -13300,11 +13356,11 @@ var init_lib = __esm({
|
|
|
13300
13356
|
}
|
|
13301
13357
|
}
|
|
13302
13358
|
},
|
|
13303
|
-
addToPath: function addToPath(
|
|
13304
|
-
var last =
|
|
13359
|
+
addToPath: function addToPath(path78, added, removed, oldPosInc, options) {
|
|
13360
|
+
var last = path78.lastComponent;
|
|
13305
13361
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
13306
13362
|
return {
|
|
13307
|
-
oldPos:
|
|
13363
|
+
oldPos: path78.oldPos + oldPosInc,
|
|
13308
13364
|
lastComponent: {
|
|
13309
13365
|
count: last.count + 1,
|
|
13310
13366
|
added,
|
|
@@ -13314,7 +13370,7 @@ var init_lib = __esm({
|
|
|
13314
13370
|
};
|
|
13315
13371
|
} else {
|
|
13316
13372
|
return {
|
|
13317
|
-
oldPos:
|
|
13373
|
+
oldPos: path78.oldPos + oldPosInc,
|
|
13318
13374
|
lastComponent: {
|
|
13319
13375
|
count: 1,
|
|
13320
13376
|
added,
|
|
@@ -13823,10 +13879,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
13823
13879
|
const memories = raw.map((m2) => {
|
|
13824
13880
|
if (!m2 || typeof m2 !== "object") return null;
|
|
13825
13881
|
const rec3 = m2;
|
|
13826
|
-
const
|
|
13882
|
+
const path78 = typeof rec3.path === "string" ? rec3.path : null;
|
|
13827
13883
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
13828
|
-
if (!
|
|
13829
|
-
const entry = { path:
|
|
13884
|
+
if (!path78 || content == null) return null;
|
|
13885
|
+
const entry = { path: path78, content };
|
|
13830
13886
|
if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
|
|
13831
13887
|
return entry;
|
|
13832
13888
|
}).filter((m2) => m2 !== null);
|
|
@@ -14629,10 +14685,10 @@ function parseAttachment(obj) {
|
|
|
14629
14685
|
const memories = raw.map((m2) => {
|
|
14630
14686
|
if (!m2 || typeof m2 !== "object") return null;
|
|
14631
14687
|
const rec3 = m2;
|
|
14632
|
-
const
|
|
14688
|
+
const path78 = typeof rec3.path === "string" ? rec3.path : null;
|
|
14633
14689
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
14634
|
-
if (!
|
|
14635
|
-
const out = { path:
|
|
14690
|
+
if (!path78 || content == null) return null;
|
|
14691
|
+
const out = { path: path78, content };
|
|
14636
14692
|
if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
|
|
14637
14693
|
return out;
|
|
14638
14694
|
}).filter((m2) => m2 !== null);
|
|
@@ -35601,8 +35657,8 @@ var require_utils = __commonJS({
|
|
|
35601
35657
|
var result = transform[inputType][outputType](input);
|
|
35602
35658
|
return result;
|
|
35603
35659
|
};
|
|
35604
|
-
exports2.resolve = function(
|
|
35605
|
-
var parts =
|
|
35660
|
+
exports2.resolve = function(path78) {
|
|
35661
|
+
var parts = path78.split("/");
|
|
35606
35662
|
var result = [];
|
|
35607
35663
|
for (var index = 0; index < parts.length; index++) {
|
|
35608
35664
|
var part = parts[index];
|
|
@@ -41455,18 +41511,18 @@ var require_object = __commonJS({
|
|
|
41455
41511
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
41456
41512
|
this.files[name] = object;
|
|
41457
41513
|
};
|
|
41458
|
-
var parentFolder = function(
|
|
41459
|
-
if (
|
|
41460
|
-
|
|
41514
|
+
var parentFolder = function(path78) {
|
|
41515
|
+
if (path78.slice(-1) === "/") {
|
|
41516
|
+
path78 = path78.substring(0, path78.length - 1);
|
|
41461
41517
|
}
|
|
41462
|
-
var lastSlash =
|
|
41463
|
-
return lastSlash > 0 ?
|
|
41518
|
+
var lastSlash = path78.lastIndexOf("/");
|
|
41519
|
+
return lastSlash > 0 ? path78.substring(0, lastSlash) : "";
|
|
41464
41520
|
};
|
|
41465
|
-
var forceTrailingSlash = function(
|
|
41466
|
-
if (
|
|
41467
|
-
|
|
41521
|
+
var forceTrailingSlash = function(path78) {
|
|
41522
|
+
if (path78.slice(-1) !== "/") {
|
|
41523
|
+
path78 += "/";
|
|
41468
41524
|
}
|
|
41469
|
-
return
|
|
41525
|
+
return path78;
|
|
41470
41526
|
};
|
|
41471
41527
|
var folderAdd = function(name, createFolders) {
|
|
41472
41528
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -42468,7 +42524,7 @@ var require_lib3 = __commonJS({
|
|
|
42468
42524
|
// src/run-case/recorder.ts
|
|
42469
42525
|
function startRunCaseRecorder(opts) {
|
|
42470
42526
|
const now = opts.now ?? Date.now;
|
|
42471
|
-
const dir =
|
|
42527
|
+
const dir = import_node_path65.default.dirname(opts.recordPath);
|
|
42472
42528
|
let stream = null;
|
|
42473
42529
|
let closing = false;
|
|
42474
42530
|
let closedSettled = false;
|
|
@@ -42482,8 +42538,8 @@ function startRunCaseRecorder(opts) {
|
|
|
42482
42538
|
});
|
|
42483
42539
|
const ensureStream = () => {
|
|
42484
42540
|
if (stream) return stream;
|
|
42485
|
-
|
|
42486
|
-
stream =
|
|
42541
|
+
import_node_fs49.default.mkdirSync(dir, { recursive: true });
|
|
42542
|
+
stream = import_node_fs49.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
42487
42543
|
stream.on("close", () => closedResolve());
|
|
42488
42544
|
return stream;
|
|
42489
42545
|
};
|
|
@@ -42508,12 +42564,12 @@ function startRunCaseRecorder(opts) {
|
|
|
42508
42564
|
};
|
|
42509
42565
|
return { tap, close, closed };
|
|
42510
42566
|
}
|
|
42511
|
-
var
|
|
42567
|
+
var import_node_fs49, import_node_path65;
|
|
42512
42568
|
var init_recorder = __esm({
|
|
42513
42569
|
"src/run-case/recorder.ts"() {
|
|
42514
42570
|
"use strict";
|
|
42515
|
-
|
|
42516
|
-
|
|
42571
|
+
import_node_fs49 = __toESM(require("fs"), 1);
|
|
42572
|
+
import_node_path65 = __toESM(require("path"), 1);
|
|
42517
42573
|
}
|
|
42518
42574
|
});
|
|
42519
42575
|
|
|
@@ -42556,7 +42612,7 @@ var init_wire = __esm({
|
|
|
42556
42612
|
// src/run-case/controller.ts
|
|
42557
42613
|
async function runController(opts) {
|
|
42558
42614
|
const now = opts.now ?? Date.now;
|
|
42559
|
-
const cwd = opts.cwd ?? (0,
|
|
42615
|
+
const cwd = opts.cwd ?? (0, import_node_fs50.mkdtempSync)(import_node_path66.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
|
|
42560
42616
|
const ownsCwd = opts.cwd === void 0;
|
|
42561
42617
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
42562
42618
|
const spawnCtx = { cwd };
|
|
@@ -42717,19 +42773,19 @@ async function runController(opts) {
|
|
|
42717
42773
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
42718
42774
|
if (ownsCwd) {
|
|
42719
42775
|
try {
|
|
42720
|
-
(0,
|
|
42776
|
+
(0, import_node_fs50.rmSync)(cwd, { recursive: true, force: true });
|
|
42721
42777
|
} catch {
|
|
42722
42778
|
}
|
|
42723
42779
|
}
|
|
42724
42780
|
return exitCode ?? 0;
|
|
42725
42781
|
}
|
|
42726
|
-
var
|
|
42782
|
+
var import_node_fs50, import_node_os23, import_node_path66;
|
|
42727
42783
|
var init_controller = __esm({
|
|
42728
42784
|
"src/run-case/controller.ts"() {
|
|
42729
42785
|
"use strict";
|
|
42730
|
-
|
|
42786
|
+
import_node_fs50 = require("fs");
|
|
42731
42787
|
import_node_os23 = __toESM(require("os"), 1);
|
|
42732
|
-
|
|
42788
|
+
import_node_path66 = __toESM(require("path"), 1);
|
|
42733
42789
|
init_claude();
|
|
42734
42790
|
init_stdout_splitter();
|
|
42735
42791
|
init_permission_stdio();
|
|
@@ -43004,8 +43060,8 @@ Env (advanced):
|
|
|
43004
43060
|
`;
|
|
43005
43061
|
|
|
43006
43062
|
// src/index.ts
|
|
43007
|
-
var
|
|
43008
|
-
var
|
|
43063
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
43064
|
+
var import_node_fs48 = __toESM(require("fs"), 1);
|
|
43009
43065
|
var import_node_os22 = __toESM(require("os"), 1);
|
|
43010
43066
|
|
|
43011
43067
|
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
@@ -43893,6 +43949,28 @@ ${r.outcome.text}${files}`;
|
|
|
43893
43949
|
return ["\u4F60\u4E4B\u524D\u59D4\u6D3E\u51FA\u53BB\u7684\u4EFB\u52A1\u6709\u4E86\u7ED3\u679C\uFF1A", "", blocks.join("\n\n")].join("\n");
|
|
43894
43950
|
}
|
|
43895
43951
|
|
|
43952
|
+
// src/session/lark-reply.ts
|
|
43953
|
+
function extractLarkReplyText(events) {
|
|
43954
|
+
let lastUserIdx = -1;
|
|
43955
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
43956
|
+
if (events[i].kind === "user_text") {
|
|
43957
|
+
lastUserIdx = i;
|
|
43958
|
+
break;
|
|
43959
|
+
}
|
|
43960
|
+
}
|
|
43961
|
+
const tail = events.slice(lastUserIdx + 1);
|
|
43962
|
+
const order = [];
|
|
43963
|
+
const latest = /* @__PURE__ */ new Map();
|
|
43964
|
+
let anon = 0;
|
|
43965
|
+
for (const ev of tail) {
|
|
43966
|
+
if (ev.kind !== "text") continue;
|
|
43967
|
+
const key = ev.partialId ?? `__snapshot_${anon++}`;
|
|
43968
|
+
if (!latest.has(key)) order.push(key);
|
|
43969
|
+
latest.set(key, ev.text);
|
|
43970
|
+
}
|
|
43971
|
+
return order.map((k2) => latest.get(k2) ?? "").filter((t) => t.length > 0).join("\n").trim();
|
|
43972
|
+
}
|
|
43973
|
+
|
|
43896
43974
|
// src/session/runner.ts
|
|
43897
43975
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
43898
43976
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
@@ -47021,6 +47099,110 @@ var SessionManager = class {
|
|
|
47021
47099
|
});
|
|
47022
47100
|
return { sessionId, ended, kill: killImpl };
|
|
47023
47101
|
}
|
|
47102
|
+
/**
|
|
47103
|
+
* LarkBotConnector(spec 2026-08-05 §5.3):把一条飞书群 @ 消息作为一个 turn 驱动
|
|
47104
|
+
* 该群的专属 guest session,turn-idle 后从 reducer buffer 提取回复文本。
|
|
47105
|
+
*
|
|
47106
|
+
* 跟 createShiftSession 的差异:
|
|
47107
|
+
* - **find-or-create**:按 capId `lark-<chatId>` 找现存 session(一群一条,D3),
|
|
47108
|
+
* 没有才建;daemon `create` 的无 dedupe 语义不变——dedupe 是本方法私有实现
|
|
47109
|
+
* - guest scope + 沙箱:群成员 query 不带 owner 权限;10min guest idle-kill + resume
|
|
47110
|
+
* - turn-idle 后**不 kill**(session 常驻,记忆即价值);延迟 settleDelayMs 等尾随
|
|
47111
|
+
* text 落盘(schemas.ts turn_end 注释:CC 写 turn_end 早于尾段正文)再读 buffer
|
|
47112
|
+
* - 回复提取:extractLarkReplyText(最后一条 user_text 之后的 text 事件拼接)
|
|
47113
|
+
*/
|
|
47114
|
+
runLarkChatTurn(args) {
|
|
47115
|
+
if (!this.deps.personaRoot) {
|
|
47116
|
+
throw new Error("runLarkChatTurn: personaRoot missing in ManagerDeps");
|
|
47117
|
+
}
|
|
47118
|
+
const capId = `lark-${args.chatId}`;
|
|
47119
|
+
const scope = {
|
|
47120
|
+
kind: "persona",
|
|
47121
|
+
personaId: args.personaId,
|
|
47122
|
+
mode: "guest",
|
|
47123
|
+
capId
|
|
47124
|
+
};
|
|
47125
|
+
const store = this.storeFor(scope);
|
|
47126
|
+
let file = store.list().find((f) => f.larkChatId === args.chatId);
|
|
47127
|
+
if (!file) {
|
|
47128
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
47129
|
+
file = {
|
|
47130
|
+
sessionId: newSessionId(),
|
|
47131
|
+
cwd: import_node_path9.default.join(this.deps.personaRoot, safeFileName(args.personaId)),
|
|
47132
|
+
tool: this.deps.getPersonaTool?.(args.personaId) ?? "claude",
|
|
47133
|
+
ownerPersonaId: args.personaId,
|
|
47134
|
+
// guest 三件套:creatorPrincipalId=capId(scopeForFile 回落防线)、
|
|
47135
|
+
// creatorDisplayName(reducer guest 分支硬性要求,缺则 spawn 抛)
|
|
47136
|
+
creatorPrincipalId: capId,
|
|
47137
|
+
creatorDisplayName: `\u98DE\u4E66\u7FA4\xB7${args.chatName ?? args.chatId}`,
|
|
47138
|
+
larkChatId: args.chatId,
|
|
47139
|
+
...args.chatName ? { larkChatName: args.chatName } : {},
|
|
47140
|
+
createdAt: now,
|
|
47141
|
+
updatedAt: now
|
|
47142
|
+
};
|
|
47143
|
+
store.write(file);
|
|
47144
|
+
this.deps.logger?.info("larkBot.runLarkChatTurn.session-created", {
|
|
47145
|
+
sessionId: file.sessionId,
|
|
47146
|
+
personaId: args.personaId,
|
|
47147
|
+
chatId: args.chatId
|
|
47148
|
+
});
|
|
47149
|
+
} else if (args.chatName && file.larkChatName !== args.chatName) {
|
|
47150
|
+
file = { ...file, larkChatName: args.chatName, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
47151
|
+
store.write(file);
|
|
47152
|
+
}
|
|
47153
|
+
const sessionId = file.sessionId;
|
|
47154
|
+
let resolveEnded = () => {
|
|
47155
|
+
};
|
|
47156
|
+
const ended = new Promise((r) => {
|
|
47157
|
+
resolveEnded = r;
|
|
47158
|
+
});
|
|
47159
|
+
let unsubscribe = () => {
|
|
47160
|
+
};
|
|
47161
|
+
let settled = false;
|
|
47162
|
+
const settle = (info) => {
|
|
47163
|
+
if (settled) return;
|
|
47164
|
+
settled = true;
|
|
47165
|
+
unsubscribe();
|
|
47166
|
+
resolveEnded(info);
|
|
47167
|
+
};
|
|
47168
|
+
const killImpl = () => {
|
|
47169
|
+
const r = this.runners.get(sessionId);
|
|
47170
|
+
if (!r) return;
|
|
47171
|
+
r.input({ kind: "command", command: { kind: "stop" } });
|
|
47172
|
+
};
|
|
47173
|
+
const settleDelayMs = args.settleDelayMs ?? 500;
|
|
47174
|
+
unsubscribe = this.subscribe(
|
|
47175
|
+
sessionId,
|
|
47176
|
+
scope,
|
|
47177
|
+
makeEndFrameHandler(sessionId, (info) => {
|
|
47178
|
+
if (info.kind === "idle") {
|
|
47179
|
+
setTimeout(() => {
|
|
47180
|
+
try {
|
|
47181
|
+
const events = this.readHistoryEventsForScope(sessionId, scope);
|
|
47182
|
+
const replyText = extractLarkReplyText(events);
|
|
47183
|
+
settle(replyText ? { ok: true, replyText } : { error: "empty reply" });
|
|
47184
|
+
} catch (err) {
|
|
47185
|
+
settle({ error: err.message });
|
|
47186
|
+
}
|
|
47187
|
+
}, settleDelayMs);
|
|
47188
|
+
} else if (info.kind === "stopped") {
|
|
47189
|
+
settle({ error: "session stopped before reply" });
|
|
47190
|
+
} else {
|
|
47191
|
+
settle({ error: info.message || "session error" });
|
|
47192
|
+
}
|
|
47193
|
+
})
|
|
47194
|
+
);
|
|
47195
|
+
const runner = this.ensureRunnerForScope(file, scope);
|
|
47196
|
+
runner.input({
|
|
47197
|
+
kind: "command",
|
|
47198
|
+
command: {
|
|
47199
|
+
kind: "send",
|
|
47200
|
+
text: args.text,
|
|
47201
|
+
senderPrincipal: makeGuestSender(capId, args.senderName)
|
|
47202
|
+
}
|
|
47203
|
+
});
|
|
47204
|
+
return { sessionId, ended, kill: killImpl };
|
|
47205
|
+
}
|
|
47024
47206
|
/**
|
|
47025
47207
|
* 老板插话:把 'inject-owner-text' input 喂给对应 runner,
|
|
47026
47208
|
* runner 不存在时按 scope 懒创建。
|
|
@@ -49024,8 +49206,8 @@ function turnStartInput(text) {
|
|
|
49024
49206
|
const items = [];
|
|
49025
49207
|
let leftover = text;
|
|
49026
49208
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
49027
|
-
const [marker, name,
|
|
49028
|
-
items.push({ type: "skill", name, path:
|
|
49209
|
+
const [marker, name, path78] = m2;
|
|
49210
|
+
items.push({ type: "skill", name, path: path78 });
|
|
49029
49211
|
leftover = leftover.replace(marker, "");
|
|
49030
49212
|
}
|
|
49031
49213
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -51526,6 +51708,374 @@ function buildShiftInternalHandlers(deps) {
|
|
|
51526
51708
|
};
|
|
51527
51709
|
}
|
|
51528
51710
|
|
|
51711
|
+
// src/handlers/lark-bot.ts
|
|
51712
|
+
init_protocol();
|
|
51713
|
+
function statusFrame(personaId2, status) {
|
|
51714
|
+
return { type: "larkBot:state", personaId: personaId2, ...status };
|
|
51715
|
+
}
|
|
51716
|
+
function buildLarkBotHandlers(deps) {
|
|
51717
|
+
const now = deps.now ?? Date.now;
|
|
51718
|
+
const groupsOf = (personaId2) => {
|
|
51719
|
+
const removed = new Set(deps.store.read(personaId2)?.removedChatIds ?? []);
|
|
51720
|
+
return deps.listLarkSessions(personaId2).filter((g2) => !removed.has(g2.chatId));
|
|
51721
|
+
};
|
|
51722
|
+
const emit = (personaId2, status2) => {
|
|
51723
|
+
deps.broadcast(statusFrame(personaId2, status2));
|
|
51724
|
+
};
|
|
51725
|
+
const bindManual = async (frame) => {
|
|
51726
|
+
const { personaId: personaId2, appId, appSecret, botName } = parseArgs2(
|
|
51727
|
+
LarkBotBindManualArgs,
|
|
51728
|
+
frame,
|
|
51729
|
+
"larkBot:bindManual"
|
|
51730
|
+
);
|
|
51731
|
+
const tunnelUrl = deps.getTunnelUrl();
|
|
51732
|
+
if (!tunnelUrl) throw new Error("larkBot bind requires tunnel to be up");
|
|
51733
|
+
const ownerId = deps.getOwnerId();
|
|
51734
|
+
if (!ownerId) throw new Error("larkBot bind requires feishu login (owner identity)");
|
|
51735
|
+
const name = botName ?? deps.getPersonaName(personaId2) ?? personaId2;
|
|
51736
|
+
await deps.cloud.bind({ personaId: personaId2, appId, appSecret, botName: name, tunnelUrl, ownerId });
|
|
51737
|
+
deps.store.write(personaId2, { appId, botName: name, boundAt: now() });
|
|
51738
|
+
emit(personaId2, { state: "bound", appId, botName: name, groups: groupsOf(personaId2) });
|
|
51739
|
+
return { response: { type: "larkBot:bindManual:ok" } };
|
|
51740
|
+
};
|
|
51741
|
+
const unbind = async (frame) => {
|
|
51742
|
+
const { personaId: personaId2 } = parseArgs2(LarkBotUnbindArgs, frame, "larkBot:unbind");
|
|
51743
|
+
const meta = deps.store.read(personaId2);
|
|
51744
|
+
if (!meta) throw new Error(`larkBot not bound: ${personaId2}`);
|
|
51745
|
+
try {
|
|
51746
|
+
await deps.cloud.unbind(meta.appId);
|
|
51747
|
+
} catch (err) {
|
|
51748
|
+
if (err.status !== 404) throw err;
|
|
51749
|
+
deps.logger?.warn(`larkBot unbind: cloud binding already gone: ${meta.appId}`);
|
|
51750
|
+
}
|
|
51751
|
+
deps.store.remove(personaId2);
|
|
51752
|
+
emit(personaId2, { state: "unbound", groups: [] });
|
|
51753
|
+
return { response: { type: "larkBot:unbind:ok" } };
|
|
51754
|
+
};
|
|
51755
|
+
const status = async (frame) => {
|
|
51756
|
+
const { personaId: personaId2 } = parseArgs2(LarkBotStatusArgs, frame, "larkBot:status");
|
|
51757
|
+
const meta = deps.store.read(personaId2);
|
|
51758
|
+
if (!meta) {
|
|
51759
|
+
return {
|
|
51760
|
+
response: { type: "larkBot:status:ok", state: "unbound", groups: [] }
|
|
51761
|
+
};
|
|
51762
|
+
}
|
|
51763
|
+
let cloudBinding;
|
|
51764
|
+
try {
|
|
51765
|
+
cloudBinding = (await deps.cloud.listBindings()).find((b2) => b2.personaId === personaId2);
|
|
51766
|
+
} catch (err) {
|
|
51767
|
+
deps.logger?.warn(`larkBot status: cloud unreachable: ${err.message}`);
|
|
51768
|
+
}
|
|
51769
|
+
const broken = cloudBinding?.status === "broken";
|
|
51770
|
+
const result = {
|
|
51771
|
+
state: broken ? "broken" : "bound",
|
|
51772
|
+
appId: meta.appId,
|
|
51773
|
+
botName: meta.botName,
|
|
51774
|
+
...broken ? { brokenReason: cloudBinding?.brokenReason ?? "unknown" } : {},
|
|
51775
|
+
groups: groupsOf(personaId2)
|
|
51776
|
+
};
|
|
51777
|
+
return { response: { type: "larkBot:status:ok", ...result } };
|
|
51778
|
+
};
|
|
51779
|
+
return {
|
|
51780
|
+
"larkBot:bindManual": bindManual,
|
|
51781
|
+
"larkBot:unbind": unbind,
|
|
51782
|
+
"larkBot:status": status
|
|
51783
|
+
};
|
|
51784
|
+
}
|
|
51785
|
+
async function refreshTunnelUrlOnStartup(deps) {
|
|
51786
|
+
if (deps.listBoundPersonaIds().length === 0) return;
|
|
51787
|
+
const tunnelUrl = deps.getTunnelUrl();
|
|
51788
|
+
if (!tunnelUrl) return;
|
|
51789
|
+
try {
|
|
51790
|
+
await deps.cloud.updateTunnelUrl(tunnelUrl);
|
|
51791
|
+
} catch (err) {
|
|
51792
|
+
deps.logger?.warn(`larkBot tunnel refresh failed: ${err.message}`);
|
|
51793
|
+
}
|
|
51794
|
+
}
|
|
51795
|
+
|
|
51796
|
+
// src/lark-bot-connector/binding-store.ts
|
|
51797
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
51798
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
51799
|
+
function createLarkBotBindingStore(personaRoot) {
|
|
51800
|
+
const filePath = (personaId2) => import_node_path27.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
|
|
51801
|
+
const read = (personaId2) => {
|
|
51802
|
+
const file = filePath(personaId2);
|
|
51803
|
+
if (!import_node_fs26.default.existsSync(file)) return null;
|
|
51804
|
+
try {
|
|
51805
|
+
const raw = JSON.parse(import_node_fs26.default.readFileSync(file, "utf8"));
|
|
51806
|
+
if (typeof raw?.appId !== "string" || raw.appId.length === 0) return null;
|
|
51807
|
+
return raw;
|
|
51808
|
+
} catch {
|
|
51809
|
+
return null;
|
|
51810
|
+
}
|
|
51811
|
+
};
|
|
51812
|
+
const write = (personaId2, meta) => {
|
|
51813
|
+
const file = filePath(personaId2);
|
|
51814
|
+
import_node_fs26.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
|
|
51815
|
+
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
51816
|
+
import_node_fs26.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
|
|
51817
|
+
import_node_fs26.default.renameSync(tmp, file);
|
|
51818
|
+
};
|
|
51819
|
+
return {
|
|
51820
|
+
read,
|
|
51821
|
+
write,
|
|
51822
|
+
remove(personaId2) {
|
|
51823
|
+
import_node_fs26.default.rmSync(filePath(personaId2), { force: true });
|
|
51824
|
+
},
|
|
51825
|
+
addRemovedChat(personaId2, chatId) {
|
|
51826
|
+
const meta = read(personaId2);
|
|
51827
|
+
if (!meta) return;
|
|
51828
|
+
const set = new Set(meta.removedChatIds ?? []);
|
|
51829
|
+
set.add(chatId);
|
|
51830
|
+
write(personaId2, { ...meta, removedChatIds: [...set] });
|
|
51831
|
+
}
|
|
51832
|
+
};
|
|
51833
|
+
}
|
|
51834
|
+
|
|
51835
|
+
// src/lark-bot-connector/cloud-client.ts
|
|
51836
|
+
var LarkBotCloudError = class extends Error {
|
|
51837
|
+
constructor(message, status) {
|
|
51838
|
+
super(message);
|
|
51839
|
+
this.status = status;
|
|
51840
|
+
this.name = "LarkBotCloudError";
|
|
51841
|
+
}
|
|
51842
|
+
status;
|
|
51843
|
+
};
|
|
51844
|
+
function createLarkBotCloudClient(opts) {
|
|
51845
|
+
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
51846
|
+
if (!f) throw new Error("fetch is not available (Node >= 18 required)");
|
|
51847
|
+
const base = opts.api.replace(/\/+$/, "");
|
|
51848
|
+
async function request(method, pathname, body) {
|
|
51849
|
+
const ac = new AbortController();
|
|
51850
|
+
const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? 15e3);
|
|
51851
|
+
let res;
|
|
51852
|
+
try {
|
|
51853
|
+
res = await f(`${base}${pathname}`, {
|
|
51854
|
+
method,
|
|
51855
|
+
signal: ac.signal,
|
|
51856
|
+
headers: {
|
|
51857
|
+
authorization: `Bearer ${opts.apiKey}`,
|
|
51858
|
+
"x-did": encodeURIComponent(opts.deviceId),
|
|
51859
|
+
"x-name": encodeURIComponent(opts.displayName),
|
|
51860
|
+
"x-scene": "daemon",
|
|
51861
|
+
"content-type": "application/json"
|
|
51862
|
+
},
|
|
51863
|
+
body: body ? JSON.stringify(body) : void 0
|
|
51864
|
+
});
|
|
51865
|
+
} catch (err) {
|
|
51866
|
+
throw new LarkBotCloudError(`lark-bot cloud request failed: ${err.message}`);
|
|
51867
|
+
} finally {
|
|
51868
|
+
clearTimeout(timer);
|
|
51869
|
+
}
|
|
51870
|
+
let json = {};
|
|
51871
|
+
try {
|
|
51872
|
+
json = await res.json();
|
|
51873
|
+
} catch {
|
|
51874
|
+
json = {};
|
|
51875
|
+
}
|
|
51876
|
+
if (!res.ok) {
|
|
51877
|
+
throw new LarkBotCloudError(
|
|
51878
|
+
`lark-bot cloud ${method} ${pathname}: HTTP ${res.status} ${JSON.stringify(json).slice(0, 200)}`,
|
|
51879
|
+
res.status
|
|
51880
|
+
);
|
|
51881
|
+
}
|
|
51882
|
+
return json;
|
|
51883
|
+
}
|
|
51884
|
+
return {
|
|
51885
|
+
async bind(args) {
|
|
51886
|
+
await request("PUT", "/api/lark-bot/bind", { ...args });
|
|
51887
|
+
},
|
|
51888
|
+
async unbind(appId) {
|
|
51889
|
+
await request("DELETE", `/api/lark-bot/bind/${encodeURIComponent(appId)}`);
|
|
51890
|
+
},
|
|
51891
|
+
async listBindings() {
|
|
51892
|
+
const json = await request("GET", "/api/lark-bot/bindings");
|
|
51893
|
+
return json.items ?? [];
|
|
51894
|
+
},
|
|
51895
|
+
async updateTunnelUrl(tunnelUrl) {
|
|
51896
|
+
await request("PATCH", "/api/lark-bot/tunnel", { tunnelUrl });
|
|
51897
|
+
},
|
|
51898
|
+
async reply(args) {
|
|
51899
|
+
await request("POST", "/api/lark-bot/reply", { ...args });
|
|
51900
|
+
},
|
|
51901
|
+
async claimEvents() {
|
|
51902
|
+
const json = await request("POST", "/api/lark-bot/events/claim");
|
|
51903
|
+
return json.items ?? [];
|
|
51904
|
+
}
|
|
51905
|
+
};
|
|
51906
|
+
}
|
|
51907
|
+
|
|
51908
|
+
// src/lark-bot-connector/chat-router.ts
|
|
51909
|
+
var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
|
|
51910
|
+
var DEFAULT_TURN_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
51911
|
+
function createLarkChatRouter(deps) {
|
|
51912
|
+
const timeoutMs = deps.turnTimeoutMs ?? DEFAULT_TURN_TIMEOUT_MS;
|
|
51913
|
+
const replyDelays = deps.replyRetryDelaysMs ?? [2e3, 8e3, 3e4];
|
|
51914
|
+
const sleep2 = deps.sleepImpl ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
51915
|
+
const queues = /* @__PURE__ */ new Map();
|
|
51916
|
+
const activity = /* @__PURE__ */ new Map();
|
|
51917
|
+
const runOne = async (env) => {
|
|
51918
|
+
if (!env.messageId) {
|
|
51919
|
+
deps.logger?.warn(`larkBot chat-router: message envelope missing messageId, drop ${env.eventId}`);
|
|
51920
|
+
return;
|
|
51921
|
+
}
|
|
51922
|
+
const chatLabel = env.chatName ?? env.chatId;
|
|
51923
|
+
const text = `[\u98DE\u4E66\u7FA4\xB7${chatLabel}] ${env.senderName ?? env.senderOpenId ?? "\u672A\u77E5\u6210\u5458"}: ${env.text ?? ""}`;
|
|
51924
|
+
const turn = deps.manager.runLarkChatTurn({
|
|
51925
|
+
personaId: env.personaId,
|
|
51926
|
+
chatId: env.chatId,
|
|
51927
|
+
chatName: env.chatName,
|
|
51928
|
+
senderOpenId: env.senderOpenId ?? "",
|
|
51929
|
+
senderName: env.senderName ?? env.senderOpenId ?? "\u672A\u77E5\u6210\u5458",
|
|
51930
|
+
text
|
|
51931
|
+
});
|
|
51932
|
+
activity.set(env.chatId, {
|
|
51933
|
+
chatId: env.chatId,
|
|
51934
|
+
chatName: env.chatName,
|
|
51935
|
+
lastActiveAt: Date.now(),
|
|
51936
|
+
personaId: env.personaId
|
|
51937
|
+
});
|
|
51938
|
+
let timedOut = false;
|
|
51939
|
+
let timer;
|
|
51940
|
+
const timeout = new Promise((resolve6) => {
|
|
51941
|
+
timer = setTimeout(() => {
|
|
51942
|
+
timedOut = true;
|
|
51943
|
+
turn.kill();
|
|
51944
|
+
resolve6({ error: "turn timeout" });
|
|
51945
|
+
}, timeoutMs);
|
|
51946
|
+
});
|
|
51947
|
+
let result;
|
|
51948
|
+
try {
|
|
51949
|
+
result = await Promise.race([turn.ended, timeout]);
|
|
51950
|
+
} finally {
|
|
51951
|
+
clearTimeout(timer);
|
|
51952
|
+
}
|
|
51953
|
+
const replyText = "ok" in result && result.ok ? result.replyText : ERROR_REPLY_TEXT;
|
|
51954
|
+
if (!("ok" in result)) {
|
|
51955
|
+
deps.logger?.warn(
|
|
51956
|
+
`larkBot turn ${timedOut ? "timeout" : "error"} (${env.chatId}): ${result.error}`
|
|
51957
|
+
);
|
|
51958
|
+
}
|
|
51959
|
+
for (let attempt = 0; attempt <= replyDelays.length; attempt++) {
|
|
51960
|
+
if (attempt > 0) await sleep2(replyDelays[attempt - 1]);
|
|
51961
|
+
try {
|
|
51962
|
+
await deps.cloud.reply({
|
|
51963
|
+
appId: env.appId,
|
|
51964
|
+
chatId: env.chatId,
|
|
51965
|
+
replyToMessageId: env.messageId,
|
|
51966
|
+
text: replyText,
|
|
51967
|
+
eventId: env.eventId
|
|
51968
|
+
});
|
|
51969
|
+
return;
|
|
51970
|
+
} catch (err) {
|
|
51971
|
+
deps.logger?.warn(
|
|
51972
|
+
`larkBot reply attempt ${attempt + 1} failed (${env.chatId}): ${err.message}`
|
|
51973
|
+
);
|
|
51974
|
+
}
|
|
51975
|
+
}
|
|
51976
|
+
};
|
|
51977
|
+
return {
|
|
51978
|
+
handleEnvelope(env) {
|
|
51979
|
+
if (env.type === "bot_removed") {
|
|
51980
|
+
deps.store.addRemovedChat(env.personaId, env.chatId);
|
|
51981
|
+
activity.delete(env.chatId);
|
|
51982
|
+
queues.delete(env.chatId);
|
|
51983
|
+
deps.logger?.info(`larkBot removed from chat ${env.chatId} (persona ${env.personaId})`);
|
|
51984
|
+
return;
|
|
51985
|
+
}
|
|
51986
|
+
const prev = queues.get(env.chatId) ?? Promise.resolve();
|
|
51987
|
+
const next = prev.then(
|
|
51988
|
+
() => runOne(env).catch(
|
|
51989
|
+
(err) => deps.logger?.warn(`larkBot chat-router runOne failed: ${err.message}`)
|
|
51990
|
+
)
|
|
51991
|
+
);
|
|
51992
|
+
queues.set(env.chatId, next);
|
|
51993
|
+
void next.finally(() => {
|
|
51994
|
+
if (queues.get(env.chatId) === next) queues.delete(env.chatId);
|
|
51995
|
+
});
|
|
51996
|
+
},
|
|
51997
|
+
listLarkSessions(personaId2) {
|
|
51998
|
+
return [...activity.values()].filter((a) => a.personaId === personaId2).map((a) => ({ chatId: a.chatId, chatName: a.chatName, lastActiveAt: a.lastActiveAt }));
|
|
51999
|
+
}
|
|
52000
|
+
};
|
|
52001
|
+
}
|
|
52002
|
+
|
|
52003
|
+
// src/lark-bot-connector/envelope.ts
|
|
52004
|
+
var import_node_crypto6 = require("crypto");
|
|
52005
|
+
var LARK_ENVELOPE_PREFIX = "clawdlbe1";
|
|
52006
|
+
function verifyLarkEventEnvelope(args) {
|
|
52007
|
+
const { token, publicKeyPem } = args;
|
|
52008
|
+
const now = args.nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
52009
|
+
const parts = token.split(".");
|
|
52010
|
+
if (parts.length !== 3 || parts[0] !== LARK_ENVELOPE_PREFIX) {
|
|
52011
|
+
return { ok: false, reason: "BAD_FORMAT" };
|
|
52012
|
+
}
|
|
52013
|
+
const [prefix, payloadB64, sigB64] = parts;
|
|
52014
|
+
let envelope;
|
|
52015
|
+
try {
|
|
52016
|
+
envelope = JSON.parse(Buffer.from(payloadB64, "base64url").toString("utf8"));
|
|
52017
|
+
} catch {
|
|
52018
|
+
return { ok: false, reason: "BAD_FORMAT" };
|
|
52019
|
+
}
|
|
52020
|
+
const data = Buffer.from(`${prefix}.${payloadB64}`, "utf8");
|
|
52021
|
+
let sigOk = false;
|
|
52022
|
+
try {
|
|
52023
|
+
sigOk = (0, import_node_crypto6.verify)(null, data, publicKeyPem, Buffer.from(sigB64, "base64url"));
|
|
52024
|
+
} catch {
|
|
52025
|
+
sigOk = false;
|
|
52026
|
+
}
|
|
52027
|
+
if (!sigOk) return { ok: false, reason: "BAD_SIGNATURE" };
|
|
52028
|
+
if (typeof envelope.exp !== "number" || envelope.exp <= now) {
|
|
52029
|
+
return { ok: false, reason: "EXPIRED" };
|
|
52030
|
+
}
|
|
52031
|
+
return { ok: true, envelope };
|
|
52032
|
+
}
|
|
52033
|
+
|
|
52034
|
+
// src/lark-bot-connector/event-endpoint.ts
|
|
52035
|
+
var DEFAULT_DEDUPE_CAPACITY = 1024;
|
|
52036
|
+
function createLarkEventDedupe(capacity = DEFAULT_DEDUPE_CAPACITY) {
|
|
52037
|
+
const seen = /* @__PURE__ */ new Map();
|
|
52038
|
+
return {
|
|
52039
|
+
has: (id) => seen.has(id),
|
|
52040
|
+
add: (id) => {
|
|
52041
|
+
if (seen.has(id)) return;
|
|
52042
|
+
seen.set(id, true);
|
|
52043
|
+
if (seen.size > capacity) {
|
|
52044
|
+
const oldest = seen.keys().next().value;
|
|
52045
|
+
if (oldest !== void 0) seen.delete(oldest);
|
|
52046
|
+
}
|
|
52047
|
+
}
|
|
52048
|
+
};
|
|
52049
|
+
}
|
|
52050
|
+
function createLarkBotEventEndpoint(deps) {
|
|
52051
|
+
const seen = deps.dedupe ?? createLarkEventDedupe(deps.dedupeCapacity ?? DEFAULT_DEDUPE_CAPACITY);
|
|
52052
|
+
return (rawBody) => {
|
|
52053
|
+
const publicKeyPem = deps.getPublicKey();
|
|
52054
|
+
if (!publicKeyPem) {
|
|
52055
|
+
return { status: 503, body: { code: "SERVER_KEY_UNAVAILABLE", message: "server public key not cached yet" } };
|
|
52056
|
+
}
|
|
52057
|
+
const r = verifyLarkEventEnvelope({
|
|
52058
|
+
token: rawBody.trim(),
|
|
52059
|
+
publicKeyPem,
|
|
52060
|
+
nowSeconds: deps.nowSeconds?.()
|
|
52061
|
+
});
|
|
52062
|
+
if (!r.ok) {
|
|
52063
|
+
return { status: 401, body: { code: r.reason, message: `lark event envelope rejected: ${r.reason}` } };
|
|
52064
|
+
}
|
|
52065
|
+
const { envelope } = r;
|
|
52066
|
+
if (seen.has(envelope.eventId)) {
|
|
52067
|
+
return { status: 202, body: { ok: true, deduped: true } };
|
|
52068
|
+
}
|
|
52069
|
+
seen.add(envelope.eventId);
|
|
52070
|
+
try {
|
|
52071
|
+
deps.route(envelope);
|
|
52072
|
+
} catch (err) {
|
|
52073
|
+
deps.logger?.warn(`larkBot event route failed: ${err.message}`);
|
|
52074
|
+
}
|
|
52075
|
+
return { status: 202, body: { ok: true } };
|
|
52076
|
+
};
|
|
52077
|
+
}
|
|
52078
|
+
|
|
51529
52079
|
// src/ticket/constants.ts
|
|
51530
52080
|
var DEFAULT_CLAWD_TICKETS_API_KEY = "cf057f047674896978ddcc813adbc4a186551a6fcf59ad9d";
|
|
51531
52081
|
function resolveClawdTicketsApiKey() {
|
|
@@ -52137,7 +52687,7 @@ var CodexHistoryReader = class {
|
|
|
52137
52687
|
};
|
|
52138
52688
|
|
|
52139
52689
|
// src/tools/codex-skills.ts
|
|
52140
|
-
var
|
|
52690
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
52141
52691
|
function str3(v2) {
|
|
52142
52692
|
return typeof v2 === "string" ? v2 : void 0;
|
|
52143
52693
|
}
|
|
@@ -52152,13 +52702,13 @@ function mapSkillsListResponse(res) {
|
|
|
52152
52702
|
const r = s ?? {};
|
|
52153
52703
|
const name = str3(r.name);
|
|
52154
52704
|
if (!name) continue;
|
|
52155
|
-
const
|
|
52705
|
+
const path78 = str3(r.path);
|
|
52156
52706
|
const description = str3(r.description);
|
|
52157
52707
|
const isPlugin = name.includes(":");
|
|
52158
52708
|
out.push({
|
|
52159
52709
|
name,
|
|
52160
52710
|
source: isPlugin ? "plugin" : "project",
|
|
52161
|
-
...
|
|
52711
|
+
...path78 ? { path: path78 } : {},
|
|
52162
52712
|
...description ? { description } : {},
|
|
52163
52713
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
52164
52714
|
});
|
|
@@ -52174,30 +52724,30 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
52174
52724
|
// 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
|
|
52175
52725
|
// codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
|
|
52176
52726
|
beforeRequest: (client) => {
|
|
52177
|
-
void client.request("skills/extraRoots/set", { extraRoots: [
|
|
52727
|
+
void client.request("skills/extraRoots/set", { extraRoots: [import_node_path28.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
|
|
52178
52728
|
}
|
|
52179
52729
|
});
|
|
52180
52730
|
return mapSkillsListResponse(res);
|
|
52181
52731
|
}
|
|
52182
52732
|
|
|
52183
52733
|
// src/workspace/browser.ts
|
|
52184
|
-
var
|
|
52734
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
52185
52735
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
52186
|
-
var
|
|
52736
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
52187
52737
|
init_protocol();
|
|
52188
52738
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
52189
52739
|
function resolveInsideCwd(cwd, subpath) {
|
|
52190
|
-
const absCwd =
|
|
52191
|
-
const joined =
|
|
52192
|
-
const rel =
|
|
52193
|
-
if (rel.startsWith("..") ||
|
|
52740
|
+
const absCwd = import_node_path29.default.resolve(cwd);
|
|
52741
|
+
const joined = import_node_path29.default.resolve(absCwd, subpath ?? ".");
|
|
52742
|
+
const rel = import_node_path29.default.relative(absCwd, joined);
|
|
52743
|
+
if (rel.startsWith("..") || import_node_path29.default.isAbsolute(rel)) {
|
|
52194
52744
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
52195
52745
|
}
|
|
52196
52746
|
return joined;
|
|
52197
52747
|
}
|
|
52198
52748
|
function ensureCwd(cwd) {
|
|
52199
52749
|
try {
|
|
52200
|
-
const stat =
|
|
52750
|
+
const stat = import_node_fs27.default.statSync(cwd);
|
|
52201
52751
|
if (!stat.isDirectory()) {
|
|
52202
52752
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
|
|
52203
52753
|
}
|
|
@@ -52211,7 +52761,7 @@ var WorkspaceBrowser = class {
|
|
|
52211
52761
|
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os8.default.homedir();
|
|
52212
52762
|
ensureCwd(cwd);
|
|
52213
52763
|
const full = resolveInsideCwd(cwd, args.path);
|
|
52214
|
-
const dirents =
|
|
52764
|
+
const dirents = import_node_fs27.default.readdirSync(full, { withFileTypes: true });
|
|
52215
52765
|
const entries = [];
|
|
52216
52766
|
for (const d of dirents) {
|
|
52217
52767
|
if (!args.showHidden && d.name.startsWith(".")) continue;
|
|
@@ -52221,7 +52771,7 @@ var WorkspaceBrowser = class {
|
|
|
52221
52771
|
mtime: ""
|
|
52222
52772
|
};
|
|
52223
52773
|
try {
|
|
52224
|
-
const st =
|
|
52774
|
+
const st = import_node_fs27.default.statSync(import_node_path29.default.join(full, d.name));
|
|
52225
52775
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
52226
52776
|
if (d.isFile()) entry.size = st.size;
|
|
52227
52777
|
} catch {
|
|
@@ -52237,14 +52787,14 @@ var WorkspaceBrowser = class {
|
|
|
52237
52787
|
read(args) {
|
|
52238
52788
|
ensureCwd(args.cwd);
|
|
52239
52789
|
const full = resolveInsideCwd(args.cwd, args.path);
|
|
52240
|
-
const st =
|
|
52790
|
+
const st = import_node_fs27.default.statSync(full);
|
|
52241
52791
|
if (!st.isFile()) {
|
|
52242
52792
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
|
|
52243
52793
|
}
|
|
52244
52794
|
if (st.size > MAX_FILE_BYTES) {
|
|
52245
52795
|
throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
|
|
52246
52796
|
}
|
|
52247
|
-
const buf =
|
|
52797
|
+
const buf = import_node_fs27.default.readFileSync(full);
|
|
52248
52798
|
const isBinary = buf.includes(0);
|
|
52249
52799
|
if (isBinary) {
|
|
52250
52800
|
return {
|
|
@@ -52266,20 +52816,20 @@ var WorkspaceBrowser = class {
|
|
|
52266
52816
|
};
|
|
52267
52817
|
|
|
52268
52818
|
// src/skills/agents-scanner.ts
|
|
52269
|
-
var
|
|
52819
|
+
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
52270
52820
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
52271
|
-
var
|
|
52821
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
52272
52822
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
52273
52823
|
function isDirLikeSync2(p2) {
|
|
52274
52824
|
try {
|
|
52275
|
-
return
|
|
52825
|
+
return import_node_fs28.default.statSync(p2).isDirectory();
|
|
52276
52826
|
} catch {
|
|
52277
52827
|
return false;
|
|
52278
52828
|
}
|
|
52279
52829
|
}
|
|
52280
52830
|
function fileExistsSync(p2) {
|
|
52281
52831
|
try {
|
|
52282
|
-
return
|
|
52832
|
+
return import_node_fs28.default.statSync(p2).isFile();
|
|
52283
52833
|
} catch {
|
|
52284
52834
|
return false;
|
|
52285
52835
|
}
|
|
@@ -52287,7 +52837,7 @@ function fileExistsSync(p2) {
|
|
|
52287
52837
|
function parseAgentFile(filePath) {
|
|
52288
52838
|
let content;
|
|
52289
52839
|
try {
|
|
52290
|
-
content =
|
|
52840
|
+
content = import_node_fs28.default.readFileSync(filePath, "utf8");
|
|
52291
52841
|
} catch {
|
|
52292
52842
|
return {};
|
|
52293
52843
|
}
|
|
@@ -52300,16 +52850,16 @@ function parseAgentFile(filePath) {
|
|
|
52300
52850
|
function scanAgentsDir(dir, source, seen, out) {
|
|
52301
52851
|
let entries;
|
|
52302
52852
|
try {
|
|
52303
|
-
entries =
|
|
52853
|
+
entries = import_node_fs28.default.readdirSync(dir, { withFileTypes: true });
|
|
52304
52854
|
} catch {
|
|
52305
52855
|
return;
|
|
52306
52856
|
}
|
|
52307
52857
|
for (const ent of entries) {
|
|
52308
52858
|
if (!ent.name.endsWith(".md")) continue;
|
|
52309
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
52859
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path30.default.join(dir, ent.name)))) {
|
|
52310
52860
|
continue;
|
|
52311
52861
|
}
|
|
52312
|
-
const filePath =
|
|
52862
|
+
const filePath = import_node_path30.default.join(dir, ent.name);
|
|
52313
52863
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
52314
52864
|
if (seen.has(baseName)) continue;
|
|
52315
52865
|
seen.add(baseName);
|
|
@@ -52327,12 +52877,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
52327
52877
|
function walk2(dir, namespaces) {
|
|
52328
52878
|
let entries;
|
|
52329
52879
|
try {
|
|
52330
|
-
entries =
|
|
52880
|
+
entries = import_node_fs28.default.readdirSync(dir, { withFileTypes: true });
|
|
52331
52881
|
} catch {
|
|
52332
52882
|
return;
|
|
52333
52883
|
}
|
|
52334
52884
|
for (const ent of entries) {
|
|
52335
|
-
const childPath =
|
|
52885
|
+
const childPath = import_node_path30.default.join(dir, ent.name);
|
|
52336
52886
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
52337
52887
|
walk2(childPath, [...namespaces, ent.name]);
|
|
52338
52888
|
continue;
|
|
@@ -52357,13 +52907,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
52357
52907
|
walk2(root, []);
|
|
52358
52908
|
}
|
|
52359
52909
|
function readInstalledPlugins2(home) {
|
|
52360
|
-
const pluginsDir =
|
|
52361
|
-
const v2 =
|
|
52362
|
-
const v1 =
|
|
52910
|
+
const pluginsDir = import_node_path30.default.join(home, ".claude", "plugins");
|
|
52911
|
+
const v2 = import_node_path30.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
52912
|
+
const v1 = import_node_path30.default.join(pluginsDir, "installed_plugins.json");
|
|
52363
52913
|
let raw = null;
|
|
52364
52914
|
for (const candidate of [v2, v1]) {
|
|
52365
52915
|
try {
|
|
52366
|
-
raw =
|
|
52916
|
+
raw = import_node_fs28.default.readFileSync(candidate, "utf8");
|
|
52367
52917
|
break;
|
|
52368
52918
|
} catch {
|
|
52369
52919
|
}
|
|
@@ -52388,19 +52938,19 @@ function readInstalledPlugins2(home) {
|
|
|
52388
52938
|
return out;
|
|
52389
52939
|
}
|
|
52390
52940
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
52391
|
-
let cur =
|
|
52392
|
-
const fsRoot =
|
|
52941
|
+
let cur = import_node_path30.default.resolve(startCwd);
|
|
52942
|
+
const fsRoot = import_node_path30.default.parse(cur).root;
|
|
52393
52943
|
while (true) {
|
|
52394
|
-
scanAgentsDir(
|
|
52944
|
+
scanAgentsDir(import_node_path30.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
52395
52945
|
let hasGit = false;
|
|
52396
52946
|
try {
|
|
52397
|
-
hasGit =
|
|
52947
|
+
hasGit = import_node_fs28.default.existsSync(import_node_path30.default.join(cur, ".git"));
|
|
52398
52948
|
} catch {
|
|
52399
52949
|
}
|
|
52400
52950
|
if (hasGit) return;
|
|
52401
52951
|
if (cur === home) return;
|
|
52402
52952
|
if (cur === fsRoot) return;
|
|
52403
|
-
const parent =
|
|
52953
|
+
const parent = import_node_path30.default.dirname(cur);
|
|
52404
52954
|
if (parent === cur) return;
|
|
52405
52955
|
cur = parent;
|
|
52406
52956
|
}
|
|
@@ -52435,7 +52985,7 @@ var AgentsScanner = class {
|
|
|
52435
52985
|
}
|
|
52436
52986
|
const fsBlock = [];
|
|
52437
52987
|
scanAgentsDir(
|
|
52438
|
-
|
|
52988
|
+
import_node_path30.default.join(this.home, ".claude", "agents"),
|
|
52439
52989
|
"global",
|
|
52440
52990
|
seen,
|
|
52441
52991
|
fsBlock
|
|
@@ -52449,7 +52999,7 @@ var AgentsScanner = class {
|
|
|
52449
52999
|
...this.extraPluginRoots
|
|
52450
53000
|
];
|
|
52451
53001
|
for (const { name, root } of plugins) {
|
|
52452
|
-
const agentsRoot =
|
|
53002
|
+
const agentsRoot = import_node_path30.default.join(root, "agents");
|
|
52453
53003
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
52454
53004
|
}
|
|
52455
53005
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -52457,15 +53007,15 @@ var AgentsScanner = class {
|
|
|
52457
53007
|
};
|
|
52458
53008
|
|
|
52459
53009
|
// src/observer/session-observer.ts
|
|
52460
|
-
var
|
|
53010
|
+
var import_node_fs30 = __toESM(require("fs"), 1);
|
|
52461
53011
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
52462
|
-
var
|
|
53012
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
52463
53013
|
init_claude_history();
|
|
52464
53014
|
|
|
52465
53015
|
// src/observer/subagent-meta-observer.ts
|
|
52466
|
-
var
|
|
53016
|
+
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
52467
53017
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
52468
|
-
var
|
|
53018
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
52469
53019
|
init_claude_history();
|
|
52470
53020
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
52471
53021
|
var SubagentMetaObserver = class {
|
|
@@ -52478,7 +53028,7 @@ var SubagentMetaObserver = class {
|
|
|
52478
53028
|
watches = /* @__PURE__ */ new Map();
|
|
52479
53029
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
52480
53030
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
52481
|
-
return
|
|
53031
|
+
return import_node_path31.default.join(
|
|
52482
53032
|
this.home,
|
|
52483
53033
|
".claude",
|
|
52484
53034
|
"projects",
|
|
@@ -52508,7 +53058,7 @@ var SubagentMetaObserver = class {
|
|
|
52508
53058
|
attachWatcher(w2) {
|
|
52509
53059
|
if (w2.watcher) return;
|
|
52510
53060
|
try {
|
|
52511
|
-
w2.watcher =
|
|
53061
|
+
w2.watcher = import_node_fs29.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
|
|
52512
53062
|
if (!name) return;
|
|
52513
53063
|
const m2 = META_RE.exec(String(name));
|
|
52514
53064
|
if (!m2) return;
|
|
@@ -52520,7 +53070,7 @@ var SubagentMetaObserver = class {
|
|
|
52520
53070
|
scan(w2) {
|
|
52521
53071
|
let entries;
|
|
52522
53072
|
try {
|
|
52523
|
-
entries =
|
|
53073
|
+
entries = import_node_fs29.default.readdirSync(w2.dirPath);
|
|
52524
53074
|
} catch {
|
|
52525
53075
|
return;
|
|
52526
53076
|
}
|
|
@@ -52534,10 +53084,10 @@ var SubagentMetaObserver = class {
|
|
|
52534
53084
|
if (!m2) return;
|
|
52535
53085
|
const agentId = m2[1];
|
|
52536
53086
|
if (w2.emitted.has(agentId)) return;
|
|
52537
|
-
const file =
|
|
53087
|
+
const file = import_node_path31.default.join(w2.dirPath, name);
|
|
52538
53088
|
let raw;
|
|
52539
53089
|
try {
|
|
52540
|
-
raw =
|
|
53090
|
+
raw = import_node_fs29.default.readFileSync(file, "utf8");
|
|
52541
53091
|
} catch {
|
|
52542
53092
|
return;
|
|
52543
53093
|
}
|
|
@@ -52594,14 +53144,14 @@ var SessionObserver = class {
|
|
|
52594
53144
|
metaObserver;
|
|
52595
53145
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
52596
53146
|
if (override) return override;
|
|
52597
|
-
return
|
|
53147
|
+
return import_node_path32.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
52598
53148
|
}
|
|
52599
53149
|
start(args) {
|
|
52600
53150
|
this.stop(args.sessionId);
|
|
52601
53151
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
52602
53152
|
let size = 0;
|
|
52603
53153
|
try {
|
|
52604
|
-
size =
|
|
53154
|
+
size = import_node_fs30.default.statSync(filePath).size;
|
|
52605
53155
|
} catch {
|
|
52606
53156
|
}
|
|
52607
53157
|
const w2 = {
|
|
@@ -52614,16 +53164,16 @@ var SessionObserver = class {
|
|
|
52614
53164
|
adapter: args.adapter,
|
|
52615
53165
|
prevIsRejectSentinel: false,
|
|
52616
53166
|
toolSessionId: args.toolSessionId,
|
|
52617
|
-
sawFile:
|
|
53167
|
+
sawFile: import_node_fs30.default.existsSync(filePath),
|
|
52618
53168
|
lastRelocateScanMs: 0,
|
|
52619
53169
|
pendingCwdDerive: false,
|
|
52620
53170
|
lastDeriveMs: 0
|
|
52621
53171
|
};
|
|
52622
53172
|
try {
|
|
52623
|
-
|
|
53173
|
+
import_node_fs30.default.mkdirSync(import_node_path32.default.dirname(filePath), { recursive: true });
|
|
52624
53174
|
} catch {
|
|
52625
53175
|
}
|
|
52626
|
-
w2.watcher =
|
|
53176
|
+
w2.watcher = import_node_fs30.default.watch(import_node_path32.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
52627
53177
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
52628
53178
|
this.poll(w2);
|
|
52629
53179
|
});
|
|
@@ -52646,7 +53196,7 @@ var SessionObserver = class {
|
|
|
52646
53196
|
// 异常静默吞,不阻塞 watcher 启动
|
|
52647
53197
|
hydrateMetaTail(w2, maxLines = 200) {
|
|
52648
53198
|
try {
|
|
52649
|
-
const raw =
|
|
53199
|
+
const raw = import_node_fs30.default.readFileSync(w2.filePath, "utf8");
|
|
52650
53200
|
if (!raw) return;
|
|
52651
53201
|
const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
52652
53202
|
if (allLines.length === 0) return;
|
|
@@ -52670,7 +53220,7 @@ var SessionObserver = class {
|
|
|
52670
53220
|
poll(w2) {
|
|
52671
53221
|
let size = 0;
|
|
52672
53222
|
try {
|
|
52673
|
-
size =
|
|
53223
|
+
size = import_node_fs30.default.statSync(w2.filePath).size;
|
|
52674
53224
|
} catch {
|
|
52675
53225
|
if (w2.sawFile) this.maybeRelocate(w2);
|
|
52676
53226
|
return;
|
|
@@ -52681,11 +53231,11 @@ var SessionObserver = class {
|
|
|
52681
53231
|
w2.buf = "";
|
|
52682
53232
|
}
|
|
52683
53233
|
if (size === w2.lastSize) return;
|
|
52684
|
-
const fd =
|
|
53234
|
+
const fd = import_node_fs30.default.openSync(w2.filePath, "r");
|
|
52685
53235
|
try {
|
|
52686
53236
|
const len = size - w2.lastSize;
|
|
52687
53237
|
const buf = Buffer.alloc(len);
|
|
52688
|
-
|
|
53238
|
+
import_node_fs30.default.readSync(fd, buf, 0, len, w2.lastSize);
|
|
52689
53239
|
w2.lastSize = size;
|
|
52690
53240
|
w2.buf += buf.toString("utf8");
|
|
52691
53241
|
let newlineIndex;
|
|
@@ -52708,7 +53258,7 @@ var SessionObserver = class {
|
|
|
52708
53258
|
}
|
|
52709
53259
|
}
|
|
52710
53260
|
} finally {
|
|
52711
|
-
|
|
53261
|
+
import_node_fs30.default.closeSync(fd);
|
|
52712
53262
|
}
|
|
52713
53263
|
if (w2.pendingCwdDerive) this.maybeDeriveCwd(w2);
|
|
52714
53264
|
}
|
|
@@ -52720,7 +53270,7 @@ var SessionObserver = class {
|
|
|
52720
53270
|
const now = Date.now();
|
|
52721
53271
|
if (now - w2.lastRelocateScanMs < 1e3) return;
|
|
52722
53272
|
w2.lastRelocateScanMs = now;
|
|
52723
|
-
const projectsRoot =
|
|
53273
|
+
const projectsRoot = import_node_path32.default.join(this.home, ".claude", "projects");
|
|
52724
53274
|
const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
|
|
52725
53275
|
if (!found || found === w2.filePath) return;
|
|
52726
53276
|
try {
|
|
@@ -52729,7 +53279,7 @@ var SessionObserver = class {
|
|
|
52729
53279
|
}
|
|
52730
53280
|
w2.filePath = found;
|
|
52731
53281
|
try {
|
|
52732
|
-
w2.watcher =
|
|
53282
|
+
w2.watcher = import_node_fs30.default.watch(import_node_path32.default.dirname(found), { persistent: false }, (_event, changedName) => {
|
|
52733
53283
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
52734
53284
|
this.poll(w2);
|
|
52735
53285
|
});
|
|
@@ -53524,8 +54074,8 @@ async function authenticate(token, deps) {
|
|
|
53524
54074
|
}
|
|
53525
54075
|
|
|
53526
54076
|
// src/legacy-cleanup.ts
|
|
53527
|
-
var
|
|
53528
|
-
var
|
|
54077
|
+
var fs35 = __toESM(require("fs/promises"), 1);
|
|
54078
|
+
var path37 = __toESM(require("path"), 1);
|
|
53529
54079
|
var LEGACY_FILES = [
|
|
53530
54080
|
"personal-capability.json",
|
|
53531
54081
|
"received-capabilities.json",
|
|
@@ -53534,9 +54084,9 @@ var LEGACY_FILES = [
|
|
|
53534
54084
|
async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
53535
54085
|
const removed = [];
|
|
53536
54086
|
for (const name of LEGACY_FILES) {
|
|
53537
|
-
const p2 =
|
|
54087
|
+
const p2 = path37.join(dataDir, name);
|
|
53538
54088
|
try {
|
|
53539
|
-
await
|
|
54089
|
+
await fs35.unlink(p2);
|
|
53540
54090
|
removed.push(name);
|
|
53541
54091
|
logger.debug("legacy capability file removed", { file: name });
|
|
53542
54092
|
} catch (err) {
|
|
@@ -53548,13 +54098,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
|
53548
54098
|
}
|
|
53549
54099
|
|
|
53550
54100
|
// src/inbox/inbox-store.ts
|
|
53551
|
-
var
|
|
53552
|
-
var
|
|
54101
|
+
var fs36 = __toESM(require("fs"), 1);
|
|
54102
|
+
var path38 = __toESM(require("path"), 1);
|
|
53553
54103
|
var INBOX_SUBDIR = "inbox";
|
|
53554
54104
|
var InboxStore = class {
|
|
53555
54105
|
constructor(dataDir) {
|
|
53556
54106
|
this.dataDir = dataDir;
|
|
53557
|
-
|
|
54107
|
+
fs36.mkdirSync(this.dirPath(), { recursive: true });
|
|
53558
54108
|
}
|
|
53559
54109
|
dataDir;
|
|
53560
54110
|
/**
|
|
@@ -53566,7 +54116,7 @@ var InboxStore = class {
|
|
|
53566
54116
|
const file = this.filePath(peerDeviceId);
|
|
53567
54117
|
let raw;
|
|
53568
54118
|
try {
|
|
53569
|
-
raw =
|
|
54119
|
+
raw = fs36.readFileSync(file, "utf8");
|
|
53570
54120
|
} catch (err) {
|
|
53571
54121
|
if (err?.code === "ENOENT") return [];
|
|
53572
54122
|
return [];
|
|
@@ -53582,7 +54132,7 @@ var InboxStore = class {
|
|
|
53582
54132
|
const dir = this.dirPath();
|
|
53583
54133
|
let entries;
|
|
53584
54134
|
try {
|
|
53585
|
-
entries =
|
|
54135
|
+
entries = fs36.readdirSync(dir);
|
|
53586
54136
|
} catch (err) {
|
|
53587
54137
|
if (err?.code === "ENOENT") return [];
|
|
53588
54138
|
return [];
|
|
@@ -53598,9 +54148,9 @@ var InboxStore = class {
|
|
|
53598
54148
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
53599
54149
|
const file = this.filePath(message.peerDeviceId);
|
|
53600
54150
|
const line = JSON.stringify(message) + "\n";
|
|
53601
|
-
|
|
54151
|
+
fs36.appendFileSync(file, line, { mode: 384 });
|
|
53602
54152
|
try {
|
|
53603
|
-
|
|
54153
|
+
fs36.chmodSync(file, 384);
|
|
53604
54154
|
} catch {
|
|
53605
54155
|
}
|
|
53606
54156
|
}
|
|
@@ -53630,7 +54180,7 @@ var InboxStore = class {
|
|
|
53630
54180
|
removeByPeerDeviceId(peerDeviceId) {
|
|
53631
54181
|
const file = this.filePath(peerDeviceId);
|
|
53632
54182
|
try {
|
|
53633
|
-
|
|
54183
|
+
fs36.unlinkSync(file);
|
|
53634
54184
|
} catch (err) {
|
|
53635
54185
|
if (err?.code === "ENOENT") return;
|
|
53636
54186
|
}
|
|
@@ -53639,18 +54189,18 @@ var InboxStore = class {
|
|
|
53639
54189
|
const file = this.filePath(peerDeviceId);
|
|
53640
54190
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
53641
54191
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
53642
|
-
|
|
53643
|
-
|
|
54192
|
+
fs36.writeFileSync(tmp, content, { mode: 384 });
|
|
54193
|
+
fs36.renameSync(tmp, file);
|
|
53644
54194
|
try {
|
|
53645
|
-
|
|
54195
|
+
fs36.chmodSync(file, 384);
|
|
53646
54196
|
} catch {
|
|
53647
54197
|
}
|
|
53648
54198
|
}
|
|
53649
54199
|
dirPath() {
|
|
53650
|
-
return
|
|
54200
|
+
return path38.join(this.dataDir, INBOX_SUBDIR);
|
|
53651
54201
|
}
|
|
53652
54202
|
filePath(peerDeviceId) {
|
|
53653
|
-
return
|
|
54203
|
+
return path38.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
53654
54204
|
}
|
|
53655
54205
|
};
|
|
53656
54206
|
function parseAllLines(raw) {
|
|
@@ -53738,8 +54288,8 @@ var InboxManager = class {
|
|
|
53738
54288
|
};
|
|
53739
54289
|
|
|
53740
54290
|
// src/state/contact-store.ts
|
|
53741
|
-
var
|
|
53742
|
-
var
|
|
54291
|
+
var fs37 = __toESM(require("fs"), 1);
|
|
54292
|
+
var path39 = __toESM(require("path"), 1);
|
|
53743
54293
|
var FILE_NAME = "contacts.json";
|
|
53744
54294
|
var ContactStore = class {
|
|
53745
54295
|
constructor(dataDir) {
|
|
@@ -53749,10 +54299,10 @@ var ContactStore = class {
|
|
|
53749
54299
|
contacts = /* @__PURE__ */ new Map();
|
|
53750
54300
|
load() {
|
|
53751
54301
|
this.contacts.clear();
|
|
53752
|
-
const file =
|
|
54302
|
+
const file = path39.join(this.dataDir, FILE_NAME);
|
|
53753
54303
|
let raw;
|
|
53754
54304
|
try {
|
|
53755
|
-
raw =
|
|
54305
|
+
raw = fs37.readFileSync(file, "utf8");
|
|
53756
54306
|
} catch (err) {
|
|
53757
54307
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
53758
54308
|
return;
|
|
@@ -53821,20 +54371,20 @@ var ContactStore = class {
|
|
|
53821
54371
|
return true;
|
|
53822
54372
|
}
|
|
53823
54373
|
flush() {
|
|
53824
|
-
const file =
|
|
54374
|
+
const file = path39.join(this.dataDir, FILE_NAME);
|
|
53825
54375
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
53826
54376
|
const content = JSON.stringify(
|
|
53827
54377
|
{ contacts: Array.from(this.contacts.values()) },
|
|
53828
54378
|
null,
|
|
53829
54379
|
2
|
|
53830
54380
|
);
|
|
53831
|
-
|
|
53832
|
-
|
|
53833
|
-
|
|
54381
|
+
fs37.mkdirSync(this.dataDir, { recursive: true });
|
|
54382
|
+
fs37.writeFileSync(tmp, content, { mode: 384 });
|
|
54383
|
+
fs37.renameSync(tmp, file);
|
|
53834
54384
|
}
|
|
53835
54385
|
renameBak(file) {
|
|
53836
54386
|
try {
|
|
53837
|
-
|
|
54387
|
+
fs37.renameSync(file, `${file}.bak`);
|
|
53838
54388
|
} catch {
|
|
53839
54389
|
}
|
|
53840
54390
|
}
|
|
@@ -53942,61 +54492,61 @@ async function connectRemote(args) {
|
|
|
53942
54492
|
}
|
|
53943
54493
|
|
|
53944
54494
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
53945
|
-
var
|
|
53946
|
-
var
|
|
54495
|
+
var fs38 = __toESM(require("fs"), 1);
|
|
54496
|
+
var path40 = __toESM(require("path"), 1);
|
|
53947
54497
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
53948
54498
|
function migrateFlattenSessions(opts) {
|
|
53949
54499
|
const dataDir = opts.dataDir;
|
|
53950
54500
|
const now = opts.now ?? Date.now;
|
|
53951
|
-
const sessionsDir =
|
|
53952
|
-
const flagPath =
|
|
54501
|
+
const sessionsDir = path40.join(dataDir, "sessions");
|
|
54502
|
+
const flagPath = path40.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
53953
54503
|
if (existsSync3(flagPath)) {
|
|
53954
54504
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
53955
54505
|
}
|
|
53956
54506
|
let movedBare = 0;
|
|
53957
54507
|
let movedVmOwner = 0;
|
|
53958
54508
|
let archivedListener = 0;
|
|
53959
|
-
const defaultDir =
|
|
54509
|
+
const defaultDir = path40.join(sessionsDir, "default");
|
|
53960
54510
|
if (existsSync3(defaultDir)) {
|
|
53961
54511
|
for (const entry of readdirSafe(defaultDir)) {
|
|
53962
54512
|
if (!entry.endsWith(".json")) continue;
|
|
53963
|
-
const src =
|
|
53964
|
-
const dst =
|
|
53965
|
-
|
|
54513
|
+
const src = path40.join(defaultDir, entry);
|
|
54514
|
+
const dst = path40.join(sessionsDir, entry);
|
|
54515
|
+
fs38.renameSync(src, dst);
|
|
53966
54516
|
movedBare += 1;
|
|
53967
54517
|
}
|
|
53968
54518
|
rmdirIfEmpty(defaultDir);
|
|
53969
54519
|
}
|
|
53970
54520
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
53971
|
-
const personaDir =
|
|
54521
|
+
const personaDir = path40.join(sessionsDir, pid);
|
|
53972
54522
|
if (!isDir(personaDir)) continue;
|
|
53973
54523
|
if (pid === "default") continue;
|
|
53974
|
-
const ownerSrc =
|
|
54524
|
+
const ownerSrc = path40.join(personaDir, "owner");
|
|
53975
54525
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
53976
|
-
const ownerDst =
|
|
53977
|
-
|
|
54526
|
+
const ownerDst = path40.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
54527
|
+
fs38.mkdirSync(ownerDst, { recursive: true });
|
|
53978
54528
|
for (const file of readdirSafe(ownerSrc)) {
|
|
53979
54529
|
if (!file.endsWith(".json")) continue;
|
|
53980
|
-
|
|
54530
|
+
fs38.renameSync(path40.join(ownerSrc, file), path40.join(ownerDst, file));
|
|
53981
54531
|
movedVmOwner += 1;
|
|
53982
54532
|
}
|
|
53983
54533
|
rmdirIfEmpty(ownerSrc);
|
|
53984
54534
|
}
|
|
53985
|
-
const listenerSrc =
|
|
54535
|
+
const listenerSrc = path40.join(personaDir, "listener");
|
|
53986
54536
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
53987
|
-
const archiveDst =
|
|
53988
|
-
|
|
54537
|
+
const archiveDst = path40.join(dataDir, ".legacy", `listener-${pid}`);
|
|
54538
|
+
fs38.mkdirSync(archiveDst, { recursive: true });
|
|
53989
54539
|
for (const file of readdirSafe(listenerSrc)) {
|
|
53990
54540
|
if (!file.endsWith(".json")) continue;
|
|
53991
|
-
|
|
54541
|
+
fs38.renameSync(path40.join(listenerSrc, file), path40.join(archiveDst, file));
|
|
53992
54542
|
archivedListener += 1;
|
|
53993
54543
|
}
|
|
53994
54544
|
rmdirIfEmpty(listenerSrc);
|
|
53995
54545
|
}
|
|
53996
54546
|
rmdirIfEmpty(personaDir);
|
|
53997
54547
|
}
|
|
53998
|
-
|
|
53999
|
-
|
|
54548
|
+
fs38.mkdirSync(sessionsDir, { recursive: true });
|
|
54549
|
+
fs38.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
54000
54550
|
return {
|
|
54001
54551
|
skipped: false,
|
|
54002
54552
|
flagWritten: true,
|
|
@@ -54007,7 +54557,7 @@ function migrateFlattenSessions(opts) {
|
|
|
54007
54557
|
}
|
|
54008
54558
|
function existsSync3(p2) {
|
|
54009
54559
|
try {
|
|
54010
|
-
|
|
54560
|
+
fs38.statSync(p2);
|
|
54011
54561
|
return true;
|
|
54012
54562
|
} catch {
|
|
54013
54563
|
return false;
|
|
@@ -54015,31 +54565,31 @@ function existsSync3(p2) {
|
|
|
54015
54565
|
}
|
|
54016
54566
|
function isDir(p2) {
|
|
54017
54567
|
try {
|
|
54018
|
-
return
|
|
54568
|
+
return fs38.statSync(p2).isDirectory();
|
|
54019
54569
|
} catch {
|
|
54020
54570
|
return false;
|
|
54021
54571
|
}
|
|
54022
54572
|
}
|
|
54023
54573
|
function readdirSafe(p2) {
|
|
54024
54574
|
try {
|
|
54025
|
-
return
|
|
54575
|
+
return fs38.readdirSync(p2);
|
|
54026
54576
|
} catch {
|
|
54027
54577
|
return [];
|
|
54028
54578
|
}
|
|
54029
54579
|
}
|
|
54030
54580
|
function rmdirIfEmpty(p2) {
|
|
54031
54581
|
try {
|
|
54032
|
-
|
|
54582
|
+
fs38.rmdirSync(p2);
|
|
54033
54583
|
} catch {
|
|
54034
54584
|
}
|
|
54035
54585
|
}
|
|
54036
54586
|
|
|
54037
54587
|
// src/transport/http-router.ts
|
|
54038
|
-
var
|
|
54039
|
-
var
|
|
54588
|
+
var import_node_fs32 = __toESM(require("fs"), 1);
|
|
54589
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
54040
54590
|
|
|
54041
54591
|
// src/attachment/mime.ts
|
|
54042
|
-
var
|
|
54592
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
54043
54593
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
54044
54594
|
var EXT_TO_NATIVE_MIME = {
|
|
54045
54595
|
// 图片
|
|
@@ -54146,14 +54696,14 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
54146
54696
|
".mk"
|
|
54147
54697
|
]);
|
|
54148
54698
|
function lookupMime(filePathOrName) {
|
|
54149
|
-
const ext =
|
|
54699
|
+
const ext = import_node_path33.default.extname(filePathOrName).toLowerCase();
|
|
54150
54700
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
54151
54701
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
54152
54702
|
return "application/octet-stream";
|
|
54153
54703
|
}
|
|
54154
54704
|
|
|
54155
54705
|
// src/attachment/sign-url.ts
|
|
54156
|
-
var
|
|
54706
|
+
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
54157
54707
|
var HMAC_ALGO = "sha256";
|
|
54158
54708
|
function base64urlEncode(buf) {
|
|
54159
54709
|
const b2 = typeof buf === "string" ? Buffer.from(buf, "utf8") : buf;
|
|
@@ -54171,7 +54721,7 @@ function decodeAbsPathFromUrl(encoded) {
|
|
|
54171
54721
|
var DOMAIN_PREFIX2 = "clawd-attach-v1|";
|
|
54172
54722
|
function computeSig(secret, absPath, e) {
|
|
54173
54723
|
const msg = e === null ? `${DOMAIN_PREFIX2}${absPath}` : `${DOMAIN_PREFIX2}${absPath}|${e}`;
|
|
54174
|
-
return
|
|
54724
|
+
return import_node_crypto7.default.createHmac(HMAC_ALGO, secret).update(msg).digest();
|
|
54175
54725
|
}
|
|
54176
54726
|
function signUrlParts(secret, absPath, ttlSeconds, now = Date.now) {
|
|
54177
54727
|
const e = ttlSeconds === null ? null : Math.floor(now() / 1e3) + ttlSeconds;
|
|
@@ -54206,7 +54756,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
54206
54756
|
if (provided.length !== expected.length) {
|
|
54207
54757
|
return { ok: false, code: "BAD_SIG" };
|
|
54208
54758
|
}
|
|
54209
|
-
if (!
|
|
54759
|
+
if (!import_node_crypto7.default.timingSafeEqual(provided, expected)) {
|
|
54210
54760
|
return { ok: false, code: "BAD_SIG" };
|
|
54211
54761
|
}
|
|
54212
54762
|
if (e !== null && now() / 1e3 > e) {
|
|
@@ -54216,9 +54766,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
54216
54766
|
}
|
|
54217
54767
|
|
|
54218
54768
|
// src/attachment/upload.ts
|
|
54219
|
-
var
|
|
54220
|
-
var
|
|
54221
|
-
var
|
|
54769
|
+
var import_node_fs31 = __toESM(require("fs"), 1);
|
|
54770
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
54771
|
+
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
54222
54772
|
var import_promises3 = require("stream/promises");
|
|
54223
54773
|
var UploadError = class extends Error {
|
|
54224
54774
|
constructor(code, message) {
|
|
@@ -54229,24 +54779,24 @@ var UploadError = class extends Error {
|
|
|
54229
54779
|
code;
|
|
54230
54780
|
};
|
|
54231
54781
|
function assertValidFileName(fileName) {
|
|
54232
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
54782
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path34.default.basename(fileName)) {
|
|
54233
54783
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
54234
54784
|
}
|
|
54235
54785
|
}
|
|
54236
54786
|
var HASH_PREFIX_LEN = 16;
|
|
54237
54787
|
async function writeUploadedAttachment(args) {
|
|
54238
54788
|
assertValidFileName(args.fileName);
|
|
54239
|
-
const attachmentsRoot =
|
|
54789
|
+
const attachmentsRoot = import_node_path34.default.join(args.sessionDir, ".attachments");
|
|
54240
54790
|
try {
|
|
54241
|
-
|
|
54791
|
+
import_node_fs31.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
54242
54792
|
} catch (err) {
|
|
54243
54793
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
54244
54794
|
}
|
|
54245
|
-
const hasher =
|
|
54795
|
+
const hasher = import_node_crypto8.default.createHash("sha256");
|
|
54246
54796
|
let actualSize = 0;
|
|
54247
|
-
const tmpPath =
|
|
54797
|
+
const tmpPath = import_node_path34.default.join(
|
|
54248
54798
|
attachmentsRoot,
|
|
54249
|
-
`.upload-${process.pid}-${Date.now()}-${
|
|
54799
|
+
`.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
|
|
54250
54800
|
);
|
|
54251
54801
|
try {
|
|
54252
54802
|
await (0, import_promises3.pipeline)(
|
|
@@ -54259,18 +54809,18 @@ async function writeUploadedAttachment(args) {
|
|
|
54259
54809
|
yield buf;
|
|
54260
54810
|
}
|
|
54261
54811
|
},
|
|
54262
|
-
|
|
54812
|
+
import_node_fs31.default.createWriteStream(tmpPath, { mode: 384 })
|
|
54263
54813
|
);
|
|
54264
54814
|
} catch (err) {
|
|
54265
54815
|
try {
|
|
54266
|
-
|
|
54816
|
+
import_node_fs31.default.unlinkSync(tmpPath);
|
|
54267
54817
|
} catch {
|
|
54268
54818
|
}
|
|
54269
54819
|
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
54270
54820
|
}
|
|
54271
54821
|
if (actualSize !== args.contentLength) {
|
|
54272
54822
|
try {
|
|
54273
|
-
|
|
54823
|
+
import_node_fs31.default.unlinkSync(tmpPath);
|
|
54274
54824
|
} catch {
|
|
54275
54825
|
}
|
|
54276
54826
|
throw new UploadError(
|
|
@@ -54279,35 +54829,35 @@ async function writeUploadedAttachment(args) {
|
|
|
54279
54829
|
);
|
|
54280
54830
|
}
|
|
54281
54831
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
54282
|
-
const hashDir =
|
|
54832
|
+
const hashDir = import_node_path34.default.join(attachmentsRoot, attachmentId);
|
|
54283
54833
|
let finalFileName;
|
|
54284
54834
|
let hashDirExists = false;
|
|
54285
54835
|
try {
|
|
54286
|
-
hashDirExists =
|
|
54836
|
+
hashDirExists = import_node_fs31.default.statSync(hashDir).isDirectory();
|
|
54287
54837
|
} catch {
|
|
54288
54838
|
}
|
|
54289
54839
|
if (hashDirExists) {
|
|
54290
|
-
const existing =
|
|
54840
|
+
const existing = import_node_fs31.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
|
|
54291
54841
|
finalFileName = existing[0] ?? args.fileName;
|
|
54292
54842
|
try {
|
|
54293
|
-
|
|
54843
|
+
import_node_fs31.default.unlinkSync(tmpPath);
|
|
54294
54844
|
} catch {
|
|
54295
54845
|
}
|
|
54296
54846
|
} else {
|
|
54297
54847
|
try {
|
|
54298
|
-
|
|
54848
|
+
import_node_fs31.default.mkdirSync(hashDir, { recursive: true });
|
|
54299
54849
|
finalFileName = args.fileName;
|
|
54300
|
-
|
|
54850
|
+
import_node_fs31.default.renameSync(tmpPath, import_node_path34.default.join(hashDir, finalFileName));
|
|
54301
54851
|
} catch (err) {
|
|
54302
54852
|
try {
|
|
54303
|
-
|
|
54853
|
+
import_node_fs31.default.unlinkSync(tmpPath);
|
|
54304
54854
|
} catch {
|
|
54305
54855
|
}
|
|
54306
54856
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
54307
54857
|
}
|
|
54308
54858
|
}
|
|
54309
|
-
const absPath =
|
|
54310
|
-
const relPath =
|
|
54859
|
+
const absPath = import_node_path34.default.join(hashDir, finalFileName);
|
|
54860
|
+
const relPath = import_node_path34.default.relative(args.sessionDir, absPath);
|
|
54311
54861
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
54312
54862
|
relPath: absPath,
|
|
54313
54863
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -54321,7 +54871,7 @@ async function writeUploadedAttachment(args) {
|
|
|
54321
54871
|
|
|
54322
54872
|
// src/extension/import.ts
|
|
54323
54873
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
54324
|
-
var
|
|
54874
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
54325
54875
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
54326
54876
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
54327
54877
|
var ImportError = class extends Error {
|
|
@@ -54339,7 +54889,7 @@ async function importZip(buf, root) {
|
|
|
54339
54889
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
54340
54890
|
}
|
|
54341
54891
|
for (const name of Object.keys(zip.files)) {
|
|
54342
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
54892
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
|
|
54343
54893
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
54344
54894
|
}
|
|
54345
54895
|
}
|
|
@@ -54372,7 +54922,7 @@ async function importZip(buf, root) {
|
|
|
54372
54922
|
);
|
|
54373
54923
|
}
|
|
54374
54924
|
}
|
|
54375
|
-
const destDir =
|
|
54925
|
+
const destDir = import_node_path35.default.join(root, manifest.id);
|
|
54376
54926
|
let destExists = false;
|
|
54377
54927
|
try {
|
|
54378
54928
|
await import_promises4.default.access(destDir);
|
|
@@ -54382,15 +54932,15 @@ async function importZip(buf, root) {
|
|
|
54382
54932
|
if (destExists) {
|
|
54383
54933
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
54384
54934
|
}
|
|
54385
|
-
const stage = await import_promises4.default.mkdtemp(
|
|
54935
|
+
const stage = await import_promises4.default.mkdtemp(import_node_path35.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
54386
54936
|
try {
|
|
54387
54937
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
54388
|
-
const dest =
|
|
54938
|
+
const dest = import_node_path35.default.join(stage, name);
|
|
54389
54939
|
if (entry.dir) {
|
|
54390
54940
|
await import_promises4.default.mkdir(dest, { recursive: true });
|
|
54391
54941
|
continue;
|
|
54392
54942
|
}
|
|
54393
|
-
await import_promises4.default.mkdir(
|
|
54943
|
+
await import_promises4.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
|
|
54394
54944
|
const content = await entry.async("nodebuffer");
|
|
54395
54945
|
await import_promises4.default.writeFile(dest, content);
|
|
54396
54946
|
}
|
|
@@ -54420,7 +54970,7 @@ var SHARE_UI_ASSET_MIME = {
|
|
|
54420
54970
|
".wasm": "application/wasm"
|
|
54421
54971
|
};
|
|
54422
54972
|
function shareUiAssetMime(filePath) {
|
|
54423
|
-
const ext =
|
|
54973
|
+
const ext = import_node_path36.default.extname(filePath).toLowerCase();
|
|
54424
54974
|
return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
|
|
54425
54975
|
}
|
|
54426
54976
|
var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
|
|
@@ -54445,6 +54995,24 @@ function authedRpcErrorStatus(code) {
|
|
|
54445
54995
|
return 400;
|
|
54446
54996
|
}
|
|
54447
54997
|
}
|
|
54998
|
+
var LARK_BOT_EVENT_MAX_BYTES = 64 * 1024;
|
|
54999
|
+
async function readRawBody(req, max) {
|
|
55000
|
+
return await new Promise((resolve6, reject) => {
|
|
55001
|
+
let size = 0;
|
|
55002
|
+
const chunks = [];
|
|
55003
|
+
req.on("data", (c) => {
|
|
55004
|
+
size += c.length;
|
|
55005
|
+
if (size > max) {
|
|
55006
|
+
reject(new Error(`body too large (> ${max} bytes)`));
|
|
55007
|
+
req.destroy();
|
|
55008
|
+
return;
|
|
55009
|
+
}
|
|
55010
|
+
chunks.push(c);
|
|
55011
|
+
});
|
|
55012
|
+
req.on("end", () => resolve6(Buffer.concat(chunks).toString("utf8")));
|
|
55013
|
+
req.on("error", reject);
|
|
55014
|
+
});
|
|
55015
|
+
}
|
|
54448
55016
|
async function readJsonBody(req, max) {
|
|
54449
55017
|
return await new Promise((resolve6, reject) => {
|
|
54450
55018
|
let size = 0;
|
|
@@ -54501,7 +55069,7 @@ function isValidUploadFileName(fileName) {
|
|
|
54501
55069
|
if (fileName === "." || fileName === "..") return false;
|
|
54502
55070
|
if (fileName.startsWith(".")) return false;
|
|
54503
55071
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
54504
|
-
return fileName ===
|
|
55072
|
+
return fileName === import_node_path36.default.basename(fileName);
|
|
54505
55073
|
}
|
|
54506
55074
|
function createHttpRouter(deps) {
|
|
54507
55075
|
return async (req, res) => {
|
|
@@ -54557,6 +55125,22 @@ function createHttpRouter(deps) {
|
|
|
54557
55125
|
else sendJson(res, 403, { code: r.reason }, AUTHED_RPC_CORS_HEADERS);
|
|
54558
55126
|
return true;
|
|
54559
55127
|
}
|
|
55128
|
+
if (url.pathname === "/lark-bot-connector/event" && req.method === "POST") {
|
|
55129
|
+
if (!deps.larkBotEvent) {
|
|
55130
|
+
sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "lark bot event not wired" });
|
|
55131
|
+
return true;
|
|
55132
|
+
}
|
|
55133
|
+
let raw;
|
|
55134
|
+
try {
|
|
55135
|
+
raw = await readRawBody(req, LARK_BOT_EVENT_MAX_BYTES);
|
|
55136
|
+
} catch (err) {
|
|
55137
|
+
sendJson(res, 400, { code: "INVALID_BODY", message: err instanceof Error ? err.message : String(err) });
|
|
55138
|
+
return true;
|
|
55139
|
+
}
|
|
55140
|
+
const r = deps.larkBotEvent(raw);
|
|
55141
|
+
sendJson(res, r.status, r.body);
|
|
55142
|
+
return true;
|
|
55143
|
+
}
|
|
54560
55144
|
if ((url.pathname === "/s" || url.pathname.startsWith("/s/")) && req.method === "GET") {
|
|
54561
55145
|
if (!deps.shareUiAssetLoader) {
|
|
54562
55146
|
sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "share-ui assets not loaded" });
|
|
@@ -54573,7 +55157,7 @@ function createHttpRouter(deps) {
|
|
|
54573
55157
|
}
|
|
54574
55158
|
let buf;
|
|
54575
55159
|
try {
|
|
54576
|
-
buf = await
|
|
55160
|
+
buf = await import_node_fs32.default.promises.readFile(abs);
|
|
54577
55161
|
} catch {
|
|
54578
55162
|
sendJson(res, 404, { code: "NOT_FOUND", message: "asset not found" });
|
|
54579
55163
|
return true;
|
|
@@ -54721,7 +55305,7 @@ function createHttpRouter(deps) {
|
|
|
54721
55305
|
sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
|
|
54722
55306
|
return true;
|
|
54723
55307
|
}
|
|
54724
|
-
sendHtml(res, 200, loader.renderViewerHtml(
|
|
55308
|
+
sendHtml(res, 200, loader.renderViewerHtml(import_node_path36.default.basename(r.absPath)));
|
|
54725
55309
|
return true;
|
|
54726
55310
|
}
|
|
54727
55311
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
@@ -54842,7 +55426,7 @@ function createHttpRouter(deps) {
|
|
|
54842
55426
|
return true;
|
|
54843
55427
|
}
|
|
54844
55428
|
let absPath;
|
|
54845
|
-
if (
|
|
55429
|
+
if (import_node_path36.default.isAbsolute(pathParam)) {
|
|
54846
55430
|
absPath = pathParam;
|
|
54847
55431
|
} else if (deps.sessionStore) {
|
|
54848
55432
|
const file = deps.sessionStore.read(sid);
|
|
@@ -54850,7 +55434,7 @@ function createHttpRouter(deps) {
|
|
|
54850
55434
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
54851
55435
|
return true;
|
|
54852
55436
|
}
|
|
54853
|
-
absPath =
|
|
55437
|
+
absPath = import_node_path36.default.join(file.cwd, pathParam);
|
|
54854
55438
|
} else {
|
|
54855
55439
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
54856
55440
|
return true;
|
|
@@ -54937,7 +55521,7 @@ function withCtx(ctx, body) {
|
|
|
54937
55521
|
function streamFile(res, absPath, logger) {
|
|
54938
55522
|
let stat;
|
|
54939
55523
|
try {
|
|
54940
|
-
stat =
|
|
55524
|
+
stat = import_node_fs32.default.statSync(absPath);
|
|
54941
55525
|
} catch (err) {
|
|
54942
55526
|
const code = err?.code;
|
|
54943
55527
|
if (code === "ENOENT") {
|
|
@@ -54952,7 +55536,7 @@ function streamFile(res, absPath, logger) {
|
|
|
54952
55536
|
return;
|
|
54953
55537
|
}
|
|
54954
55538
|
const mime = lookupMime(absPath);
|
|
54955
|
-
const basename =
|
|
55539
|
+
const basename = import_node_path36.default.basename(absPath);
|
|
54956
55540
|
res.writeHead(200, {
|
|
54957
55541
|
"Content-Type": mime,
|
|
54958
55542
|
"Content-Length": String(stat.size),
|
|
@@ -54960,7 +55544,7 @@ function streamFile(res, absPath, logger) {
|
|
|
54960
55544
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
54961
55545
|
"X-Content-Type-Options": "nosniff"
|
|
54962
55546
|
});
|
|
54963
|
-
const stream =
|
|
55547
|
+
const stream = import_node_fs32.default.createReadStream(absPath);
|
|
54964
55548
|
stream.on("error", (err) => {
|
|
54965
55549
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
54966
55550
|
res.destroy();
|
|
@@ -54969,8 +55553,8 @@ function streamFile(res, absPath, logger) {
|
|
|
54969
55553
|
}
|
|
54970
55554
|
|
|
54971
55555
|
// src/attachment/gc.ts
|
|
54972
|
-
var
|
|
54973
|
-
var
|
|
55556
|
+
var import_node_fs33 = __toESM(require("fs"), 1);
|
|
55557
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
54974
55558
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
54975
55559
|
function runAttachmentGc(args) {
|
|
54976
55560
|
const now = (args.now ?? Date.now)();
|
|
@@ -54979,38 +55563,38 @@ function runAttachmentGc(args) {
|
|
|
54979
55563
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
54980
55564
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
54981
55565
|
if (entry.stale) continue;
|
|
54982
|
-
if (
|
|
55566
|
+
if (import_node_path37.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
54983
55567
|
}
|
|
54984
55568
|
}
|
|
54985
55569
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
54986
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
55570
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path37.default.join(
|
|
54987
55571
|
args.dataDir,
|
|
54988
55572
|
"sessions",
|
|
54989
55573
|
...scopeSubPath(scope).map(safeFileName),
|
|
54990
55574
|
safeFileName(sessionId)
|
|
54991
55575
|
);
|
|
54992
|
-
const attRoot =
|
|
55576
|
+
const attRoot = import_node_path37.default.join(sessionDir, ".attachments");
|
|
54993
55577
|
let hashDirs;
|
|
54994
55578
|
try {
|
|
54995
|
-
hashDirs =
|
|
55579
|
+
hashDirs = import_node_fs33.default.readdirSync(attRoot);
|
|
54996
55580
|
} catch (err) {
|
|
54997
55581
|
if (err.code === "ENOENT") continue;
|
|
54998
55582
|
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
54999
55583
|
continue;
|
|
55000
55584
|
}
|
|
55001
55585
|
for (const hashDir of hashDirs) {
|
|
55002
|
-
const hashDirAbs =
|
|
55586
|
+
const hashDirAbs = import_node_path37.default.join(attRoot, hashDir);
|
|
55003
55587
|
let files;
|
|
55004
55588
|
try {
|
|
55005
|
-
files =
|
|
55589
|
+
files = import_node_fs33.default.readdirSync(hashDirAbs);
|
|
55006
55590
|
} catch {
|
|
55007
55591
|
continue;
|
|
55008
55592
|
}
|
|
55009
55593
|
for (const name of files) {
|
|
55010
|
-
const file =
|
|
55594
|
+
const file = import_node_path37.default.join(hashDirAbs, name);
|
|
55011
55595
|
let stat;
|
|
55012
55596
|
try {
|
|
55013
|
-
stat =
|
|
55597
|
+
stat = import_node_fs33.default.statSync(file);
|
|
55014
55598
|
} catch {
|
|
55015
55599
|
continue;
|
|
55016
55600
|
}
|
|
@@ -55019,27 +55603,27 @@ function runAttachmentGc(args) {
|
|
|
55019
55603
|
if (age < ttlMs) continue;
|
|
55020
55604
|
if (liveAbs.has(file)) continue;
|
|
55021
55605
|
try {
|
|
55022
|
-
|
|
55606
|
+
import_node_fs33.default.unlinkSync(file);
|
|
55023
55607
|
} catch (err) {
|
|
55024
55608
|
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
55025
55609
|
}
|
|
55026
55610
|
}
|
|
55027
55611
|
try {
|
|
55028
|
-
if (
|
|
55612
|
+
if (import_node_fs33.default.readdirSync(hashDirAbs).length === 0) import_node_fs33.default.rmdirSync(hashDirAbs);
|
|
55029
55613
|
} catch {
|
|
55030
55614
|
}
|
|
55031
55615
|
}
|
|
55032
55616
|
try {
|
|
55033
|
-
if (
|
|
55617
|
+
if (import_node_fs33.default.readdirSync(attRoot).length === 0) import_node_fs33.default.rmdirSync(attRoot);
|
|
55034
55618
|
} catch {
|
|
55035
55619
|
}
|
|
55036
55620
|
}
|
|
55037
55621
|
}
|
|
55038
55622
|
|
|
55039
55623
|
// src/attachment/group.ts
|
|
55040
|
-
var
|
|
55041
|
-
var
|
|
55042
|
-
var
|
|
55624
|
+
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
55625
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
55626
|
+
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
55043
55627
|
init_protocol();
|
|
55044
55628
|
var GroupFileStore = class {
|
|
55045
55629
|
dataDir;
|
|
@@ -55050,11 +55634,11 @@ var GroupFileStore = class {
|
|
|
55050
55634
|
this.logger = opts.logger;
|
|
55051
55635
|
}
|
|
55052
55636
|
rootForScope(scope) {
|
|
55053
|
-
return
|
|
55637
|
+
return import_node_path38.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
55054
55638
|
}
|
|
55055
55639
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
55056
55640
|
filePath(scope, sessionId) {
|
|
55057
|
-
return
|
|
55641
|
+
return import_node_path38.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
55058
55642
|
}
|
|
55059
55643
|
cacheKey(scope, sessionId) {
|
|
55060
55644
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -55063,7 +55647,7 @@ var GroupFileStore = class {
|
|
|
55063
55647
|
readFile(scope, sessionId) {
|
|
55064
55648
|
const file = this.filePath(scope, sessionId);
|
|
55065
55649
|
try {
|
|
55066
|
-
const raw =
|
|
55650
|
+
const raw = import_node_fs34.default.readFileSync(file, "utf8");
|
|
55067
55651
|
const parsed = JSON.parse(raw);
|
|
55068
55652
|
if (!Array.isArray(parsed)) {
|
|
55069
55653
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -55089,10 +55673,10 @@ var GroupFileStore = class {
|
|
|
55089
55673
|
}
|
|
55090
55674
|
writeFile(scope, sessionId, entries) {
|
|
55091
55675
|
const file = this.filePath(scope, sessionId);
|
|
55092
|
-
|
|
55676
|
+
import_node_fs34.default.mkdirSync(import_node_path38.default.dirname(file), { recursive: true });
|
|
55093
55677
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
55094
|
-
|
|
55095
|
-
|
|
55678
|
+
import_node_fs34.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
55679
|
+
import_node_fs34.default.renameSync(tmp, file);
|
|
55096
55680
|
}
|
|
55097
55681
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
55098
55682
|
list(scope, sessionId) {
|
|
@@ -55128,7 +55712,7 @@ var GroupFileStore = class {
|
|
|
55128
55712
|
entries[idx] = next;
|
|
55129
55713
|
} else {
|
|
55130
55714
|
next = {
|
|
55131
|
-
id: `gf-${
|
|
55715
|
+
id: `gf-${import_node_crypto9.default.randomBytes(6).toString("base64url")}`,
|
|
55132
55716
|
relPath: input.relPath,
|
|
55133
55717
|
from: input.from,
|
|
55134
55718
|
label: input.label,
|
|
@@ -55178,10 +55762,10 @@ var GroupFileStore = class {
|
|
|
55178
55762
|
};
|
|
55179
55763
|
|
|
55180
55764
|
// src/discovery/state-file.ts
|
|
55181
|
-
var
|
|
55182
|
-
var
|
|
55765
|
+
var import_node_fs35 = __toESM(require("fs"), 1);
|
|
55766
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
55183
55767
|
function defaultStateFilePath(dataDir) {
|
|
55184
|
-
return
|
|
55768
|
+
return import_node_path39.default.join(dataDir, "state.json");
|
|
55185
55769
|
}
|
|
55186
55770
|
function isPidAlive(pid) {
|
|
55187
55771
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -55203,7 +55787,7 @@ var StateFileManager = class {
|
|
|
55203
55787
|
}
|
|
55204
55788
|
read() {
|
|
55205
55789
|
try {
|
|
55206
|
-
const raw =
|
|
55790
|
+
const raw = import_node_fs35.default.readFileSync(this.file, "utf8");
|
|
55207
55791
|
const parsed = JSON.parse(raw);
|
|
55208
55792
|
return parsed;
|
|
55209
55793
|
} catch {
|
|
@@ -55217,20 +55801,20 @@ var StateFileManager = class {
|
|
|
55217
55801
|
return { status: "stale", existing };
|
|
55218
55802
|
}
|
|
55219
55803
|
write(state) {
|
|
55220
|
-
|
|
55804
|
+
import_node_fs35.default.mkdirSync(import_node_path39.default.dirname(this.file), { recursive: true });
|
|
55221
55805
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
55222
|
-
|
|
55223
|
-
|
|
55806
|
+
import_node_fs35.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
55807
|
+
import_node_fs35.default.renameSync(tmp, this.file);
|
|
55224
55808
|
if (process.platform !== "win32") {
|
|
55225
55809
|
try {
|
|
55226
|
-
|
|
55810
|
+
import_node_fs35.default.chmodSync(this.file, 384);
|
|
55227
55811
|
} catch {
|
|
55228
55812
|
}
|
|
55229
55813
|
}
|
|
55230
55814
|
}
|
|
55231
55815
|
delete() {
|
|
55232
55816
|
try {
|
|
55233
|
-
|
|
55817
|
+
import_node_fs35.default.unlinkSync(this.file);
|
|
55234
55818
|
} catch {
|
|
55235
55819
|
}
|
|
55236
55820
|
}
|
|
@@ -55244,14 +55828,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
|
|
|
55244
55828
|
}
|
|
55245
55829
|
|
|
55246
55830
|
// src/tunnel/tunnel-manager.ts
|
|
55247
|
-
var
|
|
55248
|
-
var
|
|
55249
|
-
var
|
|
55831
|
+
var import_node_fs39 = __toESM(require("fs"), 1);
|
|
55832
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
55833
|
+
var import_node_crypto10 = __toESM(require("crypto"), 1);
|
|
55250
55834
|
var import_node_child_process9 = require("child_process");
|
|
55251
55835
|
|
|
55252
55836
|
// src/tunnel/tunnel-store.ts
|
|
55253
|
-
var
|
|
55254
|
-
var
|
|
55837
|
+
var import_node_fs36 = __toESM(require("fs"), 1);
|
|
55838
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
55255
55839
|
var TunnelStore = class {
|
|
55256
55840
|
constructor(filePath) {
|
|
55257
55841
|
this.filePath = filePath;
|
|
@@ -55259,7 +55843,7 @@ var TunnelStore = class {
|
|
|
55259
55843
|
filePath;
|
|
55260
55844
|
async get() {
|
|
55261
55845
|
try {
|
|
55262
|
-
const raw = await
|
|
55846
|
+
const raw = await import_node_fs36.default.promises.readFile(this.filePath, "utf8");
|
|
55263
55847
|
const obj = JSON.parse(raw);
|
|
55264
55848
|
if (!isPersistedTunnel(obj)) return null;
|
|
55265
55849
|
return obj;
|
|
@@ -55270,22 +55854,22 @@ var TunnelStore = class {
|
|
|
55270
55854
|
}
|
|
55271
55855
|
}
|
|
55272
55856
|
async set(v2) {
|
|
55273
|
-
const dir =
|
|
55274
|
-
await
|
|
55857
|
+
const dir = import_node_path40.default.dirname(this.filePath);
|
|
55858
|
+
await import_node_fs36.default.promises.mkdir(dir, { recursive: true });
|
|
55275
55859
|
const data = JSON.stringify(v2, null, 2);
|
|
55276
55860
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
55277
|
-
await
|
|
55861
|
+
await import_node_fs36.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
55278
55862
|
if (process.platform !== "win32") {
|
|
55279
55863
|
try {
|
|
55280
|
-
await
|
|
55864
|
+
await import_node_fs36.default.promises.chmod(tmp, 384);
|
|
55281
55865
|
} catch {
|
|
55282
55866
|
}
|
|
55283
55867
|
}
|
|
55284
|
-
await
|
|
55868
|
+
await import_node_fs36.default.promises.rename(tmp, this.filePath);
|
|
55285
55869
|
}
|
|
55286
55870
|
async clear() {
|
|
55287
55871
|
try {
|
|
55288
|
-
await
|
|
55872
|
+
await import_node_fs36.default.promises.unlink(this.filePath);
|
|
55289
55873
|
} catch (err) {
|
|
55290
55874
|
const code = err?.code;
|
|
55291
55875
|
if (code !== "ENOENT") throw err;
|
|
@@ -55380,9 +55964,9 @@ function escape(v2) {
|
|
|
55380
55964
|
}
|
|
55381
55965
|
|
|
55382
55966
|
// src/tunnel/frpc-binary.ts
|
|
55383
|
-
var
|
|
55967
|
+
var import_node_fs37 = __toESM(require("fs"), 1);
|
|
55384
55968
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
55385
|
-
var
|
|
55969
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
55386
55970
|
var import_node_child_process7 = require("child_process");
|
|
55387
55971
|
var import_node_stream3 = require("stream");
|
|
55388
55972
|
var import_promises5 = require("stream/promises");
|
|
@@ -55414,20 +55998,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
55414
55998
|
}
|
|
55415
55999
|
async function ensureFrpcBinary(opts) {
|
|
55416
56000
|
if (opts.override) {
|
|
55417
|
-
if (!
|
|
56001
|
+
if (!import_node_fs37.default.existsSync(opts.override)) {
|
|
55418
56002
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
55419
56003
|
}
|
|
55420
56004
|
return opts.override;
|
|
55421
56005
|
}
|
|
55422
56006
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
55423
56007
|
const platform = opts.platform ?? detectPlatform();
|
|
55424
|
-
const binDir =
|
|
55425
|
-
|
|
56008
|
+
const binDir = import_node_path41.default.join(opts.dataDir, "bin");
|
|
56009
|
+
import_node_fs37.default.mkdirSync(binDir, { recursive: true });
|
|
55426
56010
|
cleanupStaleArtifacts(binDir);
|
|
55427
|
-
const stableBin =
|
|
55428
|
-
if (
|
|
56011
|
+
const stableBin = import_node_path41.default.join(binDir, "frpc");
|
|
56012
|
+
if (import_node_fs37.default.existsSync(stableBin)) return stableBin;
|
|
55429
56013
|
const partialBin = `${stableBin}.partial`;
|
|
55430
|
-
const tarballPath =
|
|
56014
|
+
const tarballPath = import_node_path41.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
55431
56015
|
try {
|
|
55432
56016
|
const url = frpcDownloadUrl(version2, platform);
|
|
55433
56017
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -55436,8 +56020,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
55436
56020
|
} else {
|
|
55437
56021
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
55438
56022
|
}
|
|
55439
|
-
|
|
55440
|
-
|
|
56023
|
+
import_node_fs37.default.chmodSync(partialBin, 493);
|
|
56024
|
+
import_node_fs37.default.renameSync(partialBin, stableBin);
|
|
55441
56025
|
} finally {
|
|
55442
56026
|
safeUnlink(tarballPath);
|
|
55443
56027
|
safeUnlink(partialBin);
|
|
@@ -55447,15 +56031,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
55447
56031
|
function cleanupStaleArtifacts(binDir) {
|
|
55448
56032
|
let entries;
|
|
55449
56033
|
try {
|
|
55450
|
-
entries =
|
|
56034
|
+
entries = import_node_fs37.default.readdirSync(binDir);
|
|
55451
56035
|
} catch {
|
|
55452
56036
|
return;
|
|
55453
56037
|
}
|
|
55454
56038
|
for (const name of entries) {
|
|
55455
56039
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
55456
|
-
const full =
|
|
56040
|
+
const full = import_node_path41.default.join(binDir, name);
|
|
55457
56041
|
try {
|
|
55458
|
-
|
|
56042
|
+
import_node_fs37.default.rmSync(full, { recursive: true, force: true });
|
|
55459
56043
|
} catch {
|
|
55460
56044
|
}
|
|
55461
56045
|
}
|
|
@@ -55463,7 +56047,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
55463
56047
|
}
|
|
55464
56048
|
function safeUnlink(p2) {
|
|
55465
56049
|
try {
|
|
55466
|
-
|
|
56050
|
+
import_node_fs37.default.unlinkSync(p2);
|
|
55467
56051
|
} catch {
|
|
55468
56052
|
}
|
|
55469
56053
|
}
|
|
@@ -55474,13 +56058,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
55474
56058
|
if (!res.ok || !res.body) {
|
|
55475
56059
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
55476
56060
|
}
|
|
55477
|
-
const out =
|
|
56061
|
+
const out = import_node_fs37.default.createWriteStream(dest);
|
|
55478
56062
|
const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
|
|
55479
56063
|
await (0, import_promises5.pipeline)(nodeStream, out);
|
|
55480
56064
|
}
|
|
55481
56065
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
55482
|
-
const work =
|
|
55483
|
-
|
|
56066
|
+
const work = import_node_path41.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
56067
|
+
import_node_fs37.default.mkdirSync(work, { recursive: true });
|
|
55484
56068
|
try {
|
|
55485
56069
|
await new Promise((resolve6, reject) => {
|
|
55486
56070
|
const proc = (0, import_node_child_process7.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -55488,32 +56072,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
55488
56072
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
55489
56073
|
});
|
|
55490
56074
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
55491
|
-
const src =
|
|
55492
|
-
if (!
|
|
56075
|
+
const src = import_node_path41.default.join(work, dirName, "frpc");
|
|
56076
|
+
if (!import_node_fs37.default.existsSync(src)) {
|
|
55493
56077
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
55494
56078
|
}
|
|
55495
|
-
|
|
56079
|
+
import_node_fs37.default.copyFileSync(src, destBin);
|
|
55496
56080
|
} finally {
|
|
55497
|
-
|
|
56081
|
+
import_node_fs37.default.rmSync(work, { recursive: true, force: true });
|
|
55498
56082
|
}
|
|
55499
56083
|
}
|
|
55500
56084
|
|
|
55501
56085
|
// src/tunnel/frpc-process.ts
|
|
55502
|
-
var
|
|
55503
|
-
var
|
|
56086
|
+
var import_node_fs38 = __toESM(require("fs"), 1);
|
|
56087
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
55504
56088
|
var import_node_child_process8 = require("child_process");
|
|
55505
56089
|
function frpcPidFilePath(dataDir) {
|
|
55506
|
-
return
|
|
56090
|
+
return import_node_path42.default.join(dataDir, "frpc.pid");
|
|
55507
56091
|
}
|
|
55508
56092
|
function writeFrpcPid(dataDir, pid) {
|
|
55509
56093
|
try {
|
|
55510
|
-
|
|
56094
|
+
import_node_fs38.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
55511
56095
|
} catch {
|
|
55512
56096
|
}
|
|
55513
56097
|
}
|
|
55514
56098
|
function clearFrpcPid(dataDir) {
|
|
55515
56099
|
try {
|
|
55516
|
-
|
|
56100
|
+
import_node_fs38.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
55517
56101
|
} catch {
|
|
55518
56102
|
}
|
|
55519
56103
|
}
|
|
@@ -55529,7 +56113,7 @@ function defaultIsPidAlive(pid) {
|
|
|
55529
56113
|
}
|
|
55530
56114
|
function defaultReadPidFile(file) {
|
|
55531
56115
|
try {
|
|
55532
|
-
return
|
|
56116
|
+
return import_node_fs38.default.readFileSync(file, "utf8");
|
|
55533
56117
|
} catch {
|
|
55534
56118
|
return null;
|
|
55535
56119
|
}
|
|
@@ -55545,7 +56129,7 @@ function defaultSleep2(ms) {
|
|
|
55545
56129
|
}
|
|
55546
56130
|
async function killStaleFrpc(deps) {
|
|
55547
56131
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
55548
|
-
const tomlPath =
|
|
56132
|
+
const tomlPath = import_node_path42.default.join(deps.dataDir, "frpc.toml");
|
|
55549
56133
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
55550
56134
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
55551
56135
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -55569,7 +56153,7 @@ async function killStaleFrpc(deps) {
|
|
|
55569
56153
|
}
|
|
55570
56154
|
if (victims.size === 0) {
|
|
55571
56155
|
try {
|
|
55572
|
-
|
|
56156
|
+
import_node_fs38.default.unlinkSync(pidFile);
|
|
55573
56157
|
} catch {
|
|
55574
56158
|
}
|
|
55575
56159
|
return;
|
|
@@ -55580,7 +56164,7 @@ async function killStaleFrpc(deps) {
|
|
|
55580
56164
|
}
|
|
55581
56165
|
await sleep2(deps.reapWaitMs ?? 300);
|
|
55582
56166
|
try {
|
|
55583
|
-
|
|
56167
|
+
import_node_fs38.default.unlinkSync(pidFile);
|
|
55584
56168
|
} catch {
|
|
55585
56169
|
}
|
|
55586
56170
|
}
|
|
@@ -55617,7 +56201,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
55617
56201
|
var TunnelManager = class {
|
|
55618
56202
|
constructor(deps) {
|
|
55619
56203
|
this.deps = deps;
|
|
55620
|
-
this.store = deps.store ?? new TunnelStore(
|
|
56204
|
+
this.store = deps.store ?? new TunnelStore(import_node_path43.default.join(deps.dataDir, "tunnel.json"));
|
|
55621
56205
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
55622
56206
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
55623
56207
|
}
|
|
@@ -55744,8 +56328,8 @@ var TunnelManager = class {
|
|
|
55744
56328
|
dataDir: this.deps.dataDir,
|
|
55745
56329
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
55746
56330
|
});
|
|
55747
|
-
const tomlPath =
|
|
55748
|
-
const proxyName = `clawd-${t.subdomain}-${localPort}-${
|
|
56331
|
+
const tomlPath = import_node_path43.default.join(this.deps.dataDir, "frpc.toml");
|
|
56332
|
+
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
|
|
55749
56333
|
const toml = buildFrpcToml({
|
|
55750
56334
|
serverAddr: t.frpsHost,
|
|
55751
56335
|
serverPort: t.frpsPort,
|
|
@@ -55755,14 +56339,14 @@ var TunnelManager = class {
|
|
|
55755
56339
|
localPort,
|
|
55756
56340
|
logLevel: "info"
|
|
55757
56341
|
});
|
|
55758
|
-
await
|
|
56342
|
+
await import_node_fs39.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
55759
56343
|
const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
|
|
55760
56344
|
stdio: ["ignore", "pipe", "pipe"]
|
|
55761
56345
|
});
|
|
55762
|
-
const logDir =
|
|
55763
|
-
|
|
55764
|
-
const logFilePath =
|
|
55765
|
-
const logStream =
|
|
56346
|
+
const logDir = import_node_path43.default.join(this.deps.dataDir, "log");
|
|
56347
|
+
import_node_fs39.default.mkdirSync(logDir, { recursive: true });
|
|
56348
|
+
const logFilePath = import_node_path43.default.join(logDir, "frpc.log");
|
|
56349
|
+
const logStream = import_node_fs39.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
55766
56350
|
logStream.on("error", () => {
|
|
55767
56351
|
});
|
|
55768
56352
|
const tee = (chunk) => {
|
|
@@ -55845,27 +56429,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
55845
56429
|
|
|
55846
56430
|
// src/tunnel/device-key.ts
|
|
55847
56431
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
55848
|
-
var
|
|
55849
|
-
var
|
|
56432
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
56433
|
+
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
55850
56434
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
55851
56435
|
function deriveStableDeviceKey(opts = {}) {
|
|
55852
56436
|
const hostname = opts.hostname ?? import_node_os14.default.hostname();
|
|
55853
56437
|
const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
|
|
55854
56438
|
const home = opts.home ?? import_node_os14.default.homedir();
|
|
55855
|
-
const defaultDataDir =
|
|
55856
|
-
const normalizedDataDir = opts.dataDir ?
|
|
56439
|
+
const defaultDataDir = import_node_path44.default.resolve(import_node_path44.default.join(home, ".clawd"));
|
|
56440
|
+
const normalizedDataDir = opts.dataDir ? import_node_path44.default.resolve(opts.dataDir) : null;
|
|
55857
56441
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
55858
56442
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
55859
|
-
return
|
|
56443
|
+
return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
55860
56444
|
}
|
|
55861
56445
|
|
|
55862
56446
|
// src/auth-store.ts
|
|
55863
|
-
var
|
|
55864
|
-
var
|
|
55865
|
-
var
|
|
56447
|
+
var import_node_fs40 = __toESM(require("fs"), 1);
|
|
56448
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
56449
|
+
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
55866
56450
|
var AUTH_FILE_NAME = "auth.json";
|
|
55867
56451
|
function authFilePath(dataDir) {
|
|
55868
|
-
return
|
|
56452
|
+
return import_node_path45.default.join(dataDir, AUTH_FILE_NAME);
|
|
55869
56453
|
}
|
|
55870
56454
|
function loadOrCreateAuthFile(opts) {
|
|
55871
56455
|
const file = authFilePath(opts.dataDir);
|
|
@@ -55890,14 +56474,14 @@ function loadOrCreateAuthFile(opts) {
|
|
|
55890
56474
|
return next;
|
|
55891
56475
|
}
|
|
55892
56476
|
function defaultGenerateToken() {
|
|
55893
|
-
return
|
|
56477
|
+
return import_node_crypto12.default.randomBytes(32).toString("base64url");
|
|
55894
56478
|
}
|
|
55895
56479
|
function defaultGenerateOwnerPrincipalId() {
|
|
55896
|
-
return `owner-${
|
|
56480
|
+
return `owner-${import_node_crypto12.default.randomUUID()}`;
|
|
55897
56481
|
}
|
|
55898
56482
|
function readAuthFile(file) {
|
|
55899
56483
|
try {
|
|
55900
|
-
const raw =
|
|
56484
|
+
const raw = import_node_fs40.default.readFileSync(file, "utf8");
|
|
55901
56485
|
const parsed = JSON.parse(raw);
|
|
55902
56486
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
55903
56487
|
return null;
|
|
@@ -55917,25 +56501,25 @@ function readAuthFile(file) {
|
|
|
55917
56501
|
}
|
|
55918
56502
|
}
|
|
55919
56503
|
function writeAuthFile(file, content) {
|
|
55920
|
-
|
|
55921
|
-
|
|
56504
|
+
import_node_fs40.default.mkdirSync(import_node_path45.default.dirname(file), { recursive: true });
|
|
56505
|
+
import_node_fs40.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
55922
56506
|
try {
|
|
55923
|
-
|
|
56507
|
+
import_node_fs40.default.chmodSync(file, 384);
|
|
55924
56508
|
} catch {
|
|
55925
56509
|
}
|
|
55926
56510
|
}
|
|
55927
56511
|
|
|
55928
56512
|
// src/owner-profile.ts
|
|
55929
|
-
var
|
|
56513
|
+
var import_node_fs41 = __toESM(require("fs"), 1);
|
|
55930
56514
|
var import_node_os15 = __toESM(require("os"), 1);
|
|
55931
|
-
var
|
|
56515
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
55932
56516
|
var PROFILE_FILENAME = "profile.json";
|
|
55933
56517
|
function loadOwnerDisplayName(dataDir) {
|
|
55934
56518
|
const fallback = import_node_os15.default.userInfo().username;
|
|
55935
|
-
const profilePath =
|
|
56519
|
+
const profilePath = import_node_path46.default.join(dataDir, PROFILE_FILENAME);
|
|
55936
56520
|
let raw;
|
|
55937
56521
|
try {
|
|
55938
|
-
raw =
|
|
56522
|
+
raw = import_node_fs41.default.readFileSync(profilePath, "utf8");
|
|
55939
56523
|
} catch {
|
|
55940
56524
|
return fallback;
|
|
55941
56525
|
}
|
|
@@ -55958,18 +56542,18 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
55958
56542
|
}
|
|
55959
56543
|
|
|
55960
56544
|
// src/feishu-auth/owner-identity-store.ts
|
|
55961
|
-
var
|
|
55962
|
-
var
|
|
56545
|
+
var import_node_fs42 = __toESM(require("fs"), 1);
|
|
56546
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
55963
56547
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
55964
56548
|
var OwnerIdentityStore = class {
|
|
55965
56549
|
file;
|
|
55966
56550
|
constructor(dataDir) {
|
|
55967
|
-
this.file =
|
|
56551
|
+
this.file = import_node_path47.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
55968
56552
|
}
|
|
55969
56553
|
read() {
|
|
55970
56554
|
let raw;
|
|
55971
56555
|
try {
|
|
55972
|
-
raw =
|
|
56556
|
+
raw = import_node_fs42.default.readFileSync(this.file, "utf8");
|
|
55973
56557
|
} catch {
|
|
55974
56558
|
return null;
|
|
55975
56559
|
}
|
|
@@ -55997,16 +56581,16 @@ var OwnerIdentityStore = class {
|
|
|
55997
56581
|
};
|
|
55998
56582
|
}
|
|
55999
56583
|
write(record) {
|
|
56000
|
-
|
|
56001
|
-
|
|
56584
|
+
import_node_fs42.default.mkdirSync(import_node_path47.default.dirname(this.file), { recursive: true });
|
|
56585
|
+
import_node_fs42.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
56002
56586
|
try {
|
|
56003
|
-
|
|
56587
|
+
import_node_fs42.default.chmodSync(this.file, 384);
|
|
56004
56588
|
} catch {
|
|
56005
56589
|
}
|
|
56006
56590
|
}
|
|
56007
56591
|
clear() {
|
|
56008
56592
|
try {
|
|
56009
|
-
|
|
56593
|
+
import_node_fs42.default.unlinkSync(this.file);
|
|
56010
56594
|
} catch (err) {
|
|
56011
56595
|
const code = err?.code;
|
|
56012
56596
|
if (code !== "ENOENT") throw err;
|
|
@@ -56015,7 +56599,7 @@ var OwnerIdentityStore = class {
|
|
|
56015
56599
|
};
|
|
56016
56600
|
|
|
56017
56601
|
// src/feishu-auth/login-flow.ts
|
|
56018
|
-
var
|
|
56602
|
+
var import_node_crypto13 = __toESM(require("crypto"), 1);
|
|
56019
56603
|
var STATE_TTL_MS = 5 * 60 * 1e3;
|
|
56020
56604
|
var LoginFlow = class {
|
|
56021
56605
|
constructor(deps) {
|
|
@@ -56024,7 +56608,7 @@ var LoginFlow = class {
|
|
|
56024
56608
|
deps;
|
|
56025
56609
|
pendingStates = /* @__PURE__ */ new Map();
|
|
56026
56610
|
start() {
|
|
56027
|
-
const state =
|
|
56611
|
+
const state = import_node_crypto13.default.randomBytes(16).toString("base64url");
|
|
56028
56612
|
const now = (this.deps.now ?? Date.now)();
|
|
56029
56613
|
this.pendingStates.set(state, now);
|
|
56030
56614
|
this.gcExpired(now);
|
|
@@ -56143,9 +56727,9 @@ var CentralClientError = class extends Error {
|
|
|
56143
56727
|
code;
|
|
56144
56728
|
cause;
|
|
56145
56729
|
};
|
|
56146
|
-
async function centralRequest(opts,
|
|
56730
|
+
async function centralRequest(opts, path78, init) {
|
|
56147
56731
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
56148
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
56732
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path78}`;
|
|
56149
56733
|
const ctrl = new AbortController();
|
|
56150
56734
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
56151
56735
|
let res;
|
|
@@ -56339,8 +56923,8 @@ function verifyConnectToken(args) {
|
|
|
56339
56923
|
}
|
|
56340
56924
|
|
|
56341
56925
|
// src/feishu-auth/server-key.ts
|
|
56342
|
-
var
|
|
56343
|
-
var
|
|
56926
|
+
var fs52 = __toESM(require("fs"), 1);
|
|
56927
|
+
var path56 = __toESM(require("path"), 1);
|
|
56344
56928
|
var FILE_NAME2 = "server-signing-key.json";
|
|
56345
56929
|
var ServerKeyStore = class {
|
|
56346
56930
|
constructor(dataDir) {
|
|
@@ -56348,12 +56932,12 @@ var ServerKeyStore = class {
|
|
|
56348
56932
|
}
|
|
56349
56933
|
dataDir;
|
|
56350
56934
|
filePath() {
|
|
56351
|
-
return
|
|
56935
|
+
return path56.join(this.dataDir, FILE_NAME2);
|
|
56352
56936
|
}
|
|
56353
56937
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
56354
56938
|
read() {
|
|
56355
56939
|
try {
|
|
56356
|
-
const raw =
|
|
56940
|
+
const raw = fs52.readFileSync(this.filePath(), "utf8");
|
|
56357
56941
|
const parsed = JSON.parse(raw);
|
|
56358
56942
|
if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
|
|
56359
56943
|
return parsed.publicKeyPem;
|
|
@@ -56368,12 +56952,12 @@ var ServerKeyStore = class {
|
|
|
56368
56952
|
publicKeyPem,
|
|
56369
56953
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
56370
56954
|
};
|
|
56371
|
-
|
|
56372
|
-
|
|
56955
|
+
fs52.mkdirSync(this.dataDir, { recursive: true });
|
|
56956
|
+
fs52.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
|
|
56373
56957
|
}
|
|
56374
56958
|
clear() {
|
|
56375
56959
|
try {
|
|
56376
|
-
|
|
56960
|
+
fs52.unlinkSync(this.filePath());
|
|
56377
56961
|
} catch {
|
|
56378
56962
|
}
|
|
56379
56963
|
}
|
|
@@ -56386,12 +56970,12 @@ init_protocol();
|
|
|
56386
56970
|
init_protocol();
|
|
56387
56971
|
|
|
56388
56972
|
// src/session/fork.ts
|
|
56389
|
-
var
|
|
56973
|
+
var import_node_fs43 = __toESM(require("fs"), 1);
|
|
56390
56974
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
56391
|
-
var
|
|
56975
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
56392
56976
|
init_claude_history();
|
|
56393
56977
|
function readJsonlEntries(file) {
|
|
56394
|
-
const raw =
|
|
56978
|
+
const raw = import_node_fs43.default.readFileSync(file, "utf8");
|
|
56395
56979
|
const out = [];
|
|
56396
56980
|
for (const line of raw.split("\n")) {
|
|
56397
56981
|
const t = line.trim();
|
|
@@ -56404,19 +56988,19 @@ function readJsonlEntries(file) {
|
|
|
56404
56988
|
return out;
|
|
56405
56989
|
}
|
|
56406
56990
|
function forkSession(input) {
|
|
56407
|
-
const baseDir = input.baseDir ??
|
|
56408
|
-
let projectDir =
|
|
56409
|
-
let sourceFile =
|
|
56410
|
-
if (!
|
|
56991
|
+
const baseDir = input.baseDir ?? import_node_path48.default.join(import_node_os16.default.homedir(), ".claude");
|
|
56992
|
+
let projectDir = import_node_path48.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
56993
|
+
let sourceFile = import_node_path48.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
56994
|
+
if (!import_node_fs43.default.existsSync(sourceFile)) {
|
|
56411
56995
|
const found = findTranscriptByToolSessionId(
|
|
56412
|
-
|
|
56996
|
+
import_node_path48.default.join(baseDir, "projects"),
|
|
56413
56997
|
input.toolSessionId
|
|
56414
56998
|
);
|
|
56415
56999
|
if (!found) {
|
|
56416
57000
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
56417
57001
|
}
|
|
56418
57002
|
sourceFile = found;
|
|
56419
|
-
projectDir =
|
|
57003
|
+
projectDir = import_node_path48.default.dirname(found);
|
|
56420
57004
|
}
|
|
56421
57005
|
const entries = readJsonlEntries(sourceFile);
|
|
56422
57006
|
const mainEntries = entries.filter((e) => e.isSidechain !== true);
|
|
@@ -56445,9 +57029,9 @@ function forkSession(input) {
|
|
|
56445
57029
|
}
|
|
56446
57030
|
forkedLines.push(JSON.stringify(forked));
|
|
56447
57031
|
}
|
|
56448
|
-
const forkedFilePath =
|
|
56449
|
-
|
|
56450
|
-
|
|
57032
|
+
const forkedFilePath = import_node_path48.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
57033
|
+
import_node_fs43.default.mkdirSync(projectDir, { recursive: true });
|
|
57034
|
+
import_node_fs43.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
56451
57035
|
return { forkedToolSessionId, forkedFilePath };
|
|
56452
57036
|
}
|
|
56453
57037
|
|
|
@@ -56890,7 +57474,7 @@ function buildPermissionHandlers(deps) {
|
|
|
56890
57474
|
}
|
|
56891
57475
|
|
|
56892
57476
|
// src/handlers/history.ts
|
|
56893
|
-
var
|
|
57477
|
+
var path59 = __toESM(require("path"), 1);
|
|
56894
57478
|
init_protocol();
|
|
56895
57479
|
|
|
56896
57480
|
// src/session/recent-dirs.ts
|
|
@@ -56908,7 +57492,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
56908
57492
|
}
|
|
56909
57493
|
|
|
56910
57494
|
// src/permission/persona-paths.ts
|
|
56911
|
-
var
|
|
57495
|
+
var path58 = __toESM(require("path"), 1);
|
|
56912
57496
|
function getAllowedPersonaIds(grants, action) {
|
|
56913
57497
|
const ids = /* @__PURE__ */ new Set();
|
|
56914
57498
|
for (const g2 of grants) {
|
|
@@ -56921,42 +57505,42 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
56921
57505
|
return ids;
|
|
56922
57506
|
}
|
|
56923
57507
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
56924
|
-
const target =
|
|
57508
|
+
const target = path58.resolve(absPath);
|
|
56925
57509
|
if (userWorkDir) {
|
|
56926
|
-
const u =
|
|
56927
|
-
const usep = u.endsWith(
|
|
57510
|
+
const u = path58.resolve(userWorkDir);
|
|
57511
|
+
const usep = u.endsWith(path58.sep) ? "" : path58.sep;
|
|
56928
57512
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
56929
57513
|
}
|
|
56930
|
-
const root =
|
|
56931
|
-
const sep3 = root.endsWith(
|
|
57514
|
+
const root = path58.resolve(personaRoot);
|
|
57515
|
+
const sep3 = root.endsWith(path58.sep) ? "" : path58.sep;
|
|
56932
57516
|
if (!target.startsWith(root + sep3)) return false;
|
|
56933
|
-
const rel =
|
|
57517
|
+
const rel = path58.relative(root, target);
|
|
56934
57518
|
if (!rel || rel.startsWith("..")) return false;
|
|
56935
|
-
const personaId2 = rel.split(
|
|
57519
|
+
const personaId2 = rel.split(path58.sep)[0];
|
|
56936
57520
|
if (!personaId2) return false;
|
|
56937
57521
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
56938
57522
|
if (allowed === "*") return true;
|
|
56939
57523
|
return allowed.has(personaId2);
|
|
56940
57524
|
}
|
|
56941
57525
|
function personaIdFromPath(absPath, personaRoot) {
|
|
56942
|
-
const root =
|
|
56943
|
-
const target =
|
|
56944
|
-
const sep3 = root.endsWith(
|
|
57526
|
+
const root = path58.resolve(personaRoot);
|
|
57527
|
+
const target = path58.resolve(absPath);
|
|
57528
|
+
const sep3 = root.endsWith(path58.sep) ? "" : path58.sep;
|
|
56945
57529
|
if (!target.startsWith(root + sep3)) return null;
|
|
56946
|
-
const rel =
|
|
57530
|
+
const rel = path58.relative(root, target);
|
|
56947
57531
|
if (!rel || rel.startsWith("..")) return null;
|
|
56948
|
-
const id = rel.split(
|
|
57532
|
+
const id = rel.split(path58.sep)[0];
|
|
56949
57533
|
return id || null;
|
|
56950
57534
|
}
|
|
56951
57535
|
function isPathWithin(dir, absPath) {
|
|
56952
|
-
const d =
|
|
56953
|
-
const t =
|
|
56954
|
-
const sep3 = d.endsWith(
|
|
57536
|
+
const d = path58.resolve(dir);
|
|
57537
|
+
const t = path58.resolve(absPath);
|
|
57538
|
+
const sep3 = d.endsWith(path58.sep) ? "" : path58.sep;
|
|
56955
57539
|
return t === d || t.startsWith(d + sep3);
|
|
56956
57540
|
}
|
|
56957
57541
|
function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
|
|
56958
57542
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
56959
|
-
return personaIdFromPath(
|
|
57543
|
+
return personaIdFromPath(path58.resolve(absPath), personaRoot) === personaId2;
|
|
56960
57544
|
}
|
|
56961
57545
|
|
|
56962
57546
|
// src/handlers/history.ts
|
|
@@ -57008,7 +57592,7 @@ function buildHistoryHandlers(deps) {
|
|
|
57008
57592
|
if (!pid) return false;
|
|
57009
57593
|
return isGuestPathAllowed(
|
|
57010
57594
|
ctx.grants,
|
|
57011
|
-
|
|
57595
|
+
path59.join(personaRoot, pid),
|
|
57012
57596
|
personaRoot,
|
|
57013
57597
|
"read",
|
|
57014
57598
|
userWorkDir
|
|
@@ -57020,7 +57604,7 @@ function buildHistoryHandlers(deps) {
|
|
|
57020
57604
|
};
|
|
57021
57605
|
const list = async (frame, _client, ctx) => {
|
|
57022
57606
|
const args = HistoryListArgs.parse(frame);
|
|
57023
|
-
assertGuestPath(ctx,
|
|
57607
|
+
assertGuestPath(ctx, path59.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
|
|
57024
57608
|
const sessions = await history.listSessions(args);
|
|
57025
57609
|
return { response: { type: "history:list", sessions } };
|
|
57026
57610
|
};
|
|
@@ -57053,13 +57637,13 @@ function buildHistoryHandlers(deps) {
|
|
|
57053
57637
|
};
|
|
57054
57638
|
const subagents = async (frame, _client, ctx) => {
|
|
57055
57639
|
const args = HistorySubagentsArgs.parse(frame);
|
|
57056
|
-
assertGuestPath(ctx,
|
|
57640
|
+
assertGuestPath(ctx, path59.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
57057
57641
|
const subs = await history.listSubagents(args);
|
|
57058
57642
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
57059
57643
|
};
|
|
57060
57644
|
const subagentRead = async (frame, _client, ctx) => {
|
|
57061
57645
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
57062
|
-
assertGuestPath(ctx,
|
|
57646
|
+
assertGuestPath(ctx, path59.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
57063
57647
|
const res = await history.readSubagent(args);
|
|
57064
57648
|
return { response: { type: "history:subagent-read", ...res } };
|
|
57065
57649
|
};
|
|
@@ -57068,7 +57652,7 @@ function buildHistoryHandlers(deps) {
|
|
|
57068
57652
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
57069
57653
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
57070
57654
|
const filtered = dirs.filter(
|
|
57071
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
57655
|
+
(d) => isGuestPathAllowed(ctx.grants, path59.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
57072
57656
|
);
|
|
57073
57657
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
57074
57658
|
}
|
|
@@ -57085,7 +57669,7 @@ function buildHistoryHandlers(deps) {
|
|
|
57085
57669
|
}
|
|
57086
57670
|
|
|
57087
57671
|
// src/handlers/workspace.ts
|
|
57088
|
-
var
|
|
57672
|
+
var path60 = __toESM(require("path"), 1);
|
|
57089
57673
|
var os16 = __toESM(require("os"), 1);
|
|
57090
57674
|
init_protocol();
|
|
57091
57675
|
init_protocol();
|
|
@@ -57127,22 +57711,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
57127
57711
|
const args = WorkspaceListArgs.parse(frame);
|
|
57128
57712
|
const isGuest = ctx?.principal.kind === "guest";
|
|
57129
57713
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
|
|
57130
|
-
const resolvedCwd =
|
|
57131
|
-
const target = args.path ?
|
|
57714
|
+
const resolvedCwd = path60.resolve(args.cwd ?? fallbackCwd);
|
|
57715
|
+
const target = args.path ? path60.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
57132
57716
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
57133
57717
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
57134
57718
|
return { response: { type: "workspace:list", ...res } };
|
|
57135
57719
|
};
|
|
57136
57720
|
const read = async (frame, _client, ctx) => {
|
|
57137
57721
|
const args = WorkspaceReadArgs.parse(frame);
|
|
57138
|
-
const target =
|
|
57722
|
+
const target = path60.isAbsolute(args.path) ? path60.resolve(args.path) : path60.resolve(args.cwd, args.path);
|
|
57139
57723
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
57140
57724
|
const res = workspace.read(args);
|
|
57141
57725
|
return { response: { type: "workspace:read", ...res } };
|
|
57142
57726
|
};
|
|
57143
57727
|
const skillsList = async (frame, _client, ctx) => {
|
|
57144
57728
|
const args = SkillsListArgs.parse(frame);
|
|
57145
|
-
const cwdAbs =
|
|
57729
|
+
const cwdAbs = path60.resolve(args.cwd);
|
|
57146
57730
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
57147
57731
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
57148
57732
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -57154,7 +57738,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
57154
57738
|
};
|
|
57155
57739
|
const agentsList = async (frame, _client, ctx) => {
|
|
57156
57740
|
const args = AgentsListArgs.parse(frame);
|
|
57157
|
-
const cwdAbs =
|
|
57741
|
+
const cwdAbs = path60.resolve(args.cwd);
|
|
57158
57742
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
57159
57743
|
if (args.tool === "codex") {
|
|
57160
57744
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -57176,20 +57760,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
57176
57760
|
}
|
|
57177
57761
|
|
|
57178
57762
|
// src/handlers/git.ts
|
|
57179
|
-
var
|
|
57763
|
+
var path62 = __toESM(require("path"), 1);
|
|
57180
57764
|
init_protocol();
|
|
57181
57765
|
init_protocol();
|
|
57182
57766
|
|
|
57183
57767
|
// src/workspace/git.ts
|
|
57184
57768
|
var import_node_child_process10 = require("child_process");
|
|
57185
|
-
var
|
|
57186
|
-
var
|
|
57769
|
+
var import_node_fs44 = __toESM(require("fs"), 1);
|
|
57770
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
57187
57771
|
var import_node_util = require("util");
|
|
57188
57772
|
var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
|
|
57189
57773
|
function normalizePath(p2) {
|
|
57190
|
-
const resolved =
|
|
57774
|
+
const resolved = import_node_path49.default.resolve(p2);
|
|
57191
57775
|
try {
|
|
57192
|
-
return
|
|
57776
|
+
return import_node_fs44.default.realpathSync(resolved);
|
|
57193
57777
|
} catch {
|
|
57194
57778
|
return resolved;
|
|
57195
57779
|
}
|
|
@@ -57263,7 +57847,7 @@ async function listGitBranches(cwd) {
|
|
|
57263
57847
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
57264
57848
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
57265
57849
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
57266
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
57850
|
+
if (!isGuestPathAllowed(ctx.grants, path62.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
57267
57851
|
throw new ClawdError(
|
|
57268
57852
|
ERROR_CODES.UNAUTHORIZED,
|
|
57269
57853
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -57993,6 +58577,10 @@ var METHOD_GRANT_MAP = {
|
|
|
57993
58577
|
"shift-internal:cancel": ADMIN_ANY,
|
|
57994
58578
|
"shift-internal:update": ADMIN_ANY,
|
|
57995
58579
|
"shift-internal:history": ADMIN_ANY,
|
|
58580
|
+
// ---- larkBot:* (LarkBotConnector 绑定/状态,owner-only) ----
|
|
58581
|
+
"larkBot:bindManual": ADMIN_ANY,
|
|
58582
|
+
"larkBot:unbind": ADMIN_ANY,
|
|
58583
|
+
"larkBot:status": ADMIN_ANY,
|
|
57996
58584
|
"inbox:sendDm": ADMIN_ANY,
|
|
57997
58585
|
"personaDispatch:complete": ADMIN_ANY,
|
|
57998
58586
|
"personaDispatch:list": ADMIN_ANY,
|
|
@@ -58124,21 +58712,21 @@ function computeMethodAccess(args) {
|
|
|
58124
58712
|
}
|
|
58125
58713
|
|
|
58126
58714
|
// src/version.ts
|
|
58127
|
-
var version = "0.2.
|
|
58715
|
+
var version = "0.2.287".length > 0 ? "0.2.287" : "dev";
|
|
58128
58716
|
|
|
58129
58717
|
// src/cli-probe/probe.ts
|
|
58130
|
-
var
|
|
58131
|
-
var
|
|
58718
|
+
var fs55 = __toESM(require("fs"), 1);
|
|
58719
|
+
var path63 = __toESM(require("path"), 1);
|
|
58132
58720
|
var PKG_NAME = "@clawos-dev/clawd";
|
|
58133
58721
|
var BIN_NAME = "clawd";
|
|
58134
58722
|
var MAX_PARENT_HOPS = 5;
|
|
58135
58723
|
function probeGlobalCli(pathEnv) {
|
|
58136
58724
|
if (!pathEnv) return null;
|
|
58137
|
-
for (const dir of pathEnv.split(
|
|
58725
|
+
for (const dir of pathEnv.split(path63.delimiter)) {
|
|
58138
58726
|
if (!dir) continue;
|
|
58139
58727
|
let real;
|
|
58140
58728
|
try {
|
|
58141
|
-
real =
|
|
58729
|
+
real = fs55.realpathSync(path63.join(dir, BIN_NAME));
|
|
58142
58730
|
} catch {
|
|
58143
58731
|
continue;
|
|
58144
58732
|
}
|
|
@@ -58148,15 +58736,15 @@ function probeGlobalCli(pathEnv) {
|
|
|
58148
58736
|
return null;
|
|
58149
58737
|
}
|
|
58150
58738
|
function readOwnPackageVersion(entryPath) {
|
|
58151
|
-
let dir =
|
|
58739
|
+
let dir = path63.dirname(entryPath);
|
|
58152
58740
|
for (let i = 0; i < MAX_PARENT_HOPS; i++) {
|
|
58153
58741
|
try {
|
|
58154
|
-
const raw =
|
|
58742
|
+
const raw = fs55.readFileSync(path63.join(dir, "package.json"), "utf8");
|
|
58155
58743
|
const pkg = JSON.parse(raw);
|
|
58156
58744
|
if (pkg.name !== PKG_NAME) return null;
|
|
58157
58745
|
return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
|
|
58158
58746
|
} catch {
|
|
58159
|
-
const parent =
|
|
58747
|
+
const parent = path63.dirname(dir);
|
|
58160
58748
|
if (parent === dir) return null;
|
|
58161
58749
|
dir = parent;
|
|
58162
58750
|
}
|
|
@@ -58314,7 +58902,7 @@ function buildPersonaHandlers(deps) {
|
|
|
58314
58902
|
}
|
|
58315
58903
|
|
|
58316
58904
|
// src/handlers/attachment.ts
|
|
58317
|
-
var
|
|
58905
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
58318
58906
|
init_protocol();
|
|
58319
58907
|
init_protocol();
|
|
58320
58908
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -58394,12 +58982,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
58394
58982
|
`session ${args.sessionId} scope unresolved`
|
|
58395
58983
|
);
|
|
58396
58984
|
}
|
|
58397
|
-
const cwdAbs =
|
|
58398
|
-
const candidateAbs =
|
|
58985
|
+
const cwdAbs = import_node_path50.default.resolve(sessionFile.cwd);
|
|
58986
|
+
const candidateAbs = import_node_path50.default.isAbsolute(args.relPath) ? import_node_path50.default.resolve(args.relPath) : import_node_path50.default.resolve(cwdAbs, args.relPath);
|
|
58399
58987
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
|
|
58400
58988
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
58401
58989
|
const entry = entries.find((e) => {
|
|
58402
|
-
const storedAbs =
|
|
58990
|
+
const storedAbs = import_node_path50.default.isAbsolute(e.relPath) ? import_node_path50.default.resolve(e.relPath) : import_node_path50.default.resolve(cwdAbs, e.relPath);
|
|
58403
58991
|
return storedAbs === candidateAbs && !e.stale;
|
|
58404
58992
|
});
|
|
58405
58993
|
if (!entry) {
|
|
@@ -58424,7 +59012,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
58424
59012
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
58425
59013
|
const f = deps.sessionStore.read(sessionId);
|
|
58426
59014
|
if (!f) return;
|
|
58427
|
-
assertGuestAttachmentPath(ctx,
|
|
59015
|
+
assertGuestAttachmentPath(ctx, import_node_path50.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
58428
59016
|
}
|
|
58429
59017
|
const groupAdd = async (frame, _client, ctx) => {
|
|
58430
59018
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -58439,8 +59027,8 @@ function buildAttachmentHandlers(deps) {
|
|
|
58439
59027
|
if (!scope) {
|
|
58440
59028
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
|
|
58441
59029
|
}
|
|
58442
|
-
const cwdAbs =
|
|
58443
|
-
const candidateAbs =
|
|
59030
|
+
const cwdAbs = import_node_path50.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
|
|
59031
|
+
const candidateAbs = import_node_path50.default.isAbsolute(args.relPath) ? import_node_path50.default.resolve(args.relPath) : import_node_path50.default.resolve(cwdAbs, args.relPath);
|
|
58444
59032
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
|
|
58445
59033
|
const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
58446
59034
|
const size = 0;
|
|
@@ -58499,19 +59087,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
58499
59087
|
|
|
58500
59088
|
// src/handlers/extension.ts
|
|
58501
59089
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
58502
|
-
var
|
|
59090
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
58503
59091
|
init_protocol();
|
|
58504
59092
|
|
|
58505
59093
|
// src/extension/bundle-zip.ts
|
|
58506
59094
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
58507
|
-
var
|
|
58508
|
-
var
|
|
59095
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
59096
|
+
var import_node_crypto14 = __toESM(require("crypto"), 1);
|
|
58509
59097
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
58510
59098
|
async function bundleExtensionDir(dir) {
|
|
58511
59099
|
const entries = await listFilesSorted(dir);
|
|
58512
59100
|
const zip = new import_jszip2.default();
|
|
58513
59101
|
for (const rel of entries) {
|
|
58514
|
-
const abs =
|
|
59102
|
+
const abs = import_node_path51.default.join(dir, rel);
|
|
58515
59103
|
const content = await import_promises6.default.readFile(abs);
|
|
58516
59104
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
58517
59105
|
}
|
|
@@ -58520,7 +59108,7 @@ async function bundleExtensionDir(dir) {
|
|
|
58520
59108
|
compression: "DEFLATE",
|
|
58521
59109
|
compressionOptions: { level: 6 }
|
|
58522
59110
|
});
|
|
58523
|
-
const sha256 =
|
|
59111
|
+
const sha256 = import_node_crypto14.default.createHash("sha256").update(buffer).digest("hex");
|
|
58524
59112
|
return { buffer, sha256 };
|
|
58525
59113
|
}
|
|
58526
59114
|
var FIXED_DATE = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
|
|
@@ -58532,7 +59120,7 @@ async function listFilesSorted(rootDir) {
|
|
|
58532
59120
|
return out;
|
|
58533
59121
|
}
|
|
58534
59122
|
async function walk(absRoot, relPrefix, out) {
|
|
58535
|
-
const dirAbs =
|
|
59123
|
+
const dirAbs = import_node_path51.default.join(absRoot, relPrefix);
|
|
58536
59124
|
const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
|
|
58537
59125
|
for (const e of entries) {
|
|
58538
59126
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -58586,25 +59174,25 @@ function computePublishCheck(args) {
|
|
|
58586
59174
|
|
|
58587
59175
|
// src/extension/install-flow.ts
|
|
58588
59176
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
58589
|
-
var
|
|
59177
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
58590
59178
|
var import_node_os19 = __toESM(require("os"), 1);
|
|
58591
|
-
var
|
|
59179
|
+
var import_node_crypto15 = __toESM(require("crypto"), 1);
|
|
58592
59180
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
58593
59181
|
|
|
58594
59182
|
// src/extension/paths.ts
|
|
58595
59183
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
58596
|
-
var
|
|
59184
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
58597
59185
|
function clawdHomeRoot(override) {
|
|
58598
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
59186
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path52.default.join(import_node_os18.default.homedir(), ".clawd");
|
|
58599
59187
|
}
|
|
58600
59188
|
function extensionsRoot(override) {
|
|
58601
|
-
return
|
|
59189
|
+
return import_node_path52.default.join(clawdHomeRoot(override), "extensions");
|
|
58602
59190
|
}
|
|
58603
59191
|
function publishedChannelsFile(override) {
|
|
58604
|
-
return
|
|
59192
|
+
return import_node_path52.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
58605
59193
|
}
|
|
58606
59194
|
function bundleCacheRoot(override) {
|
|
58607
|
-
return
|
|
59195
|
+
return import_node_path52.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
58608
59196
|
}
|
|
58609
59197
|
|
|
58610
59198
|
// src/extension/install-flow.ts
|
|
@@ -58617,7 +59205,7 @@ var InstallError = class extends Error {
|
|
|
58617
59205
|
};
|
|
58618
59206
|
async function installFromChannel(args, deps) {
|
|
58619
59207
|
const { channelRef, snapshotHash, bundleZip } = args;
|
|
58620
|
-
const computed =
|
|
59208
|
+
const computed = import_node_crypto15.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
58621
59209
|
if (computed !== snapshotHash) {
|
|
58622
59210
|
throw new InstallError(
|
|
58623
59211
|
"HASH_MISMATCH",
|
|
@@ -58631,7 +59219,7 @@ async function installFromChannel(args, deps) {
|
|
|
58631
59219
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
58632
59220
|
}
|
|
58633
59221
|
for (const name of Object.keys(zip.files)) {
|
|
58634
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
59222
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path53.default.isAbsolute(name)) {
|
|
58635
59223
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
58636
59224
|
}
|
|
58637
59225
|
}
|
|
@@ -58663,7 +59251,7 @@ async function installFromChannel(args, deps) {
|
|
|
58663
59251
|
);
|
|
58664
59252
|
}
|
|
58665
59253
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
58666
|
-
const destDir =
|
|
59254
|
+
const destDir = import_node_path53.default.join(deps.extensionsRoot, localExtId);
|
|
58667
59255
|
let destExists = false;
|
|
58668
59256
|
try {
|
|
58669
59257
|
await import_promises7.default.access(destDir);
|
|
@@ -58677,16 +59265,16 @@ async function installFromChannel(args, deps) {
|
|
|
58677
59265
|
);
|
|
58678
59266
|
}
|
|
58679
59267
|
const stage = await import_promises7.default.mkdtemp(
|
|
58680
|
-
|
|
59268
|
+
import_node_path53.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
58681
59269
|
);
|
|
58682
59270
|
try {
|
|
58683
59271
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
58684
|
-
const dest =
|
|
59272
|
+
const dest = import_node_path53.default.join(stage, name);
|
|
58685
59273
|
if (entry.dir) {
|
|
58686
59274
|
await import_promises7.default.mkdir(dest, { recursive: true });
|
|
58687
59275
|
continue;
|
|
58688
59276
|
}
|
|
58689
|
-
await import_promises7.default.mkdir(
|
|
59277
|
+
await import_promises7.default.mkdir(import_node_path53.default.dirname(dest), { recursive: true });
|
|
58690
59278
|
if (name === "manifest.json") {
|
|
58691
59279
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
58692
59280
|
await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -58707,9 +59295,9 @@ async function installFromChannel(args, deps) {
|
|
|
58707
59295
|
|
|
58708
59296
|
// src/extension/update-flow.ts
|
|
58709
59297
|
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
58710
|
-
var
|
|
59298
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
58711
59299
|
var import_node_os20 = __toESM(require("os"), 1);
|
|
58712
|
-
var
|
|
59300
|
+
var import_node_crypto16 = __toESM(require("crypto"), 1);
|
|
58713
59301
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
58714
59302
|
var UpdateError = class extends Error {
|
|
58715
59303
|
constructor(code, message) {
|
|
@@ -58724,11 +59312,11 @@ async function updateFromChannel(args, deps) {
|
|
|
58724
59312
|
channelRef.extId,
|
|
58725
59313
|
channelRef.ownerPrincipalId
|
|
58726
59314
|
);
|
|
58727
|
-
const liveDir =
|
|
59315
|
+
const liveDir = import_node_path54.default.join(deps.extensionsRoot, localExtId);
|
|
58728
59316
|
const prevDir = `${liveDir}.prev`;
|
|
58729
59317
|
let existingVersion;
|
|
58730
59318
|
try {
|
|
58731
|
-
const raw = await import_promises8.default.readFile(
|
|
59319
|
+
const raw = await import_promises8.default.readFile(import_node_path54.default.join(liveDir, "manifest.json"), "utf8");
|
|
58732
59320
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
58733
59321
|
if (!parsed2.success) {
|
|
58734
59322
|
throw new UpdateError(
|
|
@@ -58747,7 +59335,7 @@ async function updateFromChannel(args, deps) {
|
|
|
58747
59335
|
if (e instanceof UpdateError) throw e;
|
|
58748
59336
|
throw e;
|
|
58749
59337
|
}
|
|
58750
|
-
const computed =
|
|
59338
|
+
const computed = import_node_crypto16.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
58751
59339
|
if (computed !== snapshotHash) {
|
|
58752
59340
|
throw new UpdateError(
|
|
58753
59341
|
"HASH_MISMATCH",
|
|
@@ -58761,7 +59349,7 @@ async function updateFromChannel(args, deps) {
|
|
|
58761
59349
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
58762
59350
|
}
|
|
58763
59351
|
for (const name of Object.keys(zip.files)) {
|
|
58764
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
59352
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path54.default.isAbsolute(name)) {
|
|
58765
59353
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
58766
59354
|
}
|
|
58767
59355
|
}
|
|
@@ -58796,16 +59384,16 @@ async function updateFromChannel(args, deps) {
|
|
|
58796
59384
|
await import_promises8.default.rm(prevDir, { recursive: true, force: true });
|
|
58797
59385
|
await import_promises8.default.rename(liveDir, prevDir);
|
|
58798
59386
|
const stage = await import_promises8.default.mkdtemp(
|
|
58799
|
-
|
|
59387
|
+
import_node_path54.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
58800
59388
|
);
|
|
58801
59389
|
try {
|
|
58802
59390
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
58803
|
-
const dest =
|
|
59391
|
+
const dest = import_node_path54.default.join(stage, name);
|
|
58804
59392
|
if (entry.dir) {
|
|
58805
59393
|
await import_promises8.default.mkdir(dest, { recursive: true });
|
|
58806
59394
|
continue;
|
|
58807
59395
|
}
|
|
58808
|
-
await import_promises8.default.mkdir(
|
|
59396
|
+
await import_promises8.default.mkdir(import_node_path54.default.dirname(dest), { recursive: true });
|
|
58809
59397
|
if (name === "manifest.json") {
|
|
58810
59398
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
58811
59399
|
await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -58872,7 +59460,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
58872
59460
|
);
|
|
58873
59461
|
}
|
|
58874
59462
|
}
|
|
58875
|
-
const manifestPath =
|
|
59463
|
+
const manifestPath = import_node_path55.default.join(root, extId, "manifest.json");
|
|
58876
59464
|
const manifest = await readManifest(root, extId);
|
|
58877
59465
|
const next = { ...manifest, version: newVersion };
|
|
58878
59466
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -58880,7 +59468,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
58880
59468
|
await import_promises9.default.rename(tmp, manifestPath);
|
|
58881
59469
|
}
|
|
58882
59470
|
async function readManifest(root, extId) {
|
|
58883
|
-
const file =
|
|
59471
|
+
const file = import_node_path55.default.join(root, extId, "manifest.json");
|
|
58884
59472
|
let raw;
|
|
58885
59473
|
try {
|
|
58886
59474
|
raw = await import_promises9.default.readFile(file, "utf8");
|
|
@@ -58964,7 +59552,7 @@ function buildExtensionHandlers(deps) {
|
|
|
58964
59552
|
};
|
|
58965
59553
|
async function buildSnapshotMeta(extId) {
|
|
58966
59554
|
const manifest = await readManifest(deps.root, extId);
|
|
58967
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
59555
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path55.default.join(deps.root, extId));
|
|
58968
59556
|
return { manifest, contentHash: sha256, buffer };
|
|
58969
59557
|
}
|
|
58970
59558
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -59139,9 +59727,9 @@ function buildExtensionHandlers(deps) {
|
|
|
59139
59727
|
}
|
|
59140
59728
|
|
|
59141
59729
|
// src/app-builder/project-store.ts
|
|
59142
|
-
var
|
|
59730
|
+
var import_node_fs45 = require("fs");
|
|
59143
59731
|
var import_node_child_process11 = require("child_process");
|
|
59144
|
-
var
|
|
59732
|
+
var import_node_path56 = require("path");
|
|
59145
59733
|
init_protocol();
|
|
59146
59734
|
var PROJECTS_DIR = "projects";
|
|
59147
59735
|
var META_FILE = ".clawd-project.json";
|
|
@@ -59155,19 +59743,19 @@ var ProjectStore = class {
|
|
|
59155
59743
|
root;
|
|
59156
59744
|
/** projects/<name>/.clawd-project.json 路径 */
|
|
59157
59745
|
metaPath(name) {
|
|
59158
|
-
return (0,
|
|
59746
|
+
return (0, import_node_path56.join)(this.projectsRoot(), name, META_FILE);
|
|
59159
59747
|
}
|
|
59160
59748
|
/** projects/<name>/ 目录路径(cwd 用) */
|
|
59161
59749
|
projectDir(name) {
|
|
59162
|
-
return (0,
|
|
59750
|
+
return (0, import_node_path56.join)(this.projectsRoot(), name);
|
|
59163
59751
|
}
|
|
59164
59752
|
projectsRoot() {
|
|
59165
|
-
return (0,
|
|
59753
|
+
return (0, import_node_path56.join)(this.root, PROJECTS_DIR);
|
|
59166
59754
|
}
|
|
59167
59755
|
async list() {
|
|
59168
59756
|
let entries;
|
|
59169
59757
|
try {
|
|
59170
|
-
entries = await
|
|
59758
|
+
entries = await import_node_fs45.promises.readdir(this.projectsRoot());
|
|
59171
59759
|
} catch (err) {
|
|
59172
59760
|
if (err.code === "ENOENT") return [];
|
|
59173
59761
|
throw err;
|
|
@@ -59175,7 +59763,7 @@ var ProjectStore = class {
|
|
|
59175
59763
|
const out = [];
|
|
59176
59764
|
for (const name of entries) {
|
|
59177
59765
|
try {
|
|
59178
|
-
const raw = await
|
|
59766
|
+
const raw = await import_node_fs45.promises.readFile(this.metaPath(name), "utf8");
|
|
59179
59767
|
const json = JSON.parse(raw);
|
|
59180
59768
|
let migrated = false;
|
|
59181
59769
|
if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
|
|
@@ -59186,7 +59774,7 @@ var ProjectStore = class {
|
|
|
59186
59774
|
if (parsed.success) {
|
|
59187
59775
|
out.push(parsed.data);
|
|
59188
59776
|
if (migrated) {
|
|
59189
|
-
void
|
|
59777
|
+
void import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
|
|
59190
59778
|
});
|
|
59191
59779
|
}
|
|
59192
59780
|
}
|
|
@@ -59230,8 +59818,8 @@ var ProjectStore = class {
|
|
|
59230
59818
|
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
59231
59819
|
}
|
|
59232
59820
|
const dir = this.projectDir(name);
|
|
59233
|
-
await
|
|
59234
|
-
await
|
|
59821
|
+
await import_node_fs45.promises.mkdir(dir, { recursive: true });
|
|
59822
|
+
await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
59235
59823
|
return meta;
|
|
59236
59824
|
}
|
|
59237
59825
|
/**
|
|
@@ -59274,7 +59862,7 @@ var ProjectStore = class {
|
|
|
59274
59862
|
}
|
|
59275
59863
|
async delete(name) {
|
|
59276
59864
|
const dir = this.projectDir(name);
|
|
59277
|
-
await
|
|
59865
|
+
await import_node_fs45.promises.rm(dir, { recursive: true, force: true });
|
|
59278
59866
|
}
|
|
59279
59867
|
async updatePort(name, newPort) {
|
|
59280
59868
|
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
@@ -59290,7 +59878,7 @@ var ProjectStore = class {
|
|
|
59290
59878
|
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
59291
59879
|
}
|
|
59292
59880
|
const updated = { ...target, port: newPort };
|
|
59293
|
-
await
|
|
59881
|
+
await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
59294
59882
|
return updated;
|
|
59295
59883
|
}
|
|
59296
59884
|
/**
|
|
@@ -59307,7 +59895,7 @@ var ProjectStore = class {
|
|
|
59307
59895
|
if (!validated.success) {
|
|
59308
59896
|
throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
|
|
59309
59897
|
}
|
|
59310
|
-
await
|
|
59898
|
+
await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
59311
59899
|
return validated.data;
|
|
59312
59900
|
}
|
|
59313
59901
|
/**
|
|
@@ -59328,7 +59916,7 @@ var ProjectStore = class {
|
|
|
59328
59916
|
if (!validated.success) {
|
|
59329
59917
|
throw new Error(`invalid publishJob: ${validated.error.message}`);
|
|
59330
59918
|
}
|
|
59331
|
-
await
|
|
59919
|
+
await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
59332
59920
|
return validated.data;
|
|
59333
59921
|
}
|
|
59334
59922
|
/** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
|
|
@@ -59343,7 +59931,7 @@ var ProjectStore = class {
|
|
|
59343
59931
|
if (!validated.success) {
|
|
59344
59932
|
throw new Error(`failed to clear publishJob: ${validated.error.message}`);
|
|
59345
59933
|
}
|
|
59346
|
-
await
|
|
59934
|
+
await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
59347
59935
|
return validated.data;
|
|
59348
59936
|
}
|
|
59349
59937
|
};
|
|
@@ -59413,7 +60001,7 @@ function listPidsOnPort(port) {
|
|
|
59413
60001
|
}
|
|
59414
60002
|
|
|
59415
60003
|
// src/app-builder/publish-registry.ts
|
|
59416
|
-
var
|
|
60004
|
+
var import_node_crypto17 = require("crypto");
|
|
59417
60005
|
var PublishJobRegistry = class {
|
|
59418
60006
|
jobs = /* @__PURE__ */ new Map();
|
|
59419
60007
|
has(name) {
|
|
@@ -59430,7 +60018,7 @@ var PublishJobRegistry = class {
|
|
|
59430
60018
|
if (this.jobs.has(args.name)) {
|
|
59431
60019
|
throw new Error(`already publishing: ${args.name}`);
|
|
59432
60020
|
}
|
|
59433
|
-
const jobId = args.jobId ?? `job-${(0,
|
|
60021
|
+
const jobId = args.jobId ?? `job-${(0, import_node_crypto17.randomUUID)()}`;
|
|
59434
60022
|
this.jobs.set(args.name, {
|
|
59435
60023
|
jobId,
|
|
59436
60024
|
name: args.name,
|
|
@@ -59464,8 +60052,8 @@ var PublishJobRegistry = class {
|
|
|
59464
60052
|
|
|
59465
60053
|
// src/app-builder/publish-job-runner.ts
|
|
59466
60054
|
var import_node_child_process13 = require("child_process");
|
|
59467
|
-
var
|
|
59468
|
-
var
|
|
60055
|
+
var import_node_fs46 = require("fs");
|
|
60056
|
+
var import_node_path57 = require("path");
|
|
59469
60057
|
|
|
59470
60058
|
// src/app-builder/publish-stage-parser.ts
|
|
59471
60059
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -59497,10 +60085,10 @@ async function startPublishJob(deps, args) {
|
|
|
59497
60085
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
59498
60086
|
}
|
|
59499
60087
|
const projDir = projectDir(args.name);
|
|
59500
|
-
const logPath = (0,
|
|
60088
|
+
const logPath = (0, import_node_path57.join)(projDir, ".publish.log");
|
|
59501
60089
|
let logStream = null;
|
|
59502
60090
|
try {
|
|
59503
|
-
logStream = (0,
|
|
60091
|
+
logStream = (0, import_node_fs46.createWriteStream)(logPath, { flags: "w" });
|
|
59504
60092
|
} catch {
|
|
59505
60093
|
logStream = null;
|
|
59506
60094
|
}
|
|
@@ -59757,8 +60345,8 @@ async function recoverInterruptedJobs(deps) {
|
|
|
59757
60345
|
|
|
59758
60346
|
// src/handlers/app-builder.ts
|
|
59759
60347
|
init_protocol();
|
|
59760
|
-
var
|
|
59761
|
-
var
|
|
60348
|
+
var import_node_path58 = require("path");
|
|
60349
|
+
var import_node_fs47 = require("fs");
|
|
59762
60350
|
var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
|
|
59763
60351
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
59764
60352
|
async function recoverInterruptedPublishJobs(store, logger) {
|
|
@@ -59839,7 +60427,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
59839
60427
|
async function listAllUsersProjects() {
|
|
59840
60428
|
if (!deps.usersRoot || !deps.getStore) return [];
|
|
59841
60429
|
const getStore = deps.getStore;
|
|
59842
|
-
const userIds = await
|
|
60430
|
+
const userIds = await import_node_fs47.promises.readdir(deps.usersRoot).catch(() => []);
|
|
59843
60431
|
const perUser = await Promise.all(
|
|
59844
60432
|
userIds.map((uid) => getStore(uid).list().catch(() => []))
|
|
59845
60433
|
);
|
|
@@ -59908,8 +60496,8 @@ function buildAppBuilderHandlers(deps) {
|
|
|
59908
60496
|
const project = await userStore.create(f.name, reservedPorts);
|
|
59909
60497
|
try {
|
|
59910
60498
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
|
|
59911
|
-
const templateSrcDir = (0,
|
|
59912
|
-
const scaffoldScript = (0,
|
|
60499
|
+
const templateSrcDir = (0, import_node_path58.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
|
|
60500
|
+
const scaffoldScript = (0, import_node_path58.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
|
|
59913
60501
|
const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
|
|
59914
60502
|
deps.logger?.info("app-builder.scaffold.done", {
|
|
59915
60503
|
name: project.name,
|
|
@@ -60113,7 +60701,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
60113
60701
|
await userStore.clearPublishJob(args.name);
|
|
60114
60702
|
}
|
|
60115
60703
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
|
|
60116
|
-
const scriptPath = (0,
|
|
60704
|
+
const scriptPath = (0, import_node_path58.join)(deps.deployKitRoot, "scripts", "publish.sh");
|
|
60117
60705
|
deps.logger?.info("app-builder.publish.start", {
|
|
60118
60706
|
name: args.name,
|
|
60119
60707
|
sessionId: boundSession.sessionId,
|
|
@@ -60289,7 +60877,7 @@ function buildVisitorHandlers(deps) {
|
|
|
60289
60877
|
|
|
60290
60878
|
// src/extension/registry.ts
|
|
60291
60879
|
var import_promises10 = __toESM(require("fs/promises"), 1);
|
|
60292
|
-
var
|
|
60880
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
60293
60881
|
async function loadAll(root) {
|
|
60294
60882
|
let entries;
|
|
60295
60883
|
try {
|
|
@@ -60302,13 +60890,13 @@ async function loadAll(root) {
|
|
|
60302
60890
|
for (const ent of entries) {
|
|
60303
60891
|
if (!ent.isDirectory()) continue;
|
|
60304
60892
|
if (ent.name.startsWith(".")) continue;
|
|
60305
|
-
records.push(await loadOne(
|
|
60893
|
+
records.push(await loadOne(import_node_path59.default.join(root, ent.name), ent.name));
|
|
60306
60894
|
}
|
|
60307
60895
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
60308
60896
|
return records;
|
|
60309
60897
|
}
|
|
60310
60898
|
async function loadOne(dir, dirName) {
|
|
60311
|
-
const manifestPath =
|
|
60899
|
+
const manifestPath = import_node_path59.default.join(dir, "manifest.json");
|
|
60312
60900
|
let raw;
|
|
60313
60901
|
try {
|
|
60314
60902
|
raw = await import_promises10.default.readFile(manifestPath, "utf8");
|
|
@@ -60353,7 +60941,7 @@ async function loadOne(dir, dirName) {
|
|
|
60353
60941
|
|
|
60354
60942
|
// src/extension/uninstall.ts
|
|
60355
60943
|
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
60356
|
-
var
|
|
60944
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
60357
60945
|
var UninstallError = class extends Error {
|
|
60358
60946
|
constructor(code, message) {
|
|
60359
60947
|
super(message);
|
|
@@ -60362,7 +60950,7 @@ var UninstallError = class extends Error {
|
|
|
60362
60950
|
code;
|
|
60363
60951
|
};
|
|
60364
60952
|
async function uninstall(deps) {
|
|
60365
|
-
const dir =
|
|
60953
|
+
const dir = import_node_path60.default.join(deps.root, deps.extId);
|
|
60366
60954
|
try {
|
|
60367
60955
|
await import_promises11.default.access(dir);
|
|
60368
60956
|
} catch {
|
|
@@ -60373,7 +60961,7 @@ async function uninstall(deps) {
|
|
|
60373
60961
|
}
|
|
60374
60962
|
|
|
60375
60963
|
// src/handlers/index.ts
|
|
60376
|
-
var
|
|
60964
|
+
var import_node_crypto18 = require("crypto");
|
|
60377
60965
|
|
|
60378
60966
|
// src/handlers/peer-exec.ts
|
|
60379
60967
|
init_protocol();
|
|
@@ -60528,7 +61116,7 @@ function buildMethodHandlers(deps) {
|
|
|
60528
61116
|
const c = deps.contactStore.get(deviceId);
|
|
60529
61117
|
return c ? { deviceId: c.deviceId, remoteUrl: c.remoteUrl, connectToken: c.connectToken } : null;
|
|
60530
61118
|
},
|
|
60531
|
-
genId: () => (0,
|
|
61119
|
+
genId: () => (0, import_node_crypto18.randomUUID)(),
|
|
60532
61120
|
now: () => Date.now(),
|
|
60533
61121
|
forwardInboxPostToPeer,
|
|
60534
61122
|
logger: deps.logger
|
|
@@ -60892,7 +61480,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
|
|
|
60892
61480
|
|
|
60893
61481
|
// src/extension/runtime.ts
|
|
60894
61482
|
var import_node_child_process16 = require("child_process");
|
|
60895
|
-
var
|
|
61483
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
60896
61484
|
var import_promises12 = require("timers/promises");
|
|
60897
61485
|
|
|
60898
61486
|
// src/extension/port-allocator.ts
|
|
@@ -60993,7 +61581,7 @@ var Runtime = class {
|
|
|
60993
61581
|
/\$CLAWOS_EXT_PORT/g,
|
|
60994
61582
|
String(port)
|
|
60995
61583
|
);
|
|
60996
|
-
const dir =
|
|
61584
|
+
const dir = import_node_path61.default.join(this.root, extId);
|
|
60997
61585
|
const env = {
|
|
60998
61586
|
...process.env,
|
|
60999
61587
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -61105,7 +61693,7 @@ ${handle.stderrTail}`
|
|
|
61105
61693
|
|
|
61106
61694
|
// src/extension/published-channels.ts
|
|
61107
61695
|
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
61108
|
-
var
|
|
61696
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
61109
61697
|
init_zod();
|
|
61110
61698
|
var PublishedChannelsError = class extends Error {
|
|
61111
61699
|
constructor(code, message) {
|
|
@@ -61204,7 +61792,7 @@ var PublishedChannelStore = class {
|
|
|
61204
61792
|
)
|
|
61205
61793
|
};
|
|
61206
61794
|
const tmp = `${this.filePath}.tmp`;
|
|
61207
|
-
await import_promises13.default.mkdir(
|
|
61795
|
+
await import_promises13.default.mkdir(import_node_path62.default.dirname(this.filePath), { recursive: true });
|
|
61208
61796
|
await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
61209
61797
|
await import_promises13.default.rename(tmp, this.filePath);
|
|
61210
61798
|
}
|
|
@@ -61212,7 +61800,7 @@ var PublishedChannelStore = class {
|
|
|
61212
61800
|
|
|
61213
61801
|
// src/extension/bundle-cache.ts
|
|
61214
61802
|
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
61215
|
-
var
|
|
61803
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
61216
61804
|
var BundleCache = class {
|
|
61217
61805
|
constructor(rootDir) {
|
|
61218
61806
|
this.rootDir = rootDir;
|
|
@@ -61221,14 +61809,14 @@ var BundleCache = class {
|
|
|
61221
61809
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
61222
61810
|
async write(snapshotHash, buffer) {
|
|
61223
61811
|
await import_promises14.default.mkdir(this.rootDir, { recursive: true });
|
|
61224
|
-
const file =
|
|
61812
|
+
const file = import_node_path63.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
61225
61813
|
const tmp = `${file}.tmp`;
|
|
61226
61814
|
await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
|
|
61227
61815
|
await import_promises14.default.rename(tmp, file);
|
|
61228
61816
|
}
|
|
61229
61817
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
61230
61818
|
async read(snapshotHash) {
|
|
61231
|
-
const file =
|
|
61819
|
+
const file = import_node_path63.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
61232
61820
|
try {
|
|
61233
61821
|
return await import_promises14.default.readFile(file);
|
|
61234
61822
|
} catch (e) {
|
|
@@ -61238,7 +61826,7 @@ var BundleCache = class {
|
|
|
61238
61826
|
}
|
|
61239
61827
|
/** Idempotent — missing file is not an error. */
|
|
61240
61828
|
async delete(snapshotHash) {
|
|
61241
|
-
const file =
|
|
61829
|
+
const file = import_node_path63.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
61242
61830
|
await import_promises14.default.rm(file, { force: true });
|
|
61243
61831
|
}
|
|
61244
61832
|
};
|
|
@@ -61261,24 +61849,24 @@ async function startDaemon(config) {
|
|
|
61261
61849
|
sampling: logShippingCfg.sampling,
|
|
61262
61850
|
homeDir: import_node_os22.default.homedir()
|
|
61263
61851
|
});
|
|
61264
|
-
const logDir =
|
|
61265
|
-
|
|
61852
|
+
const logDir = import_node_path64.default.join(config.dataDir, "log");
|
|
61853
|
+
import_node_fs48.default.mkdirSync(logDir, { recursive: true });
|
|
61266
61854
|
const logger = createLogger({
|
|
61267
61855
|
level: config.logLevel,
|
|
61268
|
-
file:
|
|
61856
|
+
file: import_node_path64.default.join(logDir, "clawd.log"),
|
|
61269
61857
|
logClient
|
|
61270
61858
|
});
|
|
61271
61859
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
61272
61860
|
const screenIdleProbeLogger = createFileOnlyLogger({
|
|
61273
|
-
file:
|
|
61861
|
+
file: import_node_path64.default.join(logDir, "screen-idle-probe.log"),
|
|
61274
61862
|
level: "debug"
|
|
61275
61863
|
});
|
|
61276
61864
|
logger.info("screen-idle probe logger enabled", {
|
|
61277
|
-
file:
|
|
61865
|
+
file: import_node_path64.default.join(logDir, "screen-idle-probe.log")
|
|
61278
61866
|
});
|
|
61279
61867
|
const CAP_TARGETS = [
|
|
61280
|
-
|
|
61281
|
-
|
|
61868
|
+
import_node_path64.default.join(logDir, "clawd.log"),
|
|
61869
|
+
import_node_path64.default.join(logDir, "screen-idle-probe.log")
|
|
61282
61870
|
];
|
|
61283
61871
|
const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
|
|
61284
61872
|
const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
|
|
@@ -61374,8 +61962,8 @@ async function startDaemon(config) {
|
|
|
61374
61962
|
const agents = new AgentsScanner();
|
|
61375
61963
|
const history = new ClaudeHistoryReader();
|
|
61376
61964
|
let transport = null;
|
|
61377
|
-
const personaStore = new PersonaStore(
|
|
61378
|
-
const usersRoot =
|
|
61965
|
+
const personaStore = new PersonaStore(import_node_path64.default.join(config.dataDir, "personas"));
|
|
61966
|
+
const usersRoot = import_node_path64.default.join(config.dataDir, "users");
|
|
61379
61967
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
61380
61968
|
if (defaultsRoot) {
|
|
61381
61969
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -61396,7 +61984,7 @@ async function startDaemon(config) {
|
|
|
61396
61984
|
retirePersonaBuilder({ store: personaStore, logger });
|
|
61397
61985
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
61398
61986
|
const dispatchStore = createDispatchStore({
|
|
61399
|
-
filePath:
|
|
61987
|
+
filePath: import_node_path64.default.join(config.dataDir, "dispatch.json"),
|
|
61400
61988
|
now: () => Date.now(),
|
|
61401
61989
|
onFlushError: (err) => logger.error("dispatch store flush failed", {
|
|
61402
61990
|
reason: err instanceof Error ? err.message : String(err)
|
|
@@ -61411,18 +61999,18 @@ async function startDaemon(config) {
|
|
|
61411
61999
|
now: () => Date.now(),
|
|
61412
62000
|
onCompleted: (sid) => deliverPendingRef?.(sid)
|
|
61413
62001
|
});
|
|
61414
|
-
const here = typeof __dirname === "string" ? __dirname :
|
|
62002
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path64.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
|
|
61415
62003
|
const mcpConfigs = [];
|
|
61416
62004
|
const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
|
|
61417
62005
|
const dispatchServerCandidates = [
|
|
61418
|
-
|
|
62006
|
+
import_node_path64.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
61419
62007
|
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
61420
|
-
|
|
62008
|
+
import_node_path64.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
61421
62009
|
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
61422
62010
|
];
|
|
61423
|
-
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) =>
|
|
62011
|
+
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61424
62012
|
if (dispatchServerScriptPath) {
|
|
61425
|
-
const dispatchLogPath =
|
|
62013
|
+
const dispatchLogPath = import_node_path64.default.join(logDir, "dispatch-mcp-server.log");
|
|
61426
62014
|
const dispatchCfgPath = writeDispatchMcpConfig({
|
|
61427
62015
|
dataDir: config.dataDir,
|
|
61428
62016
|
serverScriptPath: dispatchServerScriptPath,
|
|
@@ -61442,12 +62030,12 @@ async function startDaemon(config) {
|
|
|
61442
62030
|
});
|
|
61443
62031
|
}
|
|
61444
62032
|
const ticketServerCandidates = [
|
|
61445
|
-
|
|
61446
|
-
|
|
62033
|
+
import_node_path64.default.join(here, "ticket", "mcp-server.cjs"),
|
|
62034
|
+
import_node_path64.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
61447
62035
|
];
|
|
61448
|
-
const ticketServerScriptPath = ticketServerCandidates.find((p2) =>
|
|
62036
|
+
const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61449
62037
|
if (ticketServerScriptPath) {
|
|
61450
|
-
const ticketLogPath =
|
|
62038
|
+
const ticketLogPath = import_node_path64.default.join(logDir, "ticket-mcp-server.log");
|
|
61451
62039
|
const ticketCfgPath = writeTicketMcpConfig({
|
|
61452
62040
|
dataDir: config.dataDir,
|
|
61453
62041
|
serverScriptPath: ticketServerScriptPath,
|
|
@@ -61469,12 +62057,12 @@ async function startDaemon(config) {
|
|
|
61469
62057
|
});
|
|
61470
62058
|
}
|
|
61471
62059
|
const shiftServerCandidates = [
|
|
61472
|
-
|
|
61473
|
-
|
|
62060
|
+
import_node_path64.default.join(here, "shift", "mcp-server.cjs"),
|
|
62061
|
+
import_node_path64.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
|
|
61474
62062
|
];
|
|
61475
|
-
const shiftServerScriptPath = shiftServerCandidates.find((p2) =>
|
|
62063
|
+
const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61476
62064
|
if (shiftServerScriptPath) {
|
|
61477
|
-
const shiftLogPath =
|
|
62065
|
+
const shiftLogPath = import_node_path64.default.join(logDir, "shift-mcp-server.log");
|
|
61478
62066
|
const shiftCfgPath = await writeShiftMcpConfig({
|
|
61479
62067
|
dataDir: config.dataDir,
|
|
61480
62068
|
serverScriptPath: shiftServerScriptPath,
|
|
@@ -61495,12 +62083,12 @@ async function startDaemon(config) {
|
|
|
61495
62083
|
);
|
|
61496
62084
|
}
|
|
61497
62085
|
const inboxServerCandidates = [
|
|
61498
|
-
|
|
61499
|
-
|
|
62086
|
+
import_node_path64.default.join(here, "inbox", "mcp-server.cjs"),
|
|
62087
|
+
import_node_path64.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
|
|
61500
62088
|
];
|
|
61501
|
-
const inboxServerScriptPath = inboxServerCandidates.find((p2) =>
|
|
62089
|
+
const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61502
62090
|
if (inboxServerScriptPath) {
|
|
61503
|
-
const inboxLogPath =
|
|
62091
|
+
const inboxLogPath = import_node_path64.default.join(logDir, "inbox-mcp-server.log");
|
|
61504
62092
|
const inboxCfgPath = await writeInboxMcpConfig({
|
|
61505
62093
|
dataDir: config.dataDir,
|
|
61506
62094
|
serverScriptPath: inboxServerScriptPath,
|
|
@@ -61521,10 +62109,10 @@ async function startDaemon(config) {
|
|
|
61521
62109
|
);
|
|
61522
62110
|
}
|
|
61523
62111
|
const peerOpsServerCandidates = [
|
|
61524
|
-
|
|
61525
|
-
|
|
62112
|
+
import_node_path64.default.join(here, "peer-ops", "mcp-server.cjs"),
|
|
62113
|
+
import_node_path64.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
|
|
61526
62114
|
];
|
|
61527
|
-
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) =>
|
|
62115
|
+
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61528
62116
|
if (peerOpsServerScriptPath) {
|
|
61529
62117
|
const peerOpsCfgPath = writePeerOpsMcpConfig({
|
|
61530
62118
|
dataDir: config.dataDir,
|
|
@@ -61544,12 +62132,12 @@ async function startDaemon(config) {
|
|
|
61544
62132
|
);
|
|
61545
62133
|
}
|
|
61546
62134
|
const rpcToolServerCandidates = [
|
|
61547
|
-
|
|
61548
|
-
|
|
62135
|
+
import_node_path64.default.join(here, "rpc-tool", "mcp-server.cjs"),
|
|
62136
|
+
import_node_path64.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
|
|
61549
62137
|
];
|
|
61550
|
-
const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) =>
|
|
62138
|
+
const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61551
62139
|
if (rpcToolServerScriptPath) {
|
|
61552
|
-
const rpcToolLogPath =
|
|
62140
|
+
const rpcToolLogPath = import_node_path64.default.join(logDir, "rpc-tool-mcp-server.log");
|
|
61553
62141
|
const rpcToolCfgPath = writeRpcToolMcpConfig({
|
|
61554
62142
|
dataDir: config.dataDir,
|
|
61555
62143
|
serverScriptPath: rpcToolServerScriptPath,
|
|
@@ -61570,7 +62158,7 @@ async function startDaemon(config) {
|
|
|
61570
62158
|
);
|
|
61571
62159
|
}
|
|
61572
62160
|
const shiftStore = createShiftStore({
|
|
61573
|
-
filePath:
|
|
62161
|
+
filePath: import_node_path64.default.join(config.dataDir, "shift.json"),
|
|
61574
62162
|
ownerIdProvider: () => ownerPrincipalId,
|
|
61575
62163
|
now: () => Date.now()
|
|
61576
62164
|
});
|
|
@@ -61592,7 +62180,7 @@ async function startDaemon(config) {
|
|
|
61592
62180
|
getAdapter,
|
|
61593
62181
|
historyReader: history,
|
|
61594
62182
|
dataDir: config.dataDir,
|
|
61595
|
-
personaRoot:
|
|
62183
|
+
personaRoot: import_node_path64.default.join(config.dataDir, "personas"),
|
|
61596
62184
|
// dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
|
|
61597
62185
|
// personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
|
|
61598
62186
|
getPersonaTool: (personaId2) => personaRegistry.get(personaId2)?.tool,
|
|
@@ -61643,10 +62231,10 @@ async function startDaemon(config) {
|
|
|
61643
62231
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
61644
62232
|
attachmentGroup: {
|
|
61645
62233
|
onFileEdit: (input) => {
|
|
61646
|
-
const absPath =
|
|
62234
|
+
const absPath = import_node_path64.default.isAbsolute(input.relPath) ? input.relPath : import_node_path64.default.join(input.cwd, input.relPath);
|
|
61647
62235
|
let size = 0;
|
|
61648
62236
|
try {
|
|
61649
|
-
size =
|
|
62237
|
+
size = import_node_fs48.default.statSync(absPath).size;
|
|
61650
62238
|
} catch (err) {
|
|
61651
62239
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
61652
62240
|
sessionId: input.sessionId,
|
|
@@ -61887,11 +62475,11 @@ async function startDaemon(config) {
|
|
|
61887
62475
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
61888
62476
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
61889
62477
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
61890
|
-
personaRoot:
|
|
62478
|
+
personaRoot: import_node_path64.default.join(config.dataDir, "personas"),
|
|
61891
62479
|
usersRoot
|
|
61892
62480
|
},
|
|
61893
62481
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
61894
|
-
personaRoot:
|
|
62482
|
+
personaRoot: import_node_path64.default.join(config.dataDir, "personas"),
|
|
61895
62483
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
61896
62484
|
usersRoot,
|
|
61897
62485
|
// v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
|
|
@@ -62017,11 +62605,11 @@ async function startDaemon(config) {
|
|
|
62017
62605
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
62018
62606
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
62019
62607
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
62020
|
-
appBuilderPersonaRoot:
|
|
62608
|
+
appBuilderPersonaRoot: import_node_path64.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
62021
62609
|
// 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
|
|
62022
|
-
deployKitRoot:
|
|
62610
|
+
deployKitRoot: import_node_path64.default.join(config.dataDir, "deploy-kit"),
|
|
62023
62611
|
// scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
|
|
62024
|
-
resolvePersonaRoot: (personaId2) =>
|
|
62612
|
+
resolvePersonaRoot: (personaId2) => import_node_path64.default.join(config.dataDir, "personas", personaId2),
|
|
62025
62613
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
62026
62614
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
62027
62615
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -62124,6 +62712,41 @@ async function startDaemon(config) {
|
|
|
62124
62712
|
});
|
|
62125
62713
|
shiftScheduler.start();
|
|
62126
62714
|
logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
|
|
62715
|
+
const larkBotStore = createLarkBotBindingStore(import_node_path64.default.join(config.dataDir, "personas"));
|
|
62716
|
+
const larkBotCloud = createLarkBotCloudClient({
|
|
62717
|
+
api: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
62718
|
+
apiKey: resolveClawdTicketsApiKey(),
|
|
62719
|
+
deviceId: authFile.deviceId,
|
|
62720
|
+
displayName: ownerDisplayName
|
|
62721
|
+
});
|
|
62722
|
+
const larkChatRouter = createLarkChatRouter({
|
|
62723
|
+
manager,
|
|
62724
|
+
cloud: larkBotCloud,
|
|
62725
|
+
store: larkBotStore,
|
|
62726
|
+
logger: {
|
|
62727
|
+
warn: (msg) => logger.warn(msg),
|
|
62728
|
+
info: (msg) => logger.info(msg)
|
|
62729
|
+
}
|
|
62730
|
+
});
|
|
62731
|
+
const larkEventDedupe = createLarkEventDedupe();
|
|
62732
|
+
const larkBotEventEndpoint = createLarkBotEventEndpoint({
|
|
62733
|
+
getPublicKey: () => serverKeyStore.read(),
|
|
62734
|
+
route: larkChatRouter.handleEnvelope,
|
|
62735
|
+
dedupe: larkEventDedupe,
|
|
62736
|
+
logger: { warn: (msg) => logger.warn(msg) }
|
|
62737
|
+
});
|
|
62738
|
+
const larkBotDeps = {
|
|
62739
|
+
cloud: larkBotCloud,
|
|
62740
|
+
store: larkBotStore,
|
|
62741
|
+
broadcast: (frame) => wsServer?.broadcastToOwners(frame),
|
|
62742
|
+
getTunnelUrl: () => currentTunnelUrl,
|
|
62743
|
+
getOwnerId: () => ownerIdentityStore.read()?.identity.ownerId ?? null,
|
|
62744
|
+
getPersonaName: (personaId2) => personaRegistry.get(personaId2)?.label ?? null,
|
|
62745
|
+
listLarkSessions: larkChatRouter.listLarkSessions,
|
|
62746
|
+
listBoundPersonaIds: () => personaStore.list().filter((pid) => larkBotStore.read(pid) != null),
|
|
62747
|
+
logger: { warn: (msg) => logger.warn(msg) }
|
|
62748
|
+
};
|
|
62749
|
+
Object.assign(handlers, buildLarkBotHandlers(larkBotDeps));
|
|
62127
62750
|
const authResolver = new AuthContextResolver({
|
|
62128
62751
|
ownerToken: resolvedAuthToken
|
|
62129
62752
|
});
|
|
@@ -62175,6 +62798,8 @@ async function startDaemon(config) {
|
|
|
62175
62798
|
// persona web 分享:访客换 token(POST /share/exchange)+ guest SPA serve(GET /s)
|
|
62176
62799
|
visitorExchange: exchangeVisitorToken,
|
|
62177
62800
|
...shareUiAssetLoader ? { shareUiAssetLoader } : {},
|
|
62801
|
+
// LarkBotConnector 事件入口(云端签名即凭证,无 Bearer)
|
|
62802
|
+
larkBotEvent: larkBotEventEndpoint,
|
|
62178
62803
|
// /files HMAC verify 用 auth.json token(与 attachment.signUrl 同源)。
|
|
62179
62804
|
getSignSecret: () => authFile.token,
|
|
62180
62805
|
// chatinput 附件上传(POST /attachments/upload,spec §6.1)。upload pipeline
|
|
@@ -62359,12 +62984,27 @@ async function startDaemon(config) {
|
|
|
62359
62984
|
stateMgr.write(stateSnapshot);
|
|
62360
62985
|
currentTunnelUrl = r.url;
|
|
62361
62986
|
wss.broadcastAll({ type: "tunnel:ready", url: r.url, subdomain: r.subdomain });
|
|
62987
|
+
void refreshTunnelUrlOnStartup(larkBotDeps);
|
|
62988
|
+
void (async () => {
|
|
62989
|
+
if (larkBotDeps.listBoundPersonaIds().length === 0) return;
|
|
62990
|
+
try {
|
|
62991
|
+
const items = await larkBotCloud.claimEvents();
|
|
62992
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
62993
|
+
for (const it of items) {
|
|
62994
|
+
larkEventDedupe.add(it.eventId);
|
|
62995
|
+
larkChatRouter.handleEnvelope({ ...it, iat: nowSec, exp: nowSec + 300 });
|
|
62996
|
+
}
|
|
62997
|
+
if (items.length > 0) logger.info("larkBot pending events claimed", { count: items.length });
|
|
62998
|
+
} catch (err) {
|
|
62999
|
+
logger.warn("larkBot pending events claim failed", { err: err.message });
|
|
63000
|
+
}
|
|
63001
|
+
})();
|
|
62362
63002
|
const connectUrl = resolvedAuthToken ? `${r.url}#token=${resolvedAuthToken}` : r.url;
|
|
62363
63003
|
const lines = [
|
|
62364
63004
|
`Tunnel: ${r.url}`,
|
|
62365
63005
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
62366
|
-
`Frpc config: ${
|
|
62367
|
-
`Frpc log: ${
|
|
63006
|
+
`Frpc config: ${import_node_path64.default.join(config.dataDir, "frpc.toml")}`,
|
|
63007
|
+
`Frpc log: ${import_node_path64.default.join(logDir, "frpc.log")}`
|
|
62368
63008
|
];
|
|
62369
63009
|
const width = Math.max(...lines.map((l) => l.length));
|
|
62370
63010
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -62377,8 +63017,8 @@ ${bar}
|
|
|
62377
63017
|
|
|
62378
63018
|
`);
|
|
62379
63019
|
try {
|
|
62380
|
-
const connectPath =
|
|
62381
|
-
|
|
63020
|
+
const connectPath = import_node_path64.default.join(config.dataDir, "connect.txt");
|
|
63021
|
+
import_node_fs48.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
62382
63022
|
} catch {
|
|
62383
63023
|
}
|
|
62384
63024
|
} catch (err) {
|
|
@@ -62450,9 +63090,9 @@ ${bar}
|
|
|
62450
63090
|
};
|
|
62451
63091
|
}
|
|
62452
63092
|
function migrateDropPersonsDir(dataDir) {
|
|
62453
|
-
const dir =
|
|
63093
|
+
const dir = import_node_path64.default.join(dataDir, "persons");
|
|
62454
63094
|
try {
|
|
62455
|
-
|
|
63095
|
+
import_node_fs48.default.rmSync(dir, { recursive: true, force: true });
|
|
62456
63096
|
} catch {
|
|
62457
63097
|
}
|
|
62458
63098
|
}
|