@clawos-dev/clawd 0.2.284 → 0.2.286
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 +1442 -549
- package/dist/dispatch/mcp-server.cjs +61 -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-BRh71VEW.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,46 @@ var init_shift_internal = __esm({
|
|
|
6584
6584
|
}
|
|
6585
6585
|
});
|
|
6586
6586
|
|
|
6587
|
+
// ../protocol/src/lark-bot-schemas.ts
|
|
6588
|
+
var LarkBotProvisionArgs, LarkBotProvisionCancelArgs, 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
|
+
LarkBotProvisionArgs = external_exports.object({ personaId: external_exports.string().min(1) });
|
|
6594
|
+
LarkBotProvisionCancelArgs = LarkBotProvisionArgs;
|
|
6595
|
+
LarkBotUnbindArgs = LarkBotProvisionArgs;
|
|
6596
|
+
LarkBotStatusArgs = LarkBotProvisionArgs;
|
|
6597
|
+
LarkBotBindManualArgs = external_exports.object({
|
|
6598
|
+
personaId: external_exports.string().min(1),
|
|
6599
|
+
appId: external_exports.string().min(1),
|
|
6600
|
+
appSecret: external_exports.string().min(1),
|
|
6601
|
+
botName: external_exports.string().min(1).optional()
|
|
6602
|
+
});
|
|
6603
|
+
LarkBotGroupSchema = external_exports.object({
|
|
6604
|
+
chatId: external_exports.string().min(1),
|
|
6605
|
+
chatName: external_exports.string().optional(),
|
|
6606
|
+
/** epoch ms,该群 session 最近一次活跃时间 */
|
|
6607
|
+
lastActiveAt: external_exports.number().int().optional()
|
|
6608
|
+
});
|
|
6609
|
+
LarkBotStatusResultSchema = external_exports.object({
|
|
6610
|
+
state: external_exports.enum(["unbound", "provisioning", "bound", "broken"]),
|
|
6611
|
+
appId: external_exports.string().optional(),
|
|
6612
|
+
botName: external_exports.string().optional(),
|
|
6613
|
+
/** state='provisioning' 时的当前步骤与待用户打开的授权 URL */
|
|
6614
|
+
provisioning: external_exports.object({
|
|
6615
|
+
step: external_exports.enum(["register", "authorize"]),
|
|
6616
|
+
verificationUrl: external_exports.string().optional()
|
|
6617
|
+
}).optional(),
|
|
6618
|
+
brokenReason: external_exports.string().optional(),
|
|
6619
|
+
groups: external_exports.array(LarkBotGroupSchema)
|
|
6620
|
+
});
|
|
6621
|
+
LarkBotStateFrameSchema = LarkBotStatusResultSchema.extend({
|
|
6622
|
+
personaId: external_exports.string().min(1)
|
|
6623
|
+
});
|
|
6624
|
+
}
|
|
6625
|
+
});
|
|
6626
|
+
|
|
6587
6627
|
// ../protocol/src/persona-schemas.ts
|
|
6588
6628
|
var PersonaFileSchema, PersonaSkillSummarySchema, PersonaPluginSummarySchema, PersonaSandboxSettingsSchema, PersonaInfoResponseSchema, PersonaCreateArgsSchema, PersonaIdArgsSchema, PersonaUpdateArgsSchema, CodexSandboxSettingsSchema;
|
|
6589
6629
|
var init_persona_schemas = __esm({
|
|
@@ -6994,6 +7034,14 @@ var init_schemas = __esm({
|
|
|
6994
7034
|
* mirror,留 strip 防御)。
|
|
6995
7035
|
*/
|
|
6996
7036
|
shiftFiredFromSessionId: external_exports.string().min(1).optional(),
|
|
7037
|
+
/**
|
|
7038
|
+
* LarkBotConnector(spec 2026-08-05):该 session 是某飞书群的专属会话。
|
|
7039
|
+
* larkChatId = 飞书群 chat_id(oc_ 前缀),与 persona-guest scope 的 capId `lark-<chat_id>` 对应;
|
|
7040
|
+
* 由 daemon lark-bot-connector 模块写入,UI 只读(sidebar 按此字段隐藏,Drawer 群清单按此聚合)。
|
|
7041
|
+
*/
|
|
7042
|
+
larkChatId: external_exports.string().min(1).optional(),
|
|
7043
|
+
/** 飞书群名快照(展示用,随事件里的群名更新,可能滞后于飞书侧改名) */
|
|
7044
|
+
larkChatName: external_exports.string().min(1).optional(),
|
|
6997
7045
|
createdAt: external_exports.string().min(1),
|
|
6998
7046
|
updatedAt: external_exports.string().min(1)
|
|
6999
7047
|
});
|
|
@@ -7801,6 +7849,7 @@ var init_methods = __esm({
|
|
|
7801
7849
|
init_inbox();
|
|
7802
7850
|
init_peer_exec();
|
|
7803
7851
|
init_shift_internal();
|
|
7852
|
+
init_lark_bot_schemas();
|
|
7804
7853
|
init_persona_schemas();
|
|
7805
7854
|
init_schemas();
|
|
7806
7855
|
NO_ARGS = external_exports.object({});
|
|
@@ -7979,6 +8028,26 @@ var init_methods = __esm({
|
|
|
7979
8028
|
summary: "\u67E5 shift \u7684\u6267\u884C\u5386\u53F2\uFF08\u4EC5\u521B\u5EFA\u8005\uFF09",
|
|
7980
8029
|
args: ShiftInternalHistoryArgs
|
|
7981
8030
|
},
|
|
8031
|
+
"larkBot:provision": {
|
|
8032
|
+
summary: "\u53D1\u8D77 persona \u7684\u98DE\u4E66 bot \u4E00\u952E\u88C5\u914D\uFF08\u5EFA app + \u6388 scope\uFF09\uFF0C\u8FDB\u5EA6\u4E0E\u6388\u6743 URL \u8D70 larkBot:state \u5E27\uFF1Bowner-only",
|
|
8033
|
+
args: LarkBotProvisionArgs
|
|
8034
|
+
},
|
|
8035
|
+
"larkBot:provisionCancel": {
|
|
8036
|
+
summary: "\u53D6\u6D88\u8FDB\u884C\u4E2D\u7684\u98DE\u4E66 bot \u88C5\u914D\u6D41\u7A0B\uFF1Bowner-only",
|
|
8037
|
+
args: LarkBotProvisionCancelArgs
|
|
8038
|
+
},
|
|
8039
|
+
"larkBot:bindManual": {
|
|
8040
|
+
summary: "\u624B\u586B app_id/app_secret \u76F4\u63A5\u7ED1\u5B9A\u98DE\u4E66 bot\uFF08\u88C5\u914D\u9003\u751F\u8231\uFF09\uFF1Bowner-only",
|
|
8041
|
+
args: LarkBotBindManualArgs
|
|
8042
|
+
},
|
|
8043
|
+
"larkBot:unbind": {
|
|
8044
|
+
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",
|
|
8045
|
+
args: LarkBotUnbindArgs
|
|
8046
|
+
},
|
|
8047
|
+
"larkBot:status": {
|
|
8048
|
+
summary: "\u67E5 persona \u7684\u98DE\u4E66 bot \u72B6\u6001\uFF08unbound/provisioning/bound/broken + \u670D\u52A1\u4E2D\u7FA4\u6E05\u5355\uFF09\uFF1Bowner-only",
|
|
8049
|
+
args: LarkBotStatusArgs
|
|
8050
|
+
},
|
|
7982
8051
|
"skills:list": {
|
|
7983
8052
|
summary: "\u626B\u63CF\u5E76\u5217\u51FA\u8BE5\u76EE\u5F55\u53EF\u7528\u7684 skill",
|
|
7984
8053
|
args: SkillsListArgs
|
|
@@ -8418,6 +8487,7 @@ var init_runtime = __esm({
|
|
|
8418
8487
|
init_log();
|
|
8419
8488
|
init_visitor_schemas();
|
|
8420
8489
|
init_shift_internal();
|
|
8490
|
+
init_lark_bot_schemas();
|
|
8421
8491
|
}
|
|
8422
8492
|
});
|
|
8423
8493
|
|
|
@@ -8692,8 +8762,8 @@ var require_req = __commonJS({
|
|
|
8692
8762
|
if (req.originalUrl) {
|
|
8693
8763
|
_req.url = req.originalUrl;
|
|
8694
8764
|
} else {
|
|
8695
|
-
const
|
|
8696
|
-
_req.url = typeof
|
|
8765
|
+
const path78 = req.path;
|
|
8766
|
+
_req.url = typeof path78 === "string" ? path78 : req.url ? req.url.path || req.url : void 0;
|
|
8697
8767
|
}
|
|
8698
8768
|
if (req.query) {
|
|
8699
8769
|
_req.query = req.query;
|
|
@@ -8858,14 +8928,14 @@ var require_redact = __commonJS({
|
|
|
8858
8928
|
}
|
|
8859
8929
|
return obj;
|
|
8860
8930
|
}
|
|
8861
|
-
function parsePath(
|
|
8931
|
+
function parsePath(path78) {
|
|
8862
8932
|
const parts = [];
|
|
8863
8933
|
let current = "";
|
|
8864
8934
|
let inBrackets = false;
|
|
8865
8935
|
let inQuotes = false;
|
|
8866
8936
|
let quoteChar = "";
|
|
8867
|
-
for (let i = 0; i <
|
|
8868
|
-
const char =
|
|
8937
|
+
for (let i = 0; i < path78.length; i++) {
|
|
8938
|
+
const char = path78[i];
|
|
8869
8939
|
if (!inBrackets && char === ".") {
|
|
8870
8940
|
if (current) {
|
|
8871
8941
|
parts.push(current);
|
|
@@ -8996,10 +9066,10 @@ var require_redact = __commonJS({
|
|
|
8996
9066
|
return current;
|
|
8997
9067
|
}
|
|
8998
9068
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
8999
|
-
for (const
|
|
9000
|
-
const parts = parsePath(
|
|
9069
|
+
for (const path78 of paths) {
|
|
9070
|
+
const parts = parsePath(path78);
|
|
9001
9071
|
if (parts.includes("*")) {
|
|
9002
|
-
redactWildcardPath(obj, parts, censor,
|
|
9072
|
+
redactWildcardPath(obj, parts, censor, path78, remove);
|
|
9003
9073
|
} else {
|
|
9004
9074
|
if (remove) {
|
|
9005
9075
|
removeKey(obj, parts);
|
|
@@ -9084,8 +9154,8 @@ var require_redact = __commonJS({
|
|
|
9084
9154
|
}
|
|
9085
9155
|
} else {
|
|
9086
9156
|
if (afterWildcard.includes("*")) {
|
|
9087
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
9088
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
9157
|
+
const wrappedCensor = typeof censor === "function" ? (value, path78) => {
|
|
9158
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path78];
|
|
9089
9159
|
return censor(value, fullPath);
|
|
9090
9160
|
} : censor;
|
|
9091
9161
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -9120,8 +9190,8 @@ var require_redact = __commonJS({
|
|
|
9120
9190
|
return null;
|
|
9121
9191
|
}
|
|
9122
9192
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
9123
|
-
for (const
|
|
9124
|
-
const parts = parsePath(
|
|
9193
|
+
for (const path78 of pathsToClone) {
|
|
9194
|
+
const parts = parsePath(path78);
|
|
9125
9195
|
let current = pathStructure;
|
|
9126
9196
|
for (let i = 0; i < parts.length; i++) {
|
|
9127
9197
|
const part = parts[i];
|
|
@@ -9173,24 +9243,24 @@ var require_redact = __commonJS({
|
|
|
9173
9243
|
}
|
|
9174
9244
|
return cloneSelectively(obj, pathStructure);
|
|
9175
9245
|
}
|
|
9176
|
-
function validatePath(
|
|
9177
|
-
if (typeof
|
|
9246
|
+
function validatePath(path78) {
|
|
9247
|
+
if (typeof path78 !== "string") {
|
|
9178
9248
|
throw new Error("Paths must be (non-empty) strings");
|
|
9179
9249
|
}
|
|
9180
|
-
if (
|
|
9250
|
+
if (path78 === "") {
|
|
9181
9251
|
throw new Error("Invalid redaction path ()");
|
|
9182
9252
|
}
|
|
9183
|
-
if (
|
|
9184
|
-
throw new Error(`Invalid redaction path (${
|
|
9253
|
+
if (path78.includes("..")) {
|
|
9254
|
+
throw new Error(`Invalid redaction path (${path78})`);
|
|
9185
9255
|
}
|
|
9186
|
-
if (
|
|
9187
|
-
throw new Error(`Invalid redaction path (${
|
|
9256
|
+
if (path78.includes(",")) {
|
|
9257
|
+
throw new Error(`Invalid redaction path (${path78})`);
|
|
9188
9258
|
}
|
|
9189
9259
|
let bracketCount = 0;
|
|
9190
9260
|
let inQuotes = false;
|
|
9191
9261
|
let quoteChar = "";
|
|
9192
|
-
for (let i = 0; i <
|
|
9193
|
-
const char =
|
|
9262
|
+
for (let i = 0; i < path78.length; i++) {
|
|
9263
|
+
const char = path78[i];
|
|
9194
9264
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
9195
9265
|
if (!inQuotes) {
|
|
9196
9266
|
inQuotes = true;
|
|
@@ -9204,20 +9274,20 @@ var require_redact = __commonJS({
|
|
|
9204
9274
|
} else if (char === "]" && !inQuotes) {
|
|
9205
9275
|
bracketCount--;
|
|
9206
9276
|
if (bracketCount < 0) {
|
|
9207
|
-
throw new Error(`Invalid redaction path (${
|
|
9277
|
+
throw new Error(`Invalid redaction path (${path78})`);
|
|
9208
9278
|
}
|
|
9209
9279
|
}
|
|
9210
9280
|
}
|
|
9211
9281
|
if (bracketCount !== 0) {
|
|
9212
|
-
throw new Error(`Invalid redaction path (${
|
|
9282
|
+
throw new Error(`Invalid redaction path (${path78})`);
|
|
9213
9283
|
}
|
|
9214
9284
|
}
|
|
9215
9285
|
function validatePaths(paths) {
|
|
9216
9286
|
if (!Array.isArray(paths)) {
|
|
9217
9287
|
throw new TypeError("paths must be an array");
|
|
9218
9288
|
}
|
|
9219
|
-
for (const
|
|
9220
|
-
validatePath(
|
|
9289
|
+
for (const path78 of paths) {
|
|
9290
|
+
validatePath(path78);
|
|
9221
9291
|
}
|
|
9222
9292
|
}
|
|
9223
9293
|
function slowRedact(options = {}) {
|
|
@@ -9385,8 +9455,8 @@ var require_redaction = __commonJS({
|
|
|
9385
9455
|
if (shape[k2] === null) {
|
|
9386
9456
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
9387
9457
|
} else {
|
|
9388
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
9389
|
-
return censor(value, [k2, ...
|
|
9458
|
+
const wrappedCensor = typeof censor === "function" ? (value, path78) => {
|
|
9459
|
+
return censor(value, [k2, ...path78]);
|
|
9390
9460
|
} : censor;
|
|
9391
9461
|
o[k2] = Redact({
|
|
9392
9462
|
paths: shape[k2],
|
|
@@ -9604,10 +9674,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
9604
9674
|
var require_sonic_boom = __commonJS({
|
|
9605
9675
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
9606
9676
|
"use strict";
|
|
9607
|
-
var
|
|
9677
|
+
var fs68 = require("fs");
|
|
9608
9678
|
var EventEmitter3 = require("events");
|
|
9609
9679
|
var inherits = require("util").inherits;
|
|
9610
|
-
var
|
|
9680
|
+
var path78 = require("path");
|
|
9611
9681
|
var sleep2 = require_atomic_sleep();
|
|
9612
9682
|
var assert = require("assert");
|
|
9613
9683
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -9661,20 +9731,20 @@ var require_sonic_boom = __commonJS({
|
|
|
9661
9731
|
const mode = sonic.mode;
|
|
9662
9732
|
if (sonic.sync) {
|
|
9663
9733
|
try {
|
|
9664
|
-
if (sonic.mkdir)
|
|
9665
|
-
const fd =
|
|
9734
|
+
if (sonic.mkdir) fs68.mkdirSync(path78.dirname(file), { recursive: true });
|
|
9735
|
+
const fd = fs68.openSync(file, flags, mode);
|
|
9666
9736
|
fileOpened(null, fd);
|
|
9667
9737
|
} catch (err) {
|
|
9668
9738
|
fileOpened(err);
|
|
9669
9739
|
throw err;
|
|
9670
9740
|
}
|
|
9671
9741
|
} else if (sonic.mkdir) {
|
|
9672
|
-
|
|
9742
|
+
fs68.mkdir(path78.dirname(file), { recursive: true }, (err) => {
|
|
9673
9743
|
if (err) return fileOpened(err);
|
|
9674
|
-
|
|
9744
|
+
fs68.open(file, flags, mode, fileOpened);
|
|
9675
9745
|
});
|
|
9676
9746
|
} else {
|
|
9677
|
-
|
|
9747
|
+
fs68.open(file, flags, mode, fileOpened);
|
|
9678
9748
|
}
|
|
9679
9749
|
}
|
|
9680
9750
|
function SonicBoom(opts) {
|
|
@@ -9715,8 +9785,8 @@ var require_sonic_boom = __commonJS({
|
|
|
9715
9785
|
this.flush = flushBuffer;
|
|
9716
9786
|
this.flushSync = flushBufferSync;
|
|
9717
9787
|
this._actualWrite = actualWriteBuffer;
|
|
9718
|
-
fsWriteSync = () =>
|
|
9719
|
-
fsWrite = () =>
|
|
9788
|
+
fsWriteSync = () => fs68.writeSync(this.fd, this._writingBuf);
|
|
9789
|
+
fsWrite = () => fs68.write(this.fd, this._writingBuf, this.release);
|
|
9720
9790
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
9721
9791
|
this._writingBuf = "";
|
|
9722
9792
|
this.write = write;
|
|
@@ -9725,15 +9795,15 @@ var require_sonic_boom = __commonJS({
|
|
|
9725
9795
|
this._actualWrite = actualWrite;
|
|
9726
9796
|
fsWriteSync = () => {
|
|
9727
9797
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
9728
|
-
return
|
|
9798
|
+
return fs68.writeSync(this.fd, this._writingBuf);
|
|
9729
9799
|
}
|
|
9730
|
-
return
|
|
9800
|
+
return fs68.writeSync(this.fd, this._writingBuf, "utf8");
|
|
9731
9801
|
};
|
|
9732
9802
|
fsWrite = () => {
|
|
9733
9803
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
9734
|
-
return
|
|
9804
|
+
return fs68.write(this.fd, this._writingBuf, this.release);
|
|
9735
9805
|
}
|
|
9736
|
-
return
|
|
9806
|
+
return fs68.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
9737
9807
|
};
|
|
9738
9808
|
} else {
|
|
9739
9809
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -9790,7 +9860,7 @@ var require_sonic_boom = __commonJS({
|
|
|
9790
9860
|
}
|
|
9791
9861
|
}
|
|
9792
9862
|
if (this._fsync) {
|
|
9793
|
-
|
|
9863
|
+
fs68.fsyncSync(this.fd);
|
|
9794
9864
|
}
|
|
9795
9865
|
const len = this._len;
|
|
9796
9866
|
if (this._reopening) {
|
|
@@ -9904,7 +9974,7 @@ var require_sonic_boom = __commonJS({
|
|
|
9904
9974
|
const onDrain = () => {
|
|
9905
9975
|
if (!this._fsync) {
|
|
9906
9976
|
try {
|
|
9907
|
-
|
|
9977
|
+
fs68.fsync(this.fd, (err) => {
|
|
9908
9978
|
this._flushPending = false;
|
|
9909
9979
|
cb(err);
|
|
9910
9980
|
});
|
|
@@ -10006,7 +10076,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10006
10076
|
const fd = this.fd;
|
|
10007
10077
|
this.once("ready", () => {
|
|
10008
10078
|
if (fd !== this.fd) {
|
|
10009
|
-
|
|
10079
|
+
fs68.close(fd, (err) => {
|
|
10010
10080
|
if (err) {
|
|
10011
10081
|
return this.emit("error", err);
|
|
10012
10082
|
}
|
|
@@ -10055,7 +10125,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10055
10125
|
buf = this._bufs[0];
|
|
10056
10126
|
}
|
|
10057
10127
|
try {
|
|
10058
|
-
const n = Buffer.isBuffer(buf) ?
|
|
10128
|
+
const n = Buffer.isBuffer(buf) ? fs68.writeSync(this.fd, buf) : fs68.writeSync(this.fd, buf, "utf8");
|
|
10059
10129
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
10060
10130
|
buf = releasedBufObj.writingBuf;
|
|
10061
10131
|
this._len = releasedBufObj.len;
|
|
@@ -10071,7 +10141,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10071
10141
|
}
|
|
10072
10142
|
}
|
|
10073
10143
|
try {
|
|
10074
|
-
|
|
10144
|
+
fs68.fsyncSync(this.fd);
|
|
10075
10145
|
} catch {
|
|
10076
10146
|
}
|
|
10077
10147
|
}
|
|
@@ -10092,7 +10162,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10092
10162
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
10093
10163
|
}
|
|
10094
10164
|
try {
|
|
10095
|
-
const n =
|
|
10165
|
+
const n = fs68.writeSync(this.fd, buf);
|
|
10096
10166
|
buf = buf.subarray(n);
|
|
10097
10167
|
this._len = Math.max(this._len - n, 0);
|
|
10098
10168
|
if (buf.length <= 0) {
|
|
@@ -10120,13 +10190,13 @@ var require_sonic_boom = __commonJS({
|
|
|
10120
10190
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
10121
10191
|
if (this.sync) {
|
|
10122
10192
|
try {
|
|
10123
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
10193
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs68.writeSync(this.fd, this._writingBuf) : fs68.writeSync(this.fd, this._writingBuf, "utf8");
|
|
10124
10194
|
release(null, written);
|
|
10125
10195
|
} catch (err) {
|
|
10126
10196
|
release(err);
|
|
10127
10197
|
}
|
|
10128
10198
|
} else {
|
|
10129
|
-
|
|
10199
|
+
fs68.write(this.fd, this._writingBuf, release);
|
|
10130
10200
|
}
|
|
10131
10201
|
}
|
|
10132
10202
|
function actualWriteBuffer() {
|
|
@@ -10135,7 +10205,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10135
10205
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
10136
10206
|
if (this.sync) {
|
|
10137
10207
|
try {
|
|
10138
|
-
const written =
|
|
10208
|
+
const written = fs68.writeSync(this.fd, this._writingBuf);
|
|
10139
10209
|
release(null, written);
|
|
10140
10210
|
} catch (err) {
|
|
10141
10211
|
release(err);
|
|
@@ -10144,7 +10214,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10144
10214
|
if (kCopyBuffer) {
|
|
10145
10215
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
10146
10216
|
}
|
|
10147
|
-
|
|
10217
|
+
fs68.write(this.fd, this._writingBuf, release);
|
|
10148
10218
|
}
|
|
10149
10219
|
}
|
|
10150
10220
|
function actualClose(sonic) {
|
|
@@ -10160,12 +10230,12 @@ var require_sonic_boom = __commonJS({
|
|
|
10160
10230
|
sonic._lens = [];
|
|
10161
10231
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
10162
10232
|
try {
|
|
10163
|
-
|
|
10233
|
+
fs68.fsync(sonic.fd, closeWrapped);
|
|
10164
10234
|
} catch {
|
|
10165
10235
|
}
|
|
10166
10236
|
function closeWrapped() {
|
|
10167
10237
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
10168
|
-
|
|
10238
|
+
fs68.close(sonic.fd, done);
|
|
10169
10239
|
} else {
|
|
10170
10240
|
done();
|
|
10171
10241
|
}
|
|
@@ -13300,11 +13370,11 @@ var init_lib = __esm({
|
|
|
13300
13370
|
}
|
|
13301
13371
|
}
|
|
13302
13372
|
},
|
|
13303
|
-
addToPath: function addToPath(
|
|
13304
|
-
var last =
|
|
13373
|
+
addToPath: function addToPath(path78, added, removed, oldPosInc, options) {
|
|
13374
|
+
var last = path78.lastComponent;
|
|
13305
13375
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
13306
13376
|
return {
|
|
13307
|
-
oldPos:
|
|
13377
|
+
oldPos: path78.oldPos + oldPosInc,
|
|
13308
13378
|
lastComponent: {
|
|
13309
13379
|
count: last.count + 1,
|
|
13310
13380
|
added,
|
|
@@ -13314,7 +13384,7 @@ var init_lib = __esm({
|
|
|
13314
13384
|
};
|
|
13315
13385
|
} else {
|
|
13316
13386
|
return {
|
|
13317
|
-
oldPos:
|
|
13387
|
+
oldPos: path78.oldPos + oldPosInc,
|
|
13318
13388
|
lastComponent: {
|
|
13319
13389
|
count: 1,
|
|
13320
13390
|
added,
|
|
@@ -13823,10 +13893,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
13823
13893
|
const memories = raw.map((m2) => {
|
|
13824
13894
|
if (!m2 || typeof m2 !== "object") return null;
|
|
13825
13895
|
const rec3 = m2;
|
|
13826
|
-
const
|
|
13896
|
+
const path78 = typeof rec3.path === "string" ? rec3.path : null;
|
|
13827
13897
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
13828
|
-
if (!
|
|
13829
|
-
const entry = { path:
|
|
13898
|
+
if (!path78 || content == null) return null;
|
|
13899
|
+
const entry = { path: path78, content };
|
|
13830
13900
|
if (typeof rec3.mtimeMs === "number") entry.mtimeMs = rec3.mtimeMs;
|
|
13831
13901
|
return entry;
|
|
13832
13902
|
}).filter((m2) => m2 !== null);
|
|
@@ -14629,10 +14699,10 @@ function parseAttachment(obj) {
|
|
|
14629
14699
|
const memories = raw.map((m2) => {
|
|
14630
14700
|
if (!m2 || typeof m2 !== "object") return null;
|
|
14631
14701
|
const rec3 = m2;
|
|
14632
|
-
const
|
|
14702
|
+
const path78 = typeof rec3.path === "string" ? rec3.path : null;
|
|
14633
14703
|
const content = typeof rec3.content === "string" ? rec3.content : null;
|
|
14634
|
-
if (!
|
|
14635
|
-
const out = { path:
|
|
14704
|
+
if (!path78 || content == null) return null;
|
|
14705
|
+
const out = { path: path78, content };
|
|
14636
14706
|
if (typeof rec3.mtimeMs === "number") out.mtimeMs = rec3.mtimeMs;
|
|
14637
14707
|
return out;
|
|
14638
14708
|
}).filter((m2) => m2 !== null);
|
|
@@ -35601,8 +35671,8 @@ var require_utils = __commonJS({
|
|
|
35601
35671
|
var result = transform[inputType][outputType](input);
|
|
35602
35672
|
return result;
|
|
35603
35673
|
};
|
|
35604
|
-
exports2.resolve = function(
|
|
35605
|
-
var parts =
|
|
35674
|
+
exports2.resolve = function(path78) {
|
|
35675
|
+
var parts = path78.split("/");
|
|
35606
35676
|
var result = [];
|
|
35607
35677
|
for (var index = 0; index < parts.length; index++) {
|
|
35608
35678
|
var part = parts[index];
|
|
@@ -41455,18 +41525,18 @@ var require_object = __commonJS({
|
|
|
41455
41525
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
41456
41526
|
this.files[name] = object;
|
|
41457
41527
|
};
|
|
41458
|
-
var parentFolder = function(
|
|
41459
|
-
if (
|
|
41460
|
-
|
|
41528
|
+
var parentFolder = function(path78) {
|
|
41529
|
+
if (path78.slice(-1) === "/") {
|
|
41530
|
+
path78 = path78.substring(0, path78.length - 1);
|
|
41461
41531
|
}
|
|
41462
|
-
var lastSlash =
|
|
41463
|
-
return lastSlash > 0 ?
|
|
41532
|
+
var lastSlash = path78.lastIndexOf("/");
|
|
41533
|
+
return lastSlash > 0 ? path78.substring(0, lastSlash) : "";
|
|
41464
41534
|
};
|
|
41465
|
-
var forceTrailingSlash = function(
|
|
41466
|
-
if (
|
|
41467
|
-
|
|
41535
|
+
var forceTrailingSlash = function(path78) {
|
|
41536
|
+
if (path78.slice(-1) !== "/") {
|
|
41537
|
+
path78 += "/";
|
|
41468
41538
|
}
|
|
41469
|
-
return
|
|
41539
|
+
return path78;
|
|
41470
41540
|
};
|
|
41471
41541
|
var folderAdd = function(name, createFolders) {
|
|
41472
41542
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -42468,7 +42538,7 @@ var require_lib3 = __commonJS({
|
|
|
42468
42538
|
// src/run-case/recorder.ts
|
|
42469
42539
|
function startRunCaseRecorder(opts) {
|
|
42470
42540
|
const now = opts.now ?? Date.now;
|
|
42471
|
-
const dir =
|
|
42541
|
+
const dir = import_node_path65.default.dirname(opts.recordPath);
|
|
42472
42542
|
let stream = null;
|
|
42473
42543
|
let closing = false;
|
|
42474
42544
|
let closedSettled = false;
|
|
@@ -42482,8 +42552,8 @@ function startRunCaseRecorder(opts) {
|
|
|
42482
42552
|
});
|
|
42483
42553
|
const ensureStream = () => {
|
|
42484
42554
|
if (stream) return stream;
|
|
42485
|
-
|
|
42486
|
-
stream =
|
|
42555
|
+
import_node_fs49.default.mkdirSync(dir, { recursive: true });
|
|
42556
|
+
stream = import_node_fs49.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
42487
42557
|
stream.on("close", () => closedResolve());
|
|
42488
42558
|
return stream;
|
|
42489
42559
|
};
|
|
@@ -42508,12 +42578,12 @@ function startRunCaseRecorder(opts) {
|
|
|
42508
42578
|
};
|
|
42509
42579
|
return { tap, close, closed };
|
|
42510
42580
|
}
|
|
42511
|
-
var
|
|
42581
|
+
var import_node_fs49, import_node_path65;
|
|
42512
42582
|
var init_recorder = __esm({
|
|
42513
42583
|
"src/run-case/recorder.ts"() {
|
|
42514
42584
|
"use strict";
|
|
42515
|
-
|
|
42516
|
-
|
|
42585
|
+
import_node_fs49 = __toESM(require("fs"), 1);
|
|
42586
|
+
import_node_path65 = __toESM(require("path"), 1);
|
|
42517
42587
|
}
|
|
42518
42588
|
});
|
|
42519
42589
|
|
|
@@ -42556,7 +42626,7 @@ var init_wire = __esm({
|
|
|
42556
42626
|
// src/run-case/controller.ts
|
|
42557
42627
|
async function runController(opts) {
|
|
42558
42628
|
const now = opts.now ?? Date.now;
|
|
42559
|
-
const cwd = opts.cwd ?? (0,
|
|
42629
|
+
const cwd = opts.cwd ?? (0, import_node_fs50.mkdtempSync)(import_node_path66.default.join(import_node_os23.default.tmpdir(), "clawd-runcase-"));
|
|
42560
42630
|
const ownsCwd = opts.cwd === void 0;
|
|
42561
42631
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
42562
42632
|
const spawnCtx = { cwd };
|
|
@@ -42717,19 +42787,19 @@ async function runController(opts) {
|
|
|
42717
42787
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
42718
42788
|
if (ownsCwd) {
|
|
42719
42789
|
try {
|
|
42720
|
-
(0,
|
|
42790
|
+
(0, import_node_fs50.rmSync)(cwd, { recursive: true, force: true });
|
|
42721
42791
|
} catch {
|
|
42722
42792
|
}
|
|
42723
42793
|
}
|
|
42724
42794
|
return exitCode ?? 0;
|
|
42725
42795
|
}
|
|
42726
|
-
var
|
|
42796
|
+
var import_node_fs50, import_node_os23, import_node_path66;
|
|
42727
42797
|
var init_controller = __esm({
|
|
42728
42798
|
"src/run-case/controller.ts"() {
|
|
42729
42799
|
"use strict";
|
|
42730
|
-
|
|
42800
|
+
import_node_fs50 = require("fs");
|
|
42731
42801
|
import_node_os23 = __toESM(require("os"), 1);
|
|
42732
|
-
|
|
42802
|
+
import_node_path66 = __toESM(require("path"), 1);
|
|
42733
42803
|
init_claude();
|
|
42734
42804
|
init_stdout_splitter();
|
|
42735
42805
|
init_permission_stdio();
|
|
@@ -43004,8 +43074,8 @@ Env (advanced):
|
|
|
43004
43074
|
`;
|
|
43005
43075
|
|
|
43006
43076
|
// src/index.ts
|
|
43007
|
-
var
|
|
43008
|
-
var
|
|
43077
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
43078
|
+
var import_node_fs48 = __toESM(require("fs"), 1);
|
|
43009
43079
|
var import_node_os22 = __toESM(require("os"), 1);
|
|
43010
43080
|
|
|
43011
43081
|
// ../node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
|
|
@@ -43893,6 +43963,28 @@ ${r.outcome.text}${files}`;
|
|
|
43893
43963
|
return ["\u4F60\u4E4B\u524D\u59D4\u6D3E\u51FA\u53BB\u7684\u4EFB\u52A1\u6709\u4E86\u7ED3\u679C\uFF1A", "", blocks.join("\n\n")].join("\n");
|
|
43894
43964
|
}
|
|
43895
43965
|
|
|
43966
|
+
// src/session/lark-reply.ts
|
|
43967
|
+
function extractLarkReplyText(events) {
|
|
43968
|
+
let lastUserIdx = -1;
|
|
43969
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
43970
|
+
if (events[i].kind === "user_text") {
|
|
43971
|
+
lastUserIdx = i;
|
|
43972
|
+
break;
|
|
43973
|
+
}
|
|
43974
|
+
}
|
|
43975
|
+
const tail = events.slice(lastUserIdx + 1);
|
|
43976
|
+
const order = [];
|
|
43977
|
+
const latest = /* @__PURE__ */ new Map();
|
|
43978
|
+
let anon = 0;
|
|
43979
|
+
for (const ev of tail) {
|
|
43980
|
+
if (ev.kind !== "text") continue;
|
|
43981
|
+
const key = ev.partialId ?? `__snapshot_${anon++}`;
|
|
43982
|
+
if (!latest.has(key)) order.push(key);
|
|
43983
|
+
latest.set(key, ev.text);
|
|
43984
|
+
}
|
|
43985
|
+
return order.map((k2) => latest.get(k2) ?? "").filter((t) => t.length > 0).join("\n").trim();
|
|
43986
|
+
}
|
|
43987
|
+
|
|
43896
43988
|
// src/session/runner.ts
|
|
43897
43989
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
43898
43990
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
@@ -47021,6 +47113,110 @@ var SessionManager = class {
|
|
|
47021
47113
|
});
|
|
47022
47114
|
return { sessionId, ended, kill: killImpl };
|
|
47023
47115
|
}
|
|
47116
|
+
/**
|
|
47117
|
+
* LarkBotConnector(spec 2026-08-05 §5.3):把一条飞书群 @ 消息作为一个 turn 驱动
|
|
47118
|
+
* 该群的专属 guest session,turn-idle 后从 reducer buffer 提取回复文本。
|
|
47119
|
+
*
|
|
47120
|
+
* 跟 createShiftSession 的差异:
|
|
47121
|
+
* - **find-or-create**:按 capId `lark-<chatId>` 找现存 session(一群一条,D3),
|
|
47122
|
+
* 没有才建;daemon `create` 的无 dedupe 语义不变——dedupe 是本方法私有实现
|
|
47123
|
+
* - guest scope + 沙箱:群成员 query 不带 owner 权限;10min guest idle-kill + resume
|
|
47124
|
+
* - turn-idle 后**不 kill**(session 常驻,记忆即价值);延迟 settleDelayMs 等尾随
|
|
47125
|
+
* text 落盘(schemas.ts turn_end 注释:CC 写 turn_end 早于尾段正文)再读 buffer
|
|
47126
|
+
* - 回复提取:extractLarkReplyText(最后一条 user_text 之后的 text 事件拼接)
|
|
47127
|
+
*/
|
|
47128
|
+
runLarkChatTurn(args) {
|
|
47129
|
+
if (!this.deps.personaRoot) {
|
|
47130
|
+
throw new Error("runLarkChatTurn: personaRoot missing in ManagerDeps");
|
|
47131
|
+
}
|
|
47132
|
+
const capId = `lark-${args.chatId}`;
|
|
47133
|
+
const scope = {
|
|
47134
|
+
kind: "persona",
|
|
47135
|
+
personaId: args.personaId,
|
|
47136
|
+
mode: "guest",
|
|
47137
|
+
capId
|
|
47138
|
+
};
|
|
47139
|
+
const store = this.storeFor(scope);
|
|
47140
|
+
let file = store.list().find((f) => f.larkChatId === args.chatId);
|
|
47141
|
+
if (!file) {
|
|
47142
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
47143
|
+
file = {
|
|
47144
|
+
sessionId: newSessionId(),
|
|
47145
|
+
cwd: import_node_path9.default.join(this.deps.personaRoot, safeFileName(args.personaId)),
|
|
47146
|
+
tool: this.deps.getPersonaTool?.(args.personaId) ?? "claude",
|
|
47147
|
+
ownerPersonaId: args.personaId,
|
|
47148
|
+
// guest 三件套:creatorPrincipalId=capId(scopeForFile 回落防线)、
|
|
47149
|
+
// creatorDisplayName(reducer guest 分支硬性要求,缺则 spawn 抛)
|
|
47150
|
+
creatorPrincipalId: capId,
|
|
47151
|
+
creatorDisplayName: `\u98DE\u4E66\u7FA4\xB7${args.chatName ?? args.chatId}`,
|
|
47152
|
+
larkChatId: args.chatId,
|
|
47153
|
+
...args.chatName ? { larkChatName: args.chatName } : {},
|
|
47154
|
+
createdAt: now,
|
|
47155
|
+
updatedAt: now
|
|
47156
|
+
};
|
|
47157
|
+
store.write(file);
|
|
47158
|
+
this.deps.logger?.info("larkBot.runLarkChatTurn.session-created", {
|
|
47159
|
+
sessionId: file.sessionId,
|
|
47160
|
+
personaId: args.personaId,
|
|
47161
|
+
chatId: args.chatId
|
|
47162
|
+
});
|
|
47163
|
+
} else if (args.chatName && file.larkChatName !== args.chatName) {
|
|
47164
|
+
file = { ...file, larkChatName: args.chatName, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
47165
|
+
store.write(file);
|
|
47166
|
+
}
|
|
47167
|
+
const sessionId = file.sessionId;
|
|
47168
|
+
let resolveEnded = () => {
|
|
47169
|
+
};
|
|
47170
|
+
const ended = new Promise((r) => {
|
|
47171
|
+
resolveEnded = r;
|
|
47172
|
+
});
|
|
47173
|
+
let unsubscribe = () => {
|
|
47174
|
+
};
|
|
47175
|
+
let settled = false;
|
|
47176
|
+
const settle = (info) => {
|
|
47177
|
+
if (settled) return;
|
|
47178
|
+
settled = true;
|
|
47179
|
+
unsubscribe();
|
|
47180
|
+
resolveEnded(info);
|
|
47181
|
+
};
|
|
47182
|
+
const killImpl = () => {
|
|
47183
|
+
const r = this.runners.get(sessionId);
|
|
47184
|
+
if (!r) return;
|
|
47185
|
+
r.input({ kind: "command", command: { kind: "stop" } });
|
|
47186
|
+
};
|
|
47187
|
+
const settleDelayMs = args.settleDelayMs ?? 500;
|
|
47188
|
+
unsubscribe = this.subscribe(
|
|
47189
|
+
sessionId,
|
|
47190
|
+
scope,
|
|
47191
|
+
makeEndFrameHandler(sessionId, (info) => {
|
|
47192
|
+
if (info.kind === "idle") {
|
|
47193
|
+
setTimeout(() => {
|
|
47194
|
+
try {
|
|
47195
|
+
const events = this.readHistoryEventsForScope(sessionId, scope);
|
|
47196
|
+
const replyText = extractLarkReplyText(events);
|
|
47197
|
+
settle(replyText ? { ok: true, replyText } : { error: "empty reply" });
|
|
47198
|
+
} catch (err) {
|
|
47199
|
+
settle({ error: err.message });
|
|
47200
|
+
}
|
|
47201
|
+
}, settleDelayMs);
|
|
47202
|
+
} else if (info.kind === "stopped") {
|
|
47203
|
+
settle({ error: "session stopped before reply" });
|
|
47204
|
+
} else {
|
|
47205
|
+
settle({ error: info.message || "session error" });
|
|
47206
|
+
}
|
|
47207
|
+
})
|
|
47208
|
+
);
|
|
47209
|
+
const runner = this.ensureRunnerForScope(file, scope);
|
|
47210
|
+
runner.input({
|
|
47211
|
+
kind: "command",
|
|
47212
|
+
command: {
|
|
47213
|
+
kind: "send",
|
|
47214
|
+
text: args.text,
|
|
47215
|
+
senderPrincipal: makeGuestSender(capId, args.senderName)
|
|
47216
|
+
}
|
|
47217
|
+
});
|
|
47218
|
+
return { sessionId, ended, kill: killImpl };
|
|
47219
|
+
}
|
|
47024
47220
|
/**
|
|
47025
47221
|
* 老板插话:把 'inject-owner-text' input 喂给对应 runner,
|
|
47026
47222
|
* runner 不存在时按 scope 懒创建。
|
|
@@ -49024,8 +49220,8 @@ function turnStartInput(text) {
|
|
|
49024
49220
|
const items = [];
|
|
49025
49221
|
let leftover = text;
|
|
49026
49222
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
49027
|
-
const [marker, name,
|
|
49028
|
-
items.push({ type: "skill", name, path:
|
|
49223
|
+
const [marker, name, path78] = m2;
|
|
49224
|
+
items.push({ type: "skill", name, path: path78 });
|
|
49029
49225
|
leftover = leftover.replace(marker, "");
|
|
49030
49226
|
}
|
|
49031
49227
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -51526,6 +51722,610 @@ function buildShiftInternalHandlers(deps) {
|
|
|
51526
51722
|
};
|
|
51527
51723
|
}
|
|
51528
51724
|
|
|
51725
|
+
// src/lark-bot-connector/provisioner.ts
|
|
51726
|
+
var LARK_BOT_V1_SCOPES = [
|
|
51727
|
+
"offline_access",
|
|
51728
|
+
"im:chat:readonly",
|
|
51729
|
+
"im:resource",
|
|
51730
|
+
"contact:user.base:readonly"
|
|
51731
|
+
];
|
|
51732
|
+
var REGISTRATION_URL = "https://accounts.feishu.cn/oauth/v1/app/registration";
|
|
51733
|
+
var DEVICE_AUTHORIZE_URL = "https://accounts.feishu.cn/oauth/v1/device/authorize";
|
|
51734
|
+
var DEVICE_TOKEN_URL = "https://open.feishu.cn/open-apis/authen/v2/oauth/token";
|
|
51735
|
+
var DEFAULT_POLL_INTERVAL_MS = 6e3;
|
|
51736
|
+
var DEFAULT_TIMEOUT_MS2 = 10 * 60 * 1e3;
|
|
51737
|
+
var SLOW_DOWN_STEP_MS = 5e3;
|
|
51738
|
+
var FlowCtx = class {
|
|
51739
|
+
fetchImpl;
|
|
51740
|
+
sleep;
|
|
51741
|
+
now;
|
|
51742
|
+
timeoutMs;
|
|
51743
|
+
intervalMs;
|
|
51744
|
+
cancelled = false;
|
|
51745
|
+
constructor(opts) {
|
|
51746
|
+
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
51747
|
+
if (!f) throw new Error("fetch is not available (Node >= 18 required)");
|
|
51748
|
+
this.fetchImpl = f;
|
|
51749
|
+
this.sleep = opts.sleepImpl ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
51750
|
+
this.now = opts.nowImpl ?? Date.now;
|
|
51751
|
+
this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
51752
|
+
this.intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
51753
|
+
}
|
|
51754
|
+
/**
|
|
51755
|
+
* RFC 8628 轮询循环:pollOnce 返回 null 表示 pending 继续;'slow_down' 加间隔;
|
|
51756
|
+
* 非 null 结果即完成。超时 / cancel reject。
|
|
51757
|
+
*/
|
|
51758
|
+
async poll(pollOnce) {
|
|
51759
|
+
const start = this.now();
|
|
51760
|
+
for (; ; ) {
|
|
51761
|
+
if (this.cancelled) throw new Error("flow cancelled");
|
|
51762
|
+
if (this.now() - start >= this.timeoutMs) throw new Error("flow timeout");
|
|
51763
|
+
const r = await pollOnce();
|
|
51764
|
+
if (r === "slow_down") {
|
|
51765
|
+
this.intervalMs += SLOW_DOWN_STEP_MS;
|
|
51766
|
+
} else if (r !== "pending") {
|
|
51767
|
+
return r;
|
|
51768
|
+
}
|
|
51769
|
+
await this.sleep(this.intervalMs);
|
|
51770
|
+
}
|
|
51771
|
+
}
|
|
51772
|
+
};
|
|
51773
|
+
var POST_TIMEOUT_MS = 15e3;
|
|
51774
|
+
async function postJson(ctx, url, body) {
|
|
51775
|
+
const ac = new AbortController();
|
|
51776
|
+
const timer = setTimeout(() => ac.abort(), POST_TIMEOUT_MS);
|
|
51777
|
+
let res;
|
|
51778
|
+
try {
|
|
51779
|
+
res = await ctx.fetchImpl(url, {
|
|
51780
|
+
method: "POST",
|
|
51781
|
+
headers: { "content-type": "application/json" },
|
|
51782
|
+
body: JSON.stringify(body),
|
|
51783
|
+
signal: ac.signal
|
|
51784
|
+
});
|
|
51785
|
+
} finally {
|
|
51786
|
+
clearTimeout(timer);
|
|
51787
|
+
}
|
|
51788
|
+
let parsed = {};
|
|
51789
|
+
try {
|
|
51790
|
+
parsed = await res.json();
|
|
51791
|
+
} catch {
|
|
51792
|
+
parsed = {};
|
|
51793
|
+
}
|
|
51794
|
+
return { status: res.status, json: parsed };
|
|
51795
|
+
}
|
|
51796
|
+
var TERMINAL_OAUTH_ERRORS = /* @__PURE__ */ new Set(["access_denied", "expired_token", "invalid_grant"]);
|
|
51797
|
+
function pollSignal(status, json, what) {
|
|
51798
|
+
if (status >= 200 && status < 300) return "done";
|
|
51799
|
+
const err = String(json.error ?? "");
|
|
51800
|
+
if (TERMINAL_OAUTH_ERRORS.has(err)) {
|
|
51801
|
+
throw new Error(`${what} rejected: ${err}`);
|
|
51802
|
+
}
|
|
51803
|
+
if (err === "authorization_pending" || status === 400) {
|
|
51804
|
+
if (err === "slow_down") return "slow_down";
|
|
51805
|
+
if (err === "authorization_pending") return "pending";
|
|
51806
|
+
return "pending";
|
|
51807
|
+
}
|
|
51808
|
+
if (status === 429) return "slow_down";
|
|
51809
|
+
throw new Error(`${what} failed: HTTP ${status} ${JSON.stringify(json).slice(0, 200)}`);
|
|
51810
|
+
}
|
|
51811
|
+
async function startAppRegistration(opts = {}) {
|
|
51812
|
+
const ctx = new FlowCtx(opts);
|
|
51813
|
+
const init = await postJson(ctx, REGISTRATION_URL, { action: "start", brand: "feishu" });
|
|
51814
|
+
const verificationUrl = String(init.json.verification_url ?? init.json.verification_uri ?? "");
|
|
51815
|
+
const flowId = String(init.json.flow_id ?? "");
|
|
51816
|
+
if (init.status < 200 || init.status >= 300 || !verificationUrl || !flowId) {
|
|
51817
|
+
throw new Error(
|
|
51818
|
+
`app registration start failed: HTTP ${init.status} ${JSON.stringify(init.json).slice(0, 200)}`
|
|
51819
|
+
);
|
|
51820
|
+
}
|
|
51821
|
+
return {
|
|
51822
|
+
verificationUrl,
|
|
51823
|
+
cancel: () => {
|
|
51824
|
+
ctx.cancelled = true;
|
|
51825
|
+
},
|
|
51826
|
+
complete: () => ctx.poll(async () => {
|
|
51827
|
+
const r = await postJson(ctx, REGISTRATION_URL, {
|
|
51828
|
+
action: "poll",
|
|
51829
|
+
brand: "feishu",
|
|
51830
|
+
flow_id: flowId
|
|
51831
|
+
});
|
|
51832
|
+
const sig = pollSignal(r.status, r.json, "app registration");
|
|
51833
|
+
if (sig !== "done") return sig;
|
|
51834
|
+
const appId = String(r.json.client_id ?? "");
|
|
51835
|
+
const appSecret = String(r.json.client_secret ?? "");
|
|
51836
|
+
if (!appId || !appSecret) {
|
|
51837
|
+
throw new Error("app registration succeeded but missing client_id or client_secret");
|
|
51838
|
+
}
|
|
51839
|
+
return { appId, appSecret };
|
|
51840
|
+
})
|
|
51841
|
+
};
|
|
51842
|
+
}
|
|
51843
|
+
async function startScopeAuthorization(args) {
|
|
51844
|
+
const ctx = new FlowCtx(args);
|
|
51845
|
+
const init = await postJson(ctx, DEVICE_AUTHORIZE_URL, {
|
|
51846
|
+
client_id: args.appId,
|
|
51847
|
+
scope: args.scopes.join(" ")
|
|
51848
|
+
});
|
|
51849
|
+
const verificationUrl = String(init.json.verification_url ?? init.json.verification_uri ?? "");
|
|
51850
|
+
const deviceCode = String(init.json.device_code ?? "");
|
|
51851
|
+
if (init.status < 200 || init.status >= 300 || !verificationUrl || !deviceCode) {
|
|
51852
|
+
throw new Error(
|
|
51853
|
+
`scope authorization start failed: HTTP ${init.status} ${JSON.stringify(init.json).slice(0, 200)}`
|
|
51854
|
+
);
|
|
51855
|
+
}
|
|
51856
|
+
return {
|
|
51857
|
+
verificationUrl,
|
|
51858
|
+
cancel: () => {
|
|
51859
|
+
ctx.cancelled = true;
|
|
51860
|
+
},
|
|
51861
|
+
complete: () => ctx.poll(async () => {
|
|
51862
|
+
const r = await postJson(ctx, DEVICE_TOKEN_URL, {
|
|
51863
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
51864
|
+
client_id: args.appId,
|
|
51865
|
+
device_code: deviceCode
|
|
51866
|
+
});
|
|
51867
|
+
const sig = pollSignal(r.status, r.json, "scope authorization");
|
|
51868
|
+
if (sig !== "done") return sig;
|
|
51869
|
+
const grantedSet = new Set(
|
|
51870
|
+
String(r.json.scope ?? "").split(/\s+/).filter(Boolean)
|
|
51871
|
+
);
|
|
51872
|
+
const granted = args.scopes.filter((s) => grantedSet.has(s));
|
|
51873
|
+
const denied = args.scopes.filter((s) => !grantedSet.has(s));
|
|
51874
|
+
if (granted.length === 0) {
|
|
51875
|
+
throw new Error(`scope authorization: no scopes granted (requested: ${args.scopes.join(" ")})`);
|
|
51876
|
+
}
|
|
51877
|
+
return { granted: [...granted], denied: [...denied] };
|
|
51878
|
+
})
|
|
51879
|
+
};
|
|
51880
|
+
}
|
|
51881
|
+
|
|
51882
|
+
// src/handlers/lark-bot.ts
|
|
51883
|
+
init_protocol();
|
|
51884
|
+
function statusFrame(personaId2, status) {
|
|
51885
|
+
return { type: "larkBot:state", personaId: personaId2, ...status };
|
|
51886
|
+
}
|
|
51887
|
+
function buildLarkBotHandlers(deps) {
|
|
51888
|
+
const now = deps.now ?? Date.now;
|
|
51889
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
51890
|
+
const groupsOf = (personaId2) => {
|
|
51891
|
+
const removed = new Set(deps.store.read(personaId2)?.removedChatIds ?? []);
|
|
51892
|
+
return deps.listLarkSessions(personaId2).filter((g2) => !removed.has(g2.chatId));
|
|
51893
|
+
};
|
|
51894
|
+
const emit = (personaId2, status2) => {
|
|
51895
|
+
deps.broadcast(statusFrame(personaId2, status2));
|
|
51896
|
+
};
|
|
51897
|
+
const runProvision = async (personaId2, flight) => {
|
|
51898
|
+
const finish = () => {
|
|
51899
|
+
if (inFlight.get(personaId2) === flight) inFlight.delete(personaId2);
|
|
51900
|
+
};
|
|
51901
|
+
const tunnelUrl = deps.getTunnelUrl();
|
|
51902
|
+
const ownerId = deps.getOwnerId();
|
|
51903
|
+
if (!tunnelUrl || !ownerId) {
|
|
51904
|
+
finish();
|
|
51905
|
+
emit(personaId2, { state: "unbound", brokenReason: "tunnel or owner identity unavailable", groups: [] });
|
|
51906
|
+
return;
|
|
51907
|
+
}
|
|
51908
|
+
try {
|
|
51909
|
+
const reg = await deps.provisioner.startAppRegistration();
|
|
51910
|
+
if (flight.cancelled) return finish();
|
|
51911
|
+
flight.cancelFn = reg.cancel;
|
|
51912
|
+
emit(personaId2, {
|
|
51913
|
+
state: "provisioning",
|
|
51914
|
+
provisioning: { step: "register", verificationUrl: reg.verificationUrl },
|
|
51915
|
+
groups: []
|
|
51916
|
+
});
|
|
51917
|
+
const { appId, appSecret } = await reg.complete();
|
|
51918
|
+
if (flight.cancelled) return finish();
|
|
51919
|
+
const auth = await deps.provisioner.startScopeAuthorization({
|
|
51920
|
+
appId,
|
|
51921
|
+
scopes: LARK_BOT_V1_SCOPES
|
|
51922
|
+
});
|
|
51923
|
+
if (flight.cancelled) return finish();
|
|
51924
|
+
flight.cancelFn = auth.cancel;
|
|
51925
|
+
emit(personaId2, {
|
|
51926
|
+
state: "provisioning",
|
|
51927
|
+
provisioning: { step: "authorize", verificationUrl: auth.verificationUrl },
|
|
51928
|
+
groups: []
|
|
51929
|
+
});
|
|
51930
|
+
const { denied } = await auth.complete();
|
|
51931
|
+
if (flight.cancelled) return finish();
|
|
51932
|
+
if (denied.length > 0) {
|
|
51933
|
+
deps.logger?.warn(`larkBot provision ${personaId2}: scopes denied (accepted): ${denied.join(" ")}`);
|
|
51934
|
+
}
|
|
51935
|
+
const botName = deps.getPersonaName(personaId2) ?? personaId2;
|
|
51936
|
+
await deps.cloud.bind({ personaId: personaId2, appId, appSecret, botName, tunnelUrl, ownerId });
|
|
51937
|
+
deps.store.write(personaId2, { appId, botName, boundAt: now() });
|
|
51938
|
+
finish();
|
|
51939
|
+
emit(personaId2, { state: "bound", appId, botName, groups: groupsOf(personaId2) });
|
|
51940
|
+
} catch (err) {
|
|
51941
|
+
finish();
|
|
51942
|
+
if (flight.cancelled) return;
|
|
51943
|
+
emit(personaId2, {
|
|
51944
|
+
state: "unbound",
|
|
51945
|
+
brokenReason: err.message,
|
|
51946
|
+
groups: []
|
|
51947
|
+
});
|
|
51948
|
+
}
|
|
51949
|
+
};
|
|
51950
|
+
const provision = async (frame) => {
|
|
51951
|
+
const { personaId: personaId2 } = parseArgs2(LarkBotProvisionArgs, frame, "larkBot:provision");
|
|
51952
|
+
if (deps.store.read(personaId2)) throw new Error(`larkBot already bound: ${personaId2}`);
|
|
51953
|
+
if (inFlight.has(personaId2)) throw new Error(`larkBot provision already in progress: ${personaId2}`);
|
|
51954
|
+
if (!deps.getTunnelUrl()) throw new Error("larkBot provision requires tunnel to be up");
|
|
51955
|
+
if (!deps.getOwnerId()) throw new Error("larkBot provision requires feishu login (owner identity)");
|
|
51956
|
+
const flight = { cancelled: false, cancelFn: () => {
|
|
51957
|
+
} };
|
|
51958
|
+
inFlight.set(personaId2, flight);
|
|
51959
|
+
void runProvision(personaId2, flight);
|
|
51960
|
+
return { response: { type: "larkBot:provision:ok" } };
|
|
51961
|
+
};
|
|
51962
|
+
const provisionCancel = async (frame) => {
|
|
51963
|
+
const { personaId: personaId2 } = parseArgs2(LarkBotProvisionCancelArgs, frame, "larkBot:provisionCancel");
|
|
51964
|
+
const flight = inFlight.get(personaId2);
|
|
51965
|
+
if (flight) {
|
|
51966
|
+
flight.cancelled = true;
|
|
51967
|
+
inFlight.delete(personaId2);
|
|
51968
|
+
flight.cancelFn();
|
|
51969
|
+
}
|
|
51970
|
+
emit(personaId2, { state: "unbound", groups: [] });
|
|
51971
|
+
return { response: { type: "larkBot:provisionCancel:ok" } };
|
|
51972
|
+
};
|
|
51973
|
+
const bindManual = async (frame) => {
|
|
51974
|
+
const { personaId: personaId2, appId, appSecret, botName } = parseArgs2(
|
|
51975
|
+
LarkBotBindManualArgs,
|
|
51976
|
+
frame,
|
|
51977
|
+
"larkBot:bindManual"
|
|
51978
|
+
);
|
|
51979
|
+
const tunnelUrl = deps.getTunnelUrl();
|
|
51980
|
+
if (!tunnelUrl) throw new Error("larkBot bind requires tunnel to be up");
|
|
51981
|
+
const ownerId = deps.getOwnerId();
|
|
51982
|
+
if (!ownerId) throw new Error("larkBot bind requires feishu login (owner identity)");
|
|
51983
|
+
const name = botName ?? deps.getPersonaName(personaId2) ?? personaId2;
|
|
51984
|
+
await deps.cloud.bind({ personaId: personaId2, appId, appSecret, botName: name, tunnelUrl, ownerId });
|
|
51985
|
+
deps.store.write(personaId2, { appId, botName: name, boundAt: now() });
|
|
51986
|
+
emit(personaId2, { state: "bound", appId, botName: name, groups: groupsOf(personaId2) });
|
|
51987
|
+
return { response: { type: "larkBot:bindManual:ok" } };
|
|
51988
|
+
};
|
|
51989
|
+
const unbind = async (frame) => {
|
|
51990
|
+
const { personaId: personaId2 } = parseArgs2(LarkBotUnbindArgs, frame, "larkBot:unbind");
|
|
51991
|
+
const meta = deps.store.read(personaId2);
|
|
51992
|
+
if (!meta) throw new Error(`larkBot not bound: ${personaId2}`);
|
|
51993
|
+
try {
|
|
51994
|
+
await deps.cloud.unbind(meta.appId);
|
|
51995
|
+
} catch (err) {
|
|
51996
|
+
if (err.status !== 404) throw err;
|
|
51997
|
+
deps.logger?.warn(`larkBot unbind: cloud binding already gone: ${meta.appId}`);
|
|
51998
|
+
}
|
|
51999
|
+
deps.store.remove(personaId2);
|
|
52000
|
+
emit(personaId2, { state: "unbound", groups: [] });
|
|
52001
|
+
return { response: { type: "larkBot:unbind:ok" } };
|
|
52002
|
+
};
|
|
52003
|
+
const status = async (frame) => {
|
|
52004
|
+
const { personaId: personaId2 } = parseArgs2(LarkBotStatusArgs, frame, "larkBot:status");
|
|
52005
|
+
const meta = deps.store.read(personaId2);
|
|
52006
|
+
if (!meta) {
|
|
52007
|
+
return {
|
|
52008
|
+
response: { type: "larkBot:status:ok", state: "unbound", groups: [] }
|
|
52009
|
+
};
|
|
52010
|
+
}
|
|
52011
|
+
let cloudBinding;
|
|
52012
|
+
try {
|
|
52013
|
+
cloudBinding = (await deps.cloud.listBindings()).find((b2) => b2.personaId === personaId2);
|
|
52014
|
+
} catch (err) {
|
|
52015
|
+
deps.logger?.warn(`larkBot status: cloud unreachable: ${err.message}`);
|
|
52016
|
+
}
|
|
52017
|
+
const broken = cloudBinding?.status === "broken";
|
|
52018
|
+
const result = {
|
|
52019
|
+
state: broken ? "broken" : "bound",
|
|
52020
|
+
appId: meta.appId,
|
|
52021
|
+
botName: meta.botName,
|
|
52022
|
+
...broken ? { brokenReason: cloudBinding?.brokenReason ?? "unknown" } : {},
|
|
52023
|
+
groups: groupsOf(personaId2)
|
|
52024
|
+
};
|
|
52025
|
+
return { response: { type: "larkBot:status:ok", ...result } };
|
|
52026
|
+
};
|
|
52027
|
+
return {
|
|
52028
|
+
"larkBot:provision": provision,
|
|
52029
|
+
"larkBot:provisionCancel": provisionCancel,
|
|
52030
|
+
"larkBot:bindManual": bindManual,
|
|
52031
|
+
"larkBot:unbind": unbind,
|
|
52032
|
+
"larkBot:status": status
|
|
52033
|
+
};
|
|
52034
|
+
}
|
|
52035
|
+
async function refreshTunnelUrlOnStartup(deps) {
|
|
52036
|
+
if (deps.listBoundPersonaIds().length === 0) return;
|
|
52037
|
+
const tunnelUrl = deps.getTunnelUrl();
|
|
52038
|
+
if (!tunnelUrl) return;
|
|
52039
|
+
try {
|
|
52040
|
+
await deps.cloud.updateTunnelUrl(tunnelUrl);
|
|
52041
|
+
} catch (err) {
|
|
52042
|
+
deps.logger?.warn(`larkBot tunnel refresh failed: ${err.message}`);
|
|
52043
|
+
}
|
|
52044
|
+
}
|
|
52045
|
+
|
|
52046
|
+
// src/lark-bot-connector/binding-store.ts
|
|
52047
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
52048
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
52049
|
+
function createLarkBotBindingStore(personaRoot) {
|
|
52050
|
+
const filePath = (personaId2) => import_node_path27.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
|
|
52051
|
+
const read = (personaId2) => {
|
|
52052
|
+
const file = filePath(personaId2);
|
|
52053
|
+
if (!import_node_fs26.default.existsSync(file)) return null;
|
|
52054
|
+
try {
|
|
52055
|
+
const raw = JSON.parse(import_node_fs26.default.readFileSync(file, "utf8"));
|
|
52056
|
+
if (typeof raw?.appId !== "string" || raw.appId.length === 0) return null;
|
|
52057
|
+
return raw;
|
|
52058
|
+
} catch {
|
|
52059
|
+
return null;
|
|
52060
|
+
}
|
|
52061
|
+
};
|
|
52062
|
+
const write = (personaId2, meta) => {
|
|
52063
|
+
const file = filePath(personaId2);
|
|
52064
|
+
import_node_fs26.default.mkdirSync(import_node_path27.default.dirname(file), { recursive: true });
|
|
52065
|
+
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
52066
|
+
import_node_fs26.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
|
|
52067
|
+
import_node_fs26.default.renameSync(tmp, file);
|
|
52068
|
+
};
|
|
52069
|
+
return {
|
|
52070
|
+
read,
|
|
52071
|
+
write,
|
|
52072
|
+
remove(personaId2) {
|
|
52073
|
+
import_node_fs26.default.rmSync(filePath(personaId2), { force: true });
|
|
52074
|
+
},
|
|
52075
|
+
addRemovedChat(personaId2, chatId) {
|
|
52076
|
+
const meta = read(personaId2);
|
|
52077
|
+
if (!meta) return;
|
|
52078
|
+
const set = new Set(meta.removedChatIds ?? []);
|
|
52079
|
+
set.add(chatId);
|
|
52080
|
+
write(personaId2, { ...meta, removedChatIds: [...set] });
|
|
52081
|
+
}
|
|
52082
|
+
};
|
|
52083
|
+
}
|
|
52084
|
+
|
|
52085
|
+
// src/lark-bot-connector/cloud-client.ts
|
|
52086
|
+
var LarkBotCloudError = class extends Error {
|
|
52087
|
+
constructor(message, status) {
|
|
52088
|
+
super(message);
|
|
52089
|
+
this.status = status;
|
|
52090
|
+
this.name = "LarkBotCloudError";
|
|
52091
|
+
}
|
|
52092
|
+
status;
|
|
52093
|
+
};
|
|
52094
|
+
function createLarkBotCloudClient(opts) {
|
|
52095
|
+
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
52096
|
+
if (!f) throw new Error("fetch is not available (Node >= 18 required)");
|
|
52097
|
+
const base = opts.api.replace(/\/+$/, "");
|
|
52098
|
+
async function request(method, pathname, body) {
|
|
52099
|
+
const ac = new AbortController();
|
|
52100
|
+
const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? 15e3);
|
|
52101
|
+
let res;
|
|
52102
|
+
try {
|
|
52103
|
+
res = await f(`${base}${pathname}`, {
|
|
52104
|
+
method,
|
|
52105
|
+
signal: ac.signal,
|
|
52106
|
+
headers: {
|
|
52107
|
+
authorization: `Bearer ${opts.apiKey}`,
|
|
52108
|
+
"x-did": encodeURIComponent(opts.deviceId),
|
|
52109
|
+
"x-name": encodeURIComponent(opts.displayName),
|
|
52110
|
+
"x-scene": "daemon",
|
|
52111
|
+
"content-type": "application/json"
|
|
52112
|
+
},
|
|
52113
|
+
body: body ? JSON.stringify(body) : void 0
|
|
52114
|
+
});
|
|
52115
|
+
} catch (err) {
|
|
52116
|
+
throw new LarkBotCloudError(`lark-bot cloud request failed: ${err.message}`);
|
|
52117
|
+
} finally {
|
|
52118
|
+
clearTimeout(timer);
|
|
52119
|
+
}
|
|
52120
|
+
let json = {};
|
|
52121
|
+
try {
|
|
52122
|
+
json = await res.json();
|
|
52123
|
+
} catch {
|
|
52124
|
+
json = {};
|
|
52125
|
+
}
|
|
52126
|
+
if (!res.ok) {
|
|
52127
|
+
throw new LarkBotCloudError(
|
|
52128
|
+
`lark-bot cloud ${method} ${pathname}: HTTP ${res.status} ${JSON.stringify(json).slice(0, 200)}`,
|
|
52129
|
+
res.status
|
|
52130
|
+
);
|
|
52131
|
+
}
|
|
52132
|
+
return json;
|
|
52133
|
+
}
|
|
52134
|
+
return {
|
|
52135
|
+
async bind(args) {
|
|
52136
|
+
await request("PUT", "/api/lark-bot/bind", { ...args });
|
|
52137
|
+
},
|
|
52138
|
+
async unbind(appId) {
|
|
52139
|
+
await request("DELETE", `/api/lark-bot/bind/${encodeURIComponent(appId)}`);
|
|
52140
|
+
},
|
|
52141
|
+
async listBindings() {
|
|
52142
|
+
const json = await request("GET", "/api/lark-bot/bindings");
|
|
52143
|
+
return json.items ?? [];
|
|
52144
|
+
},
|
|
52145
|
+
async updateTunnelUrl(tunnelUrl) {
|
|
52146
|
+
await request("PATCH", "/api/lark-bot/tunnel", { tunnelUrl });
|
|
52147
|
+
},
|
|
52148
|
+
async reply(args) {
|
|
52149
|
+
await request("POST", "/api/lark-bot/reply", { ...args });
|
|
52150
|
+
},
|
|
52151
|
+
async claimEvents() {
|
|
52152
|
+
const json = await request("POST", "/api/lark-bot/events/claim");
|
|
52153
|
+
return json.items ?? [];
|
|
52154
|
+
}
|
|
52155
|
+
};
|
|
52156
|
+
}
|
|
52157
|
+
|
|
52158
|
+
// src/lark-bot-connector/chat-router.ts
|
|
52159
|
+
var ERROR_REPLY_TEXT = "\u5904\u7406\u51FA\u9519\u4E86\uFF0C\u8BF7\u91CD\u8BD5";
|
|
52160
|
+
var DEFAULT_TURN_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
52161
|
+
function createLarkChatRouter(deps) {
|
|
52162
|
+
const timeoutMs = deps.turnTimeoutMs ?? DEFAULT_TURN_TIMEOUT_MS;
|
|
52163
|
+
const replyDelays = deps.replyRetryDelaysMs ?? [2e3, 8e3, 3e4];
|
|
52164
|
+
const sleep2 = deps.sleepImpl ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
52165
|
+
const queues = /* @__PURE__ */ new Map();
|
|
52166
|
+
const activity = /* @__PURE__ */ new Map();
|
|
52167
|
+
const runOne = async (env) => {
|
|
52168
|
+
if (!env.messageId) {
|
|
52169
|
+
deps.logger?.warn(`larkBot chat-router: message envelope missing messageId, drop ${env.eventId}`);
|
|
52170
|
+
return;
|
|
52171
|
+
}
|
|
52172
|
+
const chatLabel = env.chatName ?? env.chatId;
|
|
52173
|
+
const text = `[\u98DE\u4E66\u7FA4\xB7${chatLabel}] ${env.senderName ?? env.senderOpenId ?? "\u672A\u77E5\u6210\u5458"}: ${env.text ?? ""}`;
|
|
52174
|
+
const turn = deps.manager.runLarkChatTurn({
|
|
52175
|
+
personaId: env.personaId,
|
|
52176
|
+
chatId: env.chatId,
|
|
52177
|
+
chatName: env.chatName,
|
|
52178
|
+
senderOpenId: env.senderOpenId ?? "",
|
|
52179
|
+
senderName: env.senderName ?? env.senderOpenId ?? "\u672A\u77E5\u6210\u5458",
|
|
52180
|
+
text
|
|
52181
|
+
});
|
|
52182
|
+
activity.set(env.chatId, {
|
|
52183
|
+
chatId: env.chatId,
|
|
52184
|
+
chatName: env.chatName,
|
|
52185
|
+
lastActiveAt: Date.now(),
|
|
52186
|
+
personaId: env.personaId
|
|
52187
|
+
});
|
|
52188
|
+
let timedOut = false;
|
|
52189
|
+
let timer;
|
|
52190
|
+
const timeout = new Promise((resolve6) => {
|
|
52191
|
+
timer = setTimeout(() => {
|
|
52192
|
+
timedOut = true;
|
|
52193
|
+
turn.kill();
|
|
52194
|
+
resolve6({ error: "turn timeout" });
|
|
52195
|
+
}, timeoutMs);
|
|
52196
|
+
});
|
|
52197
|
+
let result;
|
|
52198
|
+
try {
|
|
52199
|
+
result = await Promise.race([turn.ended, timeout]);
|
|
52200
|
+
} finally {
|
|
52201
|
+
clearTimeout(timer);
|
|
52202
|
+
}
|
|
52203
|
+
const replyText = "ok" in result && result.ok ? result.replyText : ERROR_REPLY_TEXT;
|
|
52204
|
+
if (!("ok" in result)) {
|
|
52205
|
+
deps.logger?.warn(
|
|
52206
|
+
`larkBot turn ${timedOut ? "timeout" : "error"} (${env.chatId}): ${result.error}`
|
|
52207
|
+
);
|
|
52208
|
+
}
|
|
52209
|
+
for (let attempt = 0; attempt <= replyDelays.length; attempt++) {
|
|
52210
|
+
if (attempt > 0) await sleep2(replyDelays[attempt - 1]);
|
|
52211
|
+
try {
|
|
52212
|
+
await deps.cloud.reply({
|
|
52213
|
+
appId: env.appId,
|
|
52214
|
+
chatId: env.chatId,
|
|
52215
|
+
replyToMessageId: env.messageId,
|
|
52216
|
+
text: replyText,
|
|
52217
|
+
eventId: env.eventId
|
|
52218
|
+
});
|
|
52219
|
+
return;
|
|
52220
|
+
} catch (err) {
|
|
52221
|
+
deps.logger?.warn(
|
|
52222
|
+
`larkBot reply attempt ${attempt + 1} failed (${env.chatId}): ${err.message}`
|
|
52223
|
+
);
|
|
52224
|
+
}
|
|
52225
|
+
}
|
|
52226
|
+
};
|
|
52227
|
+
return {
|
|
52228
|
+
handleEnvelope(env) {
|
|
52229
|
+
if (env.type === "bot_removed") {
|
|
52230
|
+
deps.store.addRemovedChat(env.personaId, env.chatId);
|
|
52231
|
+
activity.delete(env.chatId);
|
|
52232
|
+
queues.delete(env.chatId);
|
|
52233
|
+
deps.logger?.info(`larkBot removed from chat ${env.chatId} (persona ${env.personaId})`);
|
|
52234
|
+
return;
|
|
52235
|
+
}
|
|
52236
|
+
const prev = queues.get(env.chatId) ?? Promise.resolve();
|
|
52237
|
+
const next = prev.then(
|
|
52238
|
+
() => runOne(env).catch(
|
|
52239
|
+
(err) => deps.logger?.warn(`larkBot chat-router runOne failed: ${err.message}`)
|
|
52240
|
+
)
|
|
52241
|
+
);
|
|
52242
|
+
queues.set(env.chatId, next);
|
|
52243
|
+
void next.finally(() => {
|
|
52244
|
+
if (queues.get(env.chatId) === next) queues.delete(env.chatId);
|
|
52245
|
+
});
|
|
52246
|
+
},
|
|
52247
|
+
listLarkSessions(personaId2) {
|
|
52248
|
+
return [...activity.values()].filter((a) => a.personaId === personaId2).map((a) => ({ chatId: a.chatId, chatName: a.chatName, lastActiveAt: a.lastActiveAt }));
|
|
52249
|
+
}
|
|
52250
|
+
};
|
|
52251
|
+
}
|
|
52252
|
+
|
|
52253
|
+
// src/lark-bot-connector/envelope.ts
|
|
52254
|
+
var import_node_crypto6 = require("crypto");
|
|
52255
|
+
var LARK_ENVELOPE_PREFIX = "clawdlbe1";
|
|
52256
|
+
function verifyLarkEventEnvelope(args) {
|
|
52257
|
+
const { token, publicKeyPem } = args;
|
|
52258
|
+
const now = args.nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
52259
|
+
const parts = token.split(".");
|
|
52260
|
+
if (parts.length !== 3 || parts[0] !== LARK_ENVELOPE_PREFIX) {
|
|
52261
|
+
return { ok: false, reason: "BAD_FORMAT" };
|
|
52262
|
+
}
|
|
52263
|
+
const [prefix, payloadB64, sigB64] = parts;
|
|
52264
|
+
let envelope;
|
|
52265
|
+
try {
|
|
52266
|
+
envelope = JSON.parse(Buffer.from(payloadB64, "base64url").toString("utf8"));
|
|
52267
|
+
} catch {
|
|
52268
|
+
return { ok: false, reason: "BAD_FORMAT" };
|
|
52269
|
+
}
|
|
52270
|
+
const data = Buffer.from(`${prefix}.${payloadB64}`, "utf8");
|
|
52271
|
+
let sigOk = false;
|
|
52272
|
+
try {
|
|
52273
|
+
sigOk = (0, import_node_crypto6.verify)(null, data, publicKeyPem, Buffer.from(sigB64, "base64url"));
|
|
52274
|
+
} catch {
|
|
52275
|
+
sigOk = false;
|
|
52276
|
+
}
|
|
52277
|
+
if (!sigOk) return { ok: false, reason: "BAD_SIGNATURE" };
|
|
52278
|
+
if (typeof envelope.exp !== "number" || envelope.exp <= now) {
|
|
52279
|
+
return { ok: false, reason: "EXPIRED" };
|
|
52280
|
+
}
|
|
52281
|
+
return { ok: true, envelope };
|
|
52282
|
+
}
|
|
52283
|
+
|
|
52284
|
+
// src/lark-bot-connector/event-endpoint.ts
|
|
52285
|
+
var DEFAULT_DEDUPE_CAPACITY = 1024;
|
|
52286
|
+
function createLarkEventDedupe(capacity = DEFAULT_DEDUPE_CAPACITY) {
|
|
52287
|
+
const seen = /* @__PURE__ */ new Map();
|
|
52288
|
+
return {
|
|
52289
|
+
has: (id) => seen.has(id),
|
|
52290
|
+
add: (id) => {
|
|
52291
|
+
if (seen.has(id)) return;
|
|
52292
|
+
seen.set(id, true);
|
|
52293
|
+
if (seen.size > capacity) {
|
|
52294
|
+
const oldest = seen.keys().next().value;
|
|
52295
|
+
if (oldest !== void 0) seen.delete(oldest);
|
|
52296
|
+
}
|
|
52297
|
+
}
|
|
52298
|
+
};
|
|
52299
|
+
}
|
|
52300
|
+
function createLarkBotEventEndpoint(deps) {
|
|
52301
|
+
const seen = deps.dedupe ?? createLarkEventDedupe(deps.dedupeCapacity ?? DEFAULT_DEDUPE_CAPACITY);
|
|
52302
|
+
return (rawBody) => {
|
|
52303
|
+
const publicKeyPem = deps.getPublicKey();
|
|
52304
|
+
if (!publicKeyPem) {
|
|
52305
|
+
return { status: 503, body: { code: "SERVER_KEY_UNAVAILABLE", message: "server public key not cached yet" } };
|
|
52306
|
+
}
|
|
52307
|
+
const r = verifyLarkEventEnvelope({
|
|
52308
|
+
token: rawBody.trim(),
|
|
52309
|
+
publicKeyPem,
|
|
52310
|
+
nowSeconds: deps.nowSeconds?.()
|
|
52311
|
+
});
|
|
52312
|
+
if (!r.ok) {
|
|
52313
|
+
return { status: 401, body: { code: r.reason, message: `lark event envelope rejected: ${r.reason}` } };
|
|
52314
|
+
}
|
|
52315
|
+
const { envelope } = r;
|
|
52316
|
+
if (seen.has(envelope.eventId)) {
|
|
52317
|
+
return { status: 202, body: { ok: true, deduped: true } };
|
|
52318
|
+
}
|
|
52319
|
+
seen.add(envelope.eventId);
|
|
52320
|
+
try {
|
|
52321
|
+
deps.route(envelope);
|
|
52322
|
+
} catch (err) {
|
|
52323
|
+
deps.logger?.warn(`larkBot event route failed: ${err.message}`);
|
|
52324
|
+
}
|
|
52325
|
+
return { status: 202, body: { ok: true } };
|
|
52326
|
+
};
|
|
52327
|
+
}
|
|
52328
|
+
|
|
51529
52329
|
// src/ticket/constants.ts
|
|
51530
52330
|
var DEFAULT_CLAWD_TICKETS_API_KEY = "cf057f047674896978ddcc813adbc4a186551a6fcf59ad9d";
|
|
51531
52331
|
function resolveClawdTicketsApiKey() {
|
|
@@ -52137,7 +52937,7 @@ var CodexHistoryReader = class {
|
|
|
52137
52937
|
};
|
|
52138
52938
|
|
|
52139
52939
|
// src/tools/codex-skills.ts
|
|
52140
|
-
var
|
|
52940
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
52141
52941
|
function str3(v2) {
|
|
52142
52942
|
return typeof v2 === "string" ? v2 : void 0;
|
|
52143
52943
|
}
|
|
@@ -52152,13 +52952,13 @@ function mapSkillsListResponse(res) {
|
|
|
52152
52952
|
const r = s ?? {};
|
|
52153
52953
|
const name = str3(r.name);
|
|
52154
52954
|
if (!name) continue;
|
|
52155
|
-
const
|
|
52955
|
+
const path78 = str3(r.path);
|
|
52156
52956
|
const description = str3(r.description);
|
|
52157
52957
|
const isPlugin = name.includes(":");
|
|
52158
52958
|
out.push({
|
|
52159
52959
|
name,
|
|
52160
52960
|
source: isPlugin ? "plugin" : "project",
|
|
52161
|
-
...
|
|
52961
|
+
...path78 ? { path: path78 } : {},
|
|
52162
52962
|
...description ? { description } : {},
|
|
52163
52963
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
52164
52964
|
});
|
|
@@ -52174,30 +52974,30 @@ async function listCodexSkills(cwd, deps = {}) {
|
|
|
52174
52974
|
// 先写 extraRoots 再写 list(stdio 按写入顺序处理,fire-and-forget 不 await 回包;
|
|
52175
52975
|
// codex-session.ts ready 序列同款,两处保持一致)。失败不阻塞 list。
|
|
52176
52976
|
beforeRequest: (client) => {
|
|
52177
|
-
void client.request("skills/extraRoots/set", { extraRoots: [
|
|
52977
|
+
void client.request("skills/extraRoots/set", { extraRoots: [import_node_path28.default.join(cwd, ".claude", "skills")] }).catch(() => void 0);
|
|
52178
52978
|
}
|
|
52179
52979
|
});
|
|
52180
52980
|
return mapSkillsListResponse(res);
|
|
52181
52981
|
}
|
|
52182
52982
|
|
|
52183
52983
|
// src/workspace/browser.ts
|
|
52184
|
-
var
|
|
52984
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
52185
52985
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
52186
|
-
var
|
|
52986
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
52187
52987
|
init_protocol();
|
|
52188
52988
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
52189
52989
|
function resolveInsideCwd(cwd, subpath) {
|
|
52190
|
-
const absCwd =
|
|
52191
|
-
const joined =
|
|
52192
|
-
const rel =
|
|
52193
|
-
if (rel.startsWith("..") ||
|
|
52990
|
+
const absCwd = import_node_path29.default.resolve(cwd);
|
|
52991
|
+
const joined = import_node_path29.default.resolve(absCwd, subpath ?? ".");
|
|
52992
|
+
const rel = import_node_path29.default.relative(absCwd, joined);
|
|
52993
|
+
if (rel.startsWith("..") || import_node_path29.default.isAbsolute(rel)) {
|
|
52194
52994
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `path escapes cwd: ${subpath}`);
|
|
52195
52995
|
}
|
|
52196
52996
|
return joined;
|
|
52197
52997
|
}
|
|
52198
52998
|
function ensureCwd(cwd) {
|
|
52199
52999
|
try {
|
|
52200
|
-
const stat =
|
|
53000
|
+
const stat = import_node_fs27.default.statSync(cwd);
|
|
52201
53001
|
if (!stat.isDirectory()) {
|
|
52202
53002
|
throw new ClawdError(ERROR_CODES.INVALID_CWD, `not a directory: ${cwd}`);
|
|
52203
53003
|
}
|
|
@@ -52211,7 +53011,7 @@ var WorkspaceBrowser = class {
|
|
|
52211
53011
|
const cwd = args.cwd && args.cwd.length > 0 ? args.cwd : import_node_os8.default.homedir();
|
|
52212
53012
|
ensureCwd(cwd);
|
|
52213
53013
|
const full = resolveInsideCwd(cwd, args.path);
|
|
52214
|
-
const dirents =
|
|
53014
|
+
const dirents = import_node_fs27.default.readdirSync(full, { withFileTypes: true });
|
|
52215
53015
|
const entries = [];
|
|
52216
53016
|
for (const d of dirents) {
|
|
52217
53017
|
if (!args.showHidden && d.name.startsWith(".")) continue;
|
|
@@ -52221,7 +53021,7 @@ var WorkspaceBrowser = class {
|
|
|
52221
53021
|
mtime: ""
|
|
52222
53022
|
};
|
|
52223
53023
|
try {
|
|
52224
|
-
const st =
|
|
53024
|
+
const st = import_node_fs27.default.statSync(import_node_path29.default.join(full, d.name));
|
|
52225
53025
|
entry.mtime = new Date(st.mtimeMs).toISOString();
|
|
52226
53026
|
if (d.isFile()) entry.size = st.size;
|
|
52227
53027
|
} catch {
|
|
@@ -52237,14 +53037,14 @@ var WorkspaceBrowser = class {
|
|
|
52237
53037
|
read(args) {
|
|
52238
53038
|
ensureCwd(args.cwd);
|
|
52239
53039
|
const full = resolveInsideCwd(args.cwd, args.path);
|
|
52240
|
-
const st =
|
|
53040
|
+
const st = import_node_fs27.default.statSync(full);
|
|
52241
53041
|
if (!st.isFile()) {
|
|
52242
53042
|
throw new ClawdError(ERROR_CODES.INVALID_PATH, `not a file: ${args.path}`);
|
|
52243
53043
|
}
|
|
52244
53044
|
if (st.size > MAX_FILE_BYTES) {
|
|
52245
53045
|
throw new ClawdError(ERROR_CODES.FILE_TOO_LARGE, `file > ${MAX_FILE_BYTES} bytes`);
|
|
52246
53046
|
}
|
|
52247
|
-
const buf =
|
|
53047
|
+
const buf = import_node_fs27.default.readFileSync(full);
|
|
52248
53048
|
const isBinary = buf.includes(0);
|
|
52249
53049
|
if (isBinary) {
|
|
52250
53050
|
return {
|
|
@@ -52266,20 +53066,20 @@ var WorkspaceBrowser = class {
|
|
|
52266
53066
|
};
|
|
52267
53067
|
|
|
52268
53068
|
// src/skills/agents-scanner.ts
|
|
52269
|
-
var
|
|
53069
|
+
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
52270
53070
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
52271
|
-
var
|
|
53071
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
52272
53072
|
var DEFAULT_POLICY_DIR_DARWIN = "/Library/Application Support/ClaudeCode/.claude/agents";
|
|
52273
53073
|
function isDirLikeSync2(p2) {
|
|
52274
53074
|
try {
|
|
52275
|
-
return
|
|
53075
|
+
return import_node_fs28.default.statSync(p2).isDirectory();
|
|
52276
53076
|
} catch {
|
|
52277
53077
|
return false;
|
|
52278
53078
|
}
|
|
52279
53079
|
}
|
|
52280
53080
|
function fileExistsSync(p2) {
|
|
52281
53081
|
try {
|
|
52282
|
-
return
|
|
53082
|
+
return import_node_fs28.default.statSync(p2).isFile();
|
|
52283
53083
|
} catch {
|
|
52284
53084
|
return false;
|
|
52285
53085
|
}
|
|
@@ -52287,7 +53087,7 @@ function fileExistsSync(p2) {
|
|
|
52287
53087
|
function parseAgentFile(filePath) {
|
|
52288
53088
|
let content;
|
|
52289
53089
|
try {
|
|
52290
|
-
content =
|
|
53090
|
+
content = import_node_fs28.default.readFileSync(filePath, "utf8");
|
|
52291
53091
|
} catch {
|
|
52292
53092
|
return {};
|
|
52293
53093
|
}
|
|
@@ -52300,16 +53100,16 @@ function parseAgentFile(filePath) {
|
|
|
52300
53100
|
function scanAgentsDir(dir, source, seen, out) {
|
|
52301
53101
|
let entries;
|
|
52302
53102
|
try {
|
|
52303
|
-
entries =
|
|
53103
|
+
entries = import_node_fs28.default.readdirSync(dir, { withFileTypes: true });
|
|
52304
53104
|
} catch {
|
|
52305
53105
|
return;
|
|
52306
53106
|
}
|
|
52307
53107
|
for (const ent of entries) {
|
|
52308
53108
|
if (!ent.name.endsWith(".md")) continue;
|
|
52309
|
-
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(
|
|
53109
|
+
if (!ent.isFile() && !(ent.isSymbolicLink() && fileExistsSync(import_node_path30.default.join(dir, ent.name)))) {
|
|
52310
53110
|
continue;
|
|
52311
53111
|
}
|
|
52312
|
-
const filePath =
|
|
53112
|
+
const filePath = import_node_path30.default.join(dir, ent.name);
|
|
52313
53113
|
const baseName = ent.name.replace(/\.md$/, "");
|
|
52314
53114
|
if (seen.has(baseName)) continue;
|
|
52315
53115
|
seen.add(baseName);
|
|
@@ -52327,12 +53127,12 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
52327
53127
|
function walk2(dir, namespaces) {
|
|
52328
53128
|
let entries;
|
|
52329
53129
|
try {
|
|
52330
|
-
entries =
|
|
53130
|
+
entries = import_node_fs28.default.readdirSync(dir, { withFileTypes: true });
|
|
52331
53131
|
} catch {
|
|
52332
53132
|
return;
|
|
52333
53133
|
}
|
|
52334
53134
|
for (const ent of entries) {
|
|
52335
|
-
const childPath =
|
|
53135
|
+
const childPath = import_node_path30.default.join(dir, ent.name);
|
|
52336
53136
|
if (ent.isDirectory() || ent.isSymbolicLink() && isDirLikeSync2(childPath)) {
|
|
52337
53137
|
walk2(childPath, [...namespaces, ent.name]);
|
|
52338
53138
|
continue;
|
|
@@ -52357,13 +53157,13 @@ function scanPluginAgentsTree(root, pluginName, seen, out) {
|
|
|
52357
53157
|
walk2(root, []);
|
|
52358
53158
|
}
|
|
52359
53159
|
function readInstalledPlugins2(home) {
|
|
52360
|
-
const pluginsDir =
|
|
52361
|
-
const v2 =
|
|
52362
|
-
const v1 =
|
|
53160
|
+
const pluginsDir = import_node_path30.default.join(home, ".claude", "plugins");
|
|
53161
|
+
const v2 = import_node_path30.default.join(pluginsDir, "installed_plugins_v2.json");
|
|
53162
|
+
const v1 = import_node_path30.default.join(pluginsDir, "installed_plugins.json");
|
|
52363
53163
|
let raw = null;
|
|
52364
53164
|
for (const candidate of [v2, v1]) {
|
|
52365
53165
|
try {
|
|
52366
|
-
raw =
|
|
53166
|
+
raw = import_node_fs28.default.readFileSync(candidate, "utf8");
|
|
52367
53167
|
break;
|
|
52368
53168
|
} catch {
|
|
52369
53169
|
}
|
|
@@ -52388,19 +53188,19 @@ function readInstalledPlugins2(home) {
|
|
|
52388
53188
|
return out;
|
|
52389
53189
|
}
|
|
52390
53190
|
function walkUpProjectAgentsDirs(startCwd, home, seen, out) {
|
|
52391
|
-
let cur =
|
|
52392
|
-
const fsRoot =
|
|
53191
|
+
let cur = import_node_path30.default.resolve(startCwd);
|
|
53192
|
+
const fsRoot = import_node_path30.default.parse(cur).root;
|
|
52393
53193
|
while (true) {
|
|
52394
|
-
scanAgentsDir(
|
|
53194
|
+
scanAgentsDir(import_node_path30.default.join(cur, ".claude", "agents"), "project", seen, out);
|
|
52395
53195
|
let hasGit = false;
|
|
52396
53196
|
try {
|
|
52397
|
-
hasGit =
|
|
53197
|
+
hasGit = import_node_fs28.default.existsSync(import_node_path30.default.join(cur, ".git"));
|
|
52398
53198
|
} catch {
|
|
52399
53199
|
}
|
|
52400
53200
|
if (hasGit) return;
|
|
52401
53201
|
if (cur === home) return;
|
|
52402
53202
|
if (cur === fsRoot) return;
|
|
52403
|
-
const parent =
|
|
53203
|
+
const parent = import_node_path30.default.dirname(cur);
|
|
52404
53204
|
if (parent === cur) return;
|
|
52405
53205
|
cur = parent;
|
|
52406
53206
|
}
|
|
@@ -52435,7 +53235,7 @@ var AgentsScanner = class {
|
|
|
52435
53235
|
}
|
|
52436
53236
|
const fsBlock = [];
|
|
52437
53237
|
scanAgentsDir(
|
|
52438
|
-
|
|
53238
|
+
import_node_path30.default.join(this.home, ".claude", "agents"),
|
|
52439
53239
|
"global",
|
|
52440
53240
|
seen,
|
|
52441
53241
|
fsBlock
|
|
@@ -52449,7 +53249,7 @@ var AgentsScanner = class {
|
|
|
52449
53249
|
...this.extraPluginRoots
|
|
52450
53250
|
];
|
|
52451
53251
|
for (const { name, root } of plugins) {
|
|
52452
|
-
const agentsRoot =
|
|
53252
|
+
const agentsRoot = import_node_path30.default.join(root, "agents");
|
|
52453
53253
|
scanPluginAgentsTree(agentsRoot, name, seen, fsBlock);
|
|
52454
53254
|
}
|
|
52455
53255
|
return [...builtinBlock, ...fsBlock];
|
|
@@ -52457,15 +53257,15 @@ var AgentsScanner = class {
|
|
|
52457
53257
|
};
|
|
52458
53258
|
|
|
52459
53259
|
// src/observer/session-observer.ts
|
|
52460
|
-
var
|
|
53260
|
+
var import_node_fs30 = __toESM(require("fs"), 1);
|
|
52461
53261
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
52462
|
-
var
|
|
53262
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
52463
53263
|
init_claude_history();
|
|
52464
53264
|
|
|
52465
53265
|
// src/observer/subagent-meta-observer.ts
|
|
52466
|
-
var
|
|
53266
|
+
var import_node_fs29 = __toESM(require("fs"), 1);
|
|
52467
53267
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
52468
|
-
var
|
|
53268
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
52469
53269
|
init_claude_history();
|
|
52470
53270
|
var META_RE = /^agent-([A-Za-z0-9_-]+)\.meta\.json$/;
|
|
52471
53271
|
var SubagentMetaObserver = class {
|
|
@@ -52478,7 +53278,7 @@ var SubagentMetaObserver = class {
|
|
|
52478
53278
|
watches = /* @__PURE__ */ new Map();
|
|
52479
53279
|
// public for spec only:测试直接拼路径写假 meta.json;生产 start() 内部自己解析
|
|
52480
53280
|
resolveSubagentDir(cwd, toolSessionId) {
|
|
52481
|
-
return
|
|
53281
|
+
return import_node_path31.default.join(
|
|
52482
53282
|
this.home,
|
|
52483
53283
|
".claude",
|
|
52484
53284
|
"projects",
|
|
@@ -52508,7 +53308,7 @@ var SubagentMetaObserver = class {
|
|
|
52508
53308
|
attachWatcher(w2) {
|
|
52509
53309
|
if (w2.watcher) return;
|
|
52510
53310
|
try {
|
|
52511
|
-
w2.watcher =
|
|
53311
|
+
w2.watcher = import_node_fs29.default.watch(w2.dirPath, { persistent: false }, (_evt, name) => {
|
|
52512
53312
|
if (!name) return;
|
|
52513
53313
|
const m2 = META_RE.exec(String(name));
|
|
52514
53314
|
if (!m2) return;
|
|
@@ -52520,7 +53320,7 @@ var SubagentMetaObserver = class {
|
|
|
52520
53320
|
scan(w2) {
|
|
52521
53321
|
let entries;
|
|
52522
53322
|
try {
|
|
52523
|
-
entries =
|
|
53323
|
+
entries = import_node_fs29.default.readdirSync(w2.dirPath);
|
|
52524
53324
|
} catch {
|
|
52525
53325
|
return;
|
|
52526
53326
|
}
|
|
@@ -52534,10 +53334,10 @@ var SubagentMetaObserver = class {
|
|
|
52534
53334
|
if (!m2) return;
|
|
52535
53335
|
const agentId = m2[1];
|
|
52536
53336
|
if (w2.emitted.has(agentId)) return;
|
|
52537
|
-
const file =
|
|
53337
|
+
const file = import_node_path31.default.join(w2.dirPath, name);
|
|
52538
53338
|
let raw;
|
|
52539
53339
|
try {
|
|
52540
|
-
raw =
|
|
53340
|
+
raw = import_node_fs29.default.readFileSync(file, "utf8");
|
|
52541
53341
|
} catch {
|
|
52542
53342
|
return;
|
|
52543
53343
|
}
|
|
@@ -52594,14 +53394,14 @@ var SessionObserver = class {
|
|
|
52594
53394
|
metaObserver;
|
|
52595
53395
|
resolveJsonlPath(cwd, toolSessionId, override) {
|
|
52596
53396
|
if (override) return override;
|
|
52597
|
-
return
|
|
53397
|
+
return import_node_path32.default.join(this.home, ".claude", "projects", cwdToHashDir(cwd), `${toolSessionId}.jsonl`);
|
|
52598
53398
|
}
|
|
52599
53399
|
start(args) {
|
|
52600
53400
|
this.stop(args.sessionId);
|
|
52601
53401
|
const filePath = this.resolveJsonlPath(args.cwd, args.toolSessionId, args.jsonlPath);
|
|
52602
53402
|
let size = 0;
|
|
52603
53403
|
try {
|
|
52604
|
-
size =
|
|
53404
|
+
size = import_node_fs30.default.statSync(filePath).size;
|
|
52605
53405
|
} catch {
|
|
52606
53406
|
}
|
|
52607
53407
|
const w2 = {
|
|
@@ -52614,16 +53414,16 @@ var SessionObserver = class {
|
|
|
52614
53414
|
adapter: args.adapter,
|
|
52615
53415
|
prevIsRejectSentinel: false,
|
|
52616
53416
|
toolSessionId: args.toolSessionId,
|
|
52617
|
-
sawFile:
|
|
53417
|
+
sawFile: import_node_fs30.default.existsSync(filePath),
|
|
52618
53418
|
lastRelocateScanMs: 0,
|
|
52619
53419
|
pendingCwdDerive: false,
|
|
52620
53420
|
lastDeriveMs: 0
|
|
52621
53421
|
};
|
|
52622
53422
|
try {
|
|
52623
|
-
|
|
53423
|
+
import_node_fs30.default.mkdirSync(import_node_path32.default.dirname(filePath), { recursive: true });
|
|
52624
53424
|
} catch {
|
|
52625
53425
|
}
|
|
52626
|
-
w2.watcher =
|
|
53426
|
+
w2.watcher = import_node_fs30.default.watch(import_node_path32.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
52627
53427
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
52628
53428
|
this.poll(w2);
|
|
52629
53429
|
});
|
|
@@ -52646,7 +53446,7 @@ var SessionObserver = class {
|
|
|
52646
53446
|
// 异常静默吞,不阻塞 watcher 启动
|
|
52647
53447
|
hydrateMetaTail(w2, maxLines = 200) {
|
|
52648
53448
|
try {
|
|
52649
|
-
const raw =
|
|
53449
|
+
const raw = import_node_fs30.default.readFileSync(w2.filePath, "utf8");
|
|
52650
53450
|
if (!raw) return;
|
|
52651
53451
|
const allLines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
52652
53452
|
if (allLines.length === 0) return;
|
|
@@ -52670,7 +53470,7 @@ var SessionObserver = class {
|
|
|
52670
53470
|
poll(w2) {
|
|
52671
53471
|
let size = 0;
|
|
52672
53472
|
try {
|
|
52673
|
-
size =
|
|
53473
|
+
size = import_node_fs30.default.statSync(w2.filePath).size;
|
|
52674
53474
|
} catch {
|
|
52675
53475
|
if (w2.sawFile) this.maybeRelocate(w2);
|
|
52676
53476
|
return;
|
|
@@ -52681,11 +53481,11 @@ var SessionObserver = class {
|
|
|
52681
53481
|
w2.buf = "";
|
|
52682
53482
|
}
|
|
52683
53483
|
if (size === w2.lastSize) return;
|
|
52684
|
-
const fd =
|
|
53484
|
+
const fd = import_node_fs30.default.openSync(w2.filePath, "r");
|
|
52685
53485
|
try {
|
|
52686
53486
|
const len = size - w2.lastSize;
|
|
52687
53487
|
const buf = Buffer.alloc(len);
|
|
52688
|
-
|
|
53488
|
+
import_node_fs30.default.readSync(fd, buf, 0, len, w2.lastSize);
|
|
52689
53489
|
w2.lastSize = size;
|
|
52690
53490
|
w2.buf += buf.toString("utf8");
|
|
52691
53491
|
let newlineIndex;
|
|
@@ -52708,7 +53508,7 @@ var SessionObserver = class {
|
|
|
52708
53508
|
}
|
|
52709
53509
|
}
|
|
52710
53510
|
} finally {
|
|
52711
|
-
|
|
53511
|
+
import_node_fs30.default.closeSync(fd);
|
|
52712
53512
|
}
|
|
52713
53513
|
if (w2.pendingCwdDerive) this.maybeDeriveCwd(w2);
|
|
52714
53514
|
}
|
|
@@ -52720,7 +53520,7 @@ var SessionObserver = class {
|
|
|
52720
53520
|
const now = Date.now();
|
|
52721
53521
|
if (now - w2.lastRelocateScanMs < 1e3) return;
|
|
52722
53522
|
w2.lastRelocateScanMs = now;
|
|
52723
|
-
const projectsRoot =
|
|
53523
|
+
const projectsRoot = import_node_path32.default.join(this.home, ".claude", "projects");
|
|
52724
53524
|
const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
|
|
52725
53525
|
if (!found || found === w2.filePath) return;
|
|
52726
53526
|
try {
|
|
@@ -52729,7 +53529,7 @@ var SessionObserver = class {
|
|
|
52729
53529
|
}
|
|
52730
53530
|
w2.filePath = found;
|
|
52731
53531
|
try {
|
|
52732
|
-
w2.watcher =
|
|
53532
|
+
w2.watcher = import_node_fs30.default.watch(import_node_path32.default.dirname(found), { persistent: false }, (_event, changedName) => {
|
|
52733
53533
|
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
52734
53534
|
this.poll(w2);
|
|
52735
53535
|
});
|
|
@@ -53524,8 +54324,8 @@ async function authenticate(token, deps) {
|
|
|
53524
54324
|
}
|
|
53525
54325
|
|
|
53526
54326
|
// src/legacy-cleanup.ts
|
|
53527
|
-
var
|
|
53528
|
-
var
|
|
54327
|
+
var fs35 = __toESM(require("fs/promises"), 1);
|
|
54328
|
+
var path37 = __toESM(require("path"), 1);
|
|
53529
54329
|
var LEGACY_FILES = [
|
|
53530
54330
|
"personal-capability.json",
|
|
53531
54331
|
"received-capabilities.json",
|
|
@@ -53534,9 +54334,9 @@ var LEGACY_FILES = [
|
|
|
53534
54334
|
async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
53535
54335
|
const removed = [];
|
|
53536
54336
|
for (const name of LEGACY_FILES) {
|
|
53537
|
-
const p2 =
|
|
54337
|
+
const p2 = path37.join(dataDir, name);
|
|
53538
54338
|
try {
|
|
53539
|
-
await
|
|
54339
|
+
await fs35.unlink(p2);
|
|
53540
54340
|
removed.push(name);
|
|
53541
54341
|
logger.debug("legacy capability file removed", { file: name });
|
|
53542
54342
|
} catch (err) {
|
|
@@ -53548,13 +54348,13 @@ async function cleanupLegacyCapabilityFiles(dataDir, logger) {
|
|
|
53548
54348
|
}
|
|
53549
54349
|
|
|
53550
54350
|
// src/inbox/inbox-store.ts
|
|
53551
|
-
var
|
|
53552
|
-
var
|
|
54351
|
+
var fs36 = __toESM(require("fs"), 1);
|
|
54352
|
+
var path38 = __toESM(require("path"), 1);
|
|
53553
54353
|
var INBOX_SUBDIR = "inbox";
|
|
53554
54354
|
var InboxStore = class {
|
|
53555
54355
|
constructor(dataDir) {
|
|
53556
54356
|
this.dataDir = dataDir;
|
|
53557
|
-
|
|
54357
|
+
fs36.mkdirSync(this.dirPath(), { recursive: true });
|
|
53558
54358
|
}
|
|
53559
54359
|
dataDir;
|
|
53560
54360
|
/**
|
|
@@ -53566,7 +54366,7 @@ var InboxStore = class {
|
|
|
53566
54366
|
const file = this.filePath(peerDeviceId);
|
|
53567
54367
|
let raw;
|
|
53568
54368
|
try {
|
|
53569
|
-
raw =
|
|
54369
|
+
raw = fs36.readFileSync(file, "utf8");
|
|
53570
54370
|
} catch (err) {
|
|
53571
54371
|
if (err?.code === "ENOENT") return [];
|
|
53572
54372
|
return [];
|
|
@@ -53582,7 +54382,7 @@ var InboxStore = class {
|
|
|
53582
54382
|
const dir = this.dirPath();
|
|
53583
54383
|
let entries;
|
|
53584
54384
|
try {
|
|
53585
|
-
entries =
|
|
54385
|
+
entries = fs36.readdirSync(dir);
|
|
53586
54386
|
} catch (err) {
|
|
53587
54387
|
if (err?.code === "ENOENT") return [];
|
|
53588
54388
|
return [];
|
|
@@ -53598,9 +54398,9 @@ var InboxStore = class {
|
|
|
53598
54398
|
if (existing.some((m2) => m2.id === message.id)) return;
|
|
53599
54399
|
const file = this.filePath(message.peerDeviceId);
|
|
53600
54400
|
const line = JSON.stringify(message) + "\n";
|
|
53601
|
-
|
|
54401
|
+
fs36.appendFileSync(file, line, { mode: 384 });
|
|
53602
54402
|
try {
|
|
53603
|
-
|
|
54403
|
+
fs36.chmodSync(file, 384);
|
|
53604
54404
|
} catch {
|
|
53605
54405
|
}
|
|
53606
54406
|
}
|
|
@@ -53630,7 +54430,7 @@ var InboxStore = class {
|
|
|
53630
54430
|
removeByPeerDeviceId(peerDeviceId) {
|
|
53631
54431
|
const file = this.filePath(peerDeviceId);
|
|
53632
54432
|
try {
|
|
53633
|
-
|
|
54433
|
+
fs36.unlinkSync(file);
|
|
53634
54434
|
} catch (err) {
|
|
53635
54435
|
if (err?.code === "ENOENT") return;
|
|
53636
54436
|
}
|
|
@@ -53639,18 +54439,18 @@ var InboxStore = class {
|
|
|
53639
54439
|
const file = this.filePath(peerDeviceId);
|
|
53640
54440
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
53641
54441
|
const content = messages.map((m2) => JSON.stringify(m2)).join("\n") + (messages.length > 0 ? "\n" : "");
|
|
53642
|
-
|
|
53643
|
-
|
|
54442
|
+
fs36.writeFileSync(tmp, content, { mode: 384 });
|
|
54443
|
+
fs36.renameSync(tmp, file);
|
|
53644
54444
|
try {
|
|
53645
|
-
|
|
54445
|
+
fs36.chmodSync(file, 384);
|
|
53646
54446
|
} catch {
|
|
53647
54447
|
}
|
|
53648
54448
|
}
|
|
53649
54449
|
dirPath() {
|
|
53650
|
-
return
|
|
54450
|
+
return path38.join(this.dataDir, INBOX_SUBDIR);
|
|
53651
54451
|
}
|
|
53652
54452
|
filePath(peerDeviceId) {
|
|
53653
|
-
return
|
|
54453
|
+
return path38.join(this.dirPath(), `${peerDeviceId}.jsonl`);
|
|
53654
54454
|
}
|
|
53655
54455
|
};
|
|
53656
54456
|
function parseAllLines(raw) {
|
|
@@ -53738,8 +54538,8 @@ var InboxManager = class {
|
|
|
53738
54538
|
};
|
|
53739
54539
|
|
|
53740
54540
|
// src/state/contact-store.ts
|
|
53741
|
-
var
|
|
53742
|
-
var
|
|
54541
|
+
var fs37 = __toESM(require("fs"), 1);
|
|
54542
|
+
var path39 = __toESM(require("path"), 1);
|
|
53743
54543
|
var FILE_NAME = "contacts.json";
|
|
53744
54544
|
var ContactStore = class {
|
|
53745
54545
|
constructor(dataDir) {
|
|
@@ -53749,10 +54549,10 @@ var ContactStore = class {
|
|
|
53749
54549
|
contacts = /* @__PURE__ */ new Map();
|
|
53750
54550
|
load() {
|
|
53751
54551
|
this.contacts.clear();
|
|
53752
|
-
const file =
|
|
54552
|
+
const file = path39.join(this.dataDir, FILE_NAME);
|
|
53753
54553
|
let raw;
|
|
53754
54554
|
try {
|
|
53755
|
-
raw =
|
|
54555
|
+
raw = fs37.readFileSync(file, "utf8");
|
|
53756
54556
|
} catch (err) {
|
|
53757
54557
|
if (err?.code !== "ENOENT") this.renameBak(file);
|
|
53758
54558
|
return;
|
|
@@ -53821,20 +54621,20 @@ var ContactStore = class {
|
|
|
53821
54621
|
return true;
|
|
53822
54622
|
}
|
|
53823
54623
|
flush() {
|
|
53824
|
-
const file =
|
|
54624
|
+
const file = path39.join(this.dataDir, FILE_NAME);
|
|
53825
54625
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
53826
54626
|
const content = JSON.stringify(
|
|
53827
54627
|
{ contacts: Array.from(this.contacts.values()) },
|
|
53828
54628
|
null,
|
|
53829
54629
|
2
|
|
53830
54630
|
);
|
|
53831
|
-
|
|
53832
|
-
|
|
53833
|
-
|
|
54631
|
+
fs37.mkdirSync(this.dataDir, { recursive: true });
|
|
54632
|
+
fs37.writeFileSync(tmp, content, { mode: 384 });
|
|
54633
|
+
fs37.renameSync(tmp, file);
|
|
53834
54634
|
}
|
|
53835
54635
|
renameBak(file) {
|
|
53836
54636
|
try {
|
|
53837
|
-
|
|
54637
|
+
fs37.renameSync(file, `${file}.bak`);
|
|
53838
54638
|
} catch {
|
|
53839
54639
|
}
|
|
53840
54640
|
}
|
|
@@ -53942,61 +54742,61 @@ async function connectRemote(args) {
|
|
|
53942
54742
|
}
|
|
53943
54743
|
|
|
53944
54744
|
// src/migrations/2026-05-20-flatten-sessions.ts
|
|
53945
|
-
var
|
|
53946
|
-
var
|
|
54745
|
+
var fs38 = __toESM(require("fs"), 1);
|
|
54746
|
+
var path40 = __toESM(require("path"), 1);
|
|
53947
54747
|
var MIGRATION_FLAG_NAME = ".migration.v1.done";
|
|
53948
54748
|
function migrateFlattenSessions(opts) {
|
|
53949
54749
|
const dataDir = opts.dataDir;
|
|
53950
54750
|
const now = opts.now ?? Date.now;
|
|
53951
|
-
const sessionsDir =
|
|
53952
|
-
const flagPath =
|
|
54751
|
+
const sessionsDir = path40.join(dataDir, "sessions");
|
|
54752
|
+
const flagPath = path40.join(sessionsDir, MIGRATION_FLAG_NAME);
|
|
53953
54753
|
if (existsSync3(flagPath)) {
|
|
53954
54754
|
return { skipped: true, flagWritten: false, movedBare: 0, movedVmOwner: 0, archivedListener: 0 };
|
|
53955
54755
|
}
|
|
53956
54756
|
let movedBare = 0;
|
|
53957
54757
|
let movedVmOwner = 0;
|
|
53958
54758
|
let archivedListener = 0;
|
|
53959
|
-
const defaultDir =
|
|
54759
|
+
const defaultDir = path40.join(sessionsDir, "default");
|
|
53960
54760
|
if (existsSync3(defaultDir)) {
|
|
53961
54761
|
for (const entry of readdirSafe(defaultDir)) {
|
|
53962
54762
|
if (!entry.endsWith(".json")) continue;
|
|
53963
|
-
const src =
|
|
53964
|
-
const dst =
|
|
53965
|
-
|
|
54763
|
+
const src = path40.join(defaultDir, entry);
|
|
54764
|
+
const dst = path40.join(sessionsDir, entry);
|
|
54765
|
+
fs38.renameSync(src, dst);
|
|
53966
54766
|
movedBare += 1;
|
|
53967
54767
|
}
|
|
53968
54768
|
rmdirIfEmpty(defaultDir);
|
|
53969
54769
|
}
|
|
53970
54770
|
for (const pid of readdirSafe(sessionsDir)) {
|
|
53971
|
-
const personaDir =
|
|
54771
|
+
const personaDir = path40.join(sessionsDir, pid);
|
|
53972
54772
|
if (!isDir(personaDir)) continue;
|
|
53973
54773
|
if (pid === "default") continue;
|
|
53974
|
-
const ownerSrc =
|
|
54774
|
+
const ownerSrc = path40.join(personaDir, "owner");
|
|
53975
54775
|
if (existsSync3(ownerSrc) && isDir(ownerSrc)) {
|
|
53976
|
-
const ownerDst =
|
|
53977
|
-
|
|
54776
|
+
const ownerDst = path40.join(dataDir, "personas", pid, ".clawd", "sessions", "owner");
|
|
54777
|
+
fs38.mkdirSync(ownerDst, { recursive: true });
|
|
53978
54778
|
for (const file of readdirSafe(ownerSrc)) {
|
|
53979
54779
|
if (!file.endsWith(".json")) continue;
|
|
53980
|
-
|
|
54780
|
+
fs38.renameSync(path40.join(ownerSrc, file), path40.join(ownerDst, file));
|
|
53981
54781
|
movedVmOwner += 1;
|
|
53982
54782
|
}
|
|
53983
54783
|
rmdirIfEmpty(ownerSrc);
|
|
53984
54784
|
}
|
|
53985
|
-
const listenerSrc =
|
|
54785
|
+
const listenerSrc = path40.join(personaDir, "listener");
|
|
53986
54786
|
if (existsSync3(listenerSrc) && isDir(listenerSrc)) {
|
|
53987
|
-
const archiveDst =
|
|
53988
|
-
|
|
54787
|
+
const archiveDst = path40.join(dataDir, ".legacy", `listener-${pid}`);
|
|
54788
|
+
fs38.mkdirSync(archiveDst, { recursive: true });
|
|
53989
54789
|
for (const file of readdirSafe(listenerSrc)) {
|
|
53990
54790
|
if (!file.endsWith(".json")) continue;
|
|
53991
|
-
|
|
54791
|
+
fs38.renameSync(path40.join(listenerSrc, file), path40.join(archiveDst, file));
|
|
53992
54792
|
archivedListener += 1;
|
|
53993
54793
|
}
|
|
53994
54794
|
rmdirIfEmpty(listenerSrc);
|
|
53995
54795
|
}
|
|
53996
54796
|
rmdirIfEmpty(personaDir);
|
|
53997
54797
|
}
|
|
53998
|
-
|
|
53999
|
-
|
|
54798
|
+
fs38.mkdirSync(sessionsDir, { recursive: true });
|
|
54799
|
+
fs38.writeFileSync(flagPath, JSON.stringify({ migratedAt: now() }, null, 2));
|
|
54000
54800
|
return {
|
|
54001
54801
|
skipped: false,
|
|
54002
54802
|
flagWritten: true,
|
|
@@ -54007,7 +54807,7 @@ function migrateFlattenSessions(opts) {
|
|
|
54007
54807
|
}
|
|
54008
54808
|
function existsSync3(p2) {
|
|
54009
54809
|
try {
|
|
54010
|
-
|
|
54810
|
+
fs38.statSync(p2);
|
|
54011
54811
|
return true;
|
|
54012
54812
|
} catch {
|
|
54013
54813
|
return false;
|
|
@@ -54015,31 +54815,31 @@ function existsSync3(p2) {
|
|
|
54015
54815
|
}
|
|
54016
54816
|
function isDir(p2) {
|
|
54017
54817
|
try {
|
|
54018
|
-
return
|
|
54818
|
+
return fs38.statSync(p2).isDirectory();
|
|
54019
54819
|
} catch {
|
|
54020
54820
|
return false;
|
|
54021
54821
|
}
|
|
54022
54822
|
}
|
|
54023
54823
|
function readdirSafe(p2) {
|
|
54024
54824
|
try {
|
|
54025
|
-
return
|
|
54825
|
+
return fs38.readdirSync(p2);
|
|
54026
54826
|
} catch {
|
|
54027
54827
|
return [];
|
|
54028
54828
|
}
|
|
54029
54829
|
}
|
|
54030
54830
|
function rmdirIfEmpty(p2) {
|
|
54031
54831
|
try {
|
|
54032
|
-
|
|
54832
|
+
fs38.rmdirSync(p2);
|
|
54033
54833
|
} catch {
|
|
54034
54834
|
}
|
|
54035
54835
|
}
|
|
54036
54836
|
|
|
54037
54837
|
// src/transport/http-router.ts
|
|
54038
|
-
var
|
|
54039
|
-
var
|
|
54838
|
+
var import_node_fs32 = __toESM(require("fs"), 1);
|
|
54839
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
54040
54840
|
|
|
54041
54841
|
// src/attachment/mime.ts
|
|
54042
|
-
var
|
|
54842
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
54043
54843
|
var TEXT_PLAIN = "text/plain; charset=utf-8";
|
|
54044
54844
|
var EXT_TO_NATIVE_MIME = {
|
|
54045
54845
|
// 图片
|
|
@@ -54146,14 +54946,14 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
54146
54946
|
".mk"
|
|
54147
54947
|
]);
|
|
54148
54948
|
function lookupMime(filePathOrName) {
|
|
54149
|
-
const ext =
|
|
54949
|
+
const ext = import_node_path33.default.extname(filePathOrName).toLowerCase();
|
|
54150
54950
|
if (EXT_TO_NATIVE_MIME[ext]) return EXT_TO_NATIVE_MIME[ext];
|
|
54151
54951
|
if (TEXT_EXTENSIONS.has(ext)) return TEXT_PLAIN;
|
|
54152
54952
|
return "application/octet-stream";
|
|
54153
54953
|
}
|
|
54154
54954
|
|
|
54155
54955
|
// src/attachment/sign-url.ts
|
|
54156
|
-
var
|
|
54956
|
+
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
54157
54957
|
var HMAC_ALGO = "sha256";
|
|
54158
54958
|
function base64urlEncode(buf) {
|
|
54159
54959
|
const b2 = typeof buf === "string" ? Buffer.from(buf, "utf8") : buf;
|
|
@@ -54171,7 +54971,7 @@ function decodeAbsPathFromUrl(encoded) {
|
|
|
54171
54971
|
var DOMAIN_PREFIX2 = "clawd-attach-v1|";
|
|
54172
54972
|
function computeSig(secret, absPath, e) {
|
|
54173
54973
|
const msg = e === null ? `${DOMAIN_PREFIX2}${absPath}` : `${DOMAIN_PREFIX2}${absPath}|${e}`;
|
|
54174
|
-
return
|
|
54974
|
+
return import_node_crypto7.default.createHmac(HMAC_ALGO, secret).update(msg).digest();
|
|
54175
54975
|
}
|
|
54176
54976
|
function signUrlParts(secret, absPath, ttlSeconds, now = Date.now) {
|
|
54177
54977
|
const e = ttlSeconds === null ? null : Math.floor(now() / 1e3) + ttlSeconds;
|
|
@@ -54206,7 +55006,7 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
54206
55006
|
if (provided.length !== expected.length) {
|
|
54207
55007
|
return { ok: false, code: "BAD_SIG" };
|
|
54208
55008
|
}
|
|
54209
|
-
if (!
|
|
55009
|
+
if (!import_node_crypto7.default.timingSafeEqual(provided, expected)) {
|
|
54210
55010
|
return { ok: false, code: "BAD_SIG" };
|
|
54211
55011
|
}
|
|
54212
55012
|
if (e !== null && now() / 1e3 > e) {
|
|
@@ -54216,9 +55016,9 @@ function verifySignedUrl(secret, absPath, eRaw, s, now = Date.now) {
|
|
|
54216
55016
|
}
|
|
54217
55017
|
|
|
54218
55018
|
// src/attachment/upload.ts
|
|
54219
|
-
var
|
|
54220
|
-
var
|
|
54221
|
-
var
|
|
55019
|
+
var import_node_fs31 = __toESM(require("fs"), 1);
|
|
55020
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
55021
|
+
var import_node_crypto8 = __toESM(require("crypto"), 1);
|
|
54222
55022
|
var import_promises3 = require("stream/promises");
|
|
54223
55023
|
var UploadError = class extends Error {
|
|
54224
55024
|
constructor(code, message) {
|
|
@@ -54229,24 +55029,24 @@ var UploadError = class extends Error {
|
|
|
54229
55029
|
code;
|
|
54230
55030
|
};
|
|
54231
55031
|
function assertValidFileName(fileName) {
|
|
54232
|
-
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !==
|
|
55032
|
+
if (fileName.length === 0 || fileName === "." || fileName === ".." || fileName.startsWith(".") || fileName.includes("/") || fileName.includes("\\") || fileName !== import_node_path34.default.basename(fileName)) {
|
|
54233
55033
|
throw new UploadError("INVALID_FILENAME", `fileName must be a plain basename, got: ${fileName}`);
|
|
54234
55034
|
}
|
|
54235
55035
|
}
|
|
54236
55036
|
var HASH_PREFIX_LEN = 16;
|
|
54237
55037
|
async function writeUploadedAttachment(args) {
|
|
54238
55038
|
assertValidFileName(args.fileName);
|
|
54239
|
-
const attachmentsRoot =
|
|
55039
|
+
const attachmentsRoot = import_node_path34.default.join(args.sessionDir, ".attachments");
|
|
54240
55040
|
try {
|
|
54241
|
-
|
|
55041
|
+
import_node_fs31.default.mkdirSync(attachmentsRoot, { recursive: true });
|
|
54242
55042
|
} catch (err) {
|
|
54243
55043
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
54244
55044
|
}
|
|
54245
|
-
const hasher =
|
|
55045
|
+
const hasher = import_node_crypto8.default.createHash("sha256");
|
|
54246
55046
|
let actualSize = 0;
|
|
54247
|
-
const tmpPath =
|
|
55047
|
+
const tmpPath = import_node_path34.default.join(
|
|
54248
55048
|
attachmentsRoot,
|
|
54249
|
-
`.upload-${process.pid}-${Date.now()}-${
|
|
55049
|
+
`.upload-${process.pid}-${Date.now()}-${import_node_crypto8.default.randomBytes(4).toString("hex")}`
|
|
54250
55050
|
);
|
|
54251
55051
|
try {
|
|
54252
55052
|
await (0, import_promises3.pipeline)(
|
|
@@ -54259,18 +55059,18 @@ async function writeUploadedAttachment(args) {
|
|
|
54259
55059
|
yield buf;
|
|
54260
55060
|
}
|
|
54261
55061
|
},
|
|
54262
|
-
|
|
55062
|
+
import_node_fs31.default.createWriteStream(tmpPath, { mode: 384 })
|
|
54263
55063
|
);
|
|
54264
55064
|
} catch (err) {
|
|
54265
55065
|
try {
|
|
54266
|
-
|
|
55066
|
+
import_node_fs31.default.unlinkSync(tmpPath);
|
|
54267
55067
|
} catch {
|
|
54268
55068
|
}
|
|
54269
55069
|
throw new UploadError("STORAGE_ERROR", `write failed: ${err.message}`);
|
|
54270
55070
|
}
|
|
54271
55071
|
if (actualSize !== args.contentLength) {
|
|
54272
55072
|
try {
|
|
54273
|
-
|
|
55073
|
+
import_node_fs31.default.unlinkSync(tmpPath);
|
|
54274
55074
|
} catch {
|
|
54275
55075
|
}
|
|
54276
55076
|
throw new UploadError(
|
|
@@ -54279,35 +55079,35 @@ async function writeUploadedAttachment(args) {
|
|
|
54279
55079
|
);
|
|
54280
55080
|
}
|
|
54281
55081
|
const attachmentId = hasher.digest("hex").slice(0, HASH_PREFIX_LEN);
|
|
54282
|
-
const hashDir =
|
|
55082
|
+
const hashDir = import_node_path34.default.join(attachmentsRoot, attachmentId);
|
|
54283
55083
|
let finalFileName;
|
|
54284
55084
|
let hashDirExists = false;
|
|
54285
55085
|
try {
|
|
54286
|
-
hashDirExists =
|
|
55086
|
+
hashDirExists = import_node_fs31.default.statSync(hashDir).isDirectory();
|
|
54287
55087
|
} catch {
|
|
54288
55088
|
}
|
|
54289
55089
|
if (hashDirExists) {
|
|
54290
|
-
const existing =
|
|
55090
|
+
const existing = import_node_fs31.default.readdirSync(hashDir).filter((n) => !n.startsWith("."));
|
|
54291
55091
|
finalFileName = existing[0] ?? args.fileName;
|
|
54292
55092
|
try {
|
|
54293
|
-
|
|
55093
|
+
import_node_fs31.default.unlinkSync(tmpPath);
|
|
54294
55094
|
} catch {
|
|
54295
55095
|
}
|
|
54296
55096
|
} else {
|
|
54297
55097
|
try {
|
|
54298
|
-
|
|
55098
|
+
import_node_fs31.default.mkdirSync(hashDir, { recursive: true });
|
|
54299
55099
|
finalFileName = args.fileName;
|
|
54300
|
-
|
|
55100
|
+
import_node_fs31.default.renameSync(tmpPath, import_node_path34.default.join(hashDir, finalFileName));
|
|
54301
55101
|
} catch (err) {
|
|
54302
55102
|
try {
|
|
54303
|
-
|
|
55103
|
+
import_node_fs31.default.unlinkSync(tmpPath);
|
|
54304
55104
|
} catch {
|
|
54305
55105
|
}
|
|
54306
55106
|
throw new UploadError("STORAGE_ERROR", `rename failed: ${err.message}`);
|
|
54307
55107
|
}
|
|
54308
55108
|
}
|
|
54309
|
-
const absPath =
|
|
54310
|
-
const relPath =
|
|
55109
|
+
const absPath = import_node_path34.default.join(hashDir, finalFileName);
|
|
55110
|
+
const relPath = import_node_path34.default.relative(args.sessionDir, absPath);
|
|
54311
55111
|
args.groupFileStore.upsert(args.scope, args.sessionId, {
|
|
54312
55112
|
relPath: absPath,
|
|
54313
55113
|
// 存绝对路径,与现有 agent 入清单的形态一致(attachment.ts:144 双形态兼容)
|
|
@@ -54321,7 +55121,7 @@ async function writeUploadedAttachment(args) {
|
|
|
54321
55121
|
|
|
54322
55122
|
// src/extension/import.ts
|
|
54323
55123
|
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
54324
|
-
var
|
|
55124
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
54325
55125
|
var import_node_os12 = __toESM(require("os"), 1);
|
|
54326
55126
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
54327
55127
|
var ImportError = class extends Error {
|
|
@@ -54339,7 +55139,7 @@ async function importZip(buf, root) {
|
|
|
54339
55139
|
throw new ImportError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
54340
55140
|
}
|
|
54341
55141
|
for (const name of Object.keys(zip.files)) {
|
|
54342
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
55142
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path35.default.isAbsolute(name)) {
|
|
54343
55143
|
throw new ImportError("ZIP_INVALID", `unsafe zip entry path: ${name}`);
|
|
54344
55144
|
}
|
|
54345
55145
|
}
|
|
@@ -54372,7 +55172,7 @@ async function importZip(buf, root) {
|
|
|
54372
55172
|
);
|
|
54373
55173
|
}
|
|
54374
55174
|
}
|
|
54375
|
-
const destDir =
|
|
55175
|
+
const destDir = import_node_path35.default.join(root, manifest.id);
|
|
54376
55176
|
let destExists = false;
|
|
54377
55177
|
try {
|
|
54378
55178
|
await import_promises4.default.access(destDir);
|
|
@@ -54382,15 +55182,15 @@ async function importZip(buf, root) {
|
|
|
54382
55182
|
if (destExists) {
|
|
54383
55183
|
throw new ImportError("ALREADY_EXISTS", `extension ${manifest.id} already installed`);
|
|
54384
55184
|
}
|
|
54385
|
-
const stage = await import_promises4.default.mkdtemp(
|
|
55185
|
+
const stage = await import_promises4.default.mkdtemp(import_node_path35.default.join(import_node_os12.default.tmpdir(), `clawd-ext-stage-${manifest.id}-`));
|
|
54386
55186
|
try {
|
|
54387
55187
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
54388
|
-
const dest =
|
|
55188
|
+
const dest = import_node_path35.default.join(stage, name);
|
|
54389
55189
|
if (entry.dir) {
|
|
54390
55190
|
await import_promises4.default.mkdir(dest, { recursive: true });
|
|
54391
55191
|
continue;
|
|
54392
55192
|
}
|
|
54393
|
-
await import_promises4.default.mkdir(
|
|
55193
|
+
await import_promises4.default.mkdir(import_node_path35.default.dirname(dest), { recursive: true });
|
|
54394
55194
|
const content = await entry.async("nodebuffer");
|
|
54395
55195
|
await import_promises4.default.writeFile(dest, content);
|
|
54396
55196
|
}
|
|
@@ -54420,7 +55220,7 @@ var SHARE_UI_ASSET_MIME = {
|
|
|
54420
55220
|
".wasm": "application/wasm"
|
|
54421
55221
|
};
|
|
54422
55222
|
function shareUiAssetMime(filePath) {
|
|
54423
|
-
const ext =
|
|
55223
|
+
const ext = import_node_path36.default.extname(filePath).toLowerCase();
|
|
54424
55224
|
return SHARE_UI_ASSET_MIME[ext] ?? lookupMime(filePath);
|
|
54425
55225
|
}
|
|
54426
55226
|
var AUTHED_RPC_ROUTE_PREFIX = "/rpc/";
|
|
@@ -54445,6 +55245,24 @@ function authedRpcErrorStatus(code) {
|
|
|
54445
55245
|
return 400;
|
|
54446
55246
|
}
|
|
54447
55247
|
}
|
|
55248
|
+
var LARK_BOT_EVENT_MAX_BYTES = 64 * 1024;
|
|
55249
|
+
async function readRawBody(req, max) {
|
|
55250
|
+
return await new Promise((resolve6, reject) => {
|
|
55251
|
+
let size = 0;
|
|
55252
|
+
const chunks = [];
|
|
55253
|
+
req.on("data", (c) => {
|
|
55254
|
+
size += c.length;
|
|
55255
|
+
if (size > max) {
|
|
55256
|
+
reject(new Error(`body too large (> ${max} bytes)`));
|
|
55257
|
+
req.destroy();
|
|
55258
|
+
return;
|
|
55259
|
+
}
|
|
55260
|
+
chunks.push(c);
|
|
55261
|
+
});
|
|
55262
|
+
req.on("end", () => resolve6(Buffer.concat(chunks).toString("utf8")));
|
|
55263
|
+
req.on("error", reject);
|
|
55264
|
+
});
|
|
55265
|
+
}
|
|
54448
55266
|
async function readJsonBody(req, max) {
|
|
54449
55267
|
return await new Promise((resolve6, reject) => {
|
|
54450
55268
|
let size = 0;
|
|
@@ -54501,7 +55319,7 @@ function isValidUploadFileName(fileName) {
|
|
|
54501
55319
|
if (fileName === "." || fileName === "..") return false;
|
|
54502
55320
|
if (fileName.startsWith(".")) return false;
|
|
54503
55321
|
if (fileName.includes("/") || fileName.includes("\\")) return false;
|
|
54504
|
-
return fileName ===
|
|
55322
|
+
return fileName === import_node_path36.default.basename(fileName);
|
|
54505
55323
|
}
|
|
54506
55324
|
function createHttpRouter(deps) {
|
|
54507
55325
|
return async (req, res) => {
|
|
@@ -54557,6 +55375,22 @@ function createHttpRouter(deps) {
|
|
|
54557
55375
|
else sendJson(res, 403, { code: r.reason }, AUTHED_RPC_CORS_HEADERS);
|
|
54558
55376
|
return true;
|
|
54559
55377
|
}
|
|
55378
|
+
if (url.pathname === "/lark-bot-connector/event" && req.method === "POST") {
|
|
55379
|
+
if (!deps.larkBotEvent) {
|
|
55380
|
+
sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "lark bot event not wired" });
|
|
55381
|
+
return true;
|
|
55382
|
+
}
|
|
55383
|
+
let raw;
|
|
55384
|
+
try {
|
|
55385
|
+
raw = await readRawBody(req, LARK_BOT_EVENT_MAX_BYTES);
|
|
55386
|
+
} catch (err) {
|
|
55387
|
+
sendJson(res, 400, { code: "INVALID_BODY", message: err instanceof Error ? err.message : String(err) });
|
|
55388
|
+
return true;
|
|
55389
|
+
}
|
|
55390
|
+
const r = deps.larkBotEvent(raw);
|
|
55391
|
+
sendJson(res, r.status, r.body);
|
|
55392
|
+
return true;
|
|
55393
|
+
}
|
|
54560
55394
|
if ((url.pathname === "/s" || url.pathname.startsWith("/s/")) && req.method === "GET") {
|
|
54561
55395
|
if (!deps.shareUiAssetLoader) {
|
|
54562
55396
|
sendJson(res, 501, { code: "NOT_IMPLEMENTED", message: "share-ui assets not loaded" });
|
|
@@ -54573,7 +55407,7 @@ function createHttpRouter(deps) {
|
|
|
54573
55407
|
}
|
|
54574
55408
|
let buf;
|
|
54575
55409
|
try {
|
|
54576
|
-
buf = await
|
|
55410
|
+
buf = await import_node_fs32.default.promises.readFile(abs);
|
|
54577
55411
|
} catch {
|
|
54578
55412
|
sendJson(res, 404, { code: "NOT_FOUND", message: "asset not found" });
|
|
54579
55413
|
return true;
|
|
@@ -54721,7 +55555,7 @@ function createHttpRouter(deps) {
|
|
|
54721
55555
|
sendHtml(res, statusByCode[r.code], loader.renderErrorHtml(r.code, msgByCode[r.code]));
|
|
54722
55556
|
return true;
|
|
54723
55557
|
}
|
|
54724
|
-
sendHtml(res, 200, loader.renderViewerHtml(
|
|
55558
|
+
sendHtml(res, 200, loader.renderViewerHtml(import_node_path36.default.basename(r.absPath)));
|
|
54725
55559
|
return true;
|
|
54726
55560
|
}
|
|
54727
55561
|
const ctx = deps.authResolver.resolveFromHeader(
|
|
@@ -54842,7 +55676,7 @@ function createHttpRouter(deps) {
|
|
|
54842
55676
|
return true;
|
|
54843
55677
|
}
|
|
54844
55678
|
let absPath;
|
|
54845
|
-
if (
|
|
55679
|
+
if (import_node_path36.default.isAbsolute(pathParam)) {
|
|
54846
55680
|
absPath = pathParam;
|
|
54847
55681
|
} else if (deps.sessionStore) {
|
|
54848
55682
|
const file = deps.sessionStore.read(sid);
|
|
@@ -54850,7 +55684,7 @@ function createHttpRouter(deps) {
|
|
|
54850
55684
|
sendJson(res, 404, { code: "NOT_FOUND", message: `session ${sid} not found` });
|
|
54851
55685
|
return true;
|
|
54852
55686
|
}
|
|
54853
|
-
absPath =
|
|
55687
|
+
absPath = import_node_path36.default.join(file.cwd, pathParam);
|
|
54854
55688
|
} else {
|
|
54855
55689
|
sendJson(res, 501, withCtx(ctx, { code: "NOT_IMPLEMENTED", message: "sessionStore not wired" }));
|
|
54856
55690
|
return true;
|
|
@@ -54937,7 +55771,7 @@ function withCtx(ctx, body) {
|
|
|
54937
55771
|
function streamFile(res, absPath, logger) {
|
|
54938
55772
|
let stat;
|
|
54939
55773
|
try {
|
|
54940
|
-
stat =
|
|
55774
|
+
stat = import_node_fs32.default.statSync(absPath);
|
|
54941
55775
|
} catch (err) {
|
|
54942
55776
|
const code = err?.code;
|
|
54943
55777
|
if (code === "ENOENT") {
|
|
@@ -54952,7 +55786,7 @@ function streamFile(res, absPath, logger) {
|
|
|
54952
55786
|
return;
|
|
54953
55787
|
}
|
|
54954
55788
|
const mime = lookupMime(absPath);
|
|
54955
|
-
const basename =
|
|
55789
|
+
const basename = import_node_path36.default.basename(absPath);
|
|
54956
55790
|
res.writeHead(200, {
|
|
54957
55791
|
"Content-Type": mime,
|
|
54958
55792
|
"Content-Length": String(stat.size),
|
|
@@ -54960,7 +55794,7 @@ function streamFile(res, absPath, logger) {
|
|
|
54960
55794
|
// 防止浏览器把任意 mime 当 html 渲染
|
|
54961
55795
|
"X-Content-Type-Options": "nosniff"
|
|
54962
55796
|
});
|
|
54963
|
-
const stream =
|
|
55797
|
+
const stream = import_node_fs32.default.createReadStream(absPath);
|
|
54964
55798
|
stream.on("error", (err) => {
|
|
54965
55799
|
logger?.warn("streamFile read error", { absPath, err: err.message });
|
|
54966
55800
|
res.destroy();
|
|
@@ -54969,8 +55803,8 @@ function streamFile(res, absPath, logger) {
|
|
|
54969
55803
|
}
|
|
54970
55804
|
|
|
54971
55805
|
// src/attachment/gc.ts
|
|
54972
|
-
var
|
|
54973
|
-
var
|
|
55806
|
+
var import_node_fs33 = __toESM(require("fs"), 1);
|
|
55807
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
54974
55808
|
var DEFAULT_TTL_MS = 30 * 24 * 3600 * 1e3;
|
|
54975
55809
|
function runAttachmentGc(args) {
|
|
54976
55810
|
const now = (args.now ?? Date.now)();
|
|
@@ -54979,38 +55813,38 @@ function runAttachmentGc(args) {
|
|
|
54979
55813
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
54980
55814
|
for (const entry of args.groupFileStore.list(scope, sessionId)) {
|
|
54981
55815
|
if (entry.stale) continue;
|
|
54982
|
-
if (
|
|
55816
|
+
if (import_node_path37.default.isAbsolute(entry.relPath)) liveAbs.add(entry.relPath);
|
|
54983
55817
|
}
|
|
54984
55818
|
}
|
|
54985
55819
|
for (const { scope, sessionId } of args.sessionScopes) {
|
|
54986
|
-
const sessionDir = args.getSessionCwd?.(sessionId) ??
|
|
55820
|
+
const sessionDir = args.getSessionCwd?.(sessionId) ?? import_node_path37.default.join(
|
|
54987
55821
|
args.dataDir,
|
|
54988
55822
|
"sessions",
|
|
54989
55823
|
...scopeSubPath(scope).map(safeFileName),
|
|
54990
55824
|
safeFileName(sessionId)
|
|
54991
55825
|
);
|
|
54992
|
-
const attRoot =
|
|
55826
|
+
const attRoot = import_node_path37.default.join(sessionDir, ".attachments");
|
|
54993
55827
|
let hashDirs;
|
|
54994
55828
|
try {
|
|
54995
|
-
hashDirs =
|
|
55829
|
+
hashDirs = import_node_fs33.default.readdirSync(attRoot);
|
|
54996
55830
|
} catch (err) {
|
|
54997
55831
|
if (err.code === "ENOENT") continue;
|
|
54998
55832
|
args.logger?.warn("attachment gc: readdir failed", { attRoot, err: err.message });
|
|
54999
55833
|
continue;
|
|
55000
55834
|
}
|
|
55001
55835
|
for (const hashDir of hashDirs) {
|
|
55002
|
-
const hashDirAbs =
|
|
55836
|
+
const hashDirAbs = import_node_path37.default.join(attRoot, hashDir);
|
|
55003
55837
|
let files;
|
|
55004
55838
|
try {
|
|
55005
|
-
files =
|
|
55839
|
+
files = import_node_fs33.default.readdirSync(hashDirAbs);
|
|
55006
55840
|
} catch {
|
|
55007
55841
|
continue;
|
|
55008
55842
|
}
|
|
55009
55843
|
for (const name of files) {
|
|
55010
|
-
const file =
|
|
55844
|
+
const file = import_node_path37.default.join(hashDirAbs, name);
|
|
55011
55845
|
let stat;
|
|
55012
55846
|
try {
|
|
55013
|
-
stat =
|
|
55847
|
+
stat = import_node_fs33.default.statSync(file);
|
|
55014
55848
|
} catch {
|
|
55015
55849
|
continue;
|
|
55016
55850
|
}
|
|
@@ -55019,27 +55853,27 @@ function runAttachmentGc(args) {
|
|
|
55019
55853
|
if (age < ttlMs) continue;
|
|
55020
55854
|
if (liveAbs.has(file)) continue;
|
|
55021
55855
|
try {
|
|
55022
|
-
|
|
55856
|
+
import_node_fs33.default.unlinkSync(file);
|
|
55023
55857
|
} catch (err) {
|
|
55024
55858
|
args.logger?.warn("attachment gc: unlink failed", { file, err: err.message });
|
|
55025
55859
|
}
|
|
55026
55860
|
}
|
|
55027
55861
|
try {
|
|
55028
|
-
if (
|
|
55862
|
+
if (import_node_fs33.default.readdirSync(hashDirAbs).length === 0) import_node_fs33.default.rmdirSync(hashDirAbs);
|
|
55029
55863
|
} catch {
|
|
55030
55864
|
}
|
|
55031
55865
|
}
|
|
55032
55866
|
try {
|
|
55033
|
-
if (
|
|
55867
|
+
if (import_node_fs33.default.readdirSync(attRoot).length === 0) import_node_fs33.default.rmdirSync(attRoot);
|
|
55034
55868
|
} catch {
|
|
55035
55869
|
}
|
|
55036
55870
|
}
|
|
55037
55871
|
}
|
|
55038
55872
|
|
|
55039
55873
|
// src/attachment/group.ts
|
|
55040
|
-
var
|
|
55041
|
-
var
|
|
55042
|
-
var
|
|
55874
|
+
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
55875
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
55876
|
+
var import_node_crypto9 = __toESM(require("crypto"), 1);
|
|
55043
55877
|
init_protocol();
|
|
55044
55878
|
var GroupFileStore = class {
|
|
55045
55879
|
dataDir;
|
|
@@ -55050,11 +55884,11 @@ var GroupFileStore = class {
|
|
|
55050
55884
|
this.logger = opts.logger;
|
|
55051
55885
|
}
|
|
55052
55886
|
rootForScope(scope) {
|
|
55053
|
-
return
|
|
55887
|
+
return import_node_path38.default.join(this.dataDir, "sessions", ...scopeSubPath(scope).map(safeFileName));
|
|
55054
55888
|
}
|
|
55055
55889
|
/** 与 SessionStore.filePath 平级,扩展名 .group-files.json */
|
|
55056
55890
|
filePath(scope, sessionId) {
|
|
55057
|
-
return
|
|
55891
|
+
return import_node_path38.default.join(this.rootForScope(scope), `${safeFileName(sessionId)}.group-files.json`);
|
|
55058
55892
|
}
|
|
55059
55893
|
cacheKey(scope, sessionId) {
|
|
55060
55894
|
return scope.kind === "default" ? `default::${sessionId}` : `persona:${scope.personaId}:${scope.mode}::${sessionId}`;
|
|
@@ -55063,7 +55897,7 @@ var GroupFileStore = class {
|
|
|
55063
55897
|
readFile(scope, sessionId) {
|
|
55064
55898
|
const file = this.filePath(scope, sessionId);
|
|
55065
55899
|
try {
|
|
55066
|
-
const raw =
|
|
55900
|
+
const raw = import_node_fs34.default.readFileSync(file, "utf8");
|
|
55067
55901
|
const parsed = JSON.parse(raw);
|
|
55068
55902
|
if (!Array.isArray(parsed)) {
|
|
55069
55903
|
this.logger?.warn("GroupFileStore.readFile: not an array; resetting session entries", {
|
|
@@ -55089,10 +55923,10 @@ var GroupFileStore = class {
|
|
|
55089
55923
|
}
|
|
55090
55924
|
writeFile(scope, sessionId, entries) {
|
|
55091
55925
|
const file = this.filePath(scope, sessionId);
|
|
55092
|
-
|
|
55926
|
+
import_node_fs34.default.mkdirSync(import_node_path38.default.dirname(file), { recursive: true });
|
|
55093
55927
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
55094
|
-
|
|
55095
|
-
|
|
55928
|
+
import_node_fs34.default.writeFileSync(tmp, JSON.stringify(entries, null, 2), { mode: 384 });
|
|
55929
|
+
import_node_fs34.default.renameSync(tmp, file);
|
|
55096
55930
|
}
|
|
55097
55931
|
/** 拉一份当前 session 的清单。读盘 → cache;之后调用复用 cache */
|
|
55098
55932
|
list(scope, sessionId) {
|
|
@@ -55128,7 +55962,7 @@ var GroupFileStore = class {
|
|
|
55128
55962
|
entries[idx] = next;
|
|
55129
55963
|
} else {
|
|
55130
55964
|
next = {
|
|
55131
|
-
id: `gf-${
|
|
55965
|
+
id: `gf-${import_node_crypto9.default.randomBytes(6).toString("base64url")}`,
|
|
55132
55966
|
relPath: input.relPath,
|
|
55133
55967
|
from: input.from,
|
|
55134
55968
|
label: input.label,
|
|
@@ -55178,10 +56012,10 @@ var GroupFileStore = class {
|
|
|
55178
56012
|
};
|
|
55179
56013
|
|
|
55180
56014
|
// src/discovery/state-file.ts
|
|
55181
|
-
var
|
|
55182
|
-
var
|
|
56015
|
+
var import_node_fs35 = __toESM(require("fs"), 1);
|
|
56016
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
55183
56017
|
function defaultStateFilePath(dataDir) {
|
|
55184
|
-
return
|
|
56018
|
+
return import_node_path39.default.join(dataDir, "state.json");
|
|
55185
56019
|
}
|
|
55186
56020
|
function isPidAlive(pid) {
|
|
55187
56021
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -55203,7 +56037,7 @@ var StateFileManager = class {
|
|
|
55203
56037
|
}
|
|
55204
56038
|
read() {
|
|
55205
56039
|
try {
|
|
55206
|
-
const raw =
|
|
56040
|
+
const raw = import_node_fs35.default.readFileSync(this.file, "utf8");
|
|
55207
56041
|
const parsed = JSON.parse(raw);
|
|
55208
56042
|
return parsed;
|
|
55209
56043
|
} catch {
|
|
@@ -55217,20 +56051,20 @@ var StateFileManager = class {
|
|
|
55217
56051
|
return { status: "stale", existing };
|
|
55218
56052
|
}
|
|
55219
56053
|
write(state) {
|
|
55220
|
-
|
|
56054
|
+
import_node_fs35.default.mkdirSync(import_node_path39.default.dirname(this.file), { recursive: true });
|
|
55221
56055
|
const tmp = `${this.file}.tmp.${process.pid}.${Date.now()}`;
|
|
55222
|
-
|
|
55223
|
-
|
|
56056
|
+
import_node_fs35.default.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
56057
|
+
import_node_fs35.default.renameSync(tmp, this.file);
|
|
55224
56058
|
if (process.platform !== "win32") {
|
|
55225
56059
|
try {
|
|
55226
|
-
|
|
56060
|
+
import_node_fs35.default.chmodSync(this.file, 384);
|
|
55227
56061
|
} catch {
|
|
55228
56062
|
}
|
|
55229
56063
|
}
|
|
55230
56064
|
}
|
|
55231
56065
|
delete() {
|
|
55232
56066
|
try {
|
|
55233
|
-
|
|
56067
|
+
import_node_fs35.default.unlinkSync(this.file);
|
|
55234
56068
|
} catch {
|
|
55235
56069
|
}
|
|
55236
56070
|
}
|
|
@@ -55244,14 +56078,14 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
|
|
|
55244
56078
|
}
|
|
55245
56079
|
|
|
55246
56080
|
// src/tunnel/tunnel-manager.ts
|
|
55247
|
-
var
|
|
55248
|
-
var
|
|
55249
|
-
var
|
|
56081
|
+
var import_node_fs39 = __toESM(require("fs"), 1);
|
|
56082
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
56083
|
+
var import_node_crypto10 = __toESM(require("crypto"), 1);
|
|
55250
56084
|
var import_node_child_process9 = require("child_process");
|
|
55251
56085
|
|
|
55252
56086
|
// src/tunnel/tunnel-store.ts
|
|
55253
|
-
var
|
|
55254
|
-
var
|
|
56087
|
+
var import_node_fs36 = __toESM(require("fs"), 1);
|
|
56088
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
55255
56089
|
var TunnelStore = class {
|
|
55256
56090
|
constructor(filePath) {
|
|
55257
56091
|
this.filePath = filePath;
|
|
@@ -55259,7 +56093,7 @@ var TunnelStore = class {
|
|
|
55259
56093
|
filePath;
|
|
55260
56094
|
async get() {
|
|
55261
56095
|
try {
|
|
55262
|
-
const raw = await
|
|
56096
|
+
const raw = await import_node_fs36.default.promises.readFile(this.filePath, "utf8");
|
|
55263
56097
|
const obj = JSON.parse(raw);
|
|
55264
56098
|
if (!isPersistedTunnel(obj)) return null;
|
|
55265
56099
|
return obj;
|
|
@@ -55270,22 +56104,22 @@ var TunnelStore = class {
|
|
|
55270
56104
|
}
|
|
55271
56105
|
}
|
|
55272
56106
|
async set(v2) {
|
|
55273
|
-
const dir =
|
|
55274
|
-
await
|
|
56107
|
+
const dir = import_node_path40.default.dirname(this.filePath);
|
|
56108
|
+
await import_node_fs36.default.promises.mkdir(dir, { recursive: true });
|
|
55275
56109
|
const data = JSON.stringify(v2, null, 2);
|
|
55276
56110
|
const tmp = `${this.filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
55277
|
-
await
|
|
56111
|
+
await import_node_fs36.default.promises.writeFile(tmp, data, { mode: 384 });
|
|
55278
56112
|
if (process.platform !== "win32") {
|
|
55279
56113
|
try {
|
|
55280
|
-
await
|
|
56114
|
+
await import_node_fs36.default.promises.chmod(tmp, 384);
|
|
55281
56115
|
} catch {
|
|
55282
56116
|
}
|
|
55283
56117
|
}
|
|
55284
|
-
await
|
|
56118
|
+
await import_node_fs36.default.promises.rename(tmp, this.filePath);
|
|
55285
56119
|
}
|
|
55286
56120
|
async clear() {
|
|
55287
56121
|
try {
|
|
55288
|
-
await
|
|
56122
|
+
await import_node_fs36.default.promises.unlink(this.filePath);
|
|
55289
56123
|
} catch (err) {
|
|
55290
56124
|
const code = err?.code;
|
|
55291
56125
|
if (code !== "ENOENT") throw err;
|
|
@@ -55380,9 +56214,9 @@ function escape(v2) {
|
|
|
55380
56214
|
}
|
|
55381
56215
|
|
|
55382
56216
|
// src/tunnel/frpc-binary.ts
|
|
55383
|
-
var
|
|
56217
|
+
var import_node_fs37 = __toESM(require("fs"), 1);
|
|
55384
56218
|
var import_node_os13 = __toESM(require("os"), 1);
|
|
55385
|
-
var
|
|
56219
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
55386
56220
|
var import_node_child_process7 = require("child_process");
|
|
55387
56221
|
var import_node_stream3 = require("stream");
|
|
55388
56222
|
var import_promises5 = require("stream/promises");
|
|
@@ -55414,20 +56248,20 @@ function frpcDownloadUrl(version2, p2) {
|
|
|
55414
56248
|
}
|
|
55415
56249
|
async function ensureFrpcBinary(opts) {
|
|
55416
56250
|
if (opts.override) {
|
|
55417
|
-
if (!
|
|
56251
|
+
if (!import_node_fs37.default.existsSync(opts.override)) {
|
|
55418
56252
|
throw new Error(`frpc binary not found at override path: ${opts.override}`);
|
|
55419
56253
|
}
|
|
55420
56254
|
return opts.override;
|
|
55421
56255
|
}
|
|
55422
56256
|
const version2 = opts.version ?? FRPC_VERSION;
|
|
55423
56257
|
const platform = opts.platform ?? detectPlatform();
|
|
55424
|
-
const binDir =
|
|
55425
|
-
|
|
56258
|
+
const binDir = import_node_path41.default.join(opts.dataDir, "bin");
|
|
56259
|
+
import_node_fs37.default.mkdirSync(binDir, { recursive: true });
|
|
55426
56260
|
cleanupStaleArtifacts(binDir);
|
|
55427
|
-
const stableBin =
|
|
55428
|
-
if (
|
|
56261
|
+
const stableBin = import_node_path41.default.join(binDir, "frpc");
|
|
56262
|
+
if (import_node_fs37.default.existsSync(stableBin)) return stableBin;
|
|
55429
56263
|
const partialBin = `${stableBin}.partial`;
|
|
55430
|
-
const tarballPath =
|
|
56264
|
+
const tarballPath = import_node_path41.default.join(binDir, `frp_${version2}_${platform.os}_${platform.arch}.tar.gz.partial`);
|
|
55431
56265
|
try {
|
|
55432
56266
|
const url = frpcDownloadUrl(version2, platform);
|
|
55433
56267
|
await downloadToFile(url, tarballPath, opts.fetchImpl);
|
|
@@ -55436,8 +56270,8 @@ async function ensureFrpcBinary(opts) {
|
|
|
55436
56270
|
} else {
|
|
55437
56271
|
await extractFrpcFromTarball(tarballPath, binDir, version2, platform, partialBin);
|
|
55438
56272
|
}
|
|
55439
|
-
|
|
55440
|
-
|
|
56273
|
+
import_node_fs37.default.chmodSync(partialBin, 493);
|
|
56274
|
+
import_node_fs37.default.renameSync(partialBin, stableBin);
|
|
55441
56275
|
} finally {
|
|
55442
56276
|
safeUnlink(tarballPath);
|
|
55443
56277
|
safeUnlink(partialBin);
|
|
@@ -55447,15 +56281,15 @@ async function ensureFrpcBinary(opts) {
|
|
|
55447
56281
|
function cleanupStaleArtifacts(binDir) {
|
|
55448
56282
|
let entries;
|
|
55449
56283
|
try {
|
|
55450
|
-
entries =
|
|
56284
|
+
entries = import_node_fs37.default.readdirSync(binDir);
|
|
55451
56285
|
} catch {
|
|
55452
56286
|
return;
|
|
55453
56287
|
}
|
|
55454
56288
|
for (const name of entries) {
|
|
55455
56289
|
if (name.endsWith(".partial") || name.startsWith("extract-")) {
|
|
55456
|
-
const full =
|
|
56290
|
+
const full = import_node_path41.default.join(binDir, name);
|
|
55457
56291
|
try {
|
|
55458
|
-
|
|
56292
|
+
import_node_fs37.default.rmSync(full, { recursive: true, force: true });
|
|
55459
56293
|
} catch {
|
|
55460
56294
|
}
|
|
55461
56295
|
}
|
|
@@ -55463,7 +56297,7 @@ function cleanupStaleArtifacts(binDir) {
|
|
|
55463
56297
|
}
|
|
55464
56298
|
function safeUnlink(p2) {
|
|
55465
56299
|
try {
|
|
55466
|
-
|
|
56300
|
+
import_node_fs37.default.unlinkSync(p2);
|
|
55467
56301
|
} catch {
|
|
55468
56302
|
}
|
|
55469
56303
|
}
|
|
@@ -55474,13 +56308,13 @@ async function downloadToFile(url, dest, fetchImpl) {
|
|
|
55474
56308
|
if (!res.ok || !res.body) {
|
|
55475
56309
|
throw new Error(`download failed: ${res.status} ${res.statusText}`);
|
|
55476
56310
|
}
|
|
55477
|
-
const out =
|
|
56311
|
+
const out = import_node_fs37.default.createWriteStream(dest);
|
|
55478
56312
|
const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
|
|
55479
56313
|
await (0, import_promises5.pipeline)(nodeStream, out);
|
|
55480
56314
|
}
|
|
55481
56315
|
async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
|
|
55482
|
-
const work =
|
|
55483
|
-
|
|
56316
|
+
const work = import_node_path41.default.join(binDir, `extract-${process.pid}-${Date.now()}`);
|
|
56317
|
+
import_node_fs37.default.mkdirSync(work, { recursive: true });
|
|
55484
56318
|
try {
|
|
55485
56319
|
await new Promise((resolve6, reject) => {
|
|
55486
56320
|
const proc = (0, import_node_child_process7.spawn)("tar", ["xzf", tarball, "-C", work], { stdio: "pipe" });
|
|
@@ -55488,32 +56322,32 @@ async function extractFrpcFromTarball(tarball, binDir, version2, platform, destB
|
|
|
55488
56322
|
proc.on("exit", (code) => code === 0 ? resolve6() : reject(new Error(`tar exited ${code}`)));
|
|
55489
56323
|
});
|
|
55490
56324
|
const dirName = `frp_${version2}_${platform.os}_${platform.arch}`;
|
|
55491
|
-
const src =
|
|
55492
|
-
if (!
|
|
56325
|
+
const src = import_node_path41.default.join(work, dirName, "frpc");
|
|
56326
|
+
if (!import_node_fs37.default.existsSync(src)) {
|
|
55493
56327
|
throw new Error(`frpc not found inside tarball at ${src}`);
|
|
55494
56328
|
}
|
|
55495
|
-
|
|
56329
|
+
import_node_fs37.default.copyFileSync(src, destBin);
|
|
55496
56330
|
} finally {
|
|
55497
|
-
|
|
56331
|
+
import_node_fs37.default.rmSync(work, { recursive: true, force: true });
|
|
55498
56332
|
}
|
|
55499
56333
|
}
|
|
55500
56334
|
|
|
55501
56335
|
// src/tunnel/frpc-process.ts
|
|
55502
|
-
var
|
|
55503
|
-
var
|
|
56336
|
+
var import_node_fs38 = __toESM(require("fs"), 1);
|
|
56337
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
55504
56338
|
var import_node_child_process8 = require("child_process");
|
|
55505
56339
|
function frpcPidFilePath(dataDir) {
|
|
55506
|
-
return
|
|
56340
|
+
return import_node_path42.default.join(dataDir, "frpc.pid");
|
|
55507
56341
|
}
|
|
55508
56342
|
function writeFrpcPid(dataDir, pid) {
|
|
55509
56343
|
try {
|
|
55510
|
-
|
|
56344
|
+
import_node_fs38.default.writeFileSync(frpcPidFilePath(dataDir), String(pid), { mode: 384 });
|
|
55511
56345
|
} catch {
|
|
55512
56346
|
}
|
|
55513
56347
|
}
|
|
55514
56348
|
function clearFrpcPid(dataDir) {
|
|
55515
56349
|
try {
|
|
55516
|
-
|
|
56350
|
+
import_node_fs38.default.unlinkSync(frpcPidFilePath(dataDir));
|
|
55517
56351
|
} catch {
|
|
55518
56352
|
}
|
|
55519
56353
|
}
|
|
@@ -55529,7 +56363,7 @@ function defaultIsPidAlive(pid) {
|
|
|
55529
56363
|
}
|
|
55530
56364
|
function defaultReadPidFile(file) {
|
|
55531
56365
|
try {
|
|
55532
|
-
return
|
|
56366
|
+
return import_node_fs38.default.readFileSync(file, "utf8");
|
|
55533
56367
|
} catch {
|
|
55534
56368
|
return null;
|
|
55535
56369
|
}
|
|
@@ -55545,7 +56379,7 @@ function defaultSleep2(ms) {
|
|
|
55545
56379
|
}
|
|
55546
56380
|
async function killStaleFrpc(deps) {
|
|
55547
56381
|
const pidFile = frpcPidFilePath(deps.dataDir);
|
|
55548
|
-
const tomlPath =
|
|
56382
|
+
const tomlPath = import_node_path42.default.join(deps.dataDir, "frpc.toml");
|
|
55549
56383
|
const readPidFile = deps.readPidFileImpl ?? defaultReadPidFile;
|
|
55550
56384
|
const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
|
|
55551
56385
|
const killPid = deps.killPidImpl ?? defaultKillPid;
|
|
@@ -55569,7 +56403,7 @@ async function killStaleFrpc(deps) {
|
|
|
55569
56403
|
}
|
|
55570
56404
|
if (victims.size === 0) {
|
|
55571
56405
|
try {
|
|
55572
|
-
|
|
56406
|
+
import_node_fs38.default.unlinkSync(pidFile);
|
|
55573
56407
|
} catch {
|
|
55574
56408
|
}
|
|
55575
56409
|
return;
|
|
@@ -55580,7 +56414,7 @@ async function killStaleFrpc(deps) {
|
|
|
55580
56414
|
}
|
|
55581
56415
|
await sleep2(deps.reapWaitMs ?? 300);
|
|
55582
56416
|
try {
|
|
55583
|
-
|
|
56417
|
+
import_node_fs38.default.unlinkSync(pidFile);
|
|
55584
56418
|
} catch {
|
|
55585
56419
|
}
|
|
55586
56420
|
}
|
|
@@ -55617,7 +56451,7 @@ var DEFAULT_TUNNEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
55617
56451
|
var TunnelManager = class {
|
|
55618
56452
|
constructor(deps) {
|
|
55619
56453
|
this.deps = deps;
|
|
55620
|
-
this.store = deps.store ?? new TunnelStore(
|
|
56454
|
+
this.store = deps.store ?? new TunnelStore(import_node_path43.default.join(deps.dataDir, "tunnel.json"));
|
|
55621
56455
|
this.ttlMs = deps.ttlMs ?? DEFAULT_TUNNEL_TTL_MS;
|
|
55622
56456
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 15e3;
|
|
55623
56457
|
}
|
|
@@ -55744,8 +56578,8 @@ var TunnelManager = class {
|
|
|
55744
56578
|
dataDir: this.deps.dataDir,
|
|
55745
56579
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
55746
56580
|
});
|
|
55747
|
-
const tomlPath =
|
|
55748
|
-
const proxyName = `clawd-${t.subdomain}-${localPort}-${
|
|
56581
|
+
const tomlPath = import_node_path43.default.join(this.deps.dataDir, "frpc.toml");
|
|
56582
|
+
const proxyName = `clawd-${t.subdomain}-${localPort}-${import_node_crypto10.default.randomBytes(3).toString("hex")}`;
|
|
55749
56583
|
const toml = buildFrpcToml({
|
|
55750
56584
|
serverAddr: t.frpsHost,
|
|
55751
56585
|
serverPort: t.frpsPort,
|
|
@@ -55755,14 +56589,14 @@ var TunnelManager = class {
|
|
|
55755
56589
|
localPort,
|
|
55756
56590
|
logLevel: "info"
|
|
55757
56591
|
});
|
|
55758
|
-
await
|
|
56592
|
+
await import_node_fs39.default.promises.writeFile(tomlPath, toml, { mode: 384 });
|
|
55759
56593
|
const proc = (this.deps.spawnImpl ?? import_node_child_process9.spawn)(frpcBin, ["-c", tomlPath], {
|
|
55760
56594
|
stdio: ["ignore", "pipe", "pipe"]
|
|
55761
56595
|
});
|
|
55762
|
-
const logDir =
|
|
55763
|
-
|
|
55764
|
-
const logFilePath =
|
|
55765
|
-
const logStream =
|
|
56596
|
+
const logDir = import_node_path43.default.join(this.deps.dataDir, "log");
|
|
56597
|
+
import_node_fs39.default.mkdirSync(logDir, { recursive: true });
|
|
56598
|
+
const logFilePath = import_node_path43.default.join(logDir, "frpc.log");
|
|
56599
|
+
const logStream = import_node_fs39.default.createWriteStream(logFilePath, { flags: "a", mode: 384 });
|
|
55766
56600
|
logStream.on("error", () => {
|
|
55767
56601
|
});
|
|
55768
56602
|
const tee = (chunk) => {
|
|
@@ -55845,27 +56679,27 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
55845
56679
|
|
|
55846
56680
|
// src/tunnel/device-key.ts
|
|
55847
56681
|
var import_node_os14 = __toESM(require("os"), 1);
|
|
55848
|
-
var
|
|
55849
|
-
var
|
|
56682
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
56683
|
+
var import_node_crypto11 = __toESM(require("crypto"), 1);
|
|
55850
56684
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
55851
56685
|
function deriveStableDeviceKey(opts = {}) {
|
|
55852
56686
|
const hostname = opts.hostname ?? import_node_os14.default.hostname();
|
|
55853
56687
|
const uid = opts.uid ?? (typeof import_node_os14.default.userInfo === "function" ? import_node_os14.default.userInfo().uid : 0);
|
|
55854
56688
|
const home = opts.home ?? import_node_os14.default.homedir();
|
|
55855
|
-
const defaultDataDir =
|
|
55856
|
-
const normalizedDataDir = opts.dataDir ?
|
|
56689
|
+
const defaultDataDir = import_node_path44.default.resolve(import_node_path44.default.join(home, ".clawd"));
|
|
56690
|
+
const normalizedDataDir = opts.dataDir ? import_node_path44.default.resolve(opts.dataDir) : null;
|
|
55857
56691
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
55858
56692
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
55859
|
-
return
|
|
56693
|
+
return import_node_crypto11.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
55860
56694
|
}
|
|
55861
56695
|
|
|
55862
56696
|
// src/auth-store.ts
|
|
55863
|
-
var
|
|
55864
|
-
var
|
|
55865
|
-
var
|
|
56697
|
+
var import_node_fs40 = __toESM(require("fs"), 1);
|
|
56698
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
56699
|
+
var import_node_crypto12 = __toESM(require("crypto"), 1);
|
|
55866
56700
|
var AUTH_FILE_NAME = "auth.json";
|
|
55867
56701
|
function authFilePath(dataDir) {
|
|
55868
|
-
return
|
|
56702
|
+
return import_node_path45.default.join(dataDir, AUTH_FILE_NAME);
|
|
55869
56703
|
}
|
|
55870
56704
|
function loadOrCreateAuthFile(opts) {
|
|
55871
56705
|
const file = authFilePath(opts.dataDir);
|
|
@@ -55890,14 +56724,14 @@ function loadOrCreateAuthFile(opts) {
|
|
|
55890
56724
|
return next;
|
|
55891
56725
|
}
|
|
55892
56726
|
function defaultGenerateToken() {
|
|
55893
|
-
return
|
|
56727
|
+
return import_node_crypto12.default.randomBytes(32).toString("base64url");
|
|
55894
56728
|
}
|
|
55895
56729
|
function defaultGenerateOwnerPrincipalId() {
|
|
55896
|
-
return `owner-${
|
|
56730
|
+
return `owner-${import_node_crypto12.default.randomUUID()}`;
|
|
55897
56731
|
}
|
|
55898
56732
|
function readAuthFile(file) {
|
|
55899
56733
|
try {
|
|
55900
|
-
const raw =
|
|
56734
|
+
const raw = import_node_fs40.default.readFileSync(file, "utf8");
|
|
55901
56735
|
const parsed = JSON.parse(raw);
|
|
55902
56736
|
if (typeof parsed?.token !== "string" || parsed.token.length === 0) {
|
|
55903
56737
|
return null;
|
|
@@ -55917,25 +56751,25 @@ function readAuthFile(file) {
|
|
|
55917
56751
|
}
|
|
55918
56752
|
}
|
|
55919
56753
|
function writeAuthFile(file, content) {
|
|
55920
|
-
|
|
55921
|
-
|
|
56754
|
+
import_node_fs40.default.mkdirSync(import_node_path45.default.dirname(file), { recursive: true });
|
|
56755
|
+
import_node_fs40.default.writeFileSync(file, JSON.stringify(content, null, 2), { mode: 384 });
|
|
55922
56756
|
try {
|
|
55923
|
-
|
|
56757
|
+
import_node_fs40.default.chmodSync(file, 384);
|
|
55924
56758
|
} catch {
|
|
55925
56759
|
}
|
|
55926
56760
|
}
|
|
55927
56761
|
|
|
55928
56762
|
// src/owner-profile.ts
|
|
55929
|
-
var
|
|
56763
|
+
var import_node_fs41 = __toESM(require("fs"), 1);
|
|
55930
56764
|
var import_node_os15 = __toESM(require("os"), 1);
|
|
55931
|
-
var
|
|
56765
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
55932
56766
|
var PROFILE_FILENAME = "profile.json";
|
|
55933
56767
|
function loadOwnerDisplayName(dataDir) {
|
|
55934
56768
|
const fallback = import_node_os15.default.userInfo().username;
|
|
55935
|
-
const profilePath =
|
|
56769
|
+
const profilePath = import_node_path46.default.join(dataDir, PROFILE_FILENAME);
|
|
55936
56770
|
let raw;
|
|
55937
56771
|
try {
|
|
55938
|
-
raw =
|
|
56772
|
+
raw = import_node_fs41.default.readFileSync(profilePath, "utf8");
|
|
55939
56773
|
} catch {
|
|
55940
56774
|
return fallback;
|
|
55941
56775
|
}
|
|
@@ -55958,18 +56792,18 @@ function loadOwnerDisplayName(dataDir) {
|
|
|
55958
56792
|
}
|
|
55959
56793
|
|
|
55960
56794
|
// src/feishu-auth/owner-identity-store.ts
|
|
55961
|
-
var
|
|
55962
|
-
var
|
|
56795
|
+
var import_node_fs42 = __toESM(require("fs"), 1);
|
|
56796
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
55963
56797
|
var OWNER_IDENTITY_FILE_NAME = "owner-identity.json";
|
|
55964
56798
|
var OwnerIdentityStore = class {
|
|
55965
56799
|
file;
|
|
55966
56800
|
constructor(dataDir) {
|
|
55967
|
-
this.file =
|
|
56801
|
+
this.file = import_node_path47.default.join(dataDir, OWNER_IDENTITY_FILE_NAME);
|
|
55968
56802
|
}
|
|
55969
56803
|
read() {
|
|
55970
56804
|
let raw;
|
|
55971
56805
|
try {
|
|
55972
|
-
raw =
|
|
56806
|
+
raw = import_node_fs42.default.readFileSync(this.file, "utf8");
|
|
55973
56807
|
} catch {
|
|
55974
56808
|
return null;
|
|
55975
56809
|
}
|
|
@@ -55997,16 +56831,16 @@ var OwnerIdentityStore = class {
|
|
|
55997
56831
|
};
|
|
55998
56832
|
}
|
|
55999
56833
|
write(record) {
|
|
56000
|
-
|
|
56001
|
-
|
|
56834
|
+
import_node_fs42.default.mkdirSync(import_node_path47.default.dirname(this.file), { recursive: true });
|
|
56835
|
+
import_node_fs42.default.writeFileSync(this.file, JSON.stringify(record, null, 2), { mode: 384 });
|
|
56002
56836
|
try {
|
|
56003
|
-
|
|
56837
|
+
import_node_fs42.default.chmodSync(this.file, 384);
|
|
56004
56838
|
} catch {
|
|
56005
56839
|
}
|
|
56006
56840
|
}
|
|
56007
56841
|
clear() {
|
|
56008
56842
|
try {
|
|
56009
|
-
|
|
56843
|
+
import_node_fs42.default.unlinkSync(this.file);
|
|
56010
56844
|
} catch (err) {
|
|
56011
56845
|
const code = err?.code;
|
|
56012
56846
|
if (code !== "ENOENT") throw err;
|
|
@@ -56015,7 +56849,7 @@ var OwnerIdentityStore = class {
|
|
|
56015
56849
|
};
|
|
56016
56850
|
|
|
56017
56851
|
// src/feishu-auth/login-flow.ts
|
|
56018
|
-
var
|
|
56852
|
+
var import_node_crypto13 = __toESM(require("crypto"), 1);
|
|
56019
56853
|
var STATE_TTL_MS = 5 * 60 * 1e3;
|
|
56020
56854
|
var LoginFlow = class {
|
|
56021
56855
|
constructor(deps) {
|
|
@@ -56024,7 +56858,7 @@ var LoginFlow = class {
|
|
|
56024
56858
|
deps;
|
|
56025
56859
|
pendingStates = /* @__PURE__ */ new Map();
|
|
56026
56860
|
start() {
|
|
56027
|
-
const state =
|
|
56861
|
+
const state = import_node_crypto13.default.randomBytes(16).toString("base64url");
|
|
56028
56862
|
const now = (this.deps.now ?? Date.now)();
|
|
56029
56863
|
this.pendingStates.set(state, now);
|
|
56030
56864
|
this.gcExpired(now);
|
|
@@ -56143,9 +56977,9 @@ var CentralClientError = class extends Error {
|
|
|
56143
56977
|
code;
|
|
56144
56978
|
cause;
|
|
56145
56979
|
};
|
|
56146
|
-
async function centralRequest(opts,
|
|
56980
|
+
async function centralRequest(opts, path78, init) {
|
|
56147
56981
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
56148
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
56982
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path78}`;
|
|
56149
56983
|
const ctrl = new AbortController();
|
|
56150
56984
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
56151
56985
|
let res;
|
|
@@ -56248,11 +57082,11 @@ var DeviceBindingClientError = class extends Error {
|
|
|
56248
57082
|
code;
|
|
56249
57083
|
cause;
|
|
56250
57084
|
};
|
|
56251
|
-
var
|
|
57085
|
+
var DEFAULT_TIMEOUT_MS3 = 8e3;
|
|
56252
57086
|
async function upsertDeviceBinding(opts) {
|
|
56253
57087
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
56254
57088
|
const ac = new AbortController();
|
|
56255
|
-
const timer = setTimeout(() => ac.abort(), opts.timeoutMs ??
|
|
57089
|
+
const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS3);
|
|
56256
57090
|
const body = { unionId: opts.unionId };
|
|
56257
57091
|
if (opts.avatarUrl != null) body.avatarUrl = opts.avatarUrl;
|
|
56258
57092
|
let res;
|
|
@@ -56339,8 +57173,8 @@ function verifyConnectToken(args) {
|
|
|
56339
57173
|
}
|
|
56340
57174
|
|
|
56341
57175
|
// src/feishu-auth/server-key.ts
|
|
56342
|
-
var
|
|
56343
|
-
var
|
|
57176
|
+
var fs52 = __toESM(require("fs"), 1);
|
|
57177
|
+
var path56 = __toESM(require("path"), 1);
|
|
56344
57178
|
var FILE_NAME2 = "server-signing-key.json";
|
|
56345
57179
|
var ServerKeyStore = class {
|
|
56346
57180
|
constructor(dataDir) {
|
|
@@ -56348,12 +57182,12 @@ var ServerKeyStore = class {
|
|
|
56348
57182
|
}
|
|
56349
57183
|
dataDir;
|
|
56350
57184
|
filePath() {
|
|
56351
|
-
return
|
|
57185
|
+
return path56.join(this.dataDir, FILE_NAME2);
|
|
56352
57186
|
}
|
|
56353
57187
|
/** 读缓存的公钥;无缓存 / 损坏 → null(调用方决定是否触发拉取) */
|
|
56354
57188
|
read() {
|
|
56355
57189
|
try {
|
|
56356
|
-
const raw =
|
|
57190
|
+
const raw = fs52.readFileSync(this.filePath(), "utf8");
|
|
56357
57191
|
const parsed = JSON.parse(raw);
|
|
56358
57192
|
if (typeof parsed.publicKeyPem === "string" && parsed.publicKeyPem.includes("PUBLIC KEY")) {
|
|
56359
57193
|
return parsed.publicKeyPem;
|
|
@@ -56368,12 +57202,12 @@ var ServerKeyStore = class {
|
|
|
56368
57202
|
publicKeyPem,
|
|
56369
57203
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
56370
57204
|
};
|
|
56371
|
-
|
|
56372
|
-
|
|
57205
|
+
fs52.mkdirSync(this.dataDir, { recursive: true });
|
|
57206
|
+
fs52.writeFileSync(this.filePath(), JSON.stringify(content, null, 2), { mode: 384 });
|
|
56373
57207
|
}
|
|
56374
57208
|
clear() {
|
|
56375
57209
|
try {
|
|
56376
|
-
|
|
57210
|
+
fs52.unlinkSync(this.filePath());
|
|
56377
57211
|
} catch {
|
|
56378
57212
|
}
|
|
56379
57213
|
}
|
|
@@ -56386,12 +57220,12 @@ init_protocol();
|
|
|
56386
57220
|
init_protocol();
|
|
56387
57221
|
|
|
56388
57222
|
// src/session/fork.ts
|
|
56389
|
-
var
|
|
57223
|
+
var import_node_fs43 = __toESM(require("fs"), 1);
|
|
56390
57224
|
var import_node_os16 = __toESM(require("os"), 1);
|
|
56391
|
-
var
|
|
57225
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
56392
57226
|
init_claude_history();
|
|
56393
57227
|
function readJsonlEntries(file) {
|
|
56394
|
-
const raw =
|
|
57228
|
+
const raw = import_node_fs43.default.readFileSync(file, "utf8");
|
|
56395
57229
|
const out = [];
|
|
56396
57230
|
for (const line of raw.split("\n")) {
|
|
56397
57231
|
const t = line.trim();
|
|
@@ -56404,19 +57238,19 @@ function readJsonlEntries(file) {
|
|
|
56404
57238
|
return out;
|
|
56405
57239
|
}
|
|
56406
57240
|
function forkSession(input) {
|
|
56407
|
-
const baseDir = input.baseDir ??
|
|
56408
|
-
let projectDir =
|
|
56409
|
-
let sourceFile =
|
|
56410
|
-
if (!
|
|
57241
|
+
const baseDir = input.baseDir ?? import_node_path48.default.join(import_node_os16.default.homedir(), ".claude");
|
|
57242
|
+
let projectDir = import_node_path48.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
57243
|
+
let sourceFile = import_node_path48.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
57244
|
+
if (!import_node_fs43.default.existsSync(sourceFile)) {
|
|
56411
57245
|
const found = findTranscriptByToolSessionId(
|
|
56412
|
-
|
|
57246
|
+
import_node_path48.default.join(baseDir, "projects"),
|
|
56413
57247
|
input.toolSessionId
|
|
56414
57248
|
);
|
|
56415
57249
|
if (!found) {
|
|
56416
57250
|
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
56417
57251
|
}
|
|
56418
57252
|
sourceFile = found;
|
|
56419
|
-
projectDir =
|
|
57253
|
+
projectDir = import_node_path48.default.dirname(found);
|
|
56420
57254
|
}
|
|
56421
57255
|
const entries = readJsonlEntries(sourceFile);
|
|
56422
57256
|
const mainEntries = entries.filter((e) => e.isSidechain !== true);
|
|
@@ -56445,9 +57279,9 @@ function forkSession(input) {
|
|
|
56445
57279
|
}
|
|
56446
57280
|
forkedLines.push(JSON.stringify(forked));
|
|
56447
57281
|
}
|
|
56448
|
-
const forkedFilePath =
|
|
56449
|
-
|
|
56450
|
-
|
|
57282
|
+
const forkedFilePath = import_node_path48.default.join(projectDir, `${forkedToolSessionId}.jsonl`);
|
|
57283
|
+
import_node_fs43.default.mkdirSync(projectDir, { recursive: true });
|
|
57284
|
+
import_node_fs43.default.writeFileSync(forkedFilePath, forkedLines.join("\n") + "\n", { mode: 384 });
|
|
56451
57285
|
return { forkedToolSessionId, forkedFilePath };
|
|
56452
57286
|
}
|
|
56453
57287
|
|
|
@@ -56890,7 +57724,7 @@ function buildPermissionHandlers(deps) {
|
|
|
56890
57724
|
}
|
|
56891
57725
|
|
|
56892
57726
|
// src/handlers/history.ts
|
|
56893
|
-
var
|
|
57727
|
+
var path59 = __toESM(require("path"), 1);
|
|
56894
57728
|
init_protocol();
|
|
56895
57729
|
|
|
56896
57730
|
// src/session/recent-dirs.ts
|
|
@@ -56908,7 +57742,7 @@ function listRecentDirs(store, limit = 50) {
|
|
|
56908
57742
|
}
|
|
56909
57743
|
|
|
56910
57744
|
// src/permission/persona-paths.ts
|
|
56911
|
-
var
|
|
57745
|
+
var path58 = __toESM(require("path"), 1);
|
|
56912
57746
|
function getAllowedPersonaIds(grants, action) {
|
|
56913
57747
|
const ids = /* @__PURE__ */ new Set();
|
|
56914
57748
|
for (const g2 of grants) {
|
|
@@ -56921,42 +57755,42 @@ function getAllowedPersonaIds(grants, action) {
|
|
|
56921
57755
|
return ids;
|
|
56922
57756
|
}
|
|
56923
57757
|
function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userWorkDir) {
|
|
56924
|
-
const target =
|
|
57758
|
+
const target = path58.resolve(absPath);
|
|
56925
57759
|
if (userWorkDir) {
|
|
56926
|
-
const u =
|
|
56927
|
-
const usep = u.endsWith(
|
|
57760
|
+
const u = path58.resolve(userWorkDir);
|
|
57761
|
+
const usep = u.endsWith(path58.sep) ? "" : path58.sep;
|
|
56928
57762
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
56929
57763
|
}
|
|
56930
|
-
const root =
|
|
56931
|
-
const sep3 = root.endsWith(
|
|
57764
|
+
const root = path58.resolve(personaRoot);
|
|
57765
|
+
const sep3 = root.endsWith(path58.sep) ? "" : path58.sep;
|
|
56932
57766
|
if (!target.startsWith(root + sep3)) return false;
|
|
56933
|
-
const rel =
|
|
57767
|
+
const rel = path58.relative(root, target);
|
|
56934
57768
|
if (!rel || rel.startsWith("..")) return false;
|
|
56935
|
-
const personaId2 = rel.split(
|
|
57769
|
+
const personaId2 = rel.split(path58.sep)[0];
|
|
56936
57770
|
if (!personaId2) return false;
|
|
56937
57771
|
const allowed = getAllowedPersonaIds(grants, action);
|
|
56938
57772
|
if (allowed === "*") return true;
|
|
56939
57773
|
return allowed.has(personaId2);
|
|
56940
57774
|
}
|
|
56941
57775
|
function personaIdFromPath(absPath, personaRoot) {
|
|
56942
|
-
const root =
|
|
56943
|
-
const target =
|
|
56944
|
-
const sep3 = root.endsWith(
|
|
57776
|
+
const root = path58.resolve(personaRoot);
|
|
57777
|
+
const target = path58.resolve(absPath);
|
|
57778
|
+
const sep3 = root.endsWith(path58.sep) ? "" : path58.sep;
|
|
56945
57779
|
if (!target.startsWith(root + sep3)) return null;
|
|
56946
|
-
const rel =
|
|
57780
|
+
const rel = path58.relative(root, target);
|
|
56947
57781
|
if (!rel || rel.startsWith("..")) return null;
|
|
56948
|
-
const id = rel.split(
|
|
57782
|
+
const id = rel.split(path58.sep)[0];
|
|
56949
57783
|
return id || null;
|
|
56950
57784
|
}
|
|
56951
57785
|
function isPathWithin(dir, absPath) {
|
|
56952
|
-
const d =
|
|
56953
|
-
const t =
|
|
56954
|
-
const sep3 = d.endsWith(
|
|
57786
|
+
const d = path58.resolve(dir);
|
|
57787
|
+
const t = path58.resolve(absPath);
|
|
57788
|
+
const sep3 = d.endsWith(path58.sep) ? "" : path58.sep;
|
|
56955
57789
|
return t === d || t.startsWith(d + sep3);
|
|
56956
57790
|
}
|
|
56957
57791
|
function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
|
|
56958
57792
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
56959
|
-
return personaIdFromPath(
|
|
57793
|
+
return personaIdFromPath(path58.resolve(absPath), personaRoot) === personaId2;
|
|
56960
57794
|
}
|
|
56961
57795
|
|
|
56962
57796
|
// src/handlers/history.ts
|
|
@@ -57008,7 +57842,7 @@ function buildHistoryHandlers(deps) {
|
|
|
57008
57842
|
if (!pid) return false;
|
|
57009
57843
|
return isGuestPathAllowed(
|
|
57010
57844
|
ctx.grants,
|
|
57011
|
-
|
|
57845
|
+
path59.join(personaRoot, pid),
|
|
57012
57846
|
personaRoot,
|
|
57013
57847
|
"read",
|
|
57014
57848
|
userWorkDir
|
|
@@ -57020,7 +57854,7 @@ function buildHistoryHandlers(deps) {
|
|
|
57020
57854
|
};
|
|
57021
57855
|
const list = async (frame, _client, ctx) => {
|
|
57022
57856
|
const args = HistoryListArgs.parse(frame);
|
|
57023
|
-
assertGuestPath(ctx,
|
|
57857
|
+
assertGuestPath(ctx, path59.resolve(args.projectPath), personaRoot, "history:list", usersRoot);
|
|
57024
57858
|
const sessions = await history.listSessions(args);
|
|
57025
57859
|
return { response: { type: "history:list", sessions } };
|
|
57026
57860
|
};
|
|
@@ -57053,13 +57887,13 @@ function buildHistoryHandlers(deps) {
|
|
|
57053
57887
|
};
|
|
57054
57888
|
const subagents = async (frame, _client, ctx) => {
|
|
57055
57889
|
const args = HistorySubagentsArgs.parse(frame);
|
|
57056
|
-
assertGuestPath(ctx,
|
|
57890
|
+
assertGuestPath(ctx, path59.resolve(args.cwd), personaRoot, "history:subagents", usersRoot);
|
|
57057
57891
|
const subs = await history.listSubagents(args);
|
|
57058
57892
|
return { response: { type: "history:subagents", subagents: subs } };
|
|
57059
57893
|
};
|
|
57060
57894
|
const subagentRead = async (frame, _client, ctx) => {
|
|
57061
57895
|
const args = HistorySubagentReadArgs.parse(frame);
|
|
57062
|
-
assertGuestPath(ctx,
|
|
57896
|
+
assertGuestPath(ctx, path59.resolve(args.cwd), personaRoot, "history:subagent-read", usersRoot);
|
|
57063
57897
|
const res = await history.readSubagent(args);
|
|
57064
57898
|
return { response: { type: "history:subagent-read", ...res } };
|
|
57065
57899
|
};
|
|
@@ -57068,7 +57902,7 @@ function buildHistoryHandlers(deps) {
|
|
|
57068
57902
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
57069
57903
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
57070
57904
|
const filtered = dirs.filter(
|
|
57071
|
-
(d) => isGuestPathAllowed(ctx.grants,
|
|
57905
|
+
(d) => isGuestPathAllowed(ctx.grants, path59.resolve(d.cwd), personaRoot, "read", userWorkDir)
|
|
57072
57906
|
);
|
|
57073
57907
|
return { response: { type: "history:recentDirs", dirs: filtered } };
|
|
57074
57908
|
}
|
|
@@ -57085,7 +57919,7 @@ function buildHistoryHandlers(deps) {
|
|
|
57085
57919
|
}
|
|
57086
57920
|
|
|
57087
57921
|
// src/handlers/workspace.ts
|
|
57088
|
-
var
|
|
57922
|
+
var path60 = __toESM(require("path"), 1);
|
|
57089
57923
|
var os16 = __toESM(require("os"), 1);
|
|
57090
57924
|
init_protocol();
|
|
57091
57925
|
init_protocol();
|
|
@@ -57127,22 +57961,22 @@ function buildWorkspaceHandlers(deps) {
|
|
|
57127
57961
|
const args = WorkspaceListArgs.parse(frame);
|
|
57128
57962
|
const isGuest = ctx?.principal.kind === "guest";
|
|
57129
57963
|
const fallbackCwd = isGuest && personaRoot ? personaRoot : os16.homedir();
|
|
57130
|
-
const resolvedCwd =
|
|
57131
|
-
const target = args.path ?
|
|
57964
|
+
const resolvedCwd = path60.resolve(args.cwd ?? fallbackCwd);
|
|
57965
|
+
const target = args.path ? path60.resolve(resolvedCwd, args.path) : resolvedCwd;
|
|
57132
57966
|
assertGuestPath2(ctx, target, personaRoot, "workspace:list", usersRoot);
|
|
57133
57967
|
const res = workspace.list({ ...args, cwd: resolvedCwd });
|
|
57134
57968
|
return { response: { type: "workspace:list", ...res } };
|
|
57135
57969
|
};
|
|
57136
57970
|
const read = async (frame, _client, ctx) => {
|
|
57137
57971
|
const args = WorkspaceReadArgs.parse(frame);
|
|
57138
|
-
const target =
|
|
57972
|
+
const target = path60.isAbsolute(args.path) ? path60.resolve(args.path) : path60.resolve(args.cwd, args.path);
|
|
57139
57973
|
assertGuestPath2(ctx, target, personaRoot, "workspace:read", usersRoot);
|
|
57140
57974
|
const res = workspace.read(args);
|
|
57141
57975
|
return { response: { type: "workspace:read", ...res } };
|
|
57142
57976
|
};
|
|
57143
57977
|
const skillsList = async (frame, _client, ctx) => {
|
|
57144
57978
|
const args = SkillsListArgs.parse(frame);
|
|
57145
|
-
const cwdAbs =
|
|
57979
|
+
const cwdAbs = path60.resolve(args.cwd);
|
|
57146
57980
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
|
|
57147
57981
|
const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
|
|
57148
57982
|
if (ctx?.principal.kind === "guest" && personaRoot) {
|
|
@@ -57154,7 +57988,7 @@ function buildWorkspaceHandlers(deps) {
|
|
|
57154
57988
|
};
|
|
57155
57989
|
const agentsList = async (frame, _client, ctx) => {
|
|
57156
57990
|
const args = AgentsListArgs.parse(frame);
|
|
57157
|
-
const cwdAbs =
|
|
57991
|
+
const cwdAbs = path60.resolve(args.cwd);
|
|
57158
57992
|
assertGuestPath2(ctx, cwdAbs, personaRoot, "agents:list", usersRoot);
|
|
57159
57993
|
if (args.tool === "codex") {
|
|
57160
57994
|
return { response: { type: "agents:list", agents: [] } };
|
|
@@ -57176,20 +58010,20 @@ function buildWorkspaceHandlers(deps) {
|
|
|
57176
58010
|
}
|
|
57177
58011
|
|
|
57178
58012
|
// src/handlers/git.ts
|
|
57179
|
-
var
|
|
58013
|
+
var path62 = __toESM(require("path"), 1);
|
|
57180
58014
|
init_protocol();
|
|
57181
58015
|
init_protocol();
|
|
57182
58016
|
|
|
57183
58017
|
// src/workspace/git.ts
|
|
57184
58018
|
var import_node_child_process10 = require("child_process");
|
|
57185
|
-
var
|
|
57186
|
-
var
|
|
58019
|
+
var import_node_fs44 = __toESM(require("fs"), 1);
|
|
58020
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
57187
58021
|
var import_node_util = require("util");
|
|
57188
58022
|
var pexec = (0, import_node_util.promisify)(import_node_child_process10.execFile);
|
|
57189
58023
|
function normalizePath(p2) {
|
|
57190
|
-
const resolved =
|
|
58024
|
+
const resolved = import_node_path49.default.resolve(p2);
|
|
57191
58025
|
try {
|
|
57192
|
-
return
|
|
58026
|
+
return import_node_fs44.default.realpathSync(resolved);
|
|
57193
58027
|
} catch {
|
|
57194
58028
|
return resolved;
|
|
57195
58029
|
}
|
|
@@ -57263,7 +58097,7 @@ async function listGitBranches(cwd) {
|
|
|
57263
58097
|
function assertGuestCwd(ctx, cwd, personaRoot, method, usersRoot) {
|
|
57264
58098
|
if (!ctx || ctx.principal.kind !== "guest" || !personaRoot) return;
|
|
57265
58099
|
const userWorkDir = usersRoot ? deriveUserWorkDir(ctx.principal.id, usersRoot) : void 0;
|
|
57266
|
-
if (!isGuestPathAllowed(ctx.grants,
|
|
58100
|
+
if (!isGuestPathAllowed(ctx.grants, path62.resolve(cwd), personaRoot, "read", userWorkDir)) {
|
|
57267
58101
|
throw new ClawdError(
|
|
57268
58102
|
ERROR_CODES.UNAUTHORIZED,
|
|
57269
58103
|
`guest ${ctx.principal.id} cannot ${method} cwd ${cwd}`
|
|
@@ -57993,6 +58827,12 @@ var METHOD_GRANT_MAP = {
|
|
|
57993
58827
|
"shift-internal:cancel": ADMIN_ANY,
|
|
57994
58828
|
"shift-internal:update": ADMIN_ANY,
|
|
57995
58829
|
"shift-internal:history": ADMIN_ANY,
|
|
58830
|
+
// ---- larkBot:* (LarkBotConnector 装配/状态,owner-only) ----
|
|
58831
|
+
"larkBot:provision": ADMIN_ANY,
|
|
58832
|
+
"larkBot:provisionCancel": ADMIN_ANY,
|
|
58833
|
+
"larkBot:bindManual": ADMIN_ANY,
|
|
58834
|
+
"larkBot:unbind": ADMIN_ANY,
|
|
58835
|
+
"larkBot:status": ADMIN_ANY,
|
|
57996
58836
|
"inbox:sendDm": ADMIN_ANY,
|
|
57997
58837
|
"personaDispatch:complete": ADMIN_ANY,
|
|
57998
58838
|
"personaDispatch:list": ADMIN_ANY,
|
|
@@ -58124,21 +58964,21 @@ function computeMethodAccess(args) {
|
|
|
58124
58964
|
}
|
|
58125
58965
|
|
|
58126
58966
|
// src/version.ts
|
|
58127
|
-
var version = "0.2.
|
|
58967
|
+
var version = "0.2.286".length > 0 ? "0.2.286" : "dev";
|
|
58128
58968
|
|
|
58129
58969
|
// src/cli-probe/probe.ts
|
|
58130
|
-
var
|
|
58131
|
-
var
|
|
58970
|
+
var fs55 = __toESM(require("fs"), 1);
|
|
58971
|
+
var path63 = __toESM(require("path"), 1);
|
|
58132
58972
|
var PKG_NAME = "@clawos-dev/clawd";
|
|
58133
58973
|
var BIN_NAME = "clawd";
|
|
58134
58974
|
var MAX_PARENT_HOPS = 5;
|
|
58135
58975
|
function probeGlobalCli(pathEnv) {
|
|
58136
58976
|
if (!pathEnv) return null;
|
|
58137
|
-
for (const dir of pathEnv.split(
|
|
58977
|
+
for (const dir of pathEnv.split(path63.delimiter)) {
|
|
58138
58978
|
if (!dir) continue;
|
|
58139
58979
|
let real;
|
|
58140
58980
|
try {
|
|
58141
|
-
real =
|
|
58981
|
+
real = fs55.realpathSync(path63.join(dir, BIN_NAME));
|
|
58142
58982
|
} catch {
|
|
58143
58983
|
continue;
|
|
58144
58984
|
}
|
|
@@ -58148,15 +58988,15 @@ function probeGlobalCli(pathEnv) {
|
|
|
58148
58988
|
return null;
|
|
58149
58989
|
}
|
|
58150
58990
|
function readOwnPackageVersion(entryPath) {
|
|
58151
|
-
let dir =
|
|
58991
|
+
let dir = path63.dirname(entryPath);
|
|
58152
58992
|
for (let i = 0; i < MAX_PARENT_HOPS; i++) {
|
|
58153
58993
|
try {
|
|
58154
|
-
const raw =
|
|
58994
|
+
const raw = fs55.readFileSync(path63.join(dir, "package.json"), "utf8");
|
|
58155
58995
|
const pkg = JSON.parse(raw);
|
|
58156
58996
|
if (pkg.name !== PKG_NAME) return null;
|
|
58157
58997
|
return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
|
|
58158
58998
|
} catch {
|
|
58159
|
-
const parent =
|
|
58999
|
+
const parent = path63.dirname(dir);
|
|
58160
59000
|
if (parent === dir) return null;
|
|
58161
59001
|
dir = parent;
|
|
58162
59002
|
}
|
|
@@ -58314,7 +59154,7 @@ function buildPersonaHandlers(deps) {
|
|
|
58314
59154
|
}
|
|
58315
59155
|
|
|
58316
59156
|
// src/handlers/attachment.ts
|
|
58317
|
-
var
|
|
59157
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
58318
59158
|
init_protocol();
|
|
58319
59159
|
init_protocol();
|
|
58320
59160
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
@@ -58394,12 +59234,12 @@ function buildAttachmentHandlers(deps) {
|
|
|
58394
59234
|
`session ${args.sessionId} scope unresolved`
|
|
58395
59235
|
);
|
|
58396
59236
|
}
|
|
58397
|
-
const cwdAbs =
|
|
58398
|
-
const candidateAbs =
|
|
59237
|
+
const cwdAbs = import_node_path50.default.resolve(sessionFile.cwd);
|
|
59238
|
+
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
59239
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.signUrl", "group-acl");
|
|
58400
59240
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
58401
59241
|
const entry = entries.find((e) => {
|
|
58402
|
-
const storedAbs =
|
|
59242
|
+
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
59243
|
return storedAbs === candidateAbs && !e.stale;
|
|
58404
59244
|
});
|
|
58405
59245
|
if (!entry) {
|
|
@@ -58424,7 +59264,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
58424
59264
|
if (!ctx || ctx.principal.kind !== "guest" || !deps.personaRoot || !deps.sessionStore) return;
|
|
58425
59265
|
const f = deps.sessionStore.read(sessionId);
|
|
58426
59266
|
if (!f) return;
|
|
58427
|
-
assertGuestAttachmentPath(ctx,
|
|
59267
|
+
assertGuestAttachmentPath(ctx, import_node_path50.default.resolve(f.cwd), deps.personaRoot, method, deps.usersRoot);
|
|
58428
59268
|
}
|
|
58429
59269
|
const groupAdd = async (frame, _client, ctx) => {
|
|
58430
59270
|
if (!deps.groupFileStore || !deps.getSessionScope) {
|
|
@@ -58439,8 +59279,8 @@ function buildAttachmentHandlers(deps) {
|
|
|
58439
59279
|
if (!scope) {
|
|
58440
59280
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
|
|
58441
59281
|
}
|
|
58442
|
-
const cwdAbs =
|
|
58443
|
-
const candidateAbs =
|
|
59282
|
+
const cwdAbs = import_node_path50.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
|
|
59283
|
+
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
59284
|
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
|
|
58445
59285
|
const from = args.origin === "agent" ? "agent" : ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
58446
59286
|
const size = 0;
|
|
@@ -58499,19 +59339,19 @@ function buildAttachmentHandlers(deps) {
|
|
|
58499
59339
|
|
|
58500
59340
|
// src/handlers/extension.ts
|
|
58501
59341
|
var import_promises9 = __toESM(require("fs/promises"), 1);
|
|
58502
|
-
var
|
|
59342
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
58503
59343
|
init_protocol();
|
|
58504
59344
|
|
|
58505
59345
|
// src/extension/bundle-zip.ts
|
|
58506
59346
|
var import_promises6 = __toESM(require("fs/promises"), 1);
|
|
58507
|
-
var
|
|
58508
|
-
var
|
|
59347
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
59348
|
+
var import_node_crypto14 = __toESM(require("crypto"), 1);
|
|
58509
59349
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
58510
59350
|
async function bundleExtensionDir(dir) {
|
|
58511
59351
|
const entries = await listFilesSorted(dir);
|
|
58512
59352
|
const zip = new import_jszip2.default();
|
|
58513
59353
|
for (const rel of entries) {
|
|
58514
|
-
const abs =
|
|
59354
|
+
const abs = import_node_path51.default.join(dir, rel);
|
|
58515
59355
|
const content = await import_promises6.default.readFile(abs);
|
|
58516
59356
|
zip.file(rel, content, { date: FIXED_DATE });
|
|
58517
59357
|
}
|
|
@@ -58520,7 +59360,7 @@ async function bundleExtensionDir(dir) {
|
|
|
58520
59360
|
compression: "DEFLATE",
|
|
58521
59361
|
compressionOptions: { level: 6 }
|
|
58522
59362
|
});
|
|
58523
|
-
const sha256 =
|
|
59363
|
+
const sha256 = import_node_crypto14.default.createHash("sha256").update(buffer).digest("hex");
|
|
58524
59364
|
return { buffer, sha256 };
|
|
58525
59365
|
}
|
|
58526
59366
|
var FIXED_DATE = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
|
|
@@ -58532,7 +59372,7 @@ async function listFilesSorted(rootDir) {
|
|
|
58532
59372
|
return out;
|
|
58533
59373
|
}
|
|
58534
59374
|
async function walk(absRoot, relPrefix, out) {
|
|
58535
|
-
const dirAbs =
|
|
59375
|
+
const dirAbs = import_node_path51.default.join(absRoot, relPrefix);
|
|
58536
59376
|
const entries = await import_promises6.default.readdir(dirAbs, { withFileTypes: true });
|
|
58537
59377
|
for (const e of entries) {
|
|
58538
59378
|
if (IGNORE_BASENAMES.has(e.name)) continue;
|
|
@@ -58586,25 +59426,25 @@ function computePublishCheck(args) {
|
|
|
58586
59426
|
|
|
58587
59427
|
// src/extension/install-flow.ts
|
|
58588
59428
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
58589
|
-
var
|
|
59429
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
58590
59430
|
var import_node_os19 = __toESM(require("os"), 1);
|
|
58591
|
-
var
|
|
59431
|
+
var import_node_crypto15 = __toESM(require("crypto"), 1);
|
|
58592
59432
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
58593
59433
|
|
|
58594
59434
|
// src/extension/paths.ts
|
|
58595
59435
|
var import_node_os18 = __toESM(require("os"), 1);
|
|
58596
|
-
var
|
|
59436
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
58597
59437
|
function clawdHomeRoot(override) {
|
|
58598
|
-
return override ?? process.env.CLAWD_HOME ??
|
|
59438
|
+
return override ?? process.env.CLAWD_HOME ?? import_node_path52.default.join(import_node_os18.default.homedir(), ".clawd");
|
|
58599
59439
|
}
|
|
58600
59440
|
function extensionsRoot(override) {
|
|
58601
|
-
return
|
|
59441
|
+
return import_node_path52.default.join(clawdHomeRoot(override), "extensions");
|
|
58602
59442
|
}
|
|
58603
59443
|
function publishedChannelsFile(override) {
|
|
58604
|
-
return
|
|
59444
|
+
return import_node_path52.default.join(clawdHomeRoot(override), "extensions-published.json");
|
|
58605
59445
|
}
|
|
58606
59446
|
function bundleCacheRoot(override) {
|
|
58607
|
-
return
|
|
59447
|
+
return import_node_path52.default.join(clawdHomeRoot(override), "extension-bundles");
|
|
58608
59448
|
}
|
|
58609
59449
|
|
|
58610
59450
|
// src/extension/install-flow.ts
|
|
@@ -58617,7 +59457,7 @@ var InstallError = class extends Error {
|
|
|
58617
59457
|
};
|
|
58618
59458
|
async function installFromChannel(args, deps) {
|
|
58619
59459
|
const { channelRef, snapshotHash, bundleZip } = args;
|
|
58620
|
-
const computed =
|
|
59460
|
+
const computed = import_node_crypto15.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
58621
59461
|
if (computed !== snapshotHash) {
|
|
58622
59462
|
throw new InstallError(
|
|
58623
59463
|
"HASH_MISMATCH",
|
|
@@ -58631,7 +59471,7 @@ async function installFromChannel(args, deps) {
|
|
|
58631
59471
|
throw new InstallError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
58632
59472
|
}
|
|
58633
59473
|
for (const name of Object.keys(zip.files)) {
|
|
58634
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
59474
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path53.default.isAbsolute(name)) {
|
|
58635
59475
|
throw new InstallError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
58636
59476
|
}
|
|
58637
59477
|
}
|
|
@@ -58663,7 +59503,7 @@ async function installFromChannel(args, deps) {
|
|
|
58663
59503
|
);
|
|
58664
59504
|
}
|
|
58665
59505
|
const localExtId = namespacedExtId(ownerSlug, channelRef.ownerPrincipalId);
|
|
58666
|
-
const destDir =
|
|
59506
|
+
const destDir = import_node_path53.default.join(deps.extensionsRoot, localExtId);
|
|
58667
59507
|
let destExists = false;
|
|
58668
59508
|
try {
|
|
58669
59509
|
await import_promises7.default.access(destDir);
|
|
@@ -58677,16 +59517,16 @@ async function installFromChannel(args, deps) {
|
|
|
58677
59517
|
);
|
|
58678
59518
|
}
|
|
58679
59519
|
const stage = await import_promises7.default.mkdtemp(
|
|
58680
|
-
|
|
59520
|
+
import_node_path53.default.join(import_node_os19.default.tmpdir(), `clawd-ext-install-${localExtId}-`)
|
|
58681
59521
|
);
|
|
58682
59522
|
try {
|
|
58683
59523
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
58684
|
-
const dest =
|
|
59524
|
+
const dest = import_node_path53.default.join(stage, name);
|
|
58685
59525
|
if (entry.dir) {
|
|
58686
59526
|
await import_promises7.default.mkdir(dest, { recursive: true });
|
|
58687
59527
|
continue;
|
|
58688
59528
|
}
|
|
58689
|
-
await import_promises7.default.mkdir(
|
|
59529
|
+
await import_promises7.default.mkdir(import_node_path53.default.dirname(dest), { recursive: true });
|
|
58690
59530
|
if (name === "manifest.json") {
|
|
58691
59531
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
58692
59532
|
await import_promises7.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -58707,9 +59547,9 @@ async function installFromChannel(args, deps) {
|
|
|
58707
59547
|
|
|
58708
59548
|
// src/extension/update-flow.ts
|
|
58709
59549
|
var import_promises8 = __toESM(require("fs/promises"), 1);
|
|
58710
|
-
var
|
|
59550
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
58711
59551
|
var import_node_os20 = __toESM(require("os"), 1);
|
|
58712
|
-
var
|
|
59552
|
+
var import_node_crypto16 = __toESM(require("crypto"), 1);
|
|
58713
59553
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
58714
59554
|
var UpdateError = class extends Error {
|
|
58715
59555
|
constructor(code, message) {
|
|
@@ -58724,11 +59564,11 @@ async function updateFromChannel(args, deps) {
|
|
|
58724
59564
|
channelRef.extId,
|
|
58725
59565
|
channelRef.ownerPrincipalId
|
|
58726
59566
|
);
|
|
58727
|
-
const liveDir =
|
|
59567
|
+
const liveDir = import_node_path54.default.join(deps.extensionsRoot, localExtId);
|
|
58728
59568
|
const prevDir = `${liveDir}.prev`;
|
|
58729
59569
|
let existingVersion;
|
|
58730
59570
|
try {
|
|
58731
|
-
const raw = await import_promises8.default.readFile(
|
|
59571
|
+
const raw = await import_promises8.default.readFile(import_node_path54.default.join(liveDir, "manifest.json"), "utf8");
|
|
58732
59572
|
const parsed2 = ExtensionManifestSchema.safeParse(JSON.parse(raw));
|
|
58733
59573
|
if (!parsed2.success) {
|
|
58734
59574
|
throw new UpdateError(
|
|
@@ -58747,7 +59587,7 @@ async function updateFromChannel(args, deps) {
|
|
|
58747
59587
|
if (e instanceof UpdateError) throw e;
|
|
58748
59588
|
throw e;
|
|
58749
59589
|
}
|
|
58750
|
-
const computed =
|
|
59590
|
+
const computed = import_node_crypto16.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
58751
59591
|
if (computed !== snapshotHash) {
|
|
58752
59592
|
throw new UpdateError(
|
|
58753
59593
|
"HASH_MISMATCH",
|
|
@@ -58761,7 +59601,7 @@ async function updateFromChannel(args, deps) {
|
|
|
58761
59601
|
throw new UpdateError("ZIP_INVALID", `failed to load zip: ${e.message}`);
|
|
58762
59602
|
}
|
|
58763
59603
|
for (const name of Object.keys(zip.files)) {
|
|
58764
|
-
if (name.includes("..") || name.startsWith("/") ||
|
|
59604
|
+
if (name.includes("..") || name.startsWith("/") || import_node_path54.default.isAbsolute(name)) {
|
|
58765
59605
|
throw new UpdateError("ZIP_INVALID", `unsafe zip entry: ${name}`);
|
|
58766
59606
|
}
|
|
58767
59607
|
}
|
|
@@ -58796,16 +59636,16 @@ async function updateFromChannel(args, deps) {
|
|
|
58796
59636
|
await import_promises8.default.rm(prevDir, { recursive: true, force: true });
|
|
58797
59637
|
await import_promises8.default.rename(liveDir, prevDir);
|
|
58798
59638
|
const stage = await import_promises8.default.mkdtemp(
|
|
58799
|
-
|
|
59639
|
+
import_node_path54.default.join(import_node_os20.default.tmpdir(), `clawd-ext-update-${localExtId}-`)
|
|
58800
59640
|
);
|
|
58801
59641
|
try {
|
|
58802
59642
|
for (const [name, entry] of Object.entries(zip.files)) {
|
|
58803
|
-
const dest =
|
|
59643
|
+
const dest = import_node_path54.default.join(stage, name);
|
|
58804
59644
|
if (entry.dir) {
|
|
58805
59645
|
await import_promises8.default.mkdir(dest, { recursive: true });
|
|
58806
59646
|
continue;
|
|
58807
59647
|
}
|
|
58808
|
-
await import_promises8.default.mkdir(
|
|
59648
|
+
await import_promises8.default.mkdir(import_node_path54.default.dirname(dest), { recursive: true });
|
|
58809
59649
|
if (name === "manifest.json") {
|
|
58810
59650
|
const rewritten = { ...parsed.data, id: localExtId };
|
|
58811
59651
|
await import_promises8.default.writeFile(dest, JSON.stringify(rewritten, null, 2));
|
|
@@ -58872,7 +59712,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
58872
59712
|
);
|
|
58873
59713
|
}
|
|
58874
59714
|
}
|
|
58875
|
-
const manifestPath =
|
|
59715
|
+
const manifestPath = import_node_path55.default.join(root, extId, "manifest.json");
|
|
58876
59716
|
const manifest = await readManifest(root, extId);
|
|
58877
59717
|
const next = { ...manifest, version: newVersion };
|
|
58878
59718
|
const tmp = `${manifestPath}.tmp`;
|
|
@@ -58880,7 +59720,7 @@ async function rewriteManifestVersion(root, extId, newVersion, previousPublished
|
|
|
58880
59720
|
await import_promises9.default.rename(tmp, manifestPath);
|
|
58881
59721
|
}
|
|
58882
59722
|
async function readManifest(root, extId) {
|
|
58883
|
-
const file =
|
|
59723
|
+
const file = import_node_path55.default.join(root, extId, "manifest.json");
|
|
58884
59724
|
let raw;
|
|
58885
59725
|
try {
|
|
58886
59726
|
raw = await import_promises9.default.readFile(file, "utf8");
|
|
@@ -58964,7 +59804,7 @@ function buildExtensionHandlers(deps) {
|
|
|
58964
59804
|
};
|
|
58965
59805
|
async function buildSnapshotMeta(extId) {
|
|
58966
59806
|
const manifest = await readManifest(deps.root, extId);
|
|
58967
|
-
const { sha256, buffer } = await bundleExtensionDir(
|
|
59807
|
+
const { sha256, buffer } = await bundleExtensionDir(import_node_path55.default.join(deps.root, extId));
|
|
58968
59808
|
return { manifest, contentHash: sha256, buffer };
|
|
58969
59809
|
}
|
|
58970
59810
|
const publish = async (frame, _client, ctx) => {
|
|
@@ -59139,9 +59979,9 @@ function buildExtensionHandlers(deps) {
|
|
|
59139
59979
|
}
|
|
59140
59980
|
|
|
59141
59981
|
// src/app-builder/project-store.ts
|
|
59142
|
-
var
|
|
59982
|
+
var import_node_fs45 = require("fs");
|
|
59143
59983
|
var import_node_child_process11 = require("child_process");
|
|
59144
|
-
var
|
|
59984
|
+
var import_node_path56 = require("path");
|
|
59145
59985
|
init_protocol();
|
|
59146
59986
|
var PROJECTS_DIR = "projects";
|
|
59147
59987
|
var META_FILE = ".clawd-project.json";
|
|
@@ -59155,19 +59995,19 @@ var ProjectStore = class {
|
|
|
59155
59995
|
root;
|
|
59156
59996
|
/** projects/<name>/.clawd-project.json 路径 */
|
|
59157
59997
|
metaPath(name) {
|
|
59158
|
-
return (0,
|
|
59998
|
+
return (0, import_node_path56.join)(this.projectsRoot(), name, META_FILE);
|
|
59159
59999
|
}
|
|
59160
60000
|
/** projects/<name>/ 目录路径(cwd 用) */
|
|
59161
60001
|
projectDir(name) {
|
|
59162
|
-
return (0,
|
|
60002
|
+
return (0, import_node_path56.join)(this.projectsRoot(), name);
|
|
59163
60003
|
}
|
|
59164
60004
|
projectsRoot() {
|
|
59165
|
-
return (0,
|
|
60005
|
+
return (0, import_node_path56.join)(this.root, PROJECTS_DIR);
|
|
59166
60006
|
}
|
|
59167
60007
|
async list() {
|
|
59168
60008
|
let entries;
|
|
59169
60009
|
try {
|
|
59170
|
-
entries = await
|
|
60010
|
+
entries = await import_node_fs45.promises.readdir(this.projectsRoot());
|
|
59171
60011
|
} catch (err) {
|
|
59172
60012
|
if (err.code === "ENOENT") return [];
|
|
59173
60013
|
throw err;
|
|
@@ -59175,7 +60015,7 @@ var ProjectStore = class {
|
|
|
59175
60015
|
const out = [];
|
|
59176
60016
|
for (const name of entries) {
|
|
59177
60017
|
try {
|
|
59178
|
-
const raw = await
|
|
60018
|
+
const raw = await import_node_fs45.promises.readFile(this.metaPath(name), "utf8");
|
|
59179
60019
|
const json = JSON.parse(raw);
|
|
59180
60020
|
let migrated = false;
|
|
59181
60021
|
if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
|
|
@@ -59186,7 +60026,7 @@ var ProjectStore = class {
|
|
|
59186
60026
|
if (parsed.success) {
|
|
59187
60027
|
out.push(parsed.data);
|
|
59188
60028
|
if (migrated) {
|
|
59189
|
-
void
|
|
60029
|
+
void import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
|
|
59190
60030
|
});
|
|
59191
60031
|
}
|
|
59192
60032
|
}
|
|
@@ -59230,8 +60070,8 @@ var ProjectStore = class {
|
|
|
59230
60070
|
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
59231
60071
|
}
|
|
59232
60072
|
const dir = this.projectDir(name);
|
|
59233
|
-
await
|
|
59234
|
-
await
|
|
60073
|
+
await import_node_fs45.promises.mkdir(dir, { recursive: true });
|
|
60074
|
+
await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
59235
60075
|
return meta;
|
|
59236
60076
|
}
|
|
59237
60077
|
/**
|
|
@@ -59274,7 +60114,7 @@ var ProjectStore = class {
|
|
|
59274
60114
|
}
|
|
59275
60115
|
async delete(name) {
|
|
59276
60116
|
const dir = this.projectDir(name);
|
|
59277
|
-
await
|
|
60117
|
+
await import_node_fs45.promises.rm(dir, { recursive: true, force: true });
|
|
59278
60118
|
}
|
|
59279
60119
|
async updatePort(name, newPort) {
|
|
59280
60120
|
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
@@ -59290,7 +60130,7 @@ var ProjectStore = class {
|
|
|
59290
60130
|
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
59291
60131
|
}
|
|
59292
60132
|
const updated = { ...target, port: newPort };
|
|
59293
|
-
await
|
|
60133
|
+
await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
59294
60134
|
return updated;
|
|
59295
60135
|
}
|
|
59296
60136
|
/**
|
|
@@ -59307,7 +60147,7 @@ var ProjectStore = class {
|
|
|
59307
60147
|
if (!validated.success) {
|
|
59308
60148
|
throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
|
|
59309
60149
|
}
|
|
59310
|
-
await
|
|
60150
|
+
await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
59311
60151
|
return validated.data;
|
|
59312
60152
|
}
|
|
59313
60153
|
/**
|
|
@@ -59328,7 +60168,7 @@ var ProjectStore = class {
|
|
|
59328
60168
|
if (!validated.success) {
|
|
59329
60169
|
throw new Error(`invalid publishJob: ${validated.error.message}`);
|
|
59330
60170
|
}
|
|
59331
|
-
await
|
|
60171
|
+
await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
59332
60172
|
return validated.data;
|
|
59333
60173
|
}
|
|
59334
60174
|
/** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
|
|
@@ -59343,7 +60183,7 @@ var ProjectStore = class {
|
|
|
59343
60183
|
if (!validated.success) {
|
|
59344
60184
|
throw new Error(`failed to clear publishJob: ${validated.error.message}`);
|
|
59345
60185
|
}
|
|
59346
|
-
await
|
|
60186
|
+
await import_node_fs45.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
59347
60187
|
return validated.data;
|
|
59348
60188
|
}
|
|
59349
60189
|
};
|
|
@@ -59413,7 +60253,7 @@ function listPidsOnPort(port) {
|
|
|
59413
60253
|
}
|
|
59414
60254
|
|
|
59415
60255
|
// src/app-builder/publish-registry.ts
|
|
59416
|
-
var
|
|
60256
|
+
var import_node_crypto17 = require("crypto");
|
|
59417
60257
|
var PublishJobRegistry = class {
|
|
59418
60258
|
jobs = /* @__PURE__ */ new Map();
|
|
59419
60259
|
has(name) {
|
|
@@ -59430,7 +60270,7 @@ var PublishJobRegistry = class {
|
|
|
59430
60270
|
if (this.jobs.has(args.name)) {
|
|
59431
60271
|
throw new Error(`already publishing: ${args.name}`);
|
|
59432
60272
|
}
|
|
59433
|
-
const jobId = args.jobId ?? `job-${(0,
|
|
60273
|
+
const jobId = args.jobId ?? `job-${(0, import_node_crypto17.randomUUID)()}`;
|
|
59434
60274
|
this.jobs.set(args.name, {
|
|
59435
60275
|
jobId,
|
|
59436
60276
|
name: args.name,
|
|
@@ -59464,8 +60304,8 @@ var PublishJobRegistry = class {
|
|
|
59464
60304
|
|
|
59465
60305
|
// src/app-builder/publish-job-runner.ts
|
|
59466
60306
|
var import_node_child_process13 = require("child_process");
|
|
59467
|
-
var
|
|
59468
|
-
var
|
|
60307
|
+
var import_node_fs46 = require("fs");
|
|
60308
|
+
var import_node_path57 = require("path");
|
|
59469
60309
|
|
|
59470
60310
|
// src/app-builder/publish-stage-parser.ts
|
|
59471
60311
|
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
@@ -59497,10 +60337,10 @@ async function startPublishJob(deps, args) {
|
|
|
59497
60337
|
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
59498
60338
|
}
|
|
59499
60339
|
const projDir = projectDir(args.name);
|
|
59500
|
-
const logPath = (0,
|
|
60340
|
+
const logPath = (0, import_node_path57.join)(projDir, ".publish.log");
|
|
59501
60341
|
let logStream = null;
|
|
59502
60342
|
try {
|
|
59503
|
-
logStream = (0,
|
|
60343
|
+
logStream = (0, import_node_fs46.createWriteStream)(logPath, { flags: "w" });
|
|
59504
60344
|
} catch {
|
|
59505
60345
|
logStream = null;
|
|
59506
60346
|
}
|
|
@@ -59757,8 +60597,8 @@ async function recoverInterruptedJobs(deps) {
|
|
|
59757
60597
|
|
|
59758
60598
|
// src/handlers/app-builder.ts
|
|
59759
60599
|
init_protocol();
|
|
59760
|
-
var
|
|
59761
|
-
var
|
|
60600
|
+
var import_node_path58 = require("path");
|
|
60601
|
+
var import_node_fs47 = require("fs");
|
|
59762
60602
|
var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
|
|
59763
60603
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
59764
60604
|
async function recoverInterruptedPublishJobs(store, logger) {
|
|
@@ -59839,7 +60679,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
59839
60679
|
async function listAllUsersProjects() {
|
|
59840
60680
|
if (!deps.usersRoot || !deps.getStore) return [];
|
|
59841
60681
|
const getStore = deps.getStore;
|
|
59842
|
-
const userIds = await
|
|
60682
|
+
const userIds = await import_node_fs47.promises.readdir(deps.usersRoot).catch(() => []);
|
|
59843
60683
|
const perUser = await Promise.all(
|
|
59844
60684
|
userIds.map((uid) => getStore(uid).list().catch(() => []))
|
|
59845
60685
|
);
|
|
@@ -59908,8 +60748,8 @@ function buildAppBuilderHandlers(deps) {
|
|
|
59908
60748
|
const project = await userStore.create(f.name, reservedPorts);
|
|
59909
60749
|
try {
|
|
59910
60750
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
|
|
59911
|
-
const templateSrcDir = (0,
|
|
59912
|
-
const scaffoldScript = (0,
|
|
60751
|
+
const templateSrcDir = (0, import_node_path58.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE);
|
|
60752
|
+
const scaffoldScript = (0, import_node_path58.join)(deps.deployKitRoot, "scripts", "new-extension.sh");
|
|
59913
60753
|
const scaffoldResult = await userStore.scaffold(project.name, templateSrcDir, scaffoldScript);
|
|
59914
60754
|
deps.logger?.info("app-builder.scaffold.done", {
|
|
59915
60755
|
name: project.name,
|
|
@@ -60113,7 +60953,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
60113
60953
|
await userStore.clearPublishJob(args.name);
|
|
60114
60954
|
}
|
|
60115
60955
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
|
|
60116
|
-
const scriptPath = (0,
|
|
60956
|
+
const scriptPath = (0, import_node_path58.join)(deps.deployKitRoot, "scripts", "publish.sh");
|
|
60117
60957
|
deps.logger?.info("app-builder.publish.start", {
|
|
60118
60958
|
name: args.name,
|
|
60119
60959
|
sessionId: boundSession.sessionId,
|
|
@@ -60289,7 +61129,7 @@ function buildVisitorHandlers(deps) {
|
|
|
60289
61129
|
|
|
60290
61130
|
// src/extension/registry.ts
|
|
60291
61131
|
var import_promises10 = __toESM(require("fs/promises"), 1);
|
|
60292
|
-
var
|
|
61132
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
60293
61133
|
async function loadAll(root) {
|
|
60294
61134
|
let entries;
|
|
60295
61135
|
try {
|
|
@@ -60302,13 +61142,13 @@ async function loadAll(root) {
|
|
|
60302
61142
|
for (const ent of entries) {
|
|
60303
61143
|
if (!ent.isDirectory()) continue;
|
|
60304
61144
|
if (ent.name.startsWith(".")) continue;
|
|
60305
|
-
records.push(await loadOne(
|
|
61145
|
+
records.push(await loadOne(import_node_path59.default.join(root, ent.name), ent.name));
|
|
60306
61146
|
}
|
|
60307
61147
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
60308
61148
|
return records;
|
|
60309
61149
|
}
|
|
60310
61150
|
async function loadOne(dir, dirName) {
|
|
60311
|
-
const manifestPath =
|
|
61151
|
+
const manifestPath = import_node_path59.default.join(dir, "manifest.json");
|
|
60312
61152
|
let raw;
|
|
60313
61153
|
try {
|
|
60314
61154
|
raw = await import_promises10.default.readFile(manifestPath, "utf8");
|
|
@@ -60353,7 +61193,7 @@ async function loadOne(dir, dirName) {
|
|
|
60353
61193
|
|
|
60354
61194
|
// src/extension/uninstall.ts
|
|
60355
61195
|
var import_promises11 = __toESM(require("fs/promises"), 1);
|
|
60356
|
-
var
|
|
61196
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
60357
61197
|
var UninstallError = class extends Error {
|
|
60358
61198
|
constructor(code, message) {
|
|
60359
61199
|
super(message);
|
|
@@ -60362,7 +61202,7 @@ var UninstallError = class extends Error {
|
|
|
60362
61202
|
code;
|
|
60363
61203
|
};
|
|
60364
61204
|
async function uninstall(deps) {
|
|
60365
|
-
const dir =
|
|
61205
|
+
const dir = import_node_path60.default.join(deps.root, deps.extId);
|
|
60366
61206
|
try {
|
|
60367
61207
|
await import_promises11.default.access(dir);
|
|
60368
61208
|
} catch {
|
|
@@ -60373,7 +61213,7 @@ async function uninstall(deps) {
|
|
|
60373
61213
|
}
|
|
60374
61214
|
|
|
60375
61215
|
// src/handlers/index.ts
|
|
60376
|
-
var
|
|
61216
|
+
var import_node_crypto18 = require("crypto");
|
|
60377
61217
|
|
|
60378
61218
|
// src/handlers/peer-exec.ts
|
|
60379
61219
|
init_protocol();
|
|
@@ -60381,11 +61221,11 @@ init_protocol();
|
|
|
60381
61221
|
// src/peer-ops/run-command.ts
|
|
60382
61222
|
var import_node_child_process14 = require("child_process");
|
|
60383
61223
|
var import_node_os21 = __toESM(require("os"), 1);
|
|
60384
|
-
var
|
|
61224
|
+
var DEFAULT_TIMEOUT_MS4 = 3e4;
|
|
60385
61225
|
var MAX_TIMEOUT_MS = 3e5;
|
|
60386
61226
|
var MAX_OUTPUT_BYTES = 1048576;
|
|
60387
61227
|
function runCommand(command, opts = {}) {
|
|
60388
|
-
const timeoutMs = Math.min(opts.timeoutMs ??
|
|
61228
|
+
const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS4, MAX_TIMEOUT_MS);
|
|
60389
61229
|
return new Promise((resolve6) => {
|
|
60390
61230
|
const child = (0, import_node_child_process14.spawn)("bash", ["-c", command], { cwd: import_node_os21.default.homedir() });
|
|
60391
61231
|
const out = [];
|
|
@@ -60528,7 +61368,7 @@ function buildMethodHandlers(deps) {
|
|
|
60528
61368
|
const c = deps.contactStore.get(deviceId);
|
|
60529
61369
|
return c ? { deviceId: c.deviceId, remoteUrl: c.remoteUrl, connectToken: c.connectToken } : null;
|
|
60530
61370
|
},
|
|
60531
|
-
genId: () => (0,
|
|
61371
|
+
genId: () => (0, import_node_crypto18.randomUUID)(),
|
|
60532
61372
|
now: () => Date.now(),
|
|
60533
61373
|
forwardInboxPostToPeer,
|
|
60534
61374
|
logger: deps.logger
|
|
@@ -60892,7 +61732,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
|
|
|
60892
61732
|
|
|
60893
61733
|
// src/extension/runtime.ts
|
|
60894
61734
|
var import_node_child_process16 = require("child_process");
|
|
60895
|
-
var
|
|
61735
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
60896
61736
|
var import_promises12 = require("timers/promises");
|
|
60897
61737
|
|
|
60898
61738
|
// src/extension/port-allocator.ts
|
|
@@ -60993,7 +61833,7 @@ var Runtime = class {
|
|
|
60993
61833
|
/\$CLAWOS_EXT_PORT/g,
|
|
60994
61834
|
String(port)
|
|
60995
61835
|
);
|
|
60996
|
-
const dir =
|
|
61836
|
+
const dir = import_node_path61.default.join(this.root, extId);
|
|
60997
61837
|
const env = {
|
|
60998
61838
|
...process.env,
|
|
60999
61839
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -61105,7 +61945,7 @@ ${handle.stderrTail}`
|
|
|
61105
61945
|
|
|
61106
61946
|
// src/extension/published-channels.ts
|
|
61107
61947
|
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
61108
|
-
var
|
|
61948
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
61109
61949
|
init_zod();
|
|
61110
61950
|
var PublishedChannelsError = class extends Error {
|
|
61111
61951
|
constructor(code, message) {
|
|
@@ -61204,7 +62044,7 @@ var PublishedChannelStore = class {
|
|
|
61204
62044
|
)
|
|
61205
62045
|
};
|
|
61206
62046
|
const tmp = `${this.filePath}.tmp`;
|
|
61207
|
-
await import_promises13.default.mkdir(
|
|
62047
|
+
await import_promises13.default.mkdir(import_node_path62.default.dirname(this.filePath), { recursive: true });
|
|
61208
62048
|
await import_promises13.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
61209
62049
|
await import_promises13.default.rename(tmp, this.filePath);
|
|
61210
62050
|
}
|
|
@@ -61212,7 +62052,7 @@ var PublishedChannelStore = class {
|
|
|
61212
62052
|
|
|
61213
62053
|
// src/extension/bundle-cache.ts
|
|
61214
62054
|
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
61215
|
-
var
|
|
62055
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
61216
62056
|
var BundleCache = class {
|
|
61217
62057
|
constructor(rootDir) {
|
|
61218
62058
|
this.rootDir = rootDir;
|
|
@@ -61221,14 +62061,14 @@ var BundleCache = class {
|
|
|
61221
62061
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
61222
62062
|
async write(snapshotHash, buffer) {
|
|
61223
62063
|
await import_promises14.default.mkdir(this.rootDir, { recursive: true });
|
|
61224
|
-
const file =
|
|
62064
|
+
const file = import_node_path63.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
61225
62065
|
const tmp = `${file}.tmp`;
|
|
61226
62066
|
await import_promises14.default.writeFile(tmp, buffer, { mode: 384 });
|
|
61227
62067
|
await import_promises14.default.rename(tmp, file);
|
|
61228
62068
|
}
|
|
61229
62069
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
61230
62070
|
async read(snapshotHash) {
|
|
61231
|
-
const file =
|
|
62071
|
+
const file = import_node_path63.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
61232
62072
|
try {
|
|
61233
62073
|
return await import_promises14.default.readFile(file);
|
|
61234
62074
|
} catch (e) {
|
|
@@ -61238,7 +62078,7 @@ var BundleCache = class {
|
|
|
61238
62078
|
}
|
|
61239
62079
|
/** Idempotent — missing file is not an error. */
|
|
61240
62080
|
async delete(snapshotHash) {
|
|
61241
|
-
const file =
|
|
62081
|
+
const file = import_node_path63.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
61242
62082
|
await import_promises14.default.rm(file, { force: true });
|
|
61243
62083
|
}
|
|
61244
62084
|
};
|
|
@@ -61261,24 +62101,24 @@ async function startDaemon(config) {
|
|
|
61261
62101
|
sampling: logShippingCfg.sampling,
|
|
61262
62102
|
homeDir: import_node_os22.default.homedir()
|
|
61263
62103
|
});
|
|
61264
|
-
const logDir =
|
|
61265
|
-
|
|
62104
|
+
const logDir = import_node_path64.default.join(config.dataDir, "log");
|
|
62105
|
+
import_node_fs48.default.mkdirSync(logDir, { recursive: true });
|
|
61266
62106
|
const logger = createLogger({
|
|
61267
62107
|
level: config.logLevel,
|
|
61268
|
-
file:
|
|
62108
|
+
file: import_node_path64.default.join(logDir, "clawd.log"),
|
|
61269
62109
|
logClient
|
|
61270
62110
|
});
|
|
61271
62111
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
61272
62112
|
const screenIdleProbeLogger = createFileOnlyLogger({
|
|
61273
|
-
file:
|
|
62113
|
+
file: import_node_path64.default.join(logDir, "screen-idle-probe.log"),
|
|
61274
62114
|
level: "debug"
|
|
61275
62115
|
});
|
|
61276
62116
|
logger.info("screen-idle probe logger enabled", {
|
|
61277
|
-
file:
|
|
62117
|
+
file: import_node_path64.default.join(logDir, "screen-idle-probe.log")
|
|
61278
62118
|
});
|
|
61279
62119
|
const CAP_TARGETS = [
|
|
61280
|
-
|
|
61281
|
-
|
|
62120
|
+
import_node_path64.default.join(logDir, "clawd.log"),
|
|
62121
|
+
import_node_path64.default.join(logDir, "screen-idle-probe.log")
|
|
61282
62122
|
];
|
|
61283
62123
|
const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
|
|
61284
62124
|
const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
|
|
@@ -61374,8 +62214,8 @@ async function startDaemon(config) {
|
|
|
61374
62214
|
const agents = new AgentsScanner();
|
|
61375
62215
|
const history = new ClaudeHistoryReader();
|
|
61376
62216
|
let transport = null;
|
|
61377
|
-
const personaStore = new PersonaStore(
|
|
61378
|
-
const usersRoot =
|
|
62217
|
+
const personaStore = new PersonaStore(import_node_path64.default.join(config.dataDir, "personas"));
|
|
62218
|
+
const usersRoot = import_node_path64.default.join(config.dataDir, "users");
|
|
61379
62219
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
61380
62220
|
if (defaultsRoot) {
|
|
61381
62221
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -61396,7 +62236,7 @@ async function startDaemon(config) {
|
|
|
61396
62236
|
retirePersonaBuilder({ store: personaStore, logger });
|
|
61397
62237
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
61398
62238
|
const dispatchStore = createDispatchStore({
|
|
61399
|
-
filePath:
|
|
62239
|
+
filePath: import_node_path64.default.join(config.dataDir, "dispatch.json"),
|
|
61400
62240
|
now: () => Date.now(),
|
|
61401
62241
|
onFlushError: (err) => logger.error("dispatch store flush failed", {
|
|
61402
62242
|
reason: err instanceof Error ? err.message : String(err)
|
|
@@ -61411,18 +62251,18 @@ async function startDaemon(config) {
|
|
|
61411
62251
|
now: () => Date.now(),
|
|
61412
62252
|
onCompleted: (sid) => deliverPendingRef?.(sid)
|
|
61413
62253
|
});
|
|
61414
|
-
const here = typeof __dirname === "string" ? __dirname :
|
|
62254
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path64.default.dirname((0, import_node_url4.fileURLToPath)(import_meta6.url));
|
|
61415
62255
|
const mcpConfigs = [];
|
|
61416
62256
|
const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
|
|
61417
62257
|
const dispatchServerCandidates = [
|
|
61418
|
-
|
|
62258
|
+
import_node_path64.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
61419
62259
|
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
61420
|
-
|
|
62260
|
+
import_node_path64.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
61421
62261
|
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
61422
62262
|
];
|
|
61423
|
-
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) =>
|
|
62263
|
+
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61424
62264
|
if (dispatchServerScriptPath) {
|
|
61425
|
-
const dispatchLogPath =
|
|
62265
|
+
const dispatchLogPath = import_node_path64.default.join(logDir, "dispatch-mcp-server.log");
|
|
61426
62266
|
const dispatchCfgPath = writeDispatchMcpConfig({
|
|
61427
62267
|
dataDir: config.dataDir,
|
|
61428
62268
|
serverScriptPath: dispatchServerScriptPath,
|
|
@@ -61442,12 +62282,12 @@ async function startDaemon(config) {
|
|
|
61442
62282
|
});
|
|
61443
62283
|
}
|
|
61444
62284
|
const ticketServerCandidates = [
|
|
61445
|
-
|
|
61446
|
-
|
|
62285
|
+
import_node_path64.default.join(here, "ticket", "mcp-server.cjs"),
|
|
62286
|
+
import_node_path64.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
61447
62287
|
];
|
|
61448
|
-
const ticketServerScriptPath = ticketServerCandidates.find((p2) =>
|
|
62288
|
+
const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61449
62289
|
if (ticketServerScriptPath) {
|
|
61450
|
-
const ticketLogPath =
|
|
62290
|
+
const ticketLogPath = import_node_path64.default.join(logDir, "ticket-mcp-server.log");
|
|
61451
62291
|
const ticketCfgPath = writeTicketMcpConfig({
|
|
61452
62292
|
dataDir: config.dataDir,
|
|
61453
62293
|
serverScriptPath: ticketServerScriptPath,
|
|
@@ -61469,12 +62309,12 @@ async function startDaemon(config) {
|
|
|
61469
62309
|
});
|
|
61470
62310
|
}
|
|
61471
62311
|
const shiftServerCandidates = [
|
|
61472
|
-
|
|
61473
|
-
|
|
62312
|
+
import_node_path64.default.join(here, "shift", "mcp-server.cjs"),
|
|
62313
|
+
import_node_path64.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
|
|
61474
62314
|
];
|
|
61475
|
-
const shiftServerScriptPath = shiftServerCandidates.find((p2) =>
|
|
62315
|
+
const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61476
62316
|
if (shiftServerScriptPath) {
|
|
61477
|
-
const shiftLogPath =
|
|
62317
|
+
const shiftLogPath = import_node_path64.default.join(logDir, "shift-mcp-server.log");
|
|
61478
62318
|
const shiftCfgPath = await writeShiftMcpConfig({
|
|
61479
62319
|
dataDir: config.dataDir,
|
|
61480
62320
|
serverScriptPath: shiftServerScriptPath,
|
|
@@ -61495,12 +62335,12 @@ async function startDaemon(config) {
|
|
|
61495
62335
|
);
|
|
61496
62336
|
}
|
|
61497
62337
|
const inboxServerCandidates = [
|
|
61498
|
-
|
|
61499
|
-
|
|
62338
|
+
import_node_path64.default.join(here, "inbox", "mcp-server.cjs"),
|
|
62339
|
+
import_node_path64.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
|
|
61500
62340
|
];
|
|
61501
|
-
const inboxServerScriptPath = inboxServerCandidates.find((p2) =>
|
|
62341
|
+
const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61502
62342
|
if (inboxServerScriptPath) {
|
|
61503
|
-
const inboxLogPath =
|
|
62343
|
+
const inboxLogPath = import_node_path64.default.join(logDir, "inbox-mcp-server.log");
|
|
61504
62344
|
const inboxCfgPath = await writeInboxMcpConfig({
|
|
61505
62345
|
dataDir: config.dataDir,
|
|
61506
62346
|
serverScriptPath: inboxServerScriptPath,
|
|
@@ -61521,10 +62361,10 @@ async function startDaemon(config) {
|
|
|
61521
62361
|
);
|
|
61522
62362
|
}
|
|
61523
62363
|
const peerOpsServerCandidates = [
|
|
61524
|
-
|
|
61525
|
-
|
|
62364
|
+
import_node_path64.default.join(here, "peer-ops", "mcp-server.cjs"),
|
|
62365
|
+
import_node_path64.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
|
|
61526
62366
|
];
|
|
61527
|
-
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) =>
|
|
62367
|
+
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61528
62368
|
if (peerOpsServerScriptPath) {
|
|
61529
62369
|
const peerOpsCfgPath = writePeerOpsMcpConfig({
|
|
61530
62370
|
dataDir: config.dataDir,
|
|
@@ -61544,12 +62384,12 @@ async function startDaemon(config) {
|
|
|
61544
62384
|
);
|
|
61545
62385
|
}
|
|
61546
62386
|
const rpcToolServerCandidates = [
|
|
61547
|
-
|
|
61548
|
-
|
|
62387
|
+
import_node_path64.default.join(here, "rpc-tool", "mcp-server.cjs"),
|
|
62388
|
+
import_node_path64.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
|
|
61549
62389
|
];
|
|
61550
|
-
const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) =>
|
|
62390
|
+
const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs48.default.existsSync(p2));
|
|
61551
62391
|
if (rpcToolServerScriptPath) {
|
|
61552
|
-
const rpcToolLogPath =
|
|
62392
|
+
const rpcToolLogPath = import_node_path64.default.join(logDir, "rpc-tool-mcp-server.log");
|
|
61553
62393
|
const rpcToolCfgPath = writeRpcToolMcpConfig({
|
|
61554
62394
|
dataDir: config.dataDir,
|
|
61555
62395
|
serverScriptPath: rpcToolServerScriptPath,
|
|
@@ -61570,7 +62410,7 @@ async function startDaemon(config) {
|
|
|
61570
62410
|
);
|
|
61571
62411
|
}
|
|
61572
62412
|
const shiftStore = createShiftStore({
|
|
61573
|
-
filePath:
|
|
62413
|
+
filePath: import_node_path64.default.join(config.dataDir, "shift.json"),
|
|
61574
62414
|
ownerIdProvider: () => ownerPrincipalId,
|
|
61575
62415
|
now: () => Date.now()
|
|
61576
62416
|
});
|
|
@@ -61592,7 +62432,7 @@ async function startDaemon(config) {
|
|
|
61592
62432
|
getAdapter,
|
|
61593
62433
|
historyReader: history,
|
|
61594
62434
|
dataDir: config.dataDir,
|
|
61595
|
-
personaRoot:
|
|
62435
|
+
personaRoot: import_node_path64.default.join(config.dataDir, "personas"),
|
|
61596
62436
|
// dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
|
|
61597
62437
|
// personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
|
|
61598
62438
|
getPersonaTool: (personaId2) => personaRegistry.get(personaId2)?.tool,
|
|
@@ -61643,10 +62483,10 @@ async function startDaemon(config) {
|
|
|
61643
62483
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
61644
62484
|
attachmentGroup: {
|
|
61645
62485
|
onFileEdit: (input) => {
|
|
61646
|
-
const absPath =
|
|
62486
|
+
const absPath = import_node_path64.default.isAbsolute(input.relPath) ? input.relPath : import_node_path64.default.join(input.cwd, input.relPath);
|
|
61647
62487
|
let size = 0;
|
|
61648
62488
|
try {
|
|
61649
|
-
size =
|
|
62489
|
+
size = import_node_fs48.default.statSync(absPath).size;
|
|
61650
62490
|
} catch (err) {
|
|
61651
62491
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
61652
62492
|
sessionId: input.sessionId,
|
|
@@ -61887,11 +62727,11 @@ async function startDaemon(config) {
|
|
|
61887
62727
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
61888
62728
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
61889
62729
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
61890
|
-
personaRoot:
|
|
62730
|
+
personaRoot: import_node_path64.default.join(config.dataDir, "personas"),
|
|
61891
62731
|
usersRoot
|
|
61892
62732
|
},
|
|
61893
62733
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
61894
|
-
personaRoot:
|
|
62734
|
+
personaRoot: import_node_path64.default.join(config.dataDir, "personas"),
|
|
61895
62735
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
61896
62736
|
usersRoot,
|
|
61897
62737
|
// v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
|
|
@@ -62017,11 +62857,11 @@ async function startDaemon(config) {
|
|
|
62017
62857
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
62018
62858
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
62019
62859
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
62020
|
-
appBuilderPersonaRoot:
|
|
62860
|
+
appBuilderPersonaRoot: import_node_path64.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
62021
62861
|
// 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
|
|
62022
|
-
deployKitRoot:
|
|
62862
|
+
deployKitRoot: import_node_path64.default.join(config.dataDir, "deploy-kit"),
|
|
62023
62863
|
// scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
|
|
62024
|
-
resolvePersonaRoot: (personaId2) =>
|
|
62864
|
+
resolvePersonaRoot: (personaId2) => import_node_path64.default.join(config.dataDir, "personas", personaId2),
|
|
62025
62865
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
62026
62866
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
62027
62867
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -62124,6 +62964,42 @@ async function startDaemon(config) {
|
|
|
62124
62964
|
});
|
|
62125
62965
|
shiftScheduler.start();
|
|
62126
62966
|
logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
|
|
62967
|
+
const larkBotStore = createLarkBotBindingStore(import_node_path64.default.join(config.dataDir, "personas"));
|
|
62968
|
+
const larkBotCloud = createLarkBotCloudClient({
|
|
62969
|
+
api: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
62970
|
+
apiKey: resolveClawdTicketsApiKey(),
|
|
62971
|
+
deviceId: authFile.deviceId,
|
|
62972
|
+
displayName: ownerDisplayName
|
|
62973
|
+
});
|
|
62974
|
+
const larkChatRouter = createLarkChatRouter({
|
|
62975
|
+
manager,
|
|
62976
|
+
cloud: larkBotCloud,
|
|
62977
|
+
store: larkBotStore,
|
|
62978
|
+
logger: {
|
|
62979
|
+
warn: (msg) => logger.warn(msg),
|
|
62980
|
+
info: (msg) => logger.info(msg)
|
|
62981
|
+
}
|
|
62982
|
+
});
|
|
62983
|
+
const larkEventDedupe = createLarkEventDedupe();
|
|
62984
|
+
const larkBotEventEndpoint = createLarkBotEventEndpoint({
|
|
62985
|
+
getPublicKey: () => serverKeyStore.read(),
|
|
62986
|
+
route: larkChatRouter.handleEnvelope,
|
|
62987
|
+
dedupe: larkEventDedupe,
|
|
62988
|
+
logger: { warn: (msg) => logger.warn(msg) }
|
|
62989
|
+
});
|
|
62990
|
+
const larkBotDeps = {
|
|
62991
|
+
provisioner: { startAppRegistration, startScopeAuthorization },
|
|
62992
|
+
cloud: larkBotCloud,
|
|
62993
|
+
store: larkBotStore,
|
|
62994
|
+
broadcast: (frame) => wsServer?.broadcastToOwners(frame),
|
|
62995
|
+
getTunnelUrl: () => currentTunnelUrl,
|
|
62996
|
+
getOwnerId: () => ownerIdentityStore.read()?.identity.ownerId ?? null,
|
|
62997
|
+
getPersonaName: (personaId2) => personaRegistry.get(personaId2)?.label ?? null,
|
|
62998
|
+
listLarkSessions: larkChatRouter.listLarkSessions,
|
|
62999
|
+
listBoundPersonaIds: () => personaStore.list().filter((pid) => larkBotStore.read(pid) != null),
|
|
63000
|
+
logger: { warn: (msg) => logger.warn(msg) }
|
|
63001
|
+
};
|
|
63002
|
+
Object.assign(handlers, buildLarkBotHandlers(larkBotDeps));
|
|
62127
63003
|
const authResolver = new AuthContextResolver({
|
|
62128
63004
|
ownerToken: resolvedAuthToken
|
|
62129
63005
|
});
|
|
@@ -62175,6 +63051,8 @@ async function startDaemon(config) {
|
|
|
62175
63051
|
// persona web 分享:访客换 token(POST /share/exchange)+ guest SPA serve(GET /s)
|
|
62176
63052
|
visitorExchange: exchangeVisitorToken,
|
|
62177
63053
|
...shareUiAssetLoader ? { shareUiAssetLoader } : {},
|
|
63054
|
+
// LarkBotConnector 事件入口(云端签名即凭证,无 Bearer)
|
|
63055
|
+
larkBotEvent: larkBotEventEndpoint,
|
|
62178
63056
|
// /files HMAC verify 用 auth.json token(与 attachment.signUrl 同源)。
|
|
62179
63057
|
getSignSecret: () => authFile.token,
|
|
62180
63058
|
// chatinput 附件上传(POST /attachments/upload,spec §6.1)。upload pipeline
|
|
@@ -62359,12 +63237,27 @@ async function startDaemon(config) {
|
|
|
62359
63237
|
stateMgr.write(stateSnapshot);
|
|
62360
63238
|
currentTunnelUrl = r.url;
|
|
62361
63239
|
wss.broadcastAll({ type: "tunnel:ready", url: r.url, subdomain: r.subdomain });
|
|
63240
|
+
void refreshTunnelUrlOnStartup(larkBotDeps);
|
|
63241
|
+
void (async () => {
|
|
63242
|
+
if (larkBotDeps.listBoundPersonaIds().length === 0) return;
|
|
63243
|
+
try {
|
|
63244
|
+
const items = await larkBotCloud.claimEvents();
|
|
63245
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
63246
|
+
for (const it of items) {
|
|
63247
|
+
larkEventDedupe.add(it.eventId);
|
|
63248
|
+
larkChatRouter.handleEnvelope({ ...it, iat: nowSec, exp: nowSec + 300 });
|
|
63249
|
+
}
|
|
63250
|
+
if (items.length > 0) logger.info("larkBot pending events claimed", { count: items.length });
|
|
63251
|
+
} catch (err) {
|
|
63252
|
+
logger.warn("larkBot pending events claim failed", { err: err.message });
|
|
63253
|
+
}
|
|
63254
|
+
})();
|
|
62362
63255
|
const connectUrl = resolvedAuthToken ? `${r.url}#token=${resolvedAuthToken}` : r.url;
|
|
62363
63256
|
const lines = [
|
|
62364
63257
|
`Tunnel: ${r.url}`,
|
|
62365
63258
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
62366
|
-
`Frpc config: ${
|
|
62367
|
-
`Frpc log: ${
|
|
63259
|
+
`Frpc config: ${import_node_path64.default.join(config.dataDir, "frpc.toml")}`,
|
|
63260
|
+
`Frpc log: ${import_node_path64.default.join(logDir, "frpc.log")}`
|
|
62368
63261
|
];
|
|
62369
63262
|
const width = Math.max(...lines.map((l) => l.length));
|
|
62370
63263
|
const bar = "\u2550".repeat(width + 4);
|
|
@@ -62377,8 +63270,8 @@ ${bar}
|
|
|
62377
63270
|
|
|
62378
63271
|
`);
|
|
62379
63272
|
try {
|
|
62380
|
-
const connectPath =
|
|
62381
|
-
|
|
63273
|
+
const connectPath = import_node_path64.default.join(config.dataDir, "connect.txt");
|
|
63274
|
+
import_node_fs48.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
62382
63275
|
} catch {
|
|
62383
63276
|
}
|
|
62384
63277
|
} catch (err) {
|
|
@@ -62450,9 +63343,9 @@ ${bar}
|
|
|
62450
63343
|
};
|
|
62451
63344
|
}
|
|
62452
63345
|
function migrateDropPersonsDir(dataDir) {
|
|
62453
|
-
const dir =
|
|
63346
|
+
const dir = import_node_path64.default.join(dataDir, "persons");
|
|
62454
63347
|
try {
|
|
62455
|
-
|
|
63348
|
+
import_node_fs48.default.rmSync(dir, { recursive: true, force: true });
|
|
62456
63349
|
} catch {
|
|
62457
63350
|
}
|
|
62458
63351
|
}
|