@vibe-lark/larkpal 0.1.63 → 0.1.64

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 (3) hide show
  1. package/bin/larkpal.js +0 -0
  2. package/dist/main.mjs +224 -150
  3. package/package.json +16 -15
package/bin/larkpal.js CHANGED
File without changes
package/dist/main.mjs CHANGED
@@ -6,7 +6,7 @@ import * as path$2 from "node:path";
6
6
  import path, { basename, dirname, extname, join, resolve } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import "dotenv/config";
9
- import { access, lstat, mkdir, open, readFile, readdir, readlink, rename, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
9
+ import { access, copyFile, lstat, mkdir, open, readFile, readdir, readlink, rename, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
10
10
  import { homedir, tmpdir } from "node:os";
11
11
  import { execFileSync, spawn } from "node:child_process";
12
12
  import { createHash, randomUUID } from "node:crypto";
@@ -18,10 +18,10 @@ import { createCipheriv, createDecipheriv, createHmac, randomBytes } from "crypt
18
18
  import path$1 from "path";
19
19
  import os from "os";
20
20
  import { EventEmitter } from "node:events";
21
+ import { pipeline } from "node:stream/promises";
22
+ import { PassThrough, Readable, Transform } from "node:stream";
21
23
  import express, { Router } from "express";
22
24
  import Busboy from "busboy";
23
- import { PassThrough, Readable, Transform } from "node:stream";
24
- import { pipeline } from "node:stream/promises";
25
25
  import { EventEmitter as EventEmitter$1 } from "events";
26
26
  import cron from "node-cron";
27
27
  import * as Lark from "@larksuiteoapi/node-sdk";
@@ -2619,6 +2619,165 @@ function getLarkpalMcpServerCommand() {
2619
2619
  };
2620
2620
  }
2621
2621
  //#endregion
2622
+ //#region src/gateway/artifact-store.ts
2623
+ const DEFAULT_ARTIFACT_TTL_MS = 4320 * 60 * 1e3;
2624
+ const DEFAULT_MAX_UPLOAD_BYTES = 50 * 1024 * 1024;
2625
+ var ArtifactUploadError = class extends Error {
2626
+ constructor(message, statusCode = 400) {
2627
+ super(message);
2628
+ this.statusCode = statusCode;
2629
+ this.name = "ArtifactUploadError";
2630
+ }
2631
+ };
2632
+ var GatewayArtifactStore = class {
2633
+ rootDir;
2634
+ maxUploadBytes;
2635
+ ttlMs;
2636
+ constructor(params) {
2637
+ const workspaceRoot = params?.workspaceRoot || resolveWorkspaceRoot();
2638
+ this.rootDir = join(workspaceRoot, ".artifacts");
2639
+ this.maxUploadBytes = params?.maxUploadBytes ?? readPositiveIntEnv("LARKPAL_ARTIFACT_MAX_UPLOAD_BYTES", DEFAULT_MAX_UPLOAD_BYTES);
2640
+ this.ttlMs = params?.ttlMs ?? readPositiveIntEnv("LARKPAL_ARTIFACT_TTL_MS", DEFAULT_ARTIFACT_TTL_MS);
2641
+ }
2642
+ async create(input) {
2643
+ validateContextId(input.sessionId, "sessionId");
2644
+ validateContextId(input.owner.tenantKey, "tenantKey");
2645
+ const artifactId = `art_${v4().replace(/-/g, "")}`;
2646
+ const createdAtMs = Date.now();
2647
+ const createdAt = new Date(createdAtMs).toISOString();
2648
+ const expiresAt = new Date(createdAtMs + this.ttlMs).toISOString();
2649
+ const artifactDir = this.getArtifactDir(input.owner.tenantKey, input.sessionId, artifactId);
2650
+ const blobPath = join(artifactDir, "blob");
2651
+ const tmpBlobPath = join(artifactDir, `.blob.${process.pid}.${Date.now()}.tmp`);
2652
+ await mkdir(artifactDir, { recursive: true });
2653
+ const hash = createHash("sha256");
2654
+ let size = 0;
2655
+ const metering = new Transform({ transform: (chunk, _encoding, callback) => {
2656
+ size += chunk.length;
2657
+ if (size > this.maxUploadBytes) {
2658
+ callback(new ArtifactUploadError(`Artifact exceeds max upload size ${this.maxUploadBytes} bytes`, 413));
2659
+ return;
2660
+ }
2661
+ hash.update(chunk);
2662
+ callback(null, chunk);
2663
+ } });
2664
+ try {
2665
+ await pipeline(input.stream, metering, createWriteStream(tmpBlobPath));
2666
+ await rename(tmpBlobPath, blobPath);
2667
+ } catch (err) {
2668
+ await rm(artifactDir, {
2669
+ recursive: true,
2670
+ force: true
2671
+ }).catch(() => void 0);
2672
+ throw err;
2673
+ }
2674
+ const metadata = {
2675
+ artifactId,
2676
+ sessionId: input.sessionId,
2677
+ tenantKey: input.owner.tenantKey,
2678
+ userId: input.owner.userId,
2679
+ openId: input.owner.openId,
2680
+ kind: "workspace-file",
2681
+ uri: `artifact://${artifactId}`,
2682
+ fileName: sanitizeFileName(input.fileName),
2683
+ mimeType: normalizeMimeType(input.mimeType),
2684
+ size,
2685
+ contentHash: `sha256:${hash.digest("hex")}`,
2686
+ createdAt,
2687
+ expiresAt,
2688
+ metadata: input.metadata,
2689
+ blobPath
2690
+ };
2691
+ await writeJson(join(artifactDir, "meta.json"), metadata);
2692
+ return toPublicRef(metadata);
2693
+ }
2694
+ async list(params) {
2695
+ validateContextId(params.sessionId, "sessionId");
2696
+ validateContextId(params.owner.tenantKey, "tenantKey");
2697
+ const sessionDir = this.getSessionDir(params.owner.tenantKey, params.sessionId);
2698
+ let entries;
2699
+ try {
2700
+ entries = await readdir(sessionDir);
2701
+ } catch {
2702
+ return [];
2703
+ }
2704
+ const results = [];
2705
+ for (const entry of entries) {
2706
+ if (!entry.startsWith("art_")) continue;
2707
+ const metadata = await readArtifactMetadata(join(sessionDir, entry, "meta.json"));
2708
+ if (!metadata) continue;
2709
+ if (!isOwnedBy(metadata, params.owner, params.sessionId)) continue;
2710
+ if (Date.parse(metadata.expiresAt) <= Date.now()) continue;
2711
+ results.push(toPublicRef(metadata));
2712
+ }
2713
+ return results.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
2714
+ }
2715
+ async statBlob(ref, owner) {
2716
+ const metadata = await readArtifactMetadata(this.getMetadataPath(owner.tenantKey, ref.sessionId, ref.artifactId));
2717
+ if (!metadata || !isOwnedBy(metadata, owner, ref.sessionId)) return null;
2718
+ const blobStat = await stat(metadata.blobPath).catch(() => null);
2719
+ return blobStat ? {
2720
+ path: metadata.blobPath,
2721
+ size: blobStat.size
2722
+ } : null;
2723
+ }
2724
+ async resolveBlob(params) {
2725
+ validateContextId(params.sessionId, "sessionId");
2726
+ validateContextId(params.owner.tenantKey, "tenantKey");
2727
+ validateContextId(params.artifactId, "artifactId");
2728
+ const metadata = await readArtifactMetadata(this.getMetadataPath(params.owner.tenantKey, params.sessionId, params.artifactId));
2729
+ if (!metadata || !isOwnedBy(metadata, params.owner, params.sessionId)) return null;
2730
+ if (Date.parse(metadata.expiresAt) <= Date.now()) return null;
2731
+ if (!await stat(metadata.blobPath).catch(() => null)) return null;
2732
+ return {
2733
+ ref: toPublicRef(metadata),
2734
+ blobPath: metadata.blobPath
2735
+ };
2736
+ }
2737
+ getSessionDir(tenantKey, sessionId) {
2738
+ return join(this.rootDir, tenantKey, sessionId);
2739
+ }
2740
+ getArtifactDir(tenantKey, sessionId, artifactId) {
2741
+ return join(this.getSessionDir(tenantKey, sessionId), artifactId);
2742
+ }
2743
+ getMetadataPath(tenantKey, sessionId, artifactId) {
2744
+ return join(this.getArtifactDir(tenantKey, sessionId, artifactId), "meta.json");
2745
+ }
2746
+ };
2747
+ function readPositiveIntEnv(name, fallback) {
2748
+ const raw = process.env[name];
2749
+ if (!raw) return fallback;
2750
+ const parsed = Number.parseInt(raw, 10);
2751
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
2752
+ }
2753
+ function validateContextId(value, fieldName) {
2754
+ if (!/^[A-Za-z0-9_.:-]{1,200}$/.test(value)) throw new ArtifactUploadError(`Invalid ${fieldName}`, 400);
2755
+ }
2756
+ function sanitizeFileName(fileName) {
2757
+ return fileName.replace(/[\\/\0\r\n]/g, "_").trim() || "upload.bin";
2758
+ }
2759
+ function normalizeMimeType(mimeType) {
2760
+ return mimeType?.trim() || "application/octet-stream";
2761
+ }
2762
+ function toPublicRef(metadata) {
2763
+ const { tenantKey: _tenantKey, userId: _userId, openId: _openId, blobPath: _blobPath, ...ref } = metadata;
2764
+ return ref;
2765
+ }
2766
+ function isOwnedBy(metadata, owner, sessionId) {
2767
+ return metadata.tenantKey === owner.tenantKey && metadata.userId === owner.userId && metadata.openId === owner.openId && metadata.sessionId === sessionId;
2768
+ }
2769
+ async function readArtifactMetadata(filePath) {
2770
+ try {
2771
+ return JSON.parse(await readFile(filePath, "utf-8"));
2772
+ } catch {
2773
+ return null;
2774
+ }
2775
+ }
2776
+ async function writeJson(filePath, data) {
2777
+ await mkdir(dirname(filePath), { recursive: true });
2778
+ await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
2779
+ }
2780
+ //#endregion
2622
2781
  //#region src/runtime/larkpal-agent-factory.ts
2623
2782
  /**
2624
2783
  * LarkpalAgent RuntimeAdapter 工厂
@@ -2766,6 +2925,7 @@ async function createLarkpalAgentAdapter() {
2766
2925
  });
2767
2926
  const { LarkpalAgentAdapter, ToolRegistry } = await import("@vibe-lark/larkpal-agent");
2768
2927
  const registry = new ToolRegistry();
2928
+ const visualMaxBatchSize = parseInt(process.env.LARKPAL_AGENT_VISUAL_MAX_BATCH_SIZE || "3", 10);
2769
2929
  const adapter = new LarkpalAgentAdapter({
2770
2930
  llm,
2771
2931
  systemPrompt,
@@ -2774,8 +2934,9 @@ async function createLarkpalAgentAdapter() {
2774
2934
  registry,
2775
2935
  scenarioManifestDirs,
2776
2936
  scenarioProviderConfig,
2937
+ artifactResolvers: [createGatewayArtifactResolver()],
2777
2938
  visualRuntime: {
2778
- maxBatchSize: parseInt(process.env.LARKPAL_AGENT_VISUAL_MAX_BATCH_SIZE || "3", 10),
2939
+ maxBatchSize: visualMaxBatchSize,
2779
2940
  allowedDirs: [process.env.LARK_CLI_WORKDIR || "/tmp/ai-knowledge-lark-cli", "/tmp"].filter(Boolean)
2780
2941
  }
2781
2942
  });
@@ -2799,6 +2960,51 @@ async function createLarkpalAgentAdapter() {
2799
2960
  else log$31.warn("未配置 LARKPAL_AGENT_MCP_SERVER_URL,Agent 无远程工具可用");
2800
2961
  return wrapLarkpalAgentAdapter(adapter);
2801
2962
  }
2963
+ function createGatewayArtifactResolver(params) {
2964
+ const store = params?.store || new GatewayArtifactStore();
2965
+ return {
2966
+ name: "larkpal-gateway-artifact-store",
2967
+ canResolve(artifact) {
2968
+ return getArtifactId(artifact) !== void 0;
2969
+ },
2970
+ async resolve(artifact, context) {
2971
+ const artifactId = getArtifactId(artifact);
2972
+ const tenantKey = context.tenantKey || context.authHeaders?.["x-tenant-key"];
2973
+ const userId = context.userId || context.authHeaders?.["x-user-id"];
2974
+ const openId = context.authHeaders?.["x-open-id"] || userId;
2975
+ if (!artifactId || !tenantKey || !userId || !openId) return void 0;
2976
+ const resolved = await store.resolveBlob({
2977
+ sessionId: context.sessionId,
2978
+ artifactId,
2979
+ owner: {
2980
+ tenantKey,
2981
+ userId,
2982
+ openId
2983
+ }
2984
+ });
2985
+ if (!resolved) return void 0;
2986
+ const targetDir = join(context.cwd, "source-artifacts", artifactId);
2987
+ const fileName = sanitizeWorkspaceFileName(resolved.ref.fileName || artifact.fileName || artifactId);
2988
+ const targetPath = join(targetDir, fileName);
2989
+ await mkdir(targetDir, { recursive: true });
2990
+ await copyFile(resolved.blobPath, targetPath);
2991
+ return {
2992
+ artifactId,
2993
+ kind: "workspace-file",
2994
+ path: targetPath,
2995
+ fileName,
2996
+ mimeType: resolved.ref.mimeType ?? artifact.mimeType,
2997
+ size: resolved.ref.size ?? artifact.size,
2998
+ contentHash: resolved.ref.contentHash ?? artifact.contentHash,
2999
+ source: artifact,
3000
+ refs: {
3001
+ uri: resolved.ref.uri,
3002
+ gatewayArtifactId: resolved.ref.artifactId
3003
+ }
3004
+ };
3005
+ }
3006
+ };
3007
+ }
2802
3008
  function wrapLarkpalAgentAdapter(adapter) {
2803
3009
  return {
2804
3010
  get name() {
@@ -2877,6 +3083,17 @@ function mergeSourceArtifacts(existing, imageArtifacts) {
2877
3083
  if (Array.isArray(existing)) return [...existing, ...imageArtifacts];
2878
3084
  return [existing, ...imageArtifacts];
2879
3085
  }
3086
+ function getArtifactId(artifact) {
3087
+ const artifactId = typeof artifact.artifactId === "string" ? artifact.artifactId.trim() : "";
3088
+ if (artifactId.startsWith("art_")) return artifactId;
3089
+ const uri = typeof artifact.uri === "string" ? artifact.uri.trim() : "";
3090
+ if (!uri.startsWith("artifact://")) return void 0;
3091
+ const idFromUri = uri.slice(11).split(/[/?#]/, 1)[0]?.trim();
3092
+ return idFromUri?.startsWith("art_") ? idFromUri : void 0;
3093
+ }
3094
+ function sanitizeWorkspaceFileName(fileName) {
3095
+ return basename(fileName).replace(/[\\/\0\r\n]/g, "_").trim() || "artifact.bin";
3096
+ }
2880
3097
  //#endregion
2881
3098
  //#region src/routing/session-router.ts
2882
3099
  /**
@@ -3216,6 +3433,7 @@ const MAX_SUMMARY_STRING_LENGTH = 200;
3216
3433
  const PROTECTED_CONTEXT_HEADERS = new Set([
3217
3434
  "x-tenant-key",
3218
3435
  "x-user-id",
3436
+ "x-open-id",
3219
3437
  "x-session-id",
3220
3438
  "x-conversation-id",
3221
3439
  "x-trace-id",
@@ -3258,6 +3476,7 @@ function buildAgentRuntimeConfig(input) {
3258
3476
  const authHeaders = buildAuthHeaders({
3259
3477
  tenantKey,
3260
3478
  userId,
3479
+ openId: input.identity?.openId,
3261
3480
  sessionId,
3262
3481
  conversationId,
3263
3482
  traceId,
@@ -3420,6 +3639,7 @@ function buildAuthHeaders(params) {
3420
3639
  const headers = {
3421
3640
  "x-tenant-key": params.tenantKey,
3422
3641
  "x-user-id": params.userId,
3642
+ ...params.openId ? { "x-open-id": params.openId } : {},
3423
3643
  "x-session-id": params.sessionId,
3424
3644
  "x-conversation-id": params.conversationId,
3425
3645
  "x-trace-id": params.traceId,
@@ -4999,152 +5219,6 @@ async function sendCallback(callbackUrl, taskId, status, result, error) {
4999
5219
  }
5000
5220
  }
5001
5221
  //#endregion
5002
- //#region src/gateway/artifact-store.ts
5003
- const DEFAULT_ARTIFACT_TTL_MS = 4320 * 60 * 1e3;
5004
- const DEFAULT_MAX_UPLOAD_BYTES = 50 * 1024 * 1024;
5005
- var ArtifactUploadError = class extends Error {
5006
- constructor(message, statusCode = 400) {
5007
- super(message);
5008
- this.statusCode = statusCode;
5009
- this.name = "ArtifactUploadError";
5010
- }
5011
- };
5012
- var GatewayArtifactStore = class {
5013
- rootDir;
5014
- maxUploadBytes;
5015
- ttlMs;
5016
- constructor(params) {
5017
- const workspaceRoot = params?.workspaceRoot || resolveWorkspaceRoot();
5018
- this.rootDir = join(workspaceRoot, ".artifacts");
5019
- this.maxUploadBytes = params?.maxUploadBytes ?? readPositiveIntEnv("LARKPAL_ARTIFACT_MAX_UPLOAD_BYTES", DEFAULT_MAX_UPLOAD_BYTES);
5020
- this.ttlMs = params?.ttlMs ?? readPositiveIntEnv("LARKPAL_ARTIFACT_TTL_MS", DEFAULT_ARTIFACT_TTL_MS);
5021
- }
5022
- async create(input) {
5023
- validateContextId(input.sessionId, "sessionId");
5024
- validateContextId(input.owner.tenantKey, "tenantKey");
5025
- const artifactId = `art_${v4().replace(/-/g, "")}`;
5026
- const createdAtMs = Date.now();
5027
- const createdAt = new Date(createdAtMs).toISOString();
5028
- const expiresAt = new Date(createdAtMs + this.ttlMs).toISOString();
5029
- const artifactDir = this.getArtifactDir(input.owner.tenantKey, input.sessionId, artifactId);
5030
- const blobPath = join(artifactDir, "blob");
5031
- const tmpBlobPath = join(artifactDir, `.blob.${process.pid}.${Date.now()}.tmp`);
5032
- await mkdir(artifactDir, { recursive: true });
5033
- const hash = createHash("sha256");
5034
- let size = 0;
5035
- const metering = new Transform({ transform: (chunk, _encoding, callback) => {
5036
- size += chunk.length;
5037
- if (size > this.maxUploadBytes) {
5038
- callback(new ArtifactUploadError(`Artifact exceeds max upload size ${this.maxUploadBytes} bytes`, 413));
5039
- return;
5040
- }
5041
- hash.update(chunk);
5042
- callback(null, chunk);
5043
- } });
5044
- try {
5045
- await pipeline(input.stream, metering, createWriteStream(tmpBlobPath));
5046
- await rename(tmpBlobPath, blobPath);
5047
- } catch (err) {
5048
- await rm(artifactDir, {
5049
- recursive: true,
5050
- force: true
5051
- }).catch(() => void 0);
5052
- throw err;
5053
- }
5054
- const metadata = {
5055
- artifactId,
5056
- sessionId: input.sessionId,
5057
- tenantKey: input.owner.tenantKey,
5058
- userId: input.owner.userId,
5059
- openId: input.owner.openId,
5060
- kind: "workspace-file",
5061
- uri: `artifact://${artifactId}`,
5062
- fileName: sanitizeFileName(input.fileName),
5063
- mimeType: normalizeMimeType(input.mimeType),
5064
- size,
5065
- contentHash: `sha256:${hash.digest("hex")}`,
5066
- createdAt,
5067
- expiresAt,
5068
- metadata: input.metadata,
5069
- blobPath
5070
- };
5071
- await writeJson(join(artifactDir, "meta.json"), metadata);
5072
- return toPublicRef(metadata);
5073
- }
5074
- async list(params) {
5075
- validateContextId(params.sessionId, "sessionId");
5076
- validateContextId(params.owner.tenantKey, "tenantKey");
5077
- const sessionDir = this.getSessionDir(params.owner.tenantKey, params.sessionId);
5078
- let entries;
5079
- try {
5080
- entries = await readdir(sessionDir);
5081
- } catch {
5082
- return [];
5083
- }
5084
- const results = [];
5085
- for (const entry of entries) {
5086
- if (!entry.startsWith("art_")) continue;
5087
- const metadata = await readArtifactMetadata(join(sessionDir, entry, "meta.json"));
5088
- if (!metadata) continue;
5089
- if (!isOwnedBy(metadata, params.owner, params.sessionId)) continue;
5090
- if (Date.parse(metadata.expiresAt) <= Date.now()) continue;
5091
- results.push(toPublicRef(metadata));
5092
- }
5093
- return results.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
5094
- }
5095
- async statBlob(ref, owner) {
5096
- const metadata = await readArtifactMetadata(this.getMetadataPath(owner.tenantKey, ref.sessionId, ref.artifactId));
5097
- if (!metadata || !isOwnedBy(metadata, owner, ref.sessionId)) return null;
5098
- const blobStat = await stat(metadata.blobPath).catch(() => null);
5099
- return blobStat ? {
5100
- path: metadata.blobPath,
5101
- size: blobStat.size
5102
- } : null;
5103
- }
5104
- getSessionDir(tenantKey, sessionId) {
5105
- return join(this.rootDir, tenantKey, sessionId);
5106
- }
5107
- getArtifactDir(tenantKey, sessionId, artifactId) {
5108
- return join(this.getSessionDir(tenantKey, sessionId), artifactId);
5109
- }
5110
- getMetadataPath(tenantKey, sessionId, artifactId) {
5111
- return join(this.getArtifactDir(tenantKey, sessionId, artifactId), "meta.json");
5112
- }
5113
- };
5114
- function readPositiveIntEnv(name, fallback) {
5115
- const raw = process.env[name];
5116
- if (!raw) return fallback;
5117
- const parsed = Number.parseInt(raw, 10);
5118
- return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
5119
- }
5120
- function validateContextId(value, fieldName) {
5121
- if (!/^[A-Za-z0-9_.:-]{1,200}$/.test(value)) throw new ArtifactUploadError(`Invalid ${fieldName}`, 400);
5122
- }
5123
- function sanitizeFileName(fileName) {
5124
- return fileName.replace(/[\\/\0\r\n]/g, "_").trim() || "upload.bin";
5125
- }
5126
- function normalizeMimeType(mimeType) {
5127
- return mimeType?.trim() || "application/octet-stream";
5128
- }
5129
- function toPublicRef(metadata) {
5130
- const { tenantKey: _tenantKey, userId: _userId, openId: _openId, blobPath: _blobPath, ...ref } = metadata;
5131
- return ref;
5132
- }
5133
- function isOwnedBy(metadata, owner, sessionId) {
5134
- return metadata.tenantKey === owner.tenantKey && metadata.userId === owner.userId && metadata.openId === owner.openId && metadata.sessionId === sessionId;
5135
- }
5136
- async function readArtifactMetadata(filePath) {
5137
- try {
5138
- return JSON.parse(await readFile(filePath, "utf-8"));
5139
- } catch {
5140
- return null;
5141
- }
5142
- }
5143
- async function writeJson(filePath, data) {
5144
- await mkdir(dirname(filePath), { recursive: true });
5145
- await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
5146
- }
5147
- //#endregion
5148
5222
  //#region src/gateway/artifact-handler.ts
5149
5223
  const log$28 = larkLogger("gateway/artifacts");
5150
5224
  function createArtifactRouter(config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe-lark/larkpal",
3
- "version": "0.1.63",
3
+ "version": "0.1.64",
4
4
  "description": "LarkPal - Lark/Feishu bot service",
5
5
  "type": "module",
6
6
  "main": "./dist/main.mjs",
@@ -21,9 +21,22 @@
21
21
  "registry": "https://registry.npmjs.org",
22
22
  "access": "public"
23
23
  },
24
+ "packageManager": "pnpm@10.32.1",
24
25
  "engines": {
25
26
  "node": ">=22"
26
27
  },
28
+ "scripts": {
29
+ "start": "node --env-file=.env bin/larkpal.js",
30
+ "build": "tsdown",
31
+ "test": "vitest run",
32
+ "test:watch": "vitest",
33
+ "lint": "eslint src/",
34
+ "lint:fix": "eslint src/ --fix",
35
+ "sit:larkpal-agent": "node scripts/sit/larkpal-agent-0.1.9-sit.mjs",
36
+ "typecheck": "tsc --noEmit",
37
+ "format": "prettier --write src/**/*.ts",
38
+ "format:check": "prettier --check src/**/*.ts"
39
+ },
27
40
  "dependencies": {
28
41
  "@larksuiteoapi/node-sdk": "^1.60.0",
29
42
  "@modelcontextprotocol/sdk": "^1.29.0",
@@ -38,7 +51,7 @@
38
51
  "zod": "^4.3.6"
39
52
  },
40
53
  "optionalDependencies": {
41
- "@vibe-lark/larkpal-agent": "^0.2.12"
54
+ "@vibe-lark/larkpal-agent": "^0.2.19"
42
55
  },
43
56
  "devDependencies": {
44
57
  "@eslint/js": "^10.0.1",
@@ -56,17 +69,5 @@
56
69
  "typescript": "^5.9.3",
57
70
  "typescript-eslint": "^8.32.1",
58
71
  "vitest": "^4.1.1"
59
- },
60
- "scripts": {
61
- "start": "node --env-file=.env bin/larkpal.js",
62
- "build": "tsdown",
63
- "test": "vitest run",
64
- "test:watch": "vitest",
65
- "lint": "eslint src/",
66
- "lint:fix": "eslint src/ --fix",
67
- "sit:larkpal-agent": "node scripts/sit/larkpal-agent-0.1.9-sit.mjs",
68
- "typecheck": "tsc --noEmit",
69
- "format": "prettier --write src/**/*.ts",
70
- "format:check": "prettier --check src/**/*.ts"
71
72
  }
72
- }
73
+ }