diff --git a/apps/leaf/package.json b/apps/leaf/package.json index 060ccf12c..adcb8cced 100644 --- a/apps/leaf/package.json +++ b/apps/leaf/package.json @@ -23,6 +23,7 @@ "chat": "^4.29.0", "date-fns": "^4.1.0", "drizzle-orm": "catalog:", + "e2b": "^2.8.4", "hono": "4.12.7", "postgres": "catalog:", "zod": "^3.25.23" diff --git a/apps/leaf/src/agent/agent.ts b/apps/leaf/src/agent/agent.ts index 68a969e04..e354a5f43 100644 --- a/apps/leaf/src/agent/agent.ts +++ b/apps/leaf/src/agent/agent.ts @@ -5,9 +5,12 @@ import type { MessageListInput } from "@mastra/core/agent/message-list"; import { z } from "zod"; import { env as chatEnv } from "../lib/env.js"; import { logger as rootLogger } from "../lib/logger.js"; +import { createE2bSandboxProvider } from "../providers/e2b/e2bSandboxProvider.js"; import type { ChatContextMessage } from "../types.js"; import { createFirecrawlTools } from "./firecrawl.js"; import { createAutumnMcpClient, getAutumnMcpTools } from "./mcp.js"; +import { sandboxConfig } from "./sandbox/config.js"; +import { createSandboxTools } from "./sandbox/createSandboxTools.js"; export const agentDocUris = [ "autumn://docs/tool-composition", @@ -31,6 +34,7 @@ Use web search only for current or external web context. Never use web search fo When web content influences the answer, cite the source URLs. Prefer searchWeb first, then scrapeUrl only for the most relevant result. Use listFeatures only when creating/customizing plan items or setting non-zero prepaid feature quantities and feature ids/types are not already known; never invent feature ids. +Use the sandbox only for short parsing, calculation, transformation, and file-analysis tasks. Never send secrets to the sandbox, never use it for Autumn writes, and treat sandbox output as advisory. Preview billing-impacting changes first, summarize the preview in short Slack-friendly bullets, then call the matching write tool with the same request args. When Autumn responses include epoch millisecond timestamps, use epochMillisecondsToDate before explaining those timestamps to a user. Treat Slack PDFs and images attached to the latest message as part of the user's request. If an attachment was skipped or unavailable, say so briefly instead of pretending to have read it. @@ -112,20 +116,24 @@ export const runChatAgent = async ({ env, logger = rootLogger, message, + channelId, threadId, resourceId, onAction, provider, + workspaceId, recentMessages, }: { token: string; env: AppEnv; logger?: AutumnLogger; message: MessageListInput; + channelId: string; onAction?: (message: string) => Promise | void; threadId: string; resourceId: string; provider: string; + workspaceId: string; recentMessages?: ChatContextMessage[]; }) => { const mcp = createAutumnMcpClient({ @@ -171,13 +179,37 @@ export const runChatAgent = async ({ apiKey: chatEnv.FIRECRAWL_API_KEY, onAction, }); + const sandboxTools = + sandboxConfig.enabled && chatEnv.E2B_API_KEY + ? createSandboxTools({ + logger, + onAction, + provider: createE2bSandboxProvider({ + apiKey: chatEnv.E2B_API_KEY, + context: { + channelId, + env, + orgId: resourceId, + provider, + threadId, + workspaceId, + }, + sessionTimeoutMs: sandboxConfig.sessionTimeoutMs, + }), + }) + : {}; + if (sandboxConfig.enabled && !chatEnv.E2B_API_KEY) { + logger.warn("Sandbox is enabled without an E2B API key", { + event: "leaf.sandbox_disabled", + }); + } await onAction?.("Reasoning over the request"); const agent = new Agent({ id: "autumn-chat", name: "Autumn Chat", instructions: `${instructions}\n\nCurrent Autumn environment: ${env}.\n\n${docsText}`, model: chatEnv.CHAT_MODEL, - tools: { ...tools, ...firecrawlTools }, + tools: { ...tools, ...firecrawlTools, ...sandboxTools }, }); const output = await agent.generate(message, { diff --git a/apps/leaf/src/agent/messages.ts b/apps/leaf/src/agent/messages.ts index 3d24127d5..cafe96f03 100644 --- a/apps/leaf/src/agent/messages.ts +++ b/apps/leaf/src/agent/messages.ts @@ -21,6 +21,7 @@ export const runMessage = async ({ onAction, recentMessages, text, + channelId, threadId, }: BotMessage) => withTimeout( @@ -55,9 +56,11 @@ export const runMessage = async ({ logger, message: preparedMessage.message, onAction, + channelId, threadId, resourceId: installation.org_id, provider: installation.provider, + workspaceId: installation.workspace_id, recentMessages, }), ); diff --git a/apps/leaf/src/agent/sandbox/config.ts b/apps/leaf/src/agent/sandbox/config.ts new file mode 100644 index 000000000..eef58b7f5 --- /dev/null +++ b/apps/leaf/src/agent/sandbox/config.ts @@ -0,0 +1,4 @@ +export const sandboxConfig = { + enabled: true, + sessionTimeoutMs: 10 * 60 * 1000, +}; diff --git a/apps/leaf/src/agent/sandbox/createSandboxTools.ts b/apps/leaf/src/agent/sandbox/createSandboxTools.ts new file mode 100644 index 000000000..50e41c2e5 --- /dev/null +++ b/apps/leaf/src/agent/sandbox/createSandboxTools.ts @@ -0,0 +1,83 @@ +import type { AutumnLogger } from "@autumn/logging"; +import { createTool } from "@mastra/core/tools"; +import { z } from "zod"; +import { logger as rootLogger } from "../../lib/logger.js"; +import { + assertSafeSandboxCommand, + sandboxLimits, + sanitizeReturnFiles, + sanitizeSandboxFiles, + truncateSandboxResult, +} from "./guardrails.js"; +import type { SandboxProvider } from "./types.js"; + +const sandboxFileSchema = z + .object({ + path: z.string().min(1), + content: z.string(), + }) + .strict(); + +export const createSandboxTools = ({ + logger = rootLogger, + onAction, + provider, +}: { + logger?: AutumnLogger; + onAction?: (message: string) => Promise | void; + provider: SandboxProvider; +}): Record> => ({ + runSandboxCommand: createTool({ + id: "runSandboxCommand", + description: + "Run a short command in an isolated sandbox for parsing, calculations, JSON/CSV transforms, and file analysis. Do not use it for Autumn writes, credentials, secrets, or direct API calls.", + inputSchema: z + .object({ + task: z.string().min(1), + command: z.string().min(1), + files: z + .array(sandboxFileSchema) + .max(sandboxLimits.maxFiles) + .optional(), + returnFiles: z + .array(z.string().min(1)) + .max(sandboxLimits.maxFiles) + .optional(), + }) + .strict(), + execute: async ({ task, command, files = [], returnFiles = [] }) => { + await onAction?.("Running sandbox analysis"); + const startedAt = Date.now(); + const safeCommand = assertSafeSandboxCommand(command); + const safeFiles = sanitizeSandboxFiles(files); + const safeReturnFiles = sanitizeReturnFiles(returnFiles); + logger.info("Calling sandbox tool", { + event: "leaf.sandbox_tool_called", + data: { + file_count: safeFiles.length, + return_file_count: safeReturnFiles.length, + command_length: safeCommand.length, + task_length: task.length, + }, + }); + const result = truncateSandboxResult( + await provider.run({ + command: safeCommand, + files: safeFiles, + returnFiles: safeReturnFiles, + timeoutMs: sandboxLimits.timeoutMs, + }), + ); + logger.info("Completed sandbox tool", { + event: "leaf.sandbox_tool_completed", + data: { + duration_ms: Date.now() - startedAt, + file_count: result.files.length, + exit_code: result.exitCode, + timed_out: result.timedOut, + }, + }); + return result; + }, + }), +}); diff --git a/apps/leaf/src/agent/sandbox/guardrails.ts b/apps/leaf/src/agent/sandbox/guardrails.ts new file mode 100644 index 000000000..0bca6deb3 --- /dev/null +++ b/apps/leaf/src/agent/sandbox/guardrails.ts @@ -0,0 +1,106 @@ +import path from "node:path"; +import type { SandboxFile, SandboxRunResult } from "./types.js"; + +export const sandboxLimits = { + maxFiles: 5, + maxInputBytes: 256 * 1024, + maxOutputBytes: 24 * 1024, + maxReturnedFileBytes: 24 * 1024, + timeoutMs: 20_000, + workDir: "/work", +}; + +const secretPatterns = [ + /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}/i, + /\bxox[baprs]-[A-Za-z0-9-]{10,}/i, + /\bsk_(?:live|test|proj)?_[A-Za-z0-9]{12,}/i, + /\beyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{10,}\b/, + /^\s*[A-Z0-9_]*(?:SECRET|TOKEN|API_KEY|PASSWORD)[A-Z0-9_]*\s*=\s*\S+/im, +]; + +const byteLength = (value: string) => Buffer.byteLength(value, "utf8"); + +const assertNoSecrets = (value: string) => { + if (secretPatterns.some((pattern) => pattern.test(value))) { + throw new Error("Sandbox input appears to contain a secret or token"); + } +}; + +const normalizePath = (filePath: string) => { + const normalized = path.posix.normalize( + filePath.startsWith("/") + ? filePath + : path.posix.join(sandboxLimits.workDir, filePath), + ); + if ( + normalized !== sandboxLimits.workDir && + !normalized.startsWith(`${sandboxLimits.workDir}/`) + ) { + throw new Error("Sandbox files must stay under /work"); + } + if (path.posix.basename(normalized).toLowerCase() === ".env") { + throw new Error("Sandbox files cannot be named .env"); + } + return normalized; +}; + +export const sanitizeSandboxFiles = (files: SandboxFile[] = []) => { + if (files.length > sandboxLimits.maxFiles) { + throw new Error( + `Sandbox input cannot exceed ${sandboxLimits.maxFiles} files`, + ); + } + + let bytes = 0; + const sanitized = files.map((file) => { + assertNoSecrets(file.path); + assertNoSecrets(file.content); + bytes += byteLength(file.content); + if (bytes > sandboxLimits.maxInputBytes) { + throw new Error("Sandbox input is too large"); + } + return { + path: normalizePath(file.path), + content: file.content, + }; + }); + + const seen = new Set(); + for (const file of sanitized) { + if (seen.has(file.path)) + throw new Error(`Duplicate sandbox file: ${file.path}`); + seen.add(file.path); + } + return sanitized; +}; + +export const sanitizeReturnFiles = (returnFiles: string[] = []) => + returnFiles.map(normalizePath); + +export const assertSafeSandboxCommand = (command: string) => { + if (!command.trim()) throw new Error("Sandbox command cannot be empty"); + assertNoSecrets(command); + return command.trim(); +}; + +export const truncateText = (value: string, maxBytes: number) => { + if (byteLength(value) <= maxBytes) return value; + let output = ""; + for (const char of value) { + if (byteLength(`${output}${char}`) > maxBytes) break; + output += char; + } + return `${output}\n[truncated]`; +}; + +export const truncateSandboxResult = ( + result: SandboxRunResult, +): SandboxRunResult => ({ + ...result, + stdout: truncateText(result.stdout, sandboxLimits.maxOutputBytes), + stderr: truncateText(result.stderr, sandboxLimits.maxOutputBytes), + files: result.files.map((file) => ({ + path: file.path, + content: truncateText(file.content, sandboxLimits.maxReturnedFileBytes), + })), +}); diff --git a/apps/leaf/src/agent/sandbox/types.ts b/apps/leaf/src/agent/sandbox/types.ts new file mode 100644 index 000000000..ea85e61c9 --- /dev/null +++ b/apps/leaf/src/agent/sandbox/types.ts @@ -0,0 +1,32 @@ +export type SandboxFile = { + path: string; + content: string; +}; + +export type SandboxRunArgs = { + command: string; + files: SandboxFile[]; + returnFiles: string[]; + timeoutMs: number; +}; + +export type SandboxRunResult = { + stdout: string; + stderr: string; + exitCode?: number; + timedOut: boolean; + files: SandboxFile[]; +}; + +export type SandboxSessionContext = { + channelId: string; + env: string; + orgId: string; + provider: string; + threadId: string; + workspaceId: string; +}; + +export type SandboxProvider = { + run(args: SandboxRunArgs): Promise; +}; diff --git a/apps/leaf/src/bot.ts b/apps/leaf/src/bot.ts index b3650bd50..90b71c7a8 100644 --- a/apps/leaf/src/bot.ts +++ b/apps/leaf/src/bot.ts @@ -149,6 +149,7 @@ const runAndReply = async ({ onAction: logAction, recentMessages, text, + channelId, threadId, }); diff --git a/apps/leaf/src/lib/env.ts b/apps/leaf/src/lib/env.ts index 6db1e9696..3de4c1257 100644 --- a/apps/leaf/src/lib/env.ts +++ b/apps/leaf/src/lib/env.ts @@ -16,6 +16,7 @@ const envSchema = z CHAT_STATE_SECRET: optionalString, CLIENT_URL: z.string().min(1).default("http://localhost:3000"), DATABASE_URL: z.string().min(1), + E2B_API_KEY: optionalString, ENCRYPTION_PASSWORD: z.string().min(1), FIRECRAWL_API_KEY: z.string().min(1), MCP_OAUTH_ENVIRONMENT: z.enum(["live", "sandbox"]).default("sandbox"), diff --git a/apps/leaf/src/providers/e2b/e2bSandboxFiles.ts b/apps/leaf/src/providers/e2b/e2bSandboxFiles.ts new file mode 100644 index 000000000..343d9465f --- /dev/null +++ b/apps/leaf/src/providers/e2b/e2bSandboxFiles.ts @@ -0,0 +1,46 @@ +import type { SandboxFile } from "../../agent/sandbox/types.js"; +import type { E2bSandbox } from "./e2bSandboxLifecycle.js"; + +export const e2bWorkDir = "/work"; + +export const ensureE2bWorkDir = async ({ + sandbox, +}: { + sandbox: E2bSandbox; +}) => { + try { + await sandbox.files.makeDir(e2bWorkDir); + } catch (error) { + if (!(error instanceof Error) || !/exist/i.test(error.message)) throw error; + } +}; + +export const writeE2bSandboxFiles = async ({ + files, + sandbox, +}: { + files: SandboxFile[]; + sandbox: E2bSandbox; +}) => { + for (const file of files) { + await sandbox.files.write(file.path, file.content); + } +}; + +export const readRequestedE2bFiles = async ({ + returnFiles, + sandbox, +}: { + returnFiles: string[]; + sandbox: E2bSandbox; +}): Promise => { + const files: SandboxFile[] = []; + for (const filePath of returnFiles) { + if (!(await sandbox.files.exists(filePath))) continue; + files.push({ + path: filePath, + content: await sandbox.files.read(filePath), + }); + } + return files; +}; diff --git a/apps/leaf/src/providers/e2b/e2bSandboxLifecycle.ts b/apps/leaf/src/providers/e2b/e2bSandboxLifecycle.ts new file mode 100644 index 000000000..f6b61316a --- /dev/null +++ b/apps/leaf/src/providers/e2b/e2bSandboxLifecycle.ts @@ -0,0 +1,78 @@ +import { Sandbox } from "e2b"; +import type { SandboxSessionContext } from "../../agent/sandbox/types.js"; +import { + e2bSandboxLookupMetadata, + e2bSandboxMetadata, +} from "./e2bSandboxMetadata.js"; + +export type E2bSandbox = Awaited>; + +export const findE2bSandbox = async ({ + apiKey, + context, +}: { + apiKey: string; + context: SandboxSessionContext; +}) => { + const paginator = Sandbox.list({ + apiKey, + query: { + metadata: e2bSandboxLookupMetadata({ context }), + state: ["running", "paused"], + }, + }); + const matches = await paginator.nextItems(); + return matches[0]; +}; + +export const createE2bSandbox = ({ + apiKey, + context, + timeoutMs, +}: { + apiKey: string; + context: SandboxSessionContext; + timeoutMs: number; +}) => + Sandbox.create({ + allowInternetAccess: false, + apiKey, + metadata: e2bSandboxMetadata({ context }), + network: { allowPublicTraffic: false }, + timeoutMs, + }); + +export const connectE2bSandbox = ({ + apiKey, + sandboxId, + timeoutMs, +}: { + apiKey: string; + sandboxId: string; + timeoutMs: number; +}) => + Sandbox.connect(sandboxId, { + apiKey, + timeoutMs, + }); + +export const findOrCreateE2bSandbox = async ({ + apiKey, + context, + timeoutMs, +}: { + apiKey: string; + context: SandboxSessionContext; + timeoutMs: number; +}) => { + const existing = await findE2bSandbox({ apiKey, context }); + if (existing) { + return connectE2bSandbox({ + apiKey, + sandboxId: existing.sandboxId, + timeoutMs, + }); + } + + return createE2bSandbox({ apiKey, context, timeoutMs }); +}; diff --git a/apps/leaf/src/providers/e2b/e2bSandboxMetadata.ts b/apps/leaf/src/providers/e2b/e2bSandboxMetadata.ts new file mode 100644 index 000000000..fe594cf9f --- /dev/null +++ b/apps/leaf/src/providers/e2b/e2bSandboxMetadata.ts @@ -0,0 +1,40 @@ +import type { SandboxSessionContext } from "../../agent/sandbox/types.js"; + +const metadataApp = "leaf"; + +export const e2bThreadKey = ({ context }: { context: SandboxSessionContext }) => + [ + context.orgId, + context.env, + context.provider, + context.workspaceId, + context.channelId, + context.threadId, + ].join(":"); + +export const e2bSandboxMetadata = ({ + context, +}: { + context: SandboxSessionContext; +}) => ({ + app: metadataApp, + channelId: context.channelId, + env: context.env, + orgId: context.orgId, + provider: context.provider, + threadId: context.threadId, + threadKey: e2bThreadKey({ context }), + workspaceId: context.workspaceId, +}); + +export const e2bSandboxLookupMetadata = ({ + context, +}: { + context: SandboxSessionContext; +}) => { + const metadata = e2bSandboxMetadata({ context }); + return { + app: metadata.app, + threadKey: metadata.threadKey, + }; +}; diff --git a/apps/leaf/src/providers/e2b/e2bSandboxProvider.ts b/apps/leaf/src/providers/e2b/e2bSandboxProvider.ts new file mode 100644 index 000000000..68bd75388 --- /dev/null +++ b/apps/leaf/src/providers/e2b/e2bSandboxProvider.ts @@ -0,0 +1,55 @@ +import type { + SandboxProvider, + SandboxRunResult, + SandboxSessionContext, +} from "../../agent/sandbox/types.js"; +import { + e2bWorkDir, + ensureE2bWorkDir, + readRequestedE2bFiles, + writeE2bSandboxFiles, +} from "./e2bSandboxFiles.js"; +import { findOrCreateE2bSandbox } from "./e2bSandboxLifecycle.js"; + +export const createE2bSandboxProvider = ({ + apiKey, + context, + sessionTimeoutMs, +}: { + apiKey: string; + context: SandboxSessionContext; + sessionTimeoutMs: number; +}): SandboxProvider => ({ + run: async ({ command, files, returnFiles, timeoutMs }) => { + const sandbox = await findOrCreateE2bSandbox({ + apiKey, + context, + timeoutMs: sessionTimeoutMs, + }); + try { + await ensureE2bWorkDir({ sandbox }); + await writeE2bSandboxFiles({ files, sandbox }); + const result = await sandbox.commands.run(command, { + cwd: e2bWorkDir, + timeoutMs, + }); + return { + stdout: result.stdout ?? "", + stderr: result.stderr ?? "", + exitCode: result.exitCode, + timedOut: false, + files: await readRequestedE2bFiles({ returnFiles, sandbox }), + } satisfies SandboxRunResult; + } catch (error) { + const timedOut = + error instanceof Error && /timeout|timed out/i.test(error.message); + if (!timedOut) throw error; + return { + stdout: "", + stderr: "Sandbox command timed out", + timedOut: true, + files: await readRequestedE2bFiles({ returnFiles, sandbox }), + }; + } + }, +}); diff --git a/apps/leaf/src/types.ts b/apps/leaf/src/types.ts index 360b0bd35..e96b2eef6 100644 --- a/apps/leaf/src/types.ts +++ b/apps/leaf/src/types.ts @@ -72,6 +72,7 @@ export type BotMessage = { onAction?: (message: string) => Promise | void; recentMessages?: ChatContextMessage[]; text: string; + channelId: string; threadId: string; }; diff --git a/apps/leaf/tests/unit/agent/sandbox/createSandboxTools.test.ts b/apps/leaf/tests/unit/agent/sandbox/createSandboxTools.test.ts new file mode 100644 index 000000000..e9285b587 --- /dev/null +++ b/apps/leaf/tests/unit/agent/sandbox/createSandboxTools.test.ts @@ -0,0 +1,88 @@ +import { describe, expect, test } from "bun:test"; +import { createSandboxTools } from "../../../../src/agent/sandbox/createSandboxTools.js"; +import type { SandboxProvider } from "../../../../src/agent/sandbox/types.js"; + +const execute = async ( + tool: { execute?: (...args: never[]) => Promise } | undefined, + input: unknown, +) => { + if (!tool?.execute) throw new Error("Tool is not executable"); + return tool.execute(input as never, {} as never); +}; + +describe("sandbox tools", () => { + test("calls provider with sanitized files and return paths", async () => { + const provider: SandboxProvider = { + run: async (args) => { + expect(args.command).toBe("python analyze.py"); + expect(args.files).toEqual([ + { path: "/work/input.json", content: '{"ok":true}' }, + ]); + expect(args.returnFiles).toEqual(["/work/result.json"]); + expect(args.timeoutMs).toBe(20_000); + return { + stdout: "done", + stderr: "", + exitCode: 0, + timedOut: false, + files: [{ path: "/work/result.json", content: '{"done":true}' }], + }; + }, + }; + const tools = createSandboxTools({ provider }); + + await expect( + execute(tools.runSandboxCommand, { + task: "analyze json", + command: "python analyze.py", + files: [{ path: "input.json", content: '{"ok":true}' }], + returnFiles: ["result.json"], + }), + ).resolves.toEqual({ + stdout: "done", + stderr: "", + exitCode: 0, + timedOut: false, + files: [{ path: "/work/result.json", content: '{"done":true}' }], + }); + }); + + test("rejects unsafe input before calling provider", async () => { + let called = false; + const provider: SandboxProvider = { + run: async () => { + called = true; + throw new Error("should not run"); + }, + }; + const tools = createSandboxTools({ provider }); + + await expect( + execute(tools.runSandboxCommand, { + task: "leak", + command: "echo ok", + files: [{ path: ".env", content: "API_KEY=secret" }], + }), + ).rejects.toThrow(); + expect(called).toBe(false); + }); + + test("truncates provider output", async () => { + const provider: SandboxProvider = { + run: async () => ({ + stdout: "a".repeat(25 * 1024), + stderr: "", + timedOut: false, + files: [{ path: "/work/out.txt", content: "b".repeat(25 * 1024) }], + }), + }; + const tools = createSandboxTools({ provider }); + const result = (await execute(tools.runSandboxCommand, { + task: "large", + command: "cat out.txt", + })) as { stdout: string; files: Array<{ content: string }> }; + + expect(result.stdout).toEndWith("[truncated]"); + expect(result.files[0]?.content).toEndWith("[truncated]"); + }); +}); diff --git a/apps/leaf/tests/unit/agent/sandbox/guardrails.test.ts b/apps/leaf/tests/unit/agent/sandbox/guardrails.test.ts new file mode 100644 index 000000000..372d3fbf0 --- /dev/null +++ b/apps/leaf/tests/unit/agent/sandbox/guardrails.test.ts @@ -0,0 +1,63 @@ +import { describe, expect, test } from "bun:test"; +import { + assertSafeSandboxCommand, + sanitizeReturnFiles, + sanitizeSandboxFiles, + truncateText, +} from "../../../../src/agent/sandbox/guardrails.js"; + +describe("sandbox guardrails", () => { + test("normalizes relative file paths under /work", () => { + expect( + sanitizeSandboxFiles([{ path: "input.json", content: "{}" }]), + ).toEqual([{ path: "/work/input.json", content: "{}" }]); + expect(sanitizeReturnFiles(["result.json"])).toEqual(["/work/result.json"]); + }); + + test("rejects files outside /work", () => { + expect(() => + sanitizeSandboxFiles([{ path: "../secrets.txt", content: "x" }]), + ).toThrow("Sandbox files must stay under /work"); + expect(() => sanitizeReturnFiles(["/etc/passwd"])).toThrow( + "Sandbox files must stay under /work", + ); + }); + + test("rejects .env files", () => { + expect(() => + sanitizeSandboxFiles([{ path: ".env", content: "FOO=bar" }]), + ).toThrow("Sandbox files cannot be named .env"); + }); + + test("rejects token-like input", () => { + expect(() => + sanitizeSandboxFiles([ + { path: "input.txt", content: "SLACK_BOT_TOKEN=xoxb-1234567890" }, + ]), + ).toThrow("Sandbox input appears to contain a secret or token"); + expect(() => + assertSafeSandboxCommand("echo Bearer abcdefghijklmnopqrstuvwxyz"), + ).toThrow("Sandbox input appears to contain a secret or token"); + }); + + test("enforces file count and total bytes", () => { + expect(() => + sanitizeSandboxFiles( + Array.from({ length: 6 }, (_, index) => ({ + path: `file-${index}.txt`, + content: "x", + })), + ), + ).toThrow("Sandbox input cannot exceed 5 files"); + expect(() => + sanitizeSandboxFiles([ + { path: "large.txt", content: "x".repeat(257 * 1024) }, + ]), + ).toThrow("Sandbox input is too large"); + }); + + test("truncates text by bytes", () => { + const result = truncateText("a".repeat(10), 5); + expect(result).toBe("aaaaa\n[truncated]"); + }); +}); diff --git a/apps/leaf/tests/unit/providers/e2b/e2bSandboxMetadata.test.ts b/apps/leaf/tests/unit/providers/e2b/e2bSandboxMetadata.test.ts new file mode 100644 index 000000000..60226f524 --- /dev/null +++ b/apps/leaf/tests/unit/providers/e2b/e2bSandboxMetadata.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, test } from "bun:test"; +import { + e2bSandboxLookupMetadata, + e2bSandboxMetadata, + e2bThreadKey, +} from "../../../../src/providers/e2b/e2bSandboxMetadata.js"; + +const context = { + channelId: "C123", + env: "live", + orgId: "org_123", + provider: "slack", + threadId: "1710000000.000", + workspaceId: "T123", +}; + +describe("E2B sandbox metadata", () => { + test("builds stable thread keys", () => { + expect(e2bThreadKey({ context })).toBe( + "org_123:live:slack:T123:C123:1710000000.000", + ); + }); + + test("builds full metadata and lookup metadata", () => { + expect(e2bSandboxMetadata({ context })).toEqual({ + app: "leaf", + channelId: "C123", + env: "live", + orgId: "org_123", + provider: "slack", + threadId: "1710000000.000", + threadKey: "org_123:live:slack:T123:C123:1710000000.000", + workspaceId: "T123", + }); + expect(e2bSandboxLookupMetadata({ context })).toEqual({ + app: "leaf", + threadKey: "org_123:live:slack:T123:C123:1710000000.000", + }); + }); +}); diff --git a/bun.lock b/bun.lock index 6c9c7419a..2a139b889 100644 --- a/bun.lock +++ b/bun.lock @@ -101,6 +101,7 @@ "chat": "^4.29.0", "date-fns": "^4.1.0", "drizzle-orm": "catalog:", + "e2b": "^2.8.4", "hono": "4.12.7", "postgres": "catalog:", "zod": "^3.25.23", @@ -1085,6 +1086,10 @@ "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], + "@connectrpc/connect": ["@connectrpc/connect@2.0.0-rc.3", "", { "peerDependencies": { "@bufbuild/protobuf": "^2.2.0" } }, "sha512-ARBt64yEyKbanyRETTjcjJuHr2YXorzQo0etyS5+P6oSeW8xEuzajA9g+zDnMcj1hlX2dQE93foIWQGfpru7gQ=="], + + "@connectrpc/connect-web": ["@connectrpc/connect-web@2.0.0-rc.3", "", { "peerDependencies": { "@bufbuild/protobuf": "^2.2.0", "@connectrpc/connect": "2.0.0-rc.3" } }, "sha512-w88P8Lsn5CCsA7MFRl2e6oLY4J/5toiNtJns/YJrlyQaWOy3RO8pDgkz+iIkG98RPMhj2thuBvsd3Cn4DKKCkw=="], + "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], "@datadog/datadog-api-client": ["@datadog/datadog-api-client@1.58.0", "", { "dependencies": { "@types/buffer-from": "^1.1.0", "@types/node": "*", "@types/pako": "^1.0.3", "buffer-from": "^1.1.2", "cross-fetch": "^3.1.5", "form-data": "^4.0.4", "loglevel": "^1.8.1", "pako": "^2.0.4" } }, "sha512-aDCMu+qEXjr8PHkT8XvY7FTzVNi2z7yVJy39I4s0lVtb+sdth4ZppMC1aCDwGJQMHK4J0aect+xKScuHy/Xilg=="], @@ -1347,7 +1352,7 @@ "@ioredis/commands": ["@ioredis/commands@1.5.1", "", {}, "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw=="], - "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + "@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="], "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], @@ -3155,6 +3160,8 @@ "common-path-prefix": ["common-path-prefix@3.0.0", "", {}, "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w=="], + "compare-versions": ["compare-versions@6.1.1", "", {}, "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg=="], + "component-emitter": ["component-emitter@1.3.1", "", {}, "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], @@ -3425,6 +3432,8 @@ "dns-socket": ["dns-socket@4.2.2", "", { "dependencies": { "dns-packet": "^5.2.4" } }, "sha512-BDeBd8najI4/lS00HSKpdFia+OvUMytaVjfzR9n5Lq8MlZRSvtbI+uLtx1+XmQFls5wFU9dssccTmQQ6nfpjdg=="], + "dockerfile-ast": ["dockerfile-ast@0.7.1", "", { "dependencies": { "vscode-languageserver-textdocument": "^1.0.8", "vscode-languageserver-types": "^3.17.3" } }, "sha512-oX/A4I0EhSkGqrFv0YuvPkBUSYp1XiY8O8zAKc8Djglx8ocz+JfOr8gP0ryRMC2myqvDLagmnZaU9ot1vG2ijw=="], + "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], "dogapi": ["dogapi@2.8.4", "", { "dependencies": { "extend": "^3.0.2", "json-bigint": "^1.0.0", "lodash": "^4.17.21", "minimist": "^1.2.5", "rc": "^1.2.8" }, "bin": { "dogapi": "bin/dogapi" } }, "sha512-065fsvu5dB0o4+ENtLjZILvXMClDNH/yA9H6L8nsdcNiz9l0Hzpn7aQaCOPYXxqyzq4CRPOdwkFXUjDOXfRGbg=="], @@ -3451,6 +3460,8 @@ "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + "e2b": ["e2b@2.27.1", "", { "dependencies": { "@bufbuild/protobuf": "^2.6.2", "@connectrpc/connect": "2.0.0-rc.3", "@connectrpc/connect-web": "2.0.0-rc.3", "chalk": "^5.3.0", "compare-versions": "^6.1.0", "dockerfile-ast": "^0.7.1", "glob": "^11.1.0", "openapi-fetch": "^0.14.1", "platform": "^1.3.6", "tar": "^7.5.11", "undici": "^7.25.0" } }, "sha512-xZ1vXSl4dpWxbvan5vihE2embXzHdlpK1N0CmFUIcj5kdGLpiQXGoQYsz1Dhy8wr9VO724DyRC7Y3iblMElLPQ=="], + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], @@ -3843,7 +3854,7 @@ "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], - "glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + "glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="], "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], @@ -4221,7 +4232,7 @@ "iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "get-proto": "^1.0.0", "has-symbols": "^1.1.0", "set-function-name": "^2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="], - "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + "jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "^9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="], "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], @@ -4793,8 +4804,12 @@ "openai": ["openai@4.104.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" }, "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA=="], + "openapi-fetch": ["openapi-fetch@0.14.1", "", { "dependencies": { "openapi-typescript-helpers": "^0.0.15" } }, "sha512-l7RarRHxlEZYjMLd/PR0slfMVse2/vvIAGm75/F7J6MlQ8/b9uUQmUF2kCPrQhJqMXSxmYWObVgeYXbFYzZR+A=="], + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], + "openapi-typescript-helpers": ["openapi-typescript-helpers@0.0.15", "", {}, "sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw=="], + "openid-client": ["openid-client@6.8.2", "", { "dependencies": { "jose": "^6.1.3", "oauth4webapi": "^3.8.4" } }, "sha512-uOvTCndr4udZsKihJ68H9bUICrriHdUVJ6Az+4Ns6cW55rwM5h0bjVIzDz2SxgOI84LKjFyjOFvERLzdTUROGA=="], "opentracing": ["opentracing@0.14.7", "", {}, "sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q=="], @@ -4887,7 +4902,7 @@ "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], "path-to-regexp": ["path-to-regexp@0.1.13", "", {}, "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA=="], @@ -4947,6 +4962,8 @@ "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + "platform": ["platform@1.3.6", "", {}, "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="], + "playwright": ["playwright@1.60.0", "", { "dependencies": { "playwright-core": "1.60.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA=="], "playwright-core": ["playwright-core@1.60.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA=="], @@ -5863,6 +5880,10 @@ "vite-tsconfig-paths": ["vite-tsconfig-paths@6.1.1", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg=="], + "vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.12", "", {}, "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA=="], + + "vscode-languageserver-types": ["vscode-languageserver-types@3.18.0", "", {}, "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g=="], + "vscode-oniguruma": ["vscode-oniguruma@2.0.1", "", {}, "sha512-poJU8iHIWnC3vgphJnrLZyI3YdqRlR27xzqDmpPXYzA93R4Gk8z7T6oqDzDoHjoikA2aS82crdXFkjELCdJsjQ=="], "vscode-textmate": ["vscode-textmate@9.3.2", "", {}, "sha512-n2uGbUcrjhUEBH16uGA0TvUfhWwliFZ1e3+pTjrkim1Mt7ydB41lV08aUvsi70OlzDWp6X7Bx3w/x3fAXIsN0Q=="], @@ -6261,10 +6282,6 @@ "@inquirer/external-editor/iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], - "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - - "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - "@jridgewell/gen-mapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], "@jridgewell/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], @@ -6715,6 +6732,8 @@ "@sentry/browser/@sentry/core": ["@sentry/core@10.53.1", "", {}, "sha512-XG4ezlkyuAPjBC5+9kXC94rXXuqYTw9NRhfaDHssbTFaGnqBR8vQX2UUgZfY7ucbeelRDGfBu1sywoU+mB04uA=="], + "@sentry/bundler-plugin-core/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + "@sentry/cli/proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], "@sentry/node/@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.7.1", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-OPFBYuXEn1E4ja3Y6eeA7O+ZnLBNcXTV5Cgsn1VaqBZ6hC5FnpZPLBNme1LJY8ZtF4aOujPKFoeWN4ik487KuQ=="], @@ -7283,8 +7302,6 @@ "glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - "glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], - "globby/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], "globby/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], @@ -7371,6 +7388,8 @@ "mocha/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + "mocha/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + "mocha/js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], "mocha/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], @@ -7447,8 +7466,6 @@ "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "pg/pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="], "pino/pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], @@ -7515,8 +7532,6 @@ "react-email/commander": ["commander@13.1.0", "", {}, "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw=="], - "react-email/glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="], - "react-email/log-symbols": ["log-symbols@7.0.1", "", { "dependencies": { "is-unicode-supported": "^2.0.0", "yoctocolors": "^2.1.1" } }, "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg=="], "react-email/next": ["next@15.5.18", "", { "dependencies": { "@next/env": "15.5.18", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.5.18", "@next/swc-darwin-x64": "15.5.18", "@next/swc-linux-arm64-gnu": "15.5.18", "@next/swc-linux-arm64-musl": "15.5.18", "@next/swc-linux-x64-gnu": "15.5.18", "@next/swc-linux-x64-musl": "15.5.18", "@next/swc-win32-arm64-msvc": "15.5.18", "@next/swc-win32-x64-msvc": "15.5.18", "sharp": "^0.34.3" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-eKL8zUJkX9Y5lE+RX/2YJoItVdGlIscyVyboeD9wSpp0PaGqjoA4tTpT2qPqz9ax+5IzGESyLSeZ/RCwbSZ2uQ=="], @@ -7627,8 +7642,6 @@ "sync-content/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], - "sync-content/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], - "tempy/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], "tempy/type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="], @@ -7995,8 +8008,6 @@ "@inquirer/core/wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - "@langchain/langgraph-sdk/p-queue/p-timeout": ["p-timeout@7.0.1", "", {}, "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg=="], "@mintlify/cli/ink/@alcalzone/ansi-tokenize": ["@alcalzone/ansi-tokenize@0.2.5", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-3NX/MpTdroi0aKz134A6RC2Gb2iXVECN4QaAXnvCIxxIm3C3AVB1mkUe8NaaiyvOpDfsrqWhYtj+Q6a62RrTsw=="], @@ -8407,6 +8418,14 @@ "@react-grab/cli/ora/string-width": ["string-width@8.2.1", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA=="], + "@sentry/bundler-plugin-core/glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "@sentry/bundler-plugin-core/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "@sentry/bundler-plugin-core/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], + + "@sentry/bundler-plugin-core/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "@sentry/node-core/import-in-the-middle/cjs-module-lexer": ["cjs-module-lexer@2.2.0", "", {}, "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ=="], "@sentry/node/@opentelemetry/instrumentation/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.211.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-swFdZq8MCdmdR22jTVGQDhwqDzcI4M10nhjXkLr1EsIzXgZBqm4ZlmmcWsg3TSNf+3mzgOiqveXmBLZuDi2Lgg=="], @@ -8821,8 +8840,6 @@ "gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], - "glob/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="], - "got/decompress-response/mimic-response": ["mimic-response@4.0.0", "", {}, "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg=="], "gradient-string/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -8893,6 +8910,12 @@ "mocha/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + "mocha/glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "mocha/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "mocha/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "mocha/js-yaml/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], "mocha/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="], @@ -9011,12 +9034,6 @@ "react-email/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], - "react-email/glob/foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - - "react-email/glob/jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "^9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="], - - "react-email/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], - "react-email/log-symbols/is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], "react-email/next/@next/env": ["@next/env@15.5.18", "", {}, "sha512-hAV85Ckd9QR6RvH04MEKwsfLTksvFpO47j9xwtoIuvuPnlwecpSi+uZTtm8HirVbtlI2Fnz//xpcSTjFdyJk+g=="], @@ -9053,12 +9070,8 @@ "read-pkg/normalize-package-data/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], - "resolve-import/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], - "restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], - "rimraf/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], - "run-jxa/execa/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], "run-jxa/execa/human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], @@ -9439,6 +9452,12 @@ "@react-grab/cli/ora/cli-cursor/restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], + "@sentry/bundler-plugin-core/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "@sentry/bundler-plugin-core/glob/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="], + + "@sentry/bundler-plugin-core/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "@sentry/node/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "@smithy/middleware-endpoint/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="], @@ -9587,8 +9606,6 @@ "find-cache-dir/pkg-dir/find-up/path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="], - "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "gradient-string/chalk/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], "ink-confirm-input/ink-text-input/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -9639,6 +9656,10 @@ "meow/read-pkg-up/read-pkg/normalize-package-data": ["normalize-package-data@3.0.3", "", { "dependencies": { "hosted-git-info": "^4.0.1", "is-core-module": "^2.5.0", "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" } }, "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA=="], + "mocha/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "mocha/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "mocha/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "msw/@inquirer/confirm/@inquirer/core/@inquirer/ansi": ["@inquirer/ansi@2.0.5", "", {}, "sha512-doc2sWgJpbFQ64UflSVd17ibMGDuxO1yKgOgLMwavzESnXjFWJqUeG8saYosqKpHp4kWiM5x1nXvEjbpx90gzw=="], @@ -9693,8 +9714,6 @@ "puppeteer/puppeteer-core/chromium-bidi/zod": ["zod@3.23.8", "", {}, "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g=="], - "react-email/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="], - "react-email/next/postcss/nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], "react-email/ora/cli-cursor/restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], @@ -9777,6 +9796,12 @@ "@react-grab/cli/ora/cli-cursor/restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], + "@sentry/bundler-plugin-core/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "@sentry/bundler-plugin-core/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "@sentry/bundler-plugin-core/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "@smithy/middleware-endpoint/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="], "@smithy/smithy-client/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="], @@ -9817,6 +9842,10 @@ "meow/read-pkg-up/read-pkg/normalize-package-data/hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], + "mocha/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "mocha/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + "ora/cli-cursor/restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], "ora/log-symbols/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], @@ -9873,6 +9902,8 @@ "@mintlify/common/sucrase/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "@sentry/bundler-plugin-core/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "atmn/eslint-plugin-react-hooks/eslint/chalk/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], "atmn/eslint-plugin-react-hooks/eslint/file-entry-cache/flat-cache/keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], @@ -9887,6 +9918,8 @@ "meow/read-pkg-up/read-pkg/normalize-package-data/hosted-git-info/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + "mocha/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "ora/log-symbols/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], "trigger.dev/c12/giget/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],