@vibe-lark/larkpal 0.1.79 → 0.1.81
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/main.mjs +34 -3
- package/package.json +1 -1
package/dist/main.mjs
CHANGED
|
@@ -22,7 +22,6 @@ import { pipeline } from "node:stream/promises";
|
|
|
22
22
|
import { PassThrough, Readable, Transform } from "node:stream";
|
|
23
23
|
import express, { Router } from "express";
|
|
24
24
|
import Busboy from "busboy";
|
|
25
|
-
import { EventEmitter as EventEmitter$1 } from "events";
|
|
26
25
|
import cron from "node-cron";
|
|
27
26
|
import * as Lark from "@larksuiteoapi/node-sdk";
|
|
28
27
|
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
@@ -4583,6 +4582,8 @@ async function handleSessionFileUpload(req, res, messageStore) {
|
|
|
4583
4582
|
traceId,
|
|
4584
4583
|
runtimeEventType: "session-file-attached",
|
|
4585
4584
|
fileName: file.fileName,
|
|
4585
|
+
originalName: file.originalName,
|
|
4586
|
+
displayName: file.displayName,
|
|
4586
4587
|
relativePath: file.relativePath,
|
|
4587
4588
|
mimeType: file.mimeType,
|
|
4588
4589
|
size: file.size,
|
|
@@ -4613,6 +4614,7 @@ function parseSessionFileUpload(req, sessionId) {
|
|
|
4613
4614
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
4614
4615
|
const busboy = Busboy({
|
|
4615
4616
|
headers: req.headers,
|
|
4617
|
+
defParamCharset: "utf8",
|
|
4616
4618
|
limits: {
|
|
4617
4619
|
fileSize: getSessionFileUploadMaxBytes(),
|
|
4618
4620
|
files: 1
|
|
@@ -4676,6 +4678,7 @@ function writeSessionFile(sessionId, params) {
|
|
|
4676
4678
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
4677
4679
|
const uploadsDir = resolve(resolveAgentCwd(sessionId), "uploads");
|
|
4678
4680
|
const fileName = buildSafeUploadFileName(params.originalName);
|
|
4681
|
+
const originalName = buildDisplayUploadFileName(params.originalName);
|
|
4679
4682
|
const destination = resolve(uploadsDir, fileName);
|
|
4680
4683
|
const relativePath = `uploads/${fileName}`;
|
|
4681
4684
|
const maxBytes = getSessionFileUploadMaxBytes();
|
|
@@ -4713,6 +4716,8 @@ function writeSessionFile(sessionId, params) {
|
|
|
4713
4716
|
sessionId,
|
|
4714
4717
|
kind: "session-file",
|
|
4715
4718
|
fileName,
|
|
4719
|
+
originalName,
|
|
4720
|
+
displayName: originalName,
|
|
4716
4721
|
relativePath,
|
|
4717
4722
|
uri: `session-file://${relativePath}`,
|
|
4718
4723
|
mimeType: params.mimeType,
|
|
@@ -4737,6 +4742,9 @@ function buildSafeUploadFileName(originalName) {
|
|
|
4737
4742
|
const stem = basename(base, extname(base)).replace(/[^A-Za-z0-9._-]/g, "_").replace(/^\.+$/, "").slice(0, 80) || "upload";
|
|
4738
4743
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}-${stem}${extension}`;
|
|
4739
4744
|
}
|
|
4745
|
+
function buildDisplayUploadFileName(originalName) {
|
|
4746
|
+
return basename(originalName).replace(/[\0\r\n]/g, "_").trim() || "upload.bin";
|
|
4747
|
+
}
|
|
4740
4748
|
function isPathInside(parent, child) {
|
|
4741
4749
|
const path = relative(parent, child);
|
|
4742
4750
|
return path !== "" && !path.startsWith("..") && !isAbsolute(path);
|
|
@@ -7785,13 +7793,17 @@ const sessionNoReplyFlags = /* @__PURE__ */ new Map();
|
|
|
7785
7793
|
/** TTL: 30 分钟 */
|
|
7786
7794
|
const TTL_MS = 1800 * 1e3;
|
|
7787
7795
|
/** 定期清理过期的 pending requests(每 5 分钟检查一次) */
|
|
7788
|
-
|
|
7796
|
+
function cleanupExpiredPendingRequests() {
|
|
7789
7797
|
const now = Date.now();
|
|
7790
7798
|
let cleaned = 0;
|
|
7791
7799
|
for (const [id, req] of pendingRequests) if (now - req.createdAt > TTL_MS) {
|
|
7792
7800
|
pendingRequests.delete(id);
|
|
7793
7801
|
cleaned++;
|
|
7794
7802
|
}
|
|
7803
|
+
return cleaned;
|
|
7804
|
+
}
|
|
7805
|
+
setInterval(() => {
|
|
7806
|
+
const cleaned = cleanupExpiredPendingRequests();
|
|
7795
7807
|
if (cleaned > 0) logger$4.info("TTL cleanup completed", {
|
|
7796
7808
|
cleaned,
|
|
7797
7809
|
remaining: pendingRequests.size
|
|
@@ -7802,7 +7814,7 @@ setInterval(() => {
|
|
|
7802
7814
|
* 事件名: `callback:${sessionId}`,payload 为 PendingMcpRequest。
|
|
7803
7815
|
* 用于 dispatch-cc 订阅并在收到 ask_user/request_permission 回调时发送飞书卡片。
|
|
7804
7816
|
*/
|
|
7805
|
-
const onMcpCallback = new EventEmitter
|
|
7817
|
+
const onMcpCallback = new EventEmitter();
|
|
7806
7818
|
onMcpCallback.setMaxListeners(100);
|
|
7807
7819
|
/**
|
|
7808
7820
|
* 将 result 存入对应的 pending request
|
|
@@ -7934,6 +7946,25 @@ function createMcpCallbackRouter() {
|
|
|
7934
7946
|
requestId
|
|
7935
7947
|
});
|
|
7936
7948
|
});
|
|
7949
|
+
router.get("/pending", (req, res) => {
|
|
7950
|
+
const sessionId = typeof req.query.session_id === "string" ? req.query.session_id : typeof req.query.sessionId === "string" ? req.query.sessionId : void 0;
|
|
7951
|
+
const cleaned = cleanupExpiredPendingRequests();
|
|
7952
|
+
const now = Date.now();
|
|
7953
|
+
const requests = [...pendingRequests.values()].filter((pending) => pending.result === void 0).filter((pending) => !sessionId || pending.sessionId === sessionId).map((pending) => ({
|
|
7954
|
+
requestId: pending.requestId,
|
|
7955
|
+
tool: pending.tool,
|
|
7956
|
+
sessionId: pending.sessionId,
|
|
7957
|
+
params: pending.params,
|
|
7958
|
+
createdAt: pending.createdAt,
|
|
7959
|
+
waitingMs: now - pending.createdAt
|
|
7960
|
+
}));
|
|
7961
|
+
logger$4.debug("pending requests listed", {
|
|
7962
|
+
sessionId,
|
|
7963
|
+
count: requests.length,
|
|
7964
|
+
cleaned
|
|
7965
|
+
});
|
|
7966
|
+
res.json({ requests });
|
|
7967
|
+
});
|
|
7937
7968
|
router.get("/resolve/:requestId", (req, res) => {
|
|
7938
7969
|
const requestId = req.params.requestId;
|
|
7939
7970
|
logger$4.debug("resolve poll", { requestId });
|