feat:support feshu via websocket
This commit is contained in:
parent
b560bdeab6
commit
bd23d04ce2
@ -1,12 +1,12 @@
|
||||
---
|
||||
summary: "Feishu (Lark) bot support, capabilities, and configuration"
|
||||
read_when:
|
||||
- Working on Feishu features or webhooks
|
||||
- Working on Feishu features
|
||||
- Integrating with Chinese enterprise messaging
|
||||
---
|
||||
# Feishu (飞书/Lark)
|
||||
|
||||
Status: experimental. Supports direct messages and groups via Bot API.
|
||||
Status: experimental. Supports direct messages and groups via Bot API using WebSocket long connection.
|
||||
|
||||
## Plugin required
|
||||
Feishu ships as a plugin and is not bundled with the core install.
|
||||
@ -23,7 +23,9 @@ Feishu ships as a plugin and is not bundled with the core install.
|
||||
3) Set the credentials:
|
||||
- Env: `FEISHU_APP_ID=...` and `FEISHU_APP_SECRET=...`
|
||||
- Or config: `channels.feishu.appId` and `channels.feishu.appSecret`
|
||||
4) Configure event subscription in Feishu console with your webhook URL
|
||||
4) Configure event subscription in Feishu console:
|
||||
- Set subscription method to **"Long Connection"**
|
||||
- Add `im.message.receive_v1` event
|
||||
5) Restart the gateway (or finish onboarding)
|
||||
6) DM access is pairing by default; approve the pairing code on first contact
|
||||
|
||||
@ -35,8 +37,6 @@ Minimal config:
|
||||
enabled: true,
|
||||
appId: "cli_xxxxxxxxxx",
|
||||
appSecret: "xxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
verificationToken: "xxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
webhookPath: "/feishu/callback",
|
||||
dmPolicy: "pairing"
|
||||
}
|
||||
}
|
||||
@ -46,6 +46,7 @@ Minimal config:
|
||||
## What it is
|
||||
Feishu (飞书) is an enterprise collaboration platform by ByteDance, also known as Lark internationally. Its Bot API allows the Gateway to run a bot for 1:1 conversations and group chats.
|
||||
- A Feishu Bot API channel owned by the Gateway
|
||||
- Uses WebSocket long connection for receiving events (no public IP needed)
|
||||
- Deterministic routing: replies go back to Feishu; the model never chooses channels
|
||||
- DMs share the agent's main session
|
||||
- Groups require @mention by default
|
||||
@ -70,11 +71,9 @@ Feishu (飞书) is an enterprise collaboration platform by ByteDance, also known
|
||||
|
||||
### 3) Configure event subscription
|
||||
1) Go to "Events and Callbacks" page
|
||||
2) Choose "Request URL Mode" (webhook)
|
||||
3) Enter your webhook URL: `https://your-gateway-host/feishu/callback`
|
||||
4) Copy the **Verification Token** and optionally the **Encrypt Key**
|
||||
5) Add event subscription: `im.message.receive_v1` (Receive messages)
|
||||
6) Click Save
|
||||
2) Set subscription method to **"Long Connection"** (WebSocket)
|
||||
3) Add event subscription: `im.message.receive_v1` (Receive messages)
|
||||
4) Click Save
|
||||
|
||||
### 4) Configure the token (env or config)
|
||||
Example:
|
||||
@ -86,9 +85,6 @@ Example:
|
||||
enabled: true,
|
||||
appId: "cli_xxxxxxxxxx",
|
||||
appSecret: "xxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
verificationToken: "xxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
encryptKey: "xxxxxxxxxxxxxxxxxxxxxxxx", // optional, for encrypted events
|
||||
webhookPath: "/feishu/callback",
|
||||
dmPolicy: "pairing"
|
||||
}
|
||||
}
|
||||
@ -98,8 +94,6 @@ Example:
|
||||
Env option (works for the default account only):
|
||||
- `FEISHU_APP_ID=cli_xxxxxxxxxx`
|
||||
- `FEISHU_APP_SECRET=xxxxxxxxxxxxxxxxxxxxxxxx`
|
||||
- `FEISHU_VERIFICATION_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx`
|
||||
- `FEISHU_ENCRYPT_KEY=xxxxxxxxxxxxxxxxxxxxxxxx`
|
||||
|
||||
Multi-account support: use `channels.feishu.accounts` with per-account credentials and optional `name`.
|
||||
|
||||
@ -114,8 +108,8 @@ Restart the gateway. Feishu starts when credentials are resolved.
|
||||
DM access defaults to pairing. Approve the code when the bot is first contacted.
|
||||
|
||||
## How it works (behavior)
|
||||
- Inbound messages arrive via webhook (Feishu sends HTTP POST to your configured path)
|
||||
- The gateway verifies the request using the verification token
|
||||
- The gateway establishes a WebSocket long connection to Feishu servers
|
||||
- Events are pushed directly through the WebSocket (no public IP needed)
|
||||
- Messages are normalized into the shared channel envelope
|
||||
- Replies always route back to the same Feishu chat
|
||||
- Long responses are chunked to 4000 characters (Feishu API limit)
|
||||
@ -123,7 +117,6 @@ DM access defaults to pairing. Approve the code when the bot is first contacted.
|
||||
## Limits
|
||||
- Outbound text is chunked to 4000 characters (Feishu API limit)
|
||||
- Media downloads/uploads are capped by `channels.feishu.mediaMaxMb` (default 20)
|
||||
- Streaming is blocked by default due to webhook-based architecture
|
||||
- Rate limits apply per the Feishu API documentation
|
||||
|
||||
## Access control (DMs)
|
||||
@ -141,33 +134,33 @@ DM access defaults to pairing. Approve the code when the bot is first contacted.
|
||||
- Configure allowed groups via `channels.feishu.groupAllowFrom` or `channels.feishu.groups`
|
||||
- Groups require @mention by default; configure per-group via `channels.feishu.groups.<chat_id>.requireMention`
|
||||
|
||||
## Webhook verification
|
||||
Feishu uses two verification mechanisms:
|
||||
1) **URL Verification**: When you first configure the webhook, Feishu sends a challenge request. The gateway responds automatically.
|
||||
2) **Event Verification**: Each event includes a `token` field that must match your verification token.
|
||||
|
||||
Optional encryption:
|
||||
- If you enable encryption in Feishu console, set `channels.feishu.encryptKey`
|
||||
- Events are encrypted with AES-256-CBC; the gateway decrypts them automatically
|
||||
|
||||
## Supported message types
|
||||
- **Text messages**: Full support with 4000 character chunking
|
||||
- **Image messages**: Logged but media upload requires image_key (planned)
|
||||
- **Interactive cards**: Full markdown support via card messages (default for replies)
|
||||
- **Text messages**: Plain text fallback
|
||||
- **Image messages**: Requires image_key (pre-uploaded images)
|
||||
- **Rich text (post)**: Planned support
|
||||
- **Interactive cards**: Planned support
|
||||
|
||||
### Markdown support
|
||||
All outbound messages use Feishu interactive card format, which supports markdown syntax:
|
||||
- **Bold**: `**text**`
|
||||
- *Italic*: `*text*`
|
||||
- ~~Strikethrough~~: `~~text~~`
|
||||
- `Code`: `` `code` ``
|
||||
- Links: `[text](url)`
|
||||
- Lists and more
|
||||
|
||||
## Capabilities
|
||||
| Feature | Status |
|
||||
|---------|--------|
|
||||
| Direct messages | Supported |
|
||||
| Groups | Supported |
|
||||
| Media (images) | Partial (text only for now) |
|
||||
| Markdown formatting | Supported (via card messages) |
|
||||
| Media (images) | Partial (requires image_key) |
|
||||
| Reactions | Not supported |
|
||||
| Threads | Not supported |
|
||||
| Polls | Not supported |
|
||||
| Native commands | Not supported |
|
||||
| Streaming | Blocked (webhook-based) |
|
||||
| Rich cards | Planned |
|
||||
| Streaming | Blocked |
|
||||
|
||||
## Delivery targets (CLI/cron)
|
||||
- Use an open_id, user_id, or chat_id as the target
|
||||
@ -178,15 +171,14 @@ Optional encryption:
|
||||
|
||||
**Bot does not respond:**
|
||||
- Check that the app credentials are valid: `clawdbot channels status --probe`
|
||||
- Verify the webhook URL is correctly configured in Feishu console
|
||||
- Check that the verification token matches
|
||||
- Verify the event subscription is set to "Long Connection" mode in Feishu console
|
||||
- Verify the sender is approved (pairing or allowFrom)
|
||||
- Check gateway logs: `clawdbot logs --follow`
|
||||
|
||||
**Webhook verification fails:**
|
||||
- Ensure your gateway is publicly accessible at the configured webhook path
|
||||
- Check that `channels.feishu.verificationToken` matches the token in Feishu console
|
||||
- If using encryption, verify `channels.feishu.encryptKey` is correct
|
||||
**WebSocket connection fails:**
|
||||
- Ensure the gateway has network access to Feishu servers
|
||||
- Check that the App ID and App Secret are correct
|
||||
- Verify the app is published and active
|
||||
|
||||
**Permission errors:**
|
||||
- Ensure the app has required permissions (`im:message`, `im:message.receive_v1`)
|
||||
@ -206,9 +198,6 @@ Provider options:
|
||||
- `channels.feishu.appId`: App ID from Feishu Open Platform
|
||||
- `channels.feishu.appSecret`: App Secret from Feishu Open Platform
|
||||
- `channels.feishu.appSecretFile`: read app secret from file path
|
||||
- `channels.feishu.verificationToken`: verification token for webhook validation
|
||||
- `channels.feishu.encryptKey`: encrypt key for event decryption (optional)
|
||||
- `channels.feishu.webhookPath`: webhook path on the gateway HTTP server (default: /feishu/callback)
|
||||
- `channels.feishu.dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing)
|
||||
- `channels.feishu.allowFrom`: DM allowlist (open_id or user_id). `open` requires `"*"`
|
||||
- `channels.feishu.groupPolicy`: `open | allowlist` (default: allowlist)
|
||||
@ -224,9 +213,6 @@ Multi-account options:
|
||||
- `channels.feishu.accounts.<id>.enabled`: enable/disable account
|
||||
- `channels.feishu.accounts.<id>.dmPolicy`: per-account DM policy
|
||||
- `channels.feishu.accounts.<id>.allowFrom`: per-account allowlist
|
||||
- `channels.feishu.accounts.<id>.verificationToken`: per-account verification token
|
||||
- `channels.feishu.accounts.<id>.encryptKey`: per-account encrypt key
|
||||
- `channels.feishu.accounts.<id>.webhookPath`: per-account webhook path
|
||||
|
||||
## International users (Lark)
|
||||
For Lark (international version), use the same configuration. The API endpoints are compatible.
|
||||
|
||||
@ -2,7 +2,6 @@ import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
|
||||
|
||||
import { feishuDock, feishuPlugin } from "./src/channel.js";
|
||||
import { handleFeishuWebhookRequest } from "./src/monitor.js";
|
||||
import { setFeishuRuntime } from "./src/runtime.js";
|
||||
|
||||
const plugin = {
|
||||
@ -13,7 +12,7 @@ const plugin = {
|
||||
register(api: ClawdbotPluginApi) {
|
||||
setFeishuRuntime(api.runtime);
|
||||
api.registerChannel({ plugin: feishuPlugin, dock: feishuDock });
|
||||
api.registerHttpHandler(handleFeishuWebhookRequest);
|
||||
// WebSocket mode - no HTTP handler needed
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -27,6 +27,9 @@
|
||||
"defaultChoice": "npm"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@larksuiteoapi/node-sdk": "^1.56.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"clawdbot": "workspace:*"
|
||||
},
|
||||
|
||||
@ -3,8 +3,6 @@
|
||||
* @see https://open.feishu.cn/document
|
||||
*/
|
||||
|
||||
import { createHash, createDecipheriv } from "node:crypto";
|
||||
|
||||
import type {
|
||||
FeishuApiResponse,
|
||||
FeishuBotInfo,
|
||||
@ -12,7 +10,6 @@ import type {
|
||||
FeishuSendMessageParams,
|
||||
FeishuSendMessageResponse,
|
||||
FeishuTokenResponse,
|
||||
FeishuWebhookPayload,
|
||||
} from "./types.js";
|
||||
|
||||
const FEISHU_API_BASE = "https://open.feishu.cn/open-apis";
|
||||
@ -214,74 +211,3 @@ export async function replyMessage(
|
||||
fetch: options?.fetch,
|
||||
});
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Webhook Verification
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Decrypt an encrypted webhook payload using the encrypt key.
|
||||
* Feishu uses AES-256-CBC with the key derived from SHA256 of the encrypt key.
|
||||
*/
|
||||
export function decryptWebhookPayload(encrypted: string, encryptKey: string): string {
|
||||
// Derive key from encrypt key using SHA256
|
||||
const key = createHash("sha256").update(encryptKey).digest();
|
||||
|
||||
// Decode base64
|
||||
const ciphertext = Buffer.from(encrypted, "base64");
|
||||
|
||||
// First 16 bytes are the IV
|
||||
const iv = ciphertext.subarray(0, 16);
|
||||
const encryptedData = ciphertext.subarray(16);
|
||||
|
||||
// Decrypt using AES-256-CBC
|
||||
const decipher = createDecipheriv("aes-256-cbc", key, iv);
|
||||
let decrypted = decipher.update(encryptedData);
|
||||
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||
|
||||
return decrypted.toString("utf8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify webhook signature using verification token.
|
||||
*/
|
||||
export function verifyWebhookToken(payload: FeishuWebhookPayload, verificationToken: string): boolean {
|
||||
// For challenge verification, token is at top level
|
||||
if (payload.token) {
|
||||
return payload.token === verificationToken;
|
||||
}
|
||||
// For events, token is in header
|
||||
if (payload.header?.token) {
|
||||
return payload.header.token === verificationToken;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse webhook payload, decrypting if necessary.
|
||||
*/
|
||||
export function parseWebhookPayload(
|
||||
rawBody: string,
|
||||
encryptKey?: string,
|
||||
): FeishuWebhookPayload | null {
|
||||
try {
|
||||
const parsed = JSON.parse(rawBody) as FeishuWebhookPayload;
|
||||
|
||||
// If encrypted, decrypt first
|
||||
if (parsed.encrypt && encryptKey) {
|
||||
const decrypted = decryptWebhookPayload(parsed.encrypt, encryptKey);
|
||||
return JSON.parse(decrypted) as FeishuWebhookPayload;
|
||||
}
|
||||
|
||||
return parsed;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build challenge response for URL verification.
|
||||
*/
|
||||
export function buildChallengeResponse(challenge: string): string {
|
||||
return JSON.stringify({ challenge });
|
||||
}
|
||||
|
||||
@ -1,19 +1,21 @@
|
||||
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||
/**
|
||||
* WebSocket-based monitor for Feishu events using long connection mode.
|
||||
* Uses the official @larksuiteoapi/node-sdk WSClient for receiving events
|
||||
* via WebSocket - no public IP or webhook setup needed.
|
||||
*
|
||||
* @see https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/event-subscription-guide/long-connection-mode
|
||||
*/
|
||||
|
||||
import * as Lark from "@larksuiteoapi/node-sdk";
|
||||
|
||||
import type { ClawdbotConfig, MarkdownTableMode } from "clawdbot/plugin-sdk";
|
||||
|
||||
import type {
|
||||
FeishuMessageEvent,
|
||||
FeishuReceiveIdType,
|
||||
FeishuWebhookPayload,
|
||||
ResolvedFeishuAccount,
|
||||
} from "./types.js";
|
||||
import {
|
||||
buildChallengeResponse,
|
||||
parseWebhookPayload,
|
||||
sendMessage,
|
||||
verifyWebhookToken,
|
||||
} from "./api.js";
|
||||
import { sendMessage } from "./api.js";
|
||||
import { getFeishuRuntime } from "./runtime.js";
|
||||
|
||||
export type FeishuRuntimeEnv = {
|
||||
@ -26,7 +28,6 @@ export type FeishuMonitorOptions = {
|
||||
config: ClawdbotConfig;
|
||||
runtime: FeishuRuntimeEnv;
|
||||
abortSignal: AbortSignal;
|
||||
webhookPath?: string;
|
||||
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void;
|
||||
};
|
||||
|
||||
@ -34,9 +35,29 @@ export type FeishuMonitorResult = {
|
||||
stop: () => void;
|
||||
};
|
||||
|
||||
const FEISHU_TEXT_LIMIT = 4000;
|
||||
// Feishu card markdown content limit (slightly lower than text to account for JSON overhead)
|
||||
const FEISHU_CARD_CONTENT_LIMIT = 3800;
|
||||
const DEFAULT_MEDIA_MAX_MB = 20;
|
||||
const DEFAULT_WEBHOOK_PATH = "/feishu/callback";
|
||||
|
||||
/**
|
||||
* Build a Feishu interactive card with markdown content.
|
||||
* Card messages support rich markdown formatting in Feishu.
|
||||
*/
|
||||
function buildMarkdownCard(content: string): string {
|
||||
const card = {
|
||||
config: {
|
||||
wide_screen_mode: true,
|
||||
enable_forward: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
tag: "markdown",
|
||||
content,
|
||||
},
|
||||
],
|
||||
};
|
||||
return JSON.stringify(card);
|
||||
}
|
||||
|
||||
type FeishuCoreRuntime = ReturnType<typeof getFeishuRuntime>;
|
||||
|
||||
@ -46,11 +67,6 @@ function logVerbose(core: FeishuCoreRuntime, runtime: FeishuRuntimeEnv, message:
|
||||
}
|
||||
}
|
||||
|
||||
function logWebhookEvent(message: string): void {
|
||||
// Use console to ensure visibility even when runtime isn't available.
|
||||
console.warn(`[feishu] ${message}`);
|
||||
}
|
||||
|
||||
type FeishuReplyTarget = {
|
||||
id: string;
|
||||
type: FeishuReceiveIdType;
|
||||
@ -73,218 +89,8 @@ function isSenderAllowed(senderId: string, allowFrom: string[]): boolean {
|
||||
});
|
||||
}
|
||||
|
||||
async function readJsonBody(req: IncomingMessage, maxBytes: number) {
|
||||
const chunks: Buffer[] = [];
|
||||
let total = 0;
|
||||
return await new Promise<{ ok: boolean; value?: string; error?: string }>((resolve) => {
|
||||
req.on("data", (chunk: Buffer) => {
|
||||
total += chunk.length;
|
||||
if (total > maxBytes) {
|
||||
resolve({ ok: false, error: "payload too large" });
|
||||
req.destroy();
|
||||
return;
|
||||
}
|
||||
chunks.push(chunk);
|
||||
});
|
||||
req.on("end", () => {
|
||||
try {
|
||||
const raw = Buffer.concat(chunks).toString("utf8");
|
||||
if (!raw.trim()) {
|
||||
resolve({ ok: false, error: "empty payload" });
|
||||
return;
|
||||
}
|
||||
resolve({ ok: true, value: raw });
|
||||
} catch (err) {
|
||||
resolve({ ok: false, error: err instanceof Error ? err.message : String(err) });
|
||||
}
|
||||
});
|
||||
req.on("error", (err) => {
|
||||
resolve({ ok: false, error: err instanceof Error ? err.message : String(err) });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
type WebhookTarget = {
|
||||
account: ResolvedFeishuAccount;
|
||||
config: ClawdbotConfig;
|
||||
runtime: FeishuRuntimeEnv;
|
||||
core: FeishuCoreRuntime;
|
||||
path: string;
|
||||
encryptKey: string;
|
||||
verificationToken: string;
|
||||
mediaMaxMb: number;
|
||||
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void;
|
||||
};
|
||||
|
||||
const webhookTargets = new Map<string, WebhookTarget[]>();
|
||||
|
||||
function normalizeWebhookPath(raw: string): string {
|
||||
const trimmed = raw.trim();
|
||||
if (!trimmed) return "/feishu/callback";
|
||||
const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
||||
if (withSlash.length > 1 && withSlash.endsWith("/")) {
|
||||
return withSlash.slice(0, -1);
|
||||
}
|
||||
return withSlash;
|
||||
}
|
||||
|
||||
export function registerFeishuWebhookTarget(target: WebhookTarget): () => void {
|
||||
const key = normalizeWebhookPath(target.path);
|
||||
const normalizedTarget = { ...target, path: key };
|
||||
const existing = webhookTargets.get(key) ?? [];
|
||||
const next = [...existing, normalizedTarget];
|
||||
webhookTargets.set(key, next);
|
||||
return () => {
|
||||
const updated = (webhookTargets.get(key) ?? []).filter(
|
||||
(entry) => entry !== normalizedTarget,
|
||||
);
|
||||
if (updated.length > 0) {
|
||||
webhookTargets.set(key, updated);
|
||||
} else {
|
||||
webhookTargets.delete(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming Feishu webhook requests.
|
||||
*/
|
||||
export async function handleFeishuWebhookRequest(
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
): Promise<boolean> {
|
||||
const url = new URL(req.url ?? "/", "http://localhost");
|
||||
const path = normalizeWebhookPath(url.pathname);
|
||||
const targets = webhookTargets.get(path);
|
||||
if (!targets || targets.length === 0) {
|
||||
if (path === DEFAULT_WEBHOOK_PATH || path.startsWith("/feishu/")) {
|
||||
logWebhookEvent(
|
||||
`webhook request received for ${path}, but no active Feishu accounts are registered`,
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (req.method !== "POST") {
|
||||
res.statusCode = 405;
|
||||
res.setHeader("Allow", "POST");
|
||||
res.end("Method Not Allowed");
|
||||
return true;
|
||||
}
|
||||
|
||||
const body = await readJsonBody(req, 1024 * 1024);
|
||||
if (!body.ok || !body.value) {
|
||||
res.statusCode = body.error === "payload too large" ? 413 : 400;
|
||||
res.end(body.error ?? "invalid payload");
|
||||
return true;
|
||||
}
|
||||
|
||||
let rawPayload: FeishuWebhookPayload | null = null;
|
||||
try {
|
||||
rawPayload = JSON.parse(body.value) as FeishuWebhookPayload;
|
||||
} catch {
|
||||
rawPayload = null;
|
||||
}
|
||||
const isEncryptedRequest = Boolean(rawPayload?.encrypt);
|
||||
const rawEventType = rawPayload?.header?.event_type ?? rawPayload?.type ?? "unknown";
|
||||
logWebhookEvent(
|
||||
`webhook hit: path=${path} method=${req.method} targets=${targets.length} encrypted=${isEncryptedRequest} event=${rawEventType}`,
|
||||
);
|
||||
|
||||
let sawTokenMismatch = false;
|
||||
let sawEncryptedWithoutKey = false;
|
||||
let sawDecryptFailure = false;
|
||||
|
||||
// Try each target to find one that can handle this request
|
||||
for (const target of targets) {
|
||||
const payload = parseWebhookPayload(body.value, target.encryptKey);
|
||||
if (!payload) {
|
||||
if (isEncryptedRequest && target.encryptKey) {
|
||||
sawDecryptFailure = true;
|
||||
target.runtime.error?.(
|
||||
`[${target.account.accountId}] Feishu webhook decrypt failed. Check encryptKey.`,
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (payload.encrypt && !target.encryptKey) {
|
||||
sawEncryptedWithoutKey = true;
|
||||
target.runtime.error?.(
|
||||
`[${target.account.accountId}] Feishu webhook is encrypted but encryptKey is not configured.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify token if configured
|
||||
if (target.verificationToken && !verifyWebhookToken(payload, target.verificationToken)) {
|
||||
sawTokenMismatch = true;
|
||||
target.runtime.error?.(
|
||||
`[${target.account.accountId}] Feishu webhook token mismatch. Check verificationToken.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle URL verification challenge
|
||||
if (payload.type === "url_verification" && payload.challenge) {
|
||||
res.statusCode = 200;
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
res.end(buildChallengeResponse(payload.challenge));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle message events
|
||||
if (payload.header?.event_type === "im.message.receive_v1" && payload.event) {
|
||||
target.statusSink?.({ lastInboundAt: Date.now() });
|
||||
processMessageEvent(
|
||||
payload.event as FeishuMessageEvent,
|
||||
target.account,
|
||||
target.config,
|
||||
target.runtime,
|
||||
target.core,
|
||||
target.mediaMaxMb,
|
||||
target.statusSink,
|
||||
).catch((err) => {
|
||||
target.runtime.error?.(`[${target.account.accountId}] Feishu webhook failed: ${String(err)}`);
|
||||
});
|
||||
|
||||
res.statusCode = 200;
|
||||
res.end("ok");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Other event types - acknowledge but don't process
|
||||
if (payload.header?.event_type) {
|
||||
target.runtime.log?.(`[feishu] ignoring event type: ${payload.header.event_type}`);
|
||||
res.statusCode = 200;
|
||||
res.end("ok");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// No target could handle the request
|
||||
if (sawEncryptedWithoutKey) {
|
||||
res.statusCode = 400;
|
||||
res.end("encrypt_key required");
|
||||
return true;
|
||||
}
|
||||
if (sawDecryptFailure) {
|
||||
res.statusCode = 400;
|
||||
res.end("decrypt failed");
|
||||
return true;
|
||||
}
|
||||
if (sawTokenMismatch) {
|
||||
res.statusCode = 401;
|
||||
res.end("unauthorized");
|
||||
return true;
|
||||
}
|
||||
res.statusCode = 401;
|
||||
res.end("unauthorized");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message event from Feishu webhook.
|
||||
* Process a message event from Feishu WebSocket.
|
||||
*/
|
||||
async function processMessageEvent(
|
||||
event: FeishuMessageEvent,
|
||||
@ -543,18 +349,19 @@ async function deliverFeishuReply(params: {
|
||||
const chunkMode = core.channel.text.resolveChunkMode(config, "feishu", account.accountId);
|
||||
const chunks = core.channel.text.chunkMarkdownTextWithMode(
|
||||
text,
|
||||
FEISHU_TEXT_LIMIT,
|
||||
FEISHU_CARD_CONTENT_LIMIT,
|
||||
chunkMode,
|
||||
);
|
||||
for (const chunk of chunks) {
|
||||
try {
|
||||
// Send as interactive card message with markdown support
|
||||
await sendMessage(
|
||||
account.appId,
|
||||
account.appSecret,
|
||||
{
|
||||
receive_id: receiveId,
|
||||
msg_type: "text",
|
||||
content: JSON.stringify({ text: chunk }),
|
||||
msg_type: "interactive",
|
||||
content: buildMarkdownCard(chunk),
|
||||
},
|
||||
receiveIdType,
|
||||
);
|
||||
@ -567,48 +374,70 @@ async function deliverFeishuReply(params: {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start monitoring Feishu webhook events.
|
||||
* Start monitoring Feishu events using WebSocket long connection.
|
||||
*/
|
||||
export async function monitorFeishuProvider(
|
||||
options: FeishuMonitorOptions,
|
||||
): Promise<FeishuMonitorResult> {
|
||||
const { account, config, runtime, abortSignal, webhookPath, statusSink } = options;
|
||||
const { account, config, runtime, abortSignal, statusSink } = options;
|
||||
|
||||
const core = getFeishuRuntime();
|
||||
const effectiveMediaMaxMb = account.config.mediaMaxMb ?? DEFAULT_MEDIA_MAX_MB;
|
||||
const path = normalizeWebhookPath(webhookPath ?? account.config.webhookPath ?? "/feishu/callback");
|
||||
|
||||
const encryptKey = account.config.encryptKey ?? process.env.FEISHU_ENCRYPT_KEY ?? "";
|
||||
const verificationToken = account.config.verificationToken ?? process.env.FEISHU_VERIFICATION_TOKEN ?? "";
|
||||
|
||||
let stopped = false;
|
||||
const stopHandlers: Array<() => void> = [];
|
||||
let wsClient: Lark.WSClient | null = null;
|
||||
|
||||
const stop = () => {
|
||||
stopped = true;
|
||||
for (const handler of stopHandlers) {
|
||||
handler();
|
||||
if (wsClient) {
|
||||
wsClient = null;
|
||||
}
|
||||
};
|
||||
|
||||
// Register webhook target
|
||||
const unregister = registerFeishuWebhookTarget({
|
||||
account,
|
||||
config,
|
||||
runtime,
|
||||
core,
|
||||
path,
|
||||
encryptKey,
|
||||
verificationToken,
|
||||
mediaMaxMb: effectiveMediaMaxMb,
|
||||
statusSink,
|
||||
// Create WebSocket client for receiving events
|
||||
wsClient = new Lark.WSClient({
|
||||
appId: account.appId,
|
||||
appSecret: account.appSecret,
|
||||
domain: Lark.Domain.Feishu,
|
||||
loggerLevel: Lark.LoggerLevel.warn,
|
||||
});
|
||||
|
||||
// Create event dispatcher with message handler
|
||||
const eventDispatcher = new Lark.EventDispatcher({}).register({
|
||||
"im.message.receive_v1": async (data) => {
|
||||
if (stopped) return;
|
||||
|
||||
statusSink?.({ lastInboundAt: Date.now() });
|
||||
|
||||
// Convert SDK event data to our internal type
|
||||
const event: FeishuMessageEvent = {
|
||||
sender: data.sender as FeishuMessageEvent["sender"],
|
||||
message: data.message as FeishuMessageEvent["message"],
|
||||
};
|
||||
|
||||
try {
|
||||
await processMessageEvent(
|
||||
event,
|
||||
account,
|
||||
config,
|
||||
runtime,
|
||||
core,
|
||||
effectiveMediaMaxMb,
|
||||
statusSink,
|
||||
);
|
||||
} catch (err) {
|
||||
runtime.error?.(`[${account.accountId}] Feishu event handler failed: ${String(err)}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Start WebSocket connection
|
||||
wsClient.start({
|
||||
eventDispatcher,
|
||||
});
|
||||
stopHandlers.push(unregister);
|
||||
|
||||
runtime.log?.(
|
||||
`[feishu] webhook ready: path=${path} encrypted=${Boolean(encryptKey)} token=${Boolean(
|
||||
verificationToken,
|
||||
)}`,
|
||||
`[feishu] WebSocket connection started for account=${account.accountId}`,
|
||||
);
|
||||
|
||||
abortSignal.addEventListener("abort", stop, { once: true });
|
||||
|
||||
@ -62,7 +62,28 @@ function inferReceiveIdType(target: string): FeishuReceiveIdType {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a text message to a Feishu user or chat.
|
||||
* Build a Feishu interactive card with markdown content.
|
||||
* Card messages support rich markdown formatting in Feishu.
|
||||
*/
|
||||
function buildMarkdownCard(content: string): string {
|
||||
const card = {
|
||||
config: {
|
||||
wide_screen_mode: true,
|
||||
enable_forward: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
tag: "markdown",
|
||||
content,
|
||||
},
|
||||
],
|
||||
};
|
||||
return JSON.stringify(card);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to a Feishu user or chat.
|
||||
* Uses interactive card format for markdown support.
|
||||
*/
|
||||
export async function sendMessageFeishu(
|
||||
to: string,
|
||||
@ -81,8 +102,8 @@ export async function sendMessageFeishu(
|
||||
|
||||
const receiveIdType = options.receiveIdType ?? inferReceiveIdType(to);
|
||||
|
||||
// Build message content
|
||||
const content = JSON.stringify({ text });
|
||||
// Build interactive card message content for markdown support
|
||||
const content = buildMarkdownCard(text);
|
||||
|
||||
try {
|
||||
// If replying to a specific message
|
||||
@ -91,7 +112,7 @@ export async function sendMessageFeishu(
|
||||
appId,
|
||||
appSecret,
|
||||
options.replyToMessageId,
|
||||
{ msg_type: "text", content },
|
||||
{ msg_type: "interactive", content },
|
||||
{ fetch: fetcher },
|
||||
);
|
||||
|
||||
@ -101,11 +122,11 @@ export async function sendMessageFeishu(
|
||||
return { ok: false, error: response.msg ?? "Failed to reply" };
|
||||
}
|
||||
|
||||
// Send new message
|
||||
// Send new message as interactive card
|
||||
const response = await sendMessage(
|
||||
appId,
|
||||
appSecret,
|
||||
{ receive_id: to.trim(), msg_type: "text", content },
|
||||
{ receive_id: to.trim(), msg_type: "interactive", content },
|
||||
receiveIdType,
|
||||
{ fetch: fetcher },
|
||||
);
|
||||
|
||||
@ -10,12 +10,6 @@ export type FeishuAccountConfig = {
|
||||
appSecret?: string;
|
||||
/** Path to file containing the app secret. */
|
||||
appSecretFile?: string;
|
||||
/** Encrypt key for event decryption (from Events and Callbacks page). */
|
||||
encryptKey?: string;
|
||||
/** Verification token for webhook validation. */
|
||||
verificationToken?: string;
|
||||
/** Webhook path for the gateway HTTP server (defaults to /feishu/callback). */
|
||||
webhookPath?: string;
|
||||
/** Direct message access policy (default: pairing). */
|
||||
dmPolicy?: "pairing" | "allowlist" | "open" | "disabled";
|
||||
/** Allowlist for DM senders (Feishu open_id or user_id). */
|
||||
@ -124,39 +118,27 @@ export type FeishuMention = {
|
||||
tenant_key?: string;
|
||||
};
|
||||
|
||||
/** Event header from webhook payload. */
|
||||
export type FeishuEventHeader = {
|
||||
event_id: string;
|
||||
event_type: string;
|
||||
create_time: string;
|
||||
token: string;
|
||||
app_id: string;
|
||||
tenant_key: string;
|
||||
};
|
||||
|
||||
/** Message receive event (im.message.receive_v1). */
|
||||
export type FeishuMessageEvent = {
|
||||
sender: FeishuSender;
|
||||
message: FeishuMessageContent;
|
||||
};
|
||||
|
||||
/** Webhook event payload. */
|
||||
export type FeishuWebhookPayload = {
|
||||
schema?: string;
|
||||
header?: FeishuEventHeader;
|
||||
event?: FeishuMessageEvent | Record<string, unknown>;
|
||||
// URL verification challenge
|
||||
challenge?: string;
|
||||
token?: string;
|
||||
type?: string;
|
||||
// Encrypted payload
|
||||
encrypt?: string;
|
||||
};
|
||||
/** Feishu message type. */
|
||||
export type FeishuMessageType =
|
||||
| "text"
|
||||
| "post"
|
||||
| "image"
|
||||
| "file"
|
||||
| "audio"
|
||||
| "media"
|
||||
| "sticker"
|
||||
| "interactive"; // Card message with markdown support
|
||||
|
||||
/** Send message request body. */
|
||||
export type FeishuSendMessageParams = {
|
||||
receive_id: string;
|
||||
msg_type: "text" | "post" | "image" | "file" | "audio" | "media" | "sticker" | "interactive";
|
||||
msg_type: FeishuMessageType;
|
||||
content: string; // JSON string
|
||||
uuid?: string;
|
||||
};
|
||||
|
||||
@ -9,6 +9,6 @@
|
||||
]
|
||||
},
|
||||
"peerDependencies": {
|
||||
"clawdbot": ">=2026.1.24-3"
|
||||
"clawdbot": ">=2026.1.24"
|
||||
}
|
||||
}
|
||||
|
||||
316
pnpm-lock.yaml
generated
316
pnpm-lock.yaml
generated
@ -306,6 +306,10 @@ importers:
|
||||
|
||||
extensions/feishu:
|
||||
dependencies:
|
||||
'@larksuiteoapi/node-sdk':
|
||||
specifier: ^1.56.1
|
||||
version: 1.56.1
|
||||
devDependencies:
|
||||
clawdbot:
|
||||
specifier: workspace:*
|
||||
version: link:../..
|
||||
@ -363,8 +367,8 @@ importers:
|
||||
extensions/memory-core:
|
||||
dependencies:
|
||||
clawdbot:
|
||||
specifier: workspace:*
|
||||
version: link:../..
|
||||
specifier: '>=2026.1.24'
|
||||
version: 2026.1.24(@types/express@5.0.6)(audio-decode@2.2.3)(devtools-protocol@0.0.1561482)(typescript@5.9.3)
|
||||
|
||||
extensions/memory-lancedb:
|
||||
dependencies:
|
||||
@ -1074,105 +1078,89 @@ packages:
|
||||
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.2.4':
|
||||
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-ppc64@1.2.4':
|
||||
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-riscv64@1.2.4':
|
||||
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.2.4':
|
||||
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.2.4':
|
||||
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
|
||||
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
|
||||
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linux-arm64@0.34.5':
|
||||
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-arm@0.34.5':
|
||||
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-ppc64@0.34.5':
|
||||
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-riscv64@0.34.5':
|
||||
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-s390x@0.34.5':
|
||||
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-x64@0.34.5':
|
||||
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.34.5':
|
||||
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.34.5':
|
||||
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-wasm32@0.34.5':
|
||||
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
|
||||
@ -1241,6 +1229,48 @@ packages:
|
||||
'@kwsites/promise-deferred@1.1.1':
|
||||
resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==}
|
||||
|
||||
'@lancedb/lancedb-darwin-arm64@0.23.0':
|
||||
resolution: {integrity: sha512-8w0sMCNMwBv2kv5+fczGeSVlNOL+BOKChSsO4usM0hMw3PmxasONPctQBsESDuPS8lQ6/AKAQc2HT/ddd5Mg5w==}
|
||||
engines: {node: '>= 18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@lancedb/lancedb-linux-arm64-gnu@0.23.0':
|
||||
resolution: {integrity: sha512-+xse2IspO7hbuHT4H62q8Ct00fTojnuBxXp1X1I3/27dDvW8E+/itFiJuTZ0YMaJc7nNr9qh9YFXZ9hZdEmReg==}
|
||||
engines: {node: '>= 18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@lancedb/lancedb-linux-arm64-musl@0.23.0':
|
||||
resolution: {integrity: sha512-c2UCtGoYjA3oDdw5y3RLK7J2th3rSjYBng+1I03vU9g092y8KATAJO/lV2AtyxSC+esSuyY1dMEaj8ADcXjZAA==}
|
||||
engines: {node: '>= 18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@lancedb/lancedb-linux-x64-gnu@0.23.0':
|
||||
resolution: {integrity: sha512-OPL7tK3JCTx43ZxvbVs+CljfCer0KrojANQbcJ2V4VAp6XBhKx1sBAlIVGuCrd93pA8UOUP3iHsM7aglPo6rCg==}
|
||||
engines: {node: '>= 18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@lancedb/lancedb-linux-x64-musl@0.23.0':
|
||||
resolution: {integrity: sha512-1ZEoQDwOrKvwPyAG+95/r1NYqX8Ca5bRek8Vr62CzWCEmHd/pFeEGWZ5STrkh+Bt3GLdi2JOivFtRbmuBAJypQ==}
|
||||
engines: {node: '>= 18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@lancedb/lancedb-win32-arm64-msvc@0.23.0':
|
||||
resolution: {integrity: sha512-OuD1mkrgXvijRlXdbx3LvfuorO04FD5qHegnTOWGXh1sIwwrvvhcJAvXUGBNLY4n/lsWvA+xTjtMwRjUitvPKg==}
|
||||
engines: {node: '>= 18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@lancedb/lancedb-win32-x64-msvc@0.23.0':
|
||||
resolution: {integrity: sha512-5ve1hvVtp8zWxSE9A+MOQaicXl2Rn0ZG/NUaMTjTD3/CQHPKFmtrqDnM5khoPICTj2O2b10F6mn4cUzl5PASgA==}
|
||||
engines: {node: '>= 18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@lancedb/lancedb@0.23.0':
|
||||
resolution: {integrity: sha512-aYrIoEG24AC+wILCL57Ius/Y4yU+xFHDPKLvmjzzN4byAjzeIGF0TC86S5RBt4Ji+dxS7yIWV5Q/gE5/fybIFQ==}
|
||||
engines: {node: '>= 18'}
|
||||
@ -1249,6 +1279,9 @@ packages:
|
||||
peerDependencies:
|
||||
apache-arrow: '>=15.0.0 <=18.1.0'
|
||||
|
||||
'@larksuiteoapi/node-sdk@1.56.1':
|
||||
resolution: {integrity: sha512-/ixtyJnWOmcupKgDXz+6G6qTLMi3cNrR+LGOuq2PMwcJ6hhXTUJNyAF+ADY7ah9OoeDniGU/UJwMb2gqKdxwcA==}
|
||||
|
||||
'@line/bot-sdk@10.6.0':
|
||||
resolution: {integrity: sha512-4hSpglL/G/cW2JCcohaYz/BS0uOSJNV9IEYdMm0EiPEvDLayoI2hGq2D86uYPQFD2gvgkyhmzdShpWLG3P5r3w==}
|
||||
engines: {node: '>=20'}
|
||||
@ -1320,28 +1353,24 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@mariozechner/clipboard-linux-riscv64-gnu@0.3.0':
|
||||
resolution: {integrity: sha512-4BC08CIaOXSSAGRZLEjqJmQfioED8ohAzwt0k2amZPEbH96YKoBNorq5EdwPf5VT+odS0DeyCwhwtxokRLZIvQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@mariozechner/clipboard-linux-x64-gnu@0.3.0':
|
||||
resolution: {integrity: sha512-GpNY5Y9nOzr0Vt0Qi5U88qwe6piiIHk44kSMexl8ns90LluN5UTNYmyfi7Xq3/lmPZCpnB2xvBTYbsXCxnopIA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@mariozechner/clipboard-linux-x64-musl@0.3.0':
|
||||
resolution: {integrity: sha512-+PnR48/x9GMY5Kh8BLjzHMx6trOegMtxAuqTM9X/bhV3QuW6sLLd7nojDHSGj/ZueK6i0tcQxvOrgNLozVtNDA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@mariozechner/clipboard-win32-arm64-msvc@0.3.0':
|
||||
resolution: {integrity: sha512-+dy2vZ1Ph4EYj0cotB+bVUVk/uKl2bh9LOp/zlnFqoCCYDN6sm+L0VyIOPPo3hjoEVdGpHe1MUxp3qG/OLwXgg==}
|
||||
@ -1442,35 +1471,30 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@napi-rs/canvas-linux-arm64-musl@0.1.88':
|
||||
resolution: {integrity: sha512-kYyNrUsHLkoGHBc77u4Unh067GrfiCUMbGHC2+OTxbeWfZkPt2o32UOQkhnSswKd9Fko/wSqqGkY956bIUzruA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@napi-rs/canvas-linux-riscv64-gnu@0.1.88':
|
||||
resolution: {integrity: sha512-HVuH7QgzB0yavYdNZDRyAsn/ejoXB0hn8twwFnOqUbCCdkV+REna7RXjSR7+PdfW0qMQ2YYWsLvVBT5iL/mGpw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@napi-rs/canvas-linux-x64-gnu@0.1.88':
|
||||
resolution: {integrity: sha512-hvcvKIcPEQrvvJtJnwD35B3qk6umFJ8dFIr8bSymfrSMem0EQsfn1ztys8ETIFndTwdNWJKWluvxztA41ivsEw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@napi-rs/canvas-linux-x64-musl@0.1.88':
|
||||
resolution: {integrity: sha512-eSMpGYY2xnZSQ6UxYJ6plDboxq4KeJ4zT5HaVkUnbObNN6DlbJe0Mclh3wifAmquXfrlgTZt6zhHsUgz++AK6g==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@napi-rs/canvas-win32-arm64-msvc@0.1.88':
|
||||
resolution: {integrity: sha512-qcIFfEgHrchyYqRrxsCeTQgpJZ/GqHiqPcU/Fvw/ARVlQeDX1VyFH+X+0gCR2tca6UJrq96vnW+5o7buCq+erA==}
|
||||
@ -1516,28 +1540,36 @@ packages:
|
||||
engines: {node: '>=20.0.0'}
|
||||
cpu: [arm64, x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@node-llama-cpp/linux-armv7l@3.15.0':
|
||||
resolution: {integrity: sha512-ZuZ3q6mejQnEP4o22la7zBv7jNR+IZfgItDm3KjAl04HUXTKJ43HpNwjnf9GyYYd+dEgtoX0MESvWz4RnGH8Jw==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
cpu: [arm, x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@node-llama-cpp/linux-x64-cuda-ext@3.15.0':
|
||||
resolution: {integrity: sha512-wQwgSl7Qm8vH56oBt7IuWWDNNsDECkVMS000C92wl3PkbzjwZFiWzehwa+kF8Lr2BBMiCJNkI5nEabhYH3RN2Q==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@node-llama-cpp/linux-x64-cuda@3.15.0':
|
||||
resolution: {integrity: sha512-mDjyVulCTRYilm9Emm3lDMx7dbI1vzGqk28Pj28shartjERTUu8aUNDYOmVKNMLpUKS1akw7vy0lMF8t4qswxQ==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@node-llama-cpp/linux-x64-vulkan@3.15.0':
|
||||
resolution: {integrity: sha512-htVIthQKq/rr8v5e7NiVtcHsstqTBAAC50kUymmDMbrzAu6d/EHacCJpNbU57b1UUa1nKN5cBqr6Jr+QqEalMA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@node-llama-cpp/linux-x64@3.15.0':
|
||||
resolution: {integrity: sha512-etUuTqSyNefRObqc5+JZviNTkuef2XEtHcQLaamEIWwjI1dj7nTD2YMZPBP7H3M3E55HSIY82vqCQ1bp6ZILiA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@node-llama-cpp/mac-arm64-metal@3.15.0':
|
||||
resolution: {integrity: sha512-3Vkq6bpyQZaIzoaLLP7H2Tt8ty5BS0zxUY2pX0ox2S9P4fp8Au0CCJuUJF4V+EKi+/PTn70A6R1QCkRMfMQJig==}
|
||||
@ -1557,6 +1589,24 @@ packages:
|
||||
cpu: [arm64, x64]
|
||||
os: [win32]
|
||||
|
||||
'@node-llama-cpp/win-x64-cuda-ext@3.15.0':
|
||||
resolution: {integrity: sha512-KQoNH9KsVtqGVXaRdPrnHPrg5w3KOM7CfynPmG1m16gmjmDSIspdPg/Dbg6DgHBfkdAzt+duRZEBk8Bg8KbDHw==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@node-llama-cpp/win-x64-cuda@3.15.0':
|
||||
resolution: {integrity: sha512-2Kyu1roDwXwFLaJgGZQISIXP9lCDZtJCx/DRcmrYRHcSUFCzo5ikOuAECyliSSQmRUAvvlRCuD+GrTcegbhojA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@node-llama-cpp/win-x64-vulkan@3.15.0':
|
||||
resolution: {integrity: sha512-sH+K7lO49WrUvCCC3RPddCBrn2ZQwKCXKL90P/NZicMRgxTPFZEVSU2jXR/bu1K8B+4lNN+z5OEbjSYs7cKEcA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@node-llama-cpp/win-x64@3.15.0':
|
||||
resolution: {integrity: sha512-gWhtc8l3HOry5guO46YfFohLQnF0NfL4On0GAO8E27JiYYxHO9nHSCfFif4+U03+FfHquZXL0znJ1qPVOiwOPw==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
@ -1867,25 +1917,21 @@ packages:
|
||||
resolution: {integrity: sha512-GubkQeQT5d3B/Jx/IiR7NMkSmXrCZcVI0BPh1i7mpFi8HgD1hQ/LbhiBKAMsMqs5bbugdQOgBEl8bOhe8JhW1g==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxfmt/linux-arm64-musl@0.26.0':
|
||||
resolution: {integrity: sha512-OEypUwK69bFPj+aa3/LYCnlIUPgoOLu//WNcriwpnWNmt47808Ht7RJSg+MNK8a7pSZHpXJ5/E6CRK/OTwFdaQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxfmt/linux-x64-gnu@0.26.0':
|
||||
resolution: {integrity: sha512-xO6iEW2bC6ZHyOTPmPWrg/nM6xgzyRPaS84rATy6F8d79wz69LdRdJ3l/PXlkqhi7XoxhvX4ExysA0Nf10ZZEQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxfmt/linux-x64-musl@0.26.0':
|
||||
resolution: {integrity: sha512-Z3KuZFC+MIuAyFCXBHY71kCsdRq1ulbsbzTe71v+hrEv7zVBn6yzql+/AZcgfIaKzWO9OXNuz5WWLWDmVALwow==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxfmt/win32-arm64@0.26.0':
|
||||
resolution: {integrity: sha512-3zRbqwVWK1mDhRhTknlQFpRFL9GhEB5GfU6U7wawnuEwpvi39q91kJ+SRJvJnhyPCARkjZBd1V8XnweN5IFd1g==}
|
||||
@ -1941,25 +1987,21 @@ packages:
|
||||
resolution: {integrity: sha512-Fow7H84Bs8XxuaK1yfSEWBC8HI7rfEQB9eR2A0J61un1WgCas7jNrt1HbT6+p6KmUH2bhR+r/RDu/6JFAvvj4g==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/linux-arm64-musl@1.41.0':
|
||||
resolution: {integrity: sha512-WoRRDNwgP5W3rjRh42Zdx8ferYnqpKoYCv2QQLenmdrLjRGYwAd52uywfkcS45mKEWHeY1RPwPkYCSROXiGb2w==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxlint/linux-x64-gnu@1.41.0':
|
||||
resolution: {integrity: sha512-75k3CKj3fOc/a/2aSgO81s3HsTZOFROthPJ+UI2Oatic1LhvH6eKjKfx3jDDyVpzeDS2qekPlc/y3N33iZz5Og==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/linux-x64-musl@1.41.0':
|
||||
resolution: {integrity: sha512-8r82eBwGPoAPn67ZvdxTlX/Z3gVb+ZtN6nbkyFzwwHWAh8yGutX+VBcVkyrePSl6XgBP4QAaddPnHmkvJjqY0g==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxlint/win32-arm64@1.41.0':
|
||||
resolution: {integrity: sha512-aK+DAcckQsNCOXKruatyYuY/ROjNiRejQB1PeJtkZwM21+8rV9ODYbvKNvt0pW+YCws7svftBSFMCpl3ke2unw==}
|
||||
@ -2031,28 +2073,24 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@reflink/reflink-linux-arm64-musl@0.1.19':
|
||||
resolution: {integrity: sha512-37iO/Dp6m5DDaC2sf3zPtx/hl9FV3Xze4xoYidrxxS9bgP3S8ALroxRK6xBG/1TtfXKTvolvp+IjrUU6ujIGmA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@reflink/reflink-linux-x64-gnu@0.1.19':
|
||||
resolution: {integrity: sha512-jbI8jvuYCaA3MVUdu8vLoLAFqC+iNMpiSuLbxlAgg7x3K5bsS8nOpTRnkLF7vISJ+rVR8W+7ThXlXlUQ93ulkw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@reflink/reflink-linux-x64-musl@0.1.19':
|
||||
resolution: {integrity: sha512-e9FBWDe+lv7QKAwtKOt6A2W/fyy/aEEfr0g6j/hWzvQcrzHCsz07BNQYlNOjTfeytrtLU7k449H1PI95jA4OjQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@reflink/reflink-win32-arm64-msvc@0.1.19':
|
||||
resolution: {integrity: sha512-09PxnVIQcd+UOn4WAW73WU6PXL7DwGS6wPlkMhMg2zlHHG65F3vHepOw06HFCq+N42qkaNAc8AKIabWvtk6cIQ==}
|
||||
@ -2105,28 +2143,24 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.1':
|
||||
resolution: {integrity: sha512-UvApLEGholmxw/HIwmUnLq3CwdydbhaHHllvWiCTNbyGom7wTwOtz5OAQbAKZYyiEOeIXZNPkM7nA4Dtng7CLw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.1':
|
||||
resolution: {integrity: sha512-uVctNgZHiGnJx5Fij7wHLhgw4uyZBVi6mykeWKOqE7bVy9Hcxn0fM/IuqdMwk6hXlaf9fFShDTFz2+YejP+x0A==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.0-rc.1':
|
||||
resolution: {integrity: sha512-T6Eg0xWwcxd/MzBcuv4Z37YVbUbJxy5cMNnbIt/Yr99wFwli30O4BPlY8hKeGyn6lWNtU0QioBS46lVzDN38bg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.0-rc.1':
|
||||
resolution: {integrity: sha512-PuGZVS2xNJyLADeh2F04b+Cz4NwvpglbtWACgrDOa5YDTEHKwmiTDjoD5eZ9/ptXtcpeFrMqD2H4Zn33KAh1Eg==}
|
||||
@ -2188,79 +2222,66 @@ packages:
|
||||
resolution: {integrity: sha512-YeGUhkN1oA+iSPzzhEjVPS29YbViOr8s4lSsFaZKLHswgqP911xx25fPOyE9+khmN6W4VeM0aevbDp4kkEoHiA==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.55.3':
|
||||
resolution: {integrity: sha512-eo0iOIOvcAlWB3Z3eh8pVM8hZ0oVkK3AjEM9nSrkSug2l15qHzF3TOwT0747omI6+CJJvl7drwZepT+re6Fy/w==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.55.3':
|
||||
resolution: {integrity: sha512-DJay3ep76bKUDImmn//W5SvpjRN5LmK/ntWyeJs/dcnwiiHESd3N4uteK9FDLf0S0W8E6Y0sVRXpOCoQclQqNg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.55.3':
|
||||
resolution: {integrity: sha512-BKKWQkY2WgJ5MC/ayvIJTHjy0JUGb5efaHCUiG/39sSUvAYRBaO3+/EK0AZT1RF3pSj86O24GLLik9mAYu0IJg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.55.3':
|
||||
resolution: {integrity: sha512-Q9nVlWtKAG7ISW80OiZGxTr6rYtyDSkauHUtvkQI6TNOJjFvpj4gcH+KaJihqYInnAzEEUetPQubRwHef4exVg==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.55.3':
|
||||
resolution: {integrity: sha512-2H5LmhzrpC4fFRNwknzmmTvvyJPHwESoJgyReXeFoYYuIDfBhP29TEXOkCJE/KxHi27mj7wDUClNq78ue3QEBQ==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.55.3':
|
||||
resolution: {integrity: sha512-9S542V0ie9LCTznPYlvaeySwBeIEa7rDBgLHKZ5S9DBgcqdJYburabm8TqiqG6mrdTzfV5uttQRHcbKff9lWtA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.55.3':
|
||||
resolution: {integrity: sha512-ukxw+YH3XXpcezLgbJeasgxyTbdpnNAkrIlFGDl7t+pgCxZ89/6n1a+MxlY7CegU+nDgrgdqDelPRNQ/47zs0g==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.55.3':
|
||||
resolution: {integrity: sha512-Iauw9UsTTvlF++FhghFJjqYxyXdggXsOqGpFBylaRopVpcbfyIIsNvkf9oGwfgIcf57z3m8+/oSYTo6HutBFNw==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.55.3':
|
||||
resolution: {integrity: sha512-3OqKAHSEQXKdq9mQ4eajqUgNIK27VZPW3I26EP8miIzuKzCJ3aW3oEn2pzF+4/Hj/Moc0YDsOtBgT5bZ56/vcA==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.55.3':
|
||||
resolution: {integrity: sha512-0CM8dSVzVIaqMcXIFej8zZrSFLnGrAE8qlNbbHfTw1EEPnFTg1U1ekI0JdzjPyzSfUsHWtodilQQG/RA55berA==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.55.3':
|
||||
resolution: {integrity: sha512-+fgJE12FZMIgBaKIAGd45rxf+5ftcycANJRWk8Vz0NnMTM5rADPGuRFTYar+Mqs560xuART7XsX2lSACa1iOmQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.55.3':
|
||||
resolution: {integrity: sha512-tMD7NnbAolWPzQlJQJjVFh/fNH3K/KnA7K8gv2dJWCwwnaK6DFCYST1QXYWfu5V0cDwarWC8Sf/cfMHniNq21A==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.55.3':
|
||||
resolution: {integrity: sha512-u5KsqxOxjEeIbn7bUK1MPM34jrnPwjeqgyin4/N6e/KzXKfpE9Mi0nCxcQjaM9lLmPcHmn/xx1yOjgTMtu1jWQ==}
|
||||
@ -2973,6 +2994,9 @@ packages:
|
||||
aws4@1.13.2:
|
||||
resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==}
|
||||
|
||||
axios@0.27.2:
|
||||
resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
|
||||
|
||||
axios@1.13.2:
|
||||
resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==}
|
||||
|
||||
@ -3116,6 +3140,11 @@ packages:
|
||||
class-variance-authority@0.7.1:
|
||||
resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
|
||||
|
||||
clawdbot@2026.1.24:
|
||||
resolution: {integrity: sha512-foszbNXzk743kQBx2Nfc2KNlStZyBAVAYLQJ+KaONh009r8oB1a74kQ8wTnKX+SDNaQ9MvaE9tOisVUi+H3F+Q==}
|
||||
engines: {node: '>=22.12.0'}
|
||||
hasBin: true
|
||||
|
||||
cli-cursor@5.0.0:
|
||||
resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==}
|
||||
engines: {node: '>=18'}
|
||||
@ -3983,28 +4012,24 @@ packages:
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.2:
|
||||
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.2:
|
||||
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
|
||||
@ -4055,6 +4080,9 @@ packages:
|
||||
lodash.debounce@4.0.8:
|
||||
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
||||
|
||||
lodash.identity@3.0.0:
|
||||
resolution: {integrity: sha512-AupTIzdLQxJS5wIYUQlgGyk2XRTfGXA+MCghDHqZk0pzUNYvd3EESS6dkChNauNYVIutcb0dfHw1ri9Q1yPV8Q==}
|
||||
|
||||
lodash.includes@4.3.0:
|
||||
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
|
||||
|
||||
@ -4073,9 +4101,15 @@ packages:
|
||||
lodash.isstring@4.0.1:
|
||||
resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
|
||||
|
||||
lodash.merge@4.6.2:
|
||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
|
||||
lodash.once@4.1.1:
|
||||
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
|
||||
|
||||
lodash.pickby@4.6.0:
|
||||
resolution: {integrity: sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==}
|
||||
|
||||
lodash@4.17.23:
|
||||
resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==}
|
||||
|
||||
@ -6694,10 +6728,53 @@ snapshots:
|
||||
'@kwsites/promise-deferred@1.1.1':
|
||||
optional: true
|
||||
|
||||
'@lancedb/lancedb-darwin-arm64@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@lancedb/lancedb-linux-arm64-gnu@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@lancedb/lancedb-linux-arm64-musl@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@lancedb/lancedb-linux-x64-gnu@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@lancedb/lancedb-linux-x64-musl@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@lancedb/lancedb-win32-arm64-msvc@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@lancedb/lancedb-win32-x64-msvc@0.23.0':
|
||||
optional: true
|
||||
|
||||
'@lancedb/lancedb@0.23.0(apache-arrow@18.1.0)':
|
||||
dependencies:
|
||||
apache-arrow: 18.1.0
|
||||
reflect-metadata: 0.2.2
|
||||
optionalDependencies:
|
||||
'@lancedb/lancedb-darwin-arm64': 0.23.0
|
||||
'@lancedb/lancedb-linux-arm64-gnu': 0.23.0
|
||||
'@lancedb/lancedb-linux-arm64-musl': 0.23.0
|
||||
'@lancedb/lancedb-linux-x64-gnu': 0.23.0
|
||||
'@lancedb/lancedb-linux-x64-musl': 0.23.0
|
||||
'@lancedb/lancedb-win32-arm64-msvc': 0.23.0
|
||||
'@lancedb/lancedb-win32-x64-msvc': 0.23.0
|
||||
|
||||
'@larksuiteoapi/node-sdk@1.56.1':
|
||||
dependencies:
|
||||
axios: 0.27.2
|
||||
lodash.identity: 3.0.0
|
||||
lodash.merge: 4.6.2
|
||||
lodash.pickby: 4.6.0
|
||||
protobufjs: 7.5.4
|
||||
qs: 6.14.1
|
||||
ws: 8.19.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- debug
|
||||
- utf-8-validate
|
||||
|
||||
'@line/bot-sdk@10.6.0':
|
||||
dependencies:
|
||||
@ -7006,6 +7083,12 @@ snapshots:
|
||||
'@node-llama-cpp/linux-armv7l@3.15.0':
|
||||
optional: true
|
||||
|
||||
'@node-llama-cpp/linux-x64-cuda-ext@3.15.0':
|
||||
optional: true
|
||||
|
||||
'@node-llama-cpp/linux-x64-cuda@3.15.0':
|
||||
optional: true
|
||||
|
||||
'@node-llama-cpp/linux-x64-vulkan@3.15.0':
|
||||
optional: true
|
||||
|
||||
@ -7021,6 +7104,15 @@ snapshots:
|
||||
'@node-llama-cpp/win-arm64@3.15.0':
|
||||
optional: true
|
||||
|
||||
'@node-llama-cpp/win-x64-cuda-ext@3.15.0':
|
||||
optional: true
|
||||
|
||||
'@node-llama-cpp/win-x64-cuda@3.15.0':
|
||||
optional: true
|
||||
|
||||
'@node-llama-cpp/win-x64-vulkan@3.15.0':
|
||||
optional: true
|
||||
|
||||
'@node-llama-cpp/win-x64@3.15.0':
|
||||
optional: true
|
||||
|
||||
@ -8645,6 +8737,13 @@ snapshots:
|
||||
|
||||
aws4@1.13.2: {}
|
||||
|
||||
axios@0.27.2:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.11(debug@4.4.3)
|
||||
form-data: 4.0.5
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
|
||||
axios@1.13.2(debug@4.4.3):
|
||||
dependencies:
|
||||
follow-redirects: 1.15.11(debug@4.4.3)
|
||||
@ -8814,6 +8913,84 @@ snapshots:
|
||||
dependencies:
|
||||
clsx: 2.1.1
|
||||
|
||||
clawdbot@2026.1.24(@types/express@5.0.6)(audio-decode@2.2.3)(devtools-protocol@0.0.1561482)(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@agentclientprotocol/sdk': 0.13.1(zod@4.3.6)
|
||||
'@aws-sdk/client-bedrock': 3.975.0
|
||||
'@buape/carbon': 0.14.0(hono@4.11.4)
|
||||
'@clack/prompts': 0.11.0
|
||||
'@grammyjs/runner': 2.0.3(grammy@1.39.3)
|
||||
'@grammyjs/transformer-throttler': 1.2.1(grammy@1.39.3)
|
||||
'@homebridge/ciao': 1.3.4
|
||||
'@line/bot-sdk': 10.6.0
|
||||
'@lydell/node-pty': 1.2.0-beta.3
|
||||
'@mariozechner/pi-agent-core': 0.49.3(ws@8.19.0)(zod@4.3.6)
|
||||
'@mariozechner/pi-ai': 0.49.3(ws@8.19.0)(zod@4.3.6)
|
||||
'@mariozechner/pi-coding-agent': 0.49.3(ws@8.19.0)(zod@4.3.6)
|
||||
'@mariozechner/pi-tui': 0.49.3
|
||||
'@mozilla/readability': 0.6.0
|
||||
'@sinclair/typebox': 0.34.47
|
||||
'@slack/bolt': 4.6.0(@types/express@5.0.6)
|
||||
'@slack/web-api': 7.13.0
|
||||
'@whiskeysockets/baileys': 7.0.0-rc.9(audio-decode@2.2.3)(sharp@0.34.5)
|
||||
ajv: 8.17.1
|
||||
body-parser: 2.2.2
|
||||
chalk: 5.6.2
|
||||
chokidar: 5.0.0
|
||||
chromium-bidi: 13.0.1(devtools-protocol@0.0.1561482)
|
||||
cli-highlight: 2.1.11
|
||||
commander: 14.0.2
|
||||
croner: 9.1.0
|
||||
detect-libc: 2.1.2
|
||||
discord-api-types: 0.38.37
|
||||
dotenv: 17.2.3
|
||||
express: 5.2.1
|
||||
file-type: 21.3.0
|
||||
grammy: 1.39.3
|
||||
hono: 4.11.4
|
||||
jiti: 2.6.1
|
||||
json5: 2.2.3
|
||||
jszip: 3.10.1
|
||||
linkedom: 0.18.12
|
||||
long: 5.3.2
|
||||
markdown-it: 14.1.0
|
||||
node-edge-tts: 1.2.9
|
||||
osc-progress: 0.3.0
|
||||
pdfjs-dist: 5.4.530
|
||||
playwright-core: 1.58.0
|
||||
proper-lockfile: 4.1.2
|
||||
qrcode-terminal: 0.12.0
|
||||
sharp: 0.34.5
|
||||
sqlite-vec: 0.1.7-alpha.2
|
||||
tar: 7.5.4
|
||||
tslog: 4.10.2
|
||||
undici: 7.19.0
|
||||
ws: 8.19.0
|
||||
yaml: 2.8.2
|
||||
zod: 4.3.6
|
||||
optionalDependencies:
|
||||
'@napi-rs/canvas': 0.1.88
|
||||
node-llama-cpp: 3.15.0(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
- '@discordjs/opus'
|
||||
- '@modelcontextprotocol/sdk'
|
||||
- '@types/express'
|
||||
- audio-decode
|
||||
- aws-crt
|
||||
- bufferutil
|
||||
- canvas
|
||||
- debug
|
||||
- devtools-protocol
|
||||
- encoding
|
||||
- ffmpeg-static
|
||||
- jimp
|
||||
- link-preview-js
|
||||
- node-opus
|
||||
- opusscript
|
||||
- supports-color
|
||||
- typescript
|
||||
- utf-8-validate
|
||||
|
||||
cli-cursor@5.0.0:
|
||||
dependencies:
|
||||
restore-cursor: 5.1.0
|
||||
@ -9865,6 +10042,8 @@ snapshots:
|
||||
lodash.debounce@4.0.8:
|
||||
optional: true
|
||||
|
||||
lodash.identity@3.0.0: {}
|
||||
|
||||
lodash.includes@4.3.0: {}
|
||||
|
||||
lodash.isboolean@3.0.3: {}
|
||||
@ -9877,8 +10056,12 @@ snapshots:
|
||||
|
||||
lodash.isstring@4.0.1: {}
|
||||
|
||||
lodash.merge@4.6.2: {}
|
||||
|
||||
lodash.once@4.1.1: {}
|
||||
|
||||
lodash.pickby@4.6.0: {}
|
||||
|
||||
lodash@4.17.23: {}
|
||||
|
||||
log-symbols@6.0.0:
|
||||
@ -10163,11 +10346,16 @@ snapshots:
|
||||
'@node-llama-cpp/linux-arm64': 3.15.0
|
||||
'@node-llama-cpp/linux-armv7l': 3.15.0
|
||||
'@node-llama-cpp/linux-x64': 3.15.0
|
||||
'@node-llama-cpp/linux-x64-cuda': 3.15.0
|
||||
'@node-llama-cpp/linux-x64-cuda-ext': 3.15.0
|
||||
'@node-llama-cpp/linux-x64-vulkan': 3.15.0
|
||||
'@node-llama-cpp/mac-arm64-metal': 3.15.0
|
||||
'@node-llama-cpp/mac-x64': 3.15.0
|
||||
'@node-llama-cpp/win-arm64': 3.15.0
|
||||
'@node-llama-cpp/win-x64': 3.15.0
|
||||
'@node-llama-cpp/win-x64-cuda': 3.15.0
|
||||
'@node-llama-cpp/win-x64-cuda-ext': 3.15.0
|
||||
'@node-llama-cpp/win-x64-vulkan': 3.15.0
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
Loading…
Reference in New Issue
Block a user