@vibe-lark/larkpal 0.1.78 → 0.1.80

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.
Files changed (2) hide show
  1. package/dist/main.mjs +68 -23
  2. package/package.json +1 -1
package/dist/main.mjs CHANGED
@@ -4583,6 +4583,8 @@ async function handleSessionFileUpload(req, res, messageStore) {
4583
4583
  traceId,
4584
4584
  runtimeEventType: "session-file-attached",
4585
4585
  fileName: file.fileName,
4586
+ originalName: file.originalName,
4587
+ displayName: file.displayName,
4586
4588
  relativePath: file.relativePath,
4587
4589
  mimeType: file.mimeType,
4588
4590
  size: file.size,
@@ -4613,6 +4615,7 @@ function parseSessionFileUpload(req, sessionId) {
4613
4615
  return new Promise((resolvePromise, rejectPromise) => {
4614
4616
  const busboy = Busboy({
4615
4617
  headers: req.headers,
4618
+ defParamCharset: "utf8",
4616
4619
  limits: {
4617
4620
  fileSize: getSessionFileUploadMaxBytes(),
4618
4621
  files: 1
@@ -4676,6 +4679,7 @@ function writeSessionFile(sessionId, params) {
4676
4679
  return new Promise((resolvePromise, rejectPromise) => {
4677
4680
  const uploadsDir = resolve(resolveAgentCwd(sessionId), "uploads");
4678
4681
  const fileName = buildSafeUploadFileName(params.originalName);
4682
+ const originalName = buildDisplayUploadFileName(params.originalName);
4679
4683
  const destination = resolve(uploadsDir, fileName);
4680
4684
  const relativePath = `uploads/${fileName}`;
4681
4685
  const maxBytes = getSessionFileUploadMaxBytes();
@@ -4713,6 +4717,8 @@ function writeSessionFile(sessionId, params) {
4713
4717
  sessionId,
4714
4718
  kind: "session-file",
4715
4719
  fileName,
4720
+ originalName,
4721
+ displayName: originalName,
4716
4722
  relativePath,
4717
4723
  uri: `session-file://${relativePath}`,
4718
4724
  mimeType: params.mimeType,
@@ -4737,6 +4743,9 @@ function buildSafeUploadFileName(originalName) {
4737
4743
  const stem = basename(base, extname(base)).replace(/[^A-Za-z0-9._-]/g, "_").replace(/^\.+$/, "").slice(0, 80) || "upload";
4738
4744
  return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}-${stem}${extension}`;
4739
4745
  }
4746
+ function buildDisplayUploadFileName(originalName) {
4747
+ return basename(originalName).replace(/[\0\r\n]/g, "_").trim() || "upload.bin";
4748
+ }
4740
4749
  function isPathInside(parent, child) {
4741
4750
  const path = relative(parent, child);
4742
4751
  return path !== "" && !path.startsWith("..") && !isAbsolute(path);
@@ -7332,6 +7341,7 @@ function asObject(value) {
7332
7341
  * 所有 hook 当前只做日志记录,不做复杂业务处理。
7333
7342
  */
7334
7343
  const logger$5 = larkLogger("gateway/hooks");
7344
+ const DELAYED_SANITIZER_RETRY_MS = 1e3;
7335
7345
  /**
7336
7346
  * 创建 HTTP Hooks 路由
7337
7347
  */
@@ -7384,7 +7394,7 @@ function createHooksRouter() {
7384
7394
  });
7385
7395
  router.post("/post-tool-use", async (req, res) => {
7386
7396
  const body = req.body;
7387
- const transcriptPath = typeof body.transcript_path === "string" ? body.transcript_path : typeof body.transcriptPath === "string" ? body.transcriptPath : void 0;
7397
+ const transcriptPath = getTranscriptPath(body);
7388
7398
  logger$5.info("hook received: post-tool-use", {
7389
7399
  method: req.method,
7390
7400
  url: req.originalUrl,
@@ -7392,36 +7402,28 @@ function createHooksRouter() {
7392
7402
  toolName: body.tool_name,
7393
7403
  transcriptPath
7394
7404
  });
7395
- if (!transcriptPath || !isTranscriptSanitizerEnabled()) {
7396
- res.json({ continue: true });
7397
- return;
7398
- }
7399
- try {
7400
- const result = await sanitizeClaudeTranscriptFile(transcriptPath);
7401
- res.json({
7402
- continue: true,
7403
- hookSpecificOutput: result.changed ? {
7404
- hookEventName: "PostToolUse",
7405
- additionalContext: `LarkPal externalized ${result.sanitizedImageBlocks} image tool result(s) from the persisted Claude transcript to reduce future replay payload.`
7406
- } : void 0
7407
- });
7408
- } catch (err) {
7409
- logger$5.warn("post-tool-use transcript sanitizer failed", {
7410
- transcriptPath,
7411
- error: err instanceof Error ? err.message : String(err)
7412
- });
7413
- res.json({ continue: true });
7414
- }
7405
+ const result = await sanitizeTranscriptFromHook("PostToolUse", transcriptPath);
7406
+ if (result?.changed === false) scheduleDelayedTranscriptSanitizer("PostToolUse", transcriptPath);
7407
+ res.json({
7408
+ continue: true,
7409
+ hookSpecificOutput: result?.changed ? {
7410
+ hookEventName: "PostToolUse",
7411
+ additionalContext: `LarkPal externalized ${result.sanitizedImageBlocks} image tool result(s) from the persisted Claude transcript to reduce future replay payload.`
7412
+ } : void 0
7413
+ });
7415
7414
  });
7416
- router.post("/session-end", (req, res) => {
7415
+ router.post("/session-end", async (req, res) => {
7417
7416
  const body = req.body;
7417
+ const transcriptPath = getTranscriptPath(body);
7418
7418
  logger$5.info("hook received: session-end", {
7419
7419
  method: req.method,
7420
7420
  url: req.originalUrl,
7421
7421
  sessionId: body.session_id,
7422
+ transcriptPath,
7422
7423
  body
7423
7424
  });
7424
- resetImageReadGuard(typeof body.transcript_path === "string" ? body.transcript_path : void 0);
7425
+ resetImageReadGuard(transcriptPath);
7426
+ if ((await sanitizeTranscriptFromHook("SessionEnd", transcriptPath))?.changed === false) scheduleDelayedTranscriptSanitizer("SessionEnd", transcriptPath);
7425
7427
  res.json({ received: true });
7426
7428
  });
7427
7429
  router.post("/notification", (req, res) => {
@@ -7435,6 +7437,47 @@ function createHooksRouter() {
7435
7437
  });
7436
7438
  return router;
7437
7439
  }
7440
+ function getTranscriptPath(body) {
7441
+ return typeof body.transcript_path === "string" ? body.transcript_path : typeof body.transcriptPath === "string" ? body.transcriptPath : void 0;
7442
+ }
7443
+ async function sanitizeTranscriptFromHook(hookEventName, transcriptPath) {
7444
+ if (!transcriptPath) {
7445
+ logger$5.info("transcript sanitizer skipped: no transcript path", { hookEventName });
7446
+ return;
7447
+ }
7448
+ if (!isTranscriptSanitizerEnabled()) {
7449
+ logger$5.info("transcript sanitizer skipped: disabled", {
7450
+ hookEventName,
7451
+ transcriptPath
7452
+ });
7453
+ return;
7454
+ }
7455
+ try {
7456
+ const result = await sanitizeClaudeTranscriptFile(transcriptPath);
7457
+ logger$5.info("transcript sanitizer completed", {
7458
+ hookEventName,
7459
+ transcriptPath,
7460
+ changed: result.changed,
7461
+ lines: result.lines,
7462
+ sanitizedImageBlocks: result.sanitizedImageBlocks,
7463
+ artifacts: result.artifacts
7464
+ });
7465
+ return result;
7466
+ } catch (err) {
7467
+ logger$5.warn("transcript sanitizer failed", {
7468
+ hookEventName,
7469
+ transcriptPath,
7470
+ error: err instanceof Error ? err.message : String(err)
7471
+ });
7472
+ return;
7473
+ }
7474
+ }
7475
+ function scheduleDelayedTranscriptSanitizer(hookEventName, transcriptPath) {
7476
+ if (!transcriptPath || !isTranscriptSanitizerEnabled()) return;
7477
+ setTimeout(() => {
7478
+ sanitizeTranscriptFromHook(`${hookEventName}:delayed`, transcriptPath);
7479
+ }, DELAYED_SANITIZER_RETRY_MS).unref();
7480
+ }
7438
7481
  //#endregion
7439
7482
  //#region src/memory/store.ts
7440
7483
  const log$27 = larkLogger("memory/store");
@@ -20139,6 +20182,8 @@ async function main() {
20139
20182
  logger.info("LarkPal 启动中...");
20140
20183
  if (process.env.LARKPAL_HEADLESS === "1" || process.env.LARKPAL_HEADLESS === "true") {
20141
20184
  logger.info("Headless 模式启动 — 跳过飞书凭证/preflight/WebSocket");
20185
+ await ensureDefaults();
20186
+ logger.info("Headless 默认配置检查完成");
20142
20187
  await startHeadless();
20143
20188
  return;
20144
20189
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-lark/larkpal",
3
- "version": "0.1.78",
3
+ "version": "0.1.80",
4
4
  "description": "LarkPal - Lark/Feishu bot service",
5
5
  "type": "module",
6
6
  "main": "./dist/main.mjs",