diff --git a/.changeset/daytona-isolate-driver.md b/.changeset/daytona-isolate-driver.md new file mode 100644 index 000000000..bfd212917 --- /dev/null +++ b/.changeset/daytona-isolate-driver.md @@ -0,0 +1,5 @@ +--- +'@tanstack/ai-isolate-daytona': minor +--- + +Add the Daytona sandbox isolate driver for Code Mode. diff --git a/docs/code-mode/code-mode-isolates.md b/docs/code-mode/code-mode-isolates.md index 81c447fcd..1b8e89853 100644 --- a/docs/code-mode/code-mode-isolates.md +++ b/docs/code-mode/code-mode-isolates.md @@ -2,7 +2,7 @@ title: Code Mode Isolate Drivers id: code-mode-isolates order: 4 -description: "Compare Code Mode sandbox drivers — Node isolated-vm, QuickJS WASM, and Cloudflare Workers — and choose the right runtime for your deployment." +description: "Compare Code Mode sandbox drivers — Node isolated-vm, QuickJS WASM, Cloudflare Workers, and Daytona sandboxes — and choose the right runtime for your deployment." keywords: - tanstack ai - code mode @@ -10,6 +10,7 @@ keywords: - isolated-vm - quickjs - cloudflare workers + - daytona - sandbox - secure execution --- @@ -18,15 +19,15 @@ Isolate drivers provide the secure sandbox runtimes that [Code Mode](./code-mode ## Choosing a Driver -| | Node (`isolated-vm`) | QuickJS (WASM) | Cloudflare Workers | -|---|---|---|---| -| **Best for** | Server-side Node.js apps | Browsers, edge, portability | Edge deployments on Cloudflare | -| **Performance** | Fast (V8 JIT) | Slower (interpreted) | Fast (V8 on Cloudflare edge) | -| **Native deps** | Yes (C++ addon) | None | None | -| **Browser support** | No | Yes | N/A | -| **Memory limit** | Configurable | Configurable | N/A | -| **Stack size limit** | N/A | Configurable | N/A | -| **Setup** | `pnpm add` | `pnpm add` | Deploy a Worker first | +| | Node (`isolated-vm`) | QuickJS (WASM) | Cloudflare Workers | Daytona | +|---|---|---|---|---| +| **Best for** | Server-side Node.js apps | Browsers, edge, portability | Edge deployments on Cloudflare | Full remote Linux sandboxes | +| **Performance** | Fast (V8 JIT) | Slower (interpreted) | Fast (V8 on Cloudflare edge) | Fast (native runtime; remote call) | +| **Native deps** | Yes (C++ addon) | None | None | None | +| **Browser support** | No | Yes | N/A | Yes | +| **Memory limit** | Configurable | Configurable | N/A | Configurable | +| **Stack size limit** | N/A | Configurable | N/A | N/A | +| **Setup** | `pnpm add` | `pnpm add` | Deploy a Worker first | Create or pass a Daytona sandbox | --- @@ -182,9 +183,68 @@ Each round-trip adds network latency, so the `maxToolRounds` limit both prevents --- +## Daytona Driver (`@tanstack/ai-isolate-daytona`) + +Runs generated code inside a Daytona sandbox through `sandbox.process.codeRun`. Your application process still owns TanStack tool implementations; the Daytona sandbox only receives wrapped generated code plus replayed tool results. + +### Installation + +```bash +pnpm add @tanstack/ai-isolate-daytona +``` + +If your application creates sandboxes with the official Daytona SDK, also install it: + +```bash +pnpm add @daytona/sdk +``` + +### Usage + +```typescript +import { Daytona } from '@daytona/sdk' +import { createDaytonaIsolateDriver } from '@tanstack/ai-isolate-daytona' + +const daytona = new Daytona() +const sandbox = await daytona.create({ language: 'typescript' }) + +const driver = createDaytonaIsolateDriver({ + sandbox, + timeout: 30_000, + maxToolRounds: 10, +}) +``` + +### Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `sandbox` | `DaytonaSandboxLike` | — | **Required.** A caller-owned Daytona sandbox-like object with `process.codeRun(code, params?, timeout?)`. | +| `timeout` | `number` | `30000` | Maximum wall-clock time for the entire execution, including replay rounds, in milliseconds. | +| `maxToolRounds` | `number` | `10` | Maximum number of sandbox <-> host tool callback rounds. Prevents infinite loops when generated code repeatedly asks for tools. | + +### How it works + +The driver uses the same host-owned tool replay shape as the Cloudflare driver without Cloudflare's parent Worker / Dynamic Worker split: + +```text +Driver (your server) Daytona sandbox +───────────────────── ─────────────── +Send: wrapped code ──────▶ Execute with process.codeRun + ◀────── Return: need_tools with tool requests +Execute tools locally +Replay with toolResults ──────▶ Continue execution + ◀────── Return: final result / more tool requests +...repeat until done... +``` + +Use this driver when you want Code Mode execution in a full Daytona sandbox instead of an in-process isolate, QuickJS WASM runtime, or Cloudflare Worker. The sandbox should use a language/runtime capable of executing the JavaScript emitted by Code Mode, and your application remains responsible for sandbox lifecycle, filesystem, network, cleanup, and secret policy. Creating a Code Mode context does not create or delete a Daytona sandbox. + +--- + ## The `IsolateDriver` Interface -All three drivers satisfy this interface, exported from `@tanstack/ai-code-mode`: +All provided drivers satisfy this interface, exported from `@tanstack/ai-code-mode`: ```typescript interface IsolateDriver { diff --git a/docs/code-mode/code-mode.md b/docs/code-mode/code-mode.md index 5cad9fa1d..284e08b8e 100644 --- a/docs/code-mode/code-mode.md +++ b/docs/code-mode/code-mode.md @@ -35,7 +35,7 @@ Tools you pass to Code Mode are converted to typed function stubs that appear in ### Secure sandboxing -Generated code runs in an isolated environment (V8 isolate, QuickJS WASM, or Cloudflare Worker) with no access to the host file system, network, or process. The sandbox has configurable timeouts and memory limits. +Generated code runs in an isolated environment (V8 isolate, QuickJS WASM, Cloudflare Worker, or Daytona sandbox) with no access to the host file system, network, or process. The sandbox has configurable timeouts and memory limits. ## Getting Started @@ -56,6 +56,9 @@ pnpm add @tanstack/ai-isolate-quickjs # Cloudflare Workers — run on the edge pnpm add @tanstack/ai-isolate-cloudflare + +# Daytona sandboxes — run in a remote Daytona sandbox +pnpm add @tanstack/ai-isolate-daytona @daytona/sdk ``` ### 2. Define tools @@ -208,6 +211,7 @@ interface IsolateDriver { | `@tanstack/ai-isolate-node` | `createNodeIsolateDriver()` | Node.js | | `@tanstack/ai-isolate-quickjs` | `createQuickJSIsolateDriver()` | Node.js, browser, edge | | `@tanstack/ai-isolate-cloudflare` | `createCloudflareIsolateDriver()` | Cloudflare Workers | +| `@tanstack/ai-isolate-daytona` | `createDaytonaIsolateDriver()` | Daytona sandboxes | For full configuration options for each driver, see [Isolate Drivers](./code-mode-isolates.md). @@ -223,7 +227,7 @@ These utilities are used internally and are exported for custom pipelines: For a full comparison of drivers with all configuration options, see [Isolate Drivers](./code-mode-isolates.md). -In brief: use the **Node driver** for server-side Node.js (fastest, V8 JIT), **QuickJS** for browsers or portable edge deployments (no native deps), and the **Cloudflare driver** when you deploy to Cloudflare Workers. +In brief: use the **Node driver** for server-side Node.js (fastest, V8 JIT), **QuickJS** for browsers or portable edge deployments (no native deps), the **Cloudflare driver** when you deploy to Cloudflare Workers, and the **Daytona driver** when you want execution inside a full remote Linux sandbox. ## Custom Events @@ -289,4 +293,4 @@ pnpm eval -- --no-judge # skip Anthropic-based judging - [Showing Code Mode in the UI](./client-integration) — Display execution progress in your React app - [Code Mode with Skills](./code-mode-with-skills) — Add persistent, reusable skill libraries -- [Isolate Drivers](./code-mode-isolates) — Compare Node, QuickJS, and Cloudflare sandbox runtimes +- [Isolate Drivers](./code-mode-isolates) — Compare Node, QuickJS, Cloudflare, and Daytona sandbox runtimes diff --git a/packages/ai-isolate-daytona/README.md b/packages/ai-isolate-daytona/README.md new file mode 100644 index 000000000..0aee0eb31 --- /dev/null +++ b/packages/ai-isolate-daytona/README.md @@ -0,0 +1,91 @@ +# @tanstack/ai-isolate-daytona + +Daytona sandbox driver for TanStack AI Code Mode. + +This package runs generated JavaScript or TypeScript in a caller-provided Daytona sandbox and keeps TanStack tool implementations in your host process. When generated code calls an `external_*` tool, the sandbox returns a `need_tools` payload, the host executes the matching `ToolBinding.execute` callbacks, and the driver replays the code with accumulated tool results until it completes. + +## Installation + +```bash +pnpm add @tanstack/ai-isolate-daytona @tanstack/ai-code-mode +``` + +If you use the official Daytona SDK to create sandboxes, install it in your app too: + +```bash +pnpm add @daytona/sdk +``` + +## Usage + +```typescript +import { Daytona } from '@daytona/sdk' +import { createCodeMode } from '@tanstack/ai-code-mode' +import { createDaytonaIsolateDriver } from '@tanstack/ai-isolate-daytona' + +const daytona = new Daytona() +const sandbox = await daytona.create({ language: 'typescript' }) + +const driver = createDaytonaIsolateDriver({ + sandbox, + timeout: 30_000, + maxToolRounds: 10, +}) + +const { tool, systemPrompt } = createCodeMode({ + driver, + tools: [myServerTool], +}) +``` + +The driver accepts a structural sandbox object with `sandbox.process.codeRun(...)`; it does not require `@daytona/sdk` as a package dependency. + +## API + +### `createDaytonaIsolateDriver(config)` + +Creates an isolate driver that delegates Code Mode execution to a Daytona sandbox. + +- `sandbox` (required): caller-owned object with `process.codeRun(code, params?, timeout?)` +- `timeout` (optional): total execution timeout across replay rounds, in milliseconds (default: `30000`) +- `maxToolRounds` (optional): maximum `need_tools` replay rounds per execution (default: `10`) + +## Requirements + +- Use a sandbox language/runtime that can execute the JavaScript emitted by Code Mode. +- Tool inputs and outputs must be JSON-serializable. +- Sandbox lifecycle, network access, filesystem contents, secrets, and cleanup are owned by your application. Creating a Code Mode context does not create or delete a Daytona sandbox. + +## How It Works + +```text +Host process Daytona sandbox +------------ --------------- +createCodeMode + tools +wrap generated code ---------> run with process.codeRun +execute host tools <--------- need_tools requests +replay with toolResults ---------> continue execution +final result/logs <--------- done or error envelope +``` + +The host process talks directly to a Daytona sandbox through `process.codeRun`, while tool execution stays host-owned. + +## Validation + +Run the package checks once the implementation files are present: + +```bash +pnpm --filter @tanstack/ai-isolate-daytona test:lib +pnpm --filter @tanstack/ai-isolate-daytona test:types +pnpm --filter @tanstack/ai-isolate-daytona test:eslint +pnpm --filter @tanstack/ai-isolate-daytona build +pnpm --filter @tanstack/ai-isolate-daytona test:build +``` + +Live Daytona validation should be gated on explicit credentials and sandbox setup in the implementation tests or a local smoke script. + +```bash +DAYTONA_LIVE_TEST=1 DAYTONA_API_KEY=... pnpm --filter @tanstack/ai-isolate-daytona test:live +``` + +The live suite is skipped unless `DAYTONA_LIVE_TEST=1` and `DAYTONA_API_KEY` are both present. diff --git a/packages/ai-isolate-daytona/package.json b/packages/ai-isolate-daytona/package.json new file mode 100644 index 000000000..f153871a7 --- /dev/null +++ b/packages/ai-isolate-daytona/package.json @@ -0,0 +1,59 @@ +{ + "name": "@tanstack/ai-isolate-daytona", + "version": "0.0.1", + "description": "Daytona sandbox driver for TanStack AI Code Mode TypeScript execution.", + "author": "", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/TanStack/ai.git", + "directory": "packages/ai-isolate-daytona" + }, + "type": "module", + "module": "./dist/esm/index.js", + "types": "./dist/esm/index.d.ts", + "exports": { + ".": { + "types": "./dist/esm/index.d.ts", + "import": "./dist/esm/index.js" + } + }, + "sideEffects": false, + "engines": { + "node": ">=18" + }, + "files": [ + "dist", + "src" + ], + "scripts": { + "build": "vite build", + "clean": "premove ./build ./dist", + "lint:fix": "eslint ./src --fix", + "test:build": "publint --strict", + "test:eslint": "eslint ./src", + "test:live": "vitest --run tests/live.test.ts", + "test:lib": "vitest --passWithNoTests", + "test:lib:dev": "pnpm test:lib --watch", + "test:types": "tsc" + }, + "keywords": [ + "ai", + "ai-sdk", + "typescript", + "tanstack", + "code-mode", + "daytona", + "sandbox", + "isolate", + "code-execution" + ], + "peerDependencies": { + "@tanstack/ai-code-mode": "workspace:*" + }, + "devDependencies": { + "@daytona/sdk": "^0.180.0", + "@tanstack/ai-code-mode": "workspace:*", + "@vitest/coverage-v8": "4.0.14" + } +} diff --git a/packages/ai-isolate-daytona/src/index.ts b/packages/ai-isolate-daytona/src/index.ts new file mode 100644 index 000000000..5c26e5ad1 --- /dev/null +++ b/packages/ai-isolate-daytona/src/index.ts @@ -0,0 +1,36 @@ +/** + * @tanstack/ai-isolate-daytona + * + * Daytona sandbox driver for TanStack AI Code Mode. + * Execute LLM-generated code inside a caller-provided Daytona sandbox. + * + * @example + * ```typescript + * import { createDaytonaIsolateDriver } from '@tanstack/ai-isolate-daytona' + * + * const driver = createDaytonaIsolateDriver({ sandbox }) + * ``` + * + * @packageDocumentation + */ + +export { + createDaytonaIsolateDriver, + type DaytonaIsolateDriverConfig, +} from './isolate-driver' + +export type { + DaytonaCodeRunArtifacts, + DaytonaCodeRunParams, + DaytonaCodeRunResponse, + DaytonaProcessLike, + DaytonaSandboxLike, +} from './types' + +export type { + ExecutionResult, + IsolateConfig, + IsolateContext, + IsolateDriver, + NormalizedError, +} from '@tanstack/ai-code-mode' diff --git a/packages/ai-isolate-daytona/src/isolate-driver.ts b/packages/ai-isolate-daytona/src/isolate-driver.ts new file mode 100644 index 000000000..129f87066 --- /dev/null +++ b/packages/ai-isolate-daytona/src/isolate-driver.ts @@ -0,0 +1,555 @@ +import { randomUUID } from 'node:crypto' +import { DAYTONA_RESULT_MARKER, wrapCode } from './wrap-code' +import type { + ExecutionResult, + IsolateConfig, + IsolateContext, + IsolateDriver, + NormalizedError, + ToolBinding, +} from '@tanstack/ai-code-mode' +import type { + DaytonaCodeRunResponse, + DaytonaExecutionEnvelope, + DaytonaExecutionError, + DaytonaSandboxLike, + ToolCallRequest, + ToolResultPayload, + ToolSchema, +} from './types' + +const TOOL_CALL_ID = /^tc_(0|[1-9]\d*)$/ + +export interface DaytonaIsolateDriverConfig { + /** + * Caller-owned Daytona SDK sandbox or any object with a compatible + * `process.codeRun`. Context disposal prevents further use of this sandbox, + * but sandbox creation and cleanup stay with the caller. + */ + sandbox: DaytonaSandboxLike + + /** + * Default total execution timeout in milliseconds (default: 30000). + * Each Daytona `codeRun` receives the remaining budget as whole seconds. + */ + timeout?: number + + /** + * Maximum number of tool callback rounds (default: 10). + */ + maxToolRounds?: number +} + +function bindingsToSchemas( + bindings: Record, +): Array { + return Object.entries(bindings).map(([name, binding]) => ({ + name, + description: binding.description, + inputSchema: binding.inputSchema, + })) +} + +function normalizeError(error: unknown): DaytonaExecutionError { + if (error instanceof Error) { + return { + name: error.name, + message: error.message, + ...(error.stack !== undefined ? { stack: error.stack } : {}), + } + } + + if (typeof error === 'object' && error !== null) { + const record = error as Record + return { + name: typeof record.name === 'string' ? record.name : 'Error', + message: typeof record.message === 'string' ? record.message : 'Error', + } + } + + return { name: 'Error', message: String(error) } +} + +function toNormalizedError(error: DaytonaExecutionError): NormalizedError { + return { + name: error.name, + message: error.message, + ...(error.stack !== undefined ? { stack: error.stack } : {}), + } +} + +function timeoutMsToSeconds(timeout: number): number { + return Math.ceil(timeout / 1000) +} + +function createResultMarker(): string { + return `${DAYTONA_RESULT_MARKER}:${randomUUID()}:` +} + +function validateTimeoutMs(timeout: number, fieldName: string): number { + if (!Number.isFinite(timeout) || timeout <= 0) { + throw new Error(`${fieldName} must be a finite positive number`) + } + return timeout +} + +function validateMaxToolRounds(maxToolRounds: number): number { + if ( + !Number.isFinite(maxToolRounds) || + !Number.isInteger(maxToolRounds) || + maxToolRounds < 0 + ) { + throw new Error('maxToolRounds must be a finite non-negative integer') + } + return maxToolRounds +} + +function outputFromCodeRun(response: DaytonaCodeRunResponse): string { + const stdout = response.artifacts?.stdout + if (stdout !== undefined) { + return stdout + } + if (response.result !== undefined) { + return response.result + } + return '' +} + +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null +} + +function hasOwn(object: T, key: PropertyKey): key is keyof T { + return Object.prototype.hasOwnProperty.call(object, key) +} + +function toolCallIdFor(index: number): string { + return `tc_${index}` +} + +async function withTimeout( + promise: Promise, + milliseconds: number, +): Promise { + let timer: number | undefined + const timeout = new Promise((resolve) => { + timer = setTimeout(resolve, milliseconds) + }) + + try { + return await Promise.race([promise, timeout]) + } finally { + if (timer !== undefined) { + clearTimeout(timer) + } + } +} + +function readStringArray(value: unknown, fieldName: string): Array { + if (!Array.isArray(value)) { + throw new Error(`Daytona envelope field '${fieldName}' must be an array`) + } + if (!value.every((item): item is string => typeof item === 'string')) { + throw new Error( + `Daytona envelope field '${fieldName}' must contain only strings`, + ) + } + return value +} + +function readExecutionError( + value: unknown, + fieldName: string, +): DaytonaExecutionError { + if (!isRecord(value)) { + throw new Error(`Daytona envelope field '${fieldName}' must be an object`) + } + + const { name, message, stack } = value + if (typeof name !== 'string' || typeof message !== 'string') { + throw new Error( + `Daytona envelope field '${fieldName}' must include string name and message`, + ) + } + + return { + name, + message, + ...(typeof stack === 'string' ? { stack } : {}), + } +} + +function readToolCalls(value: unknown): Array { + if (!Array.isArray(value)) { + throw new Error("Daytona envelope field 'toolCalls' must be an array") + } + + const seenIds = new Set() + + return value.map((item) => { + if (!isRecord(item)) { + throw new Error('Daytona tool call must be an object') + } + + const { id, name, args } = item + if (typeof id !== 'string' || typeof name !== 'string') { + throw new Error('Daytona tool call must include string id and name') + } + if (!TOOL_CALL_ID.test(id)) { + throw new Error(`Invalid Daytona tool call id: ${id}`) + } + if (seenIds.has(id)) { + throw new Error(`Duplicate Daytona tool call id: ${id}`) + } + + seenIds.add(id) + return { id, name, args } + }) +} + +function assertNewToolCallId( + toolResults: Record, + id: string, +): void { + if (hasOwn(toolResults, id)) { + throw new Error(`Daytona tool call id already has a cached result: ${id}`) + } +} + +function assertExpectedToolCalls( + toolCalls: Array, + nextToolCallIndex: number, + toolResults: Record, +): void { + if (toolCalls.length === 0) { + throw new Error('Daytona need_tools response must include tool calls') + } + + toolCalls.forEach((toolCall, index) => { + assertNewToolCallId(toolResults, toolCall.id) + + const expectedId = toolCallIdFor(nextToolCallIndex + index) + if (toolCall.id !== expectedId) { + throw new Error( + `Daytona tool call ids must be contiguous from ${expectedId}; received ${toolCall.id}`, + ) + } + }) +} + +async function executeToolCall( + bindings: Record, + toolCall: ToolCallRequest, +): Promise<[string, ToolResultPayload]> { + const binding = hasOwn(bindings, toolCall.name) + ? bindings[toolCall.name] + : undefined + + if (!binding) { + return [ + toolCall.id, + { + success: false, + error: `Unknown tool: ${toolCall.name}`, + }, + ] + } + + try { + const value = await binding.execute(toolCall.args) + return [toolCall.id, { success: true, value }] + } catch (toolError) { + const error = normalizeError(toolError) + return [ + toolCall.id, + { + success: false, + error: error.message, + }, + ] + } +} + +function parseExecutionEnvelope( + output: string, + resultMarker: string, +): DaytonaExecutionEnvelope { + const markerLine = output + .split(/\r?\n/) + .reverse() + .find((line) => line.startsWith(resultMarker)) + + if (!markerLine) { + throw new Error('Daytona codeRun output did not include Code Mode marker') + } + + const jsonText = markerLine.slice(resultMarker.length) + const parsed: unknown = JSON.parse(jsonText) + + if (!isRecord(parsed) || typeof parsed.status !== 'string') { + throw new Error('Daytona codeRun marker did not contain a valid envelope') + } + + if (parsed.status === 'done') { + if (typeof parsed.success !== 'boolean') { + throw new Error("Daytona envelope field 'success' must be a boolean") + } + + if (parsed.success) { + if (parsed.error !== undefined) { + throw new Error('Daytona success envelope must not include error') + } + + return { + status: 'done', + success: true, + value: parsed.value, + logs: readStringArray(parsed.logs, 'logs'), + } + } + + if (parsed.value !== undefined) { + throw new Error('Daytona failure envelope must not include value') + } + + return { + status: 'done', + success: false, + error: readExecutionError(parsed.error, 'error'), + logs: readStringArray(parsed.logs, 'logs'), + } + } + + if (parsed.status === 'need_tools') { + return { + status: 'need_tools', + toolCalls: readToolCalls(parsed.toolCalls), + logs: readStringArray(parsed.logs, 'logs'), + } + } + + if (parsed.status === 'error') { + return { + status: 'error', + error: readExecutionError(parsed.error, 'error'), + } + } + + throw new Error(`Unknown Daytona execution status: ${parsed.status}`) +} + +class DaytonaIsolateContext implements IsolateContext { + private disposed = false + + constructor( + private readonly sandbox: DaytonaSandboxLike, + private readonly bindings: Record, + private readonly timeoutMs: number, + private readonly maxToolRounds: number, + ) {} + + private disposedResult(logs: Array): ExecutionResult { + return { + success: false, + error: { + name: 'DisposedError', + message: 'Context has been disposed', + }, + logs, + } + } + + private timeoutResult(logs: Array): ExecutionResult { + return { + success: false, + error: { + name: 'TimeoutError', + message: `Exceeded Daytona execution timeout (${this.timeoutMs}ms)`, + }, + logs, + } + } + + private isDisposed(): boolean { + return this.disposed + } + + private remainingTimeoutSeconds(deadlineMs: number): number | undefined { + const remainingMs = deadlineMs - Date.now() + if (remainingMs <= 0) { + return undefined + } + return timeoutMsToSeconds(remainingMs) + } + + private remainingTimeoutMs(deadlineMs: number): number | undefined { + const remainingMs = deadlineMs - Date.now() + return remainingMs > 0 ? remainingMs : undefined + } + + async execute(code: string): Promise> { + if (this.isDisposed()) { + return this.disposedResult([]) + } + + const tools = bindingsToSchemas(this.bindings) + let toolResults: Record | undefined + let allLogs: Array = [] + let toolRounds = 0 + let nextToolCallIndex = 0 + const deadlineMs = Date.now() + this.timeoutMs + + for (;;) { + try { + if (this.isDisposed()) { + return this.disposedResult(allLogs) + } + + const remainingCodeRunMs = this.remainingTimeoutMs(deadlineMs) + if (remainingCodeRunMs === undefined) { + return this.timeoutResult(allLogs) + } + + const resultMarker = createResultMarker() + const wrappedCode = wrapCode(code, tools, toolResults, resultMarker) + const response = await withTimeout( + this.sandbox.process.codeRun( + wrappedCode, + undefined, + timeoutMsToSeconds(remainingCodeRunMs), + ), + remainingCodeRunMs, + ) + if (response === undefined) { + return this.timeoutResult(allLogs) + } + const output = outputFromCodeRun(response) + const result = parseExecutionEnvelope(output, resultMarker) + + if (result.status === 'error') { + return { + success: false, + error: toNormalizedError(result.error), + logs: allLogs, + } + } + + if (result.status === 'done') { + allLogs = result.logs + if (this.isDisposed()) { + return this.disposedResult(allLogs) + } + if (!result.success) { + return { + success: false, + error: toNormalizedError(result.error), + logs: allLogs, + } + } + + return { + success: true, + value: result.value as T, + logs: allLogs, + } + } + + allLogs = result.logs + if (this.isDisposed()) { + return this.disposedResult(allLogs) + } + + if (toolRounds >= this.maxToolRounds) { + return { + success: false, + error: { + name: 'MaxRoundsExceeded', + message: `Exceeded maximum tool callback rounds (${this.maxToolRounds})`, + }, + logs: allLogs, + } + } + + const cachedToolResults = { ...(toolResults ?? {}) } + assertExpectedToolCalls( + result.toolCalls, + nextToolCallIndex, + cachedToolResults, + ) + toolRounds++ + nextToolCallIndex += result.toolCalls.length + + if (this.isDisposed()) { + return this.disposedResult(allLogs) + } + + const remainingToolMs = this.remainingTimeoutMs(deadlineMs) + if (remainingToolMs === undefined) { + return this.timeoutResult(allLogs) + } + const batchEntries = await withTimeout( + Promise.all( + result.toolCalls.map((toolCall) => + executeToolCall(this.bindings, toolCall), + ), + ), + remainingToolMs, + ) + if (batchEntries === undefined) { + return this.timeoutResult(allLogs) + } + if (this.isDisposed()) { + return this.disposedResult(allLogs) + } + if (this.remainingTimeoutSeconds(deadlineMs) === undefined) { + return this.timeoutResult(allLogs) + } + const batchResults: Record = {} + for (const [id, payload] of batchEntries) { + batchResults[id] = payload + } + toolResults = { ...cachedToolResults, ...batchResults } + } catch (error) { + const normalized = normalizeError(error) + return { + success: false, + error: { + name: 'DaytonaExecutionError', + message: `Failed to execute code in Daytona sandbox: ${normalized.message}`, + }, + logs: allLogs, + } + } + } + } + + dispose(): Promise { + this.disposed = true + return Promise.resolve() + } +} + +export function createDaytonaIsolateDriver( + config: DaytonaIsolateDriverConfig, +): IsolateDriver { + const sandbox = config.sandbox + const defaultTimeoutMs = validateTimeoutMs(config.timeout ?? 30000, 'timeout') + const maxToolRounds = validateMaxToolRounds(config.maxToolRounds ?? 10) + + return { + createContext(isolateConfig: IsolateConfig): Promise { + const timeoutMs = validateTimeoutMs( + isolateConfig.timeout ?? defaultTimeoutMs, + 'timeout', + ) + return Promise.resolve( + new DaytonaIsolateContext( + sandbox, + isolateConfig.bindings, + timeoutMs, + maxToolRounds, + ), + ) + }, + } +} diff --git a/packages/ai-isolate-daytona/src/types.ts b/packages/ai-isolate-daytona/src/types.ts new file mode 100644 index 000000000..e8a371ce7 --- /dev/null +++ b/packages/ai-isolate-daytona/src/types.ts @@ -0,0 +1,85 @@ +/** + * Structural Daytona process/code-run types plus the host/sandbox protocol. + */ + +export interface DaytonaCodeRunArtifacts { + stdout?: string | undefined +} + +export interface DaytonaCodeRunResponse { + exitCode?: number | undefined + result?: string | undefined + artifacts?: DaytonaCodeRunArtifacts | undefined +} + +export interface DaytonaCodeRunParams { + argv?: Array | undefined + env?: Record | undefined +} + +export interface DaytonaProcessLike { + codeRun: ( + code: string, + params?: DaytonaCodeRunParams, + timeoutSeconds?: number, + ) => Promise +} + +export interface DaytonaSandboxLike { + process: DaytonaProcessLike +} + +export interface ToolSchema { + name: string + description: string + inputSchema: Record +} + +export interface ToolCallRequest { + id: string + name: string + args: unknown +} + +export type ToolResultPayload = + | { + success: true + value?: unknown + error?: never + } + | { + success: false + error: string + value?: never + } + +export interface DaytonaExecutionError { + name: string + message: string + stack?: string | undefined +} + +export type DaytonaExecutionEnvelope = + | { + status: 'done' + success: true + value?: unknown + error?: never + logs: Array + } + | { + status: 'done' + success: false + error: DaytonaExecutionError + value?: never + logs: Array + } + | { + status: 'need_tools' + toolCalls: Array + logs: Array + } + | { + status: 'error' + error: DaytonaExecutionError + } diff --git a/packages/ai-isolate-daytona/src/wrap-code.ts b/packages/ai-isolate-daytona/src/wrap-code.ts new file mode 100644 index 000000000..87e54d0cc --- /dev/null +++ b/packages/ai-isolate-daytona/src/wrap-code.ts @@ -0,0 +1,218 @@ +import type { ToolResultPayload, ToolSchema } from './types' + +export const DAYTONA_RESULT_MARKER = '__TANSTACK_AI_CODE_MODE_RESULT__' + +const VALID_TOOL_NAME = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/ + +const RESERVED_TOOL_NAMES = new Set([ + 'break', + 'case', + 'catch', + 'class', + 'const', + 'continue', + 'debugger', + 'default', + 'delete', + 'do', + 'else', + 'enum', + 'export', + 'extends', + 'false', + 'finally', + 'for', + 'function', + 'if', + 'import', + 'in', + 'instanceof', + 'new', + 'null', + 'return', + 'super', + 'switch', + 'this', + 'throw', + 'true', + 'try', + 'typeof', + 'var', + 'void', + 'while', + 'with', + 'yield', + 'let', + 'static', + 'implements', + 'interface', + 'package', + 'private', + 'protected', + 'public', + 'await', + 'async', +]) + +function assertSafeToolName(name: string): void { + if (!VALID_TOOL_NAME.test(name)) { + throw new Error( + `Invalid tool name '${name}': must match ${VALID_TOOL_NAME} (letters, digits, _, $; cannot start with a digit)`, + ) + } + if (RESERVED_TOOL_NAMES.has(name)) { + throw new Error(`Invalid tool name '${name}': reserved JavaScript keyword`) + } +} + +export function generateToolWrappers(tools: Array): string { + const wrappers: Array = [] + + for (const tool of tools) { + assertSafeToolName(tool.name) + + wrappers.push(` + async function ${tool.name}(input) { + const callId = 'tc_' + (__toolCallIdx++); + const result = __toolResults[callId]; + if (!result) { + __pendingToolCalls.push({ id: callId, name: '${tool.name}', args: input }); + throw new __ToolCallNeeded(callId); + } + if (!result.success) { + throw new Error(result.error || 'Tool call failed'); + } + return result.value; + } + `) + } + + return wrappers.join('\n') +} + +export function wrapCode( + code: string, + tools: Array, + toolResults?: Record, + resultMarker = DAYTONA_RESULT_MARKER, +): string { + const toolWrappers = generateToolWrappers(tools) + const toolResultsJson = toolResults ? JSON.stringify(toolResults) : '{}' + + return ` + const __hostConsole = globalThis.console; + + function __stringProperty(__value, __key) { + try { + const __property = __value && typeof __value === 'object' ? __value[__key] : undefined; + return typeof __property === 'string' ? __property : undefined; + } catch { + return undefined; + } + } + + function __normalizeError(__error) { + if (__error instanceof Error) { + return { + name: __error.name || 'Error', + message: __error.message || String(__error), + stack: __error.stack, + }; + } + + if (__error && typeof __error === 'object') { + return { + name: __stringProperty(__error, 'name') || 'Error', + message: __stringProperty(__error, 'message') || 'Error', + stack: __stringProperty(__error, 'stack'), + }; + } + + return { + name: 'Error', + message: String(__error), + }; + } + + function __formatConsoleArg(__arg) { + if (typeof __arg === 'string') { + return __arg; + } + + try { + const __json = JSON.stringify(__arg); + if (__json !== undefined) { + return __json; + } + } catch { + // Fall through to String(); logging must not fail user code. + } + + try { + return String(__arg); + } catch { + return '[Unserializable]'; + } + } + + (async function() { + let __toolCallIdx = 0; + const __pendingToolCalls = []; + const __toolResults = ${toolResultsJson}; + const __logs = []; + + class __ToolCallNeeded extends Error { + constructor(callId) { + super('Tool call needed: ' + callId); + this.callId = callId; + } + } + + const console = { + log: (...args) => __logs.push(args.map(__formatConsoleArg).join(' ')), + error: (...args) => __logs.push('ERROR: ' + args.map(__formatConsoleArg).join(' ')), + warn: (...args) => __logs.push('WARN: ' + args.map(__formatConsoleArg).join(' ')), + info: (...args) => __logs.push('INFO: ' + args.map(__formatConsoleArg).join(' ')), + }; + + ${toolWrappers} + + try { + const __userResult = await (async function() { + ${code} + })(); + + return { + status: 'done', + success: true, + value: __userResult, + logs: __logs, + }; + } catch (__error) { + if (__error instanceof __ToolCallNeeded) { + return { + status: 'need_tools', + toolCalls: __pendingToolCalls, + logs: __logs, + }; + } + + return { + status: 'done', + success: false, + error: __normalizeError(__error), + logs: __logs, + }; + } + })() + .then((__envelope) => { + __hostConsole.log(${JSON.stringify(resultMarker)} + JSON.stringify(__envelope)); + }) + .catch((__error) => { + __hostConsole.log(${JSON.stringify(resultMarker)} + JSON.stringify({ + status: 'error', + error: __normalizeError(__error), + })); + }); + ` +} diff --git a/packages/ai-isolate-daytona/tests/isolate-driver.test.ts b/packages/ai-isolate-daytona/tests/isolate-driver.test.ts new file mode 100644 index 000000000..bffd5fdfa --- /dev/null +++ b/packages/ai-isolate-daytona/tests/isolate-driver.test.ts @@ -0,0 +1,1056 @@ +import { describe, expect, it, vi } from 'vitest' +import { createDaytonaIsolateDriver } from '../src/isolate-driver' +import { DAYTONA_RESULT_MARKER } from '../src/wrap-code' +import type { ToolBinding } from '@tanstack/ai-code-mode' +import type { + DaytonaCodeRunParams, + DaytonaCodeRunResponse, + DaytonaExecutionEnvelope, + DaytonaSandboxLike, +} from '../src/types' + +function envelope(response: DaytonaExecutionEnvelope): DaytonaCodeRunResponse { + return { + exitCode: 0, + result: `${DAYTONA_RESULT_MARKER}${JSON.stringify(response)}`, + artifacts: { + stdout: `${DAYTONA_RESULT_MARKER}${JSON.stringify(response)}`, + }, + } +} + +function stdoutWithEnvelope( + prefix: string, + response: DaytonaExecutionEnvelope, +): DaytonaCodeRunResponse { + const stdout = `${prefix}\n${DAYTONA_RESULT_MARKER}${JSON.stringify(response)}` + return { + exitCode: 0, + result: stdout, + artifacts: { stdout }, + } +} + +function resultMarkerFromCode(code: string): string { + const match = code.match(/"(__TANSTACK_AI_CODE_MODE_RESULT__:[^"]+)"/) + return match?.[1] ?? DAYTONA_RESULT_MARKER +} + +function rewriteOutputMarker( + output: string | undefined, + resultMarker: string, +): string | undefined { + if (output === undefined) { + return undefined + } + + return output + .split(/\r?\n/) + .map((line) => + line.startsWith(DAYTONA_RESULT_MARKER) + ? `${resultMarker}${line.slice(DAYTONA_RESULT_MARKER.length)}` + : line, + ) + .join('\n') +} + +function rewriteResponseMarker( + code: string, + response: DaytonaCodeRunResponse, +): DaytonaCodeRunResponse { + const resultMarker = resultMarkerFromCode(code) + return { + ...response, + result: rewriteOutputMarker(response.result, resultMarker), + artifacts: + response.artifacts === undefined + ? undefined + : { + ...response.artifacts, + stdout: rewriteOutputMarker( + response.artifacts.stdout, + resultMarker, + ), + }, + } +} + +function makeSandbox( + codeRun: ( + code: string, + params?: DaytonaCodeRunParams, + timeoutSeconds?: number, + ) => Promise, +): DaytonaSandboxLike { + return { + process: { + codeRun: async (code, params, timeoutSeconds) => + rewriteResponseMarker( + code, + await codeRun(code, params, timeoutSeconds), + ), + }, + } +} + +function makeBinding( + name: string, + execute: (args: unknown) => Promise, +): ToolBinding { + return { + name, + description: `${name} tool`, + inputSchema: { type: 'object', properties: {} }, + execute, + } +} + +describe('createDaytonaIsolateDriver', () => { + it('rejects invalid driver config', () => { + const sandbox = makeSandbox(vi.fn()) + + expect(() => createDaytonaIsolateDriver({ sandbox, timeout: 0 })).toThrow( + /timeout must be a finite positive number/, + ) + expect(() => + createDaytonaIsolateDriver({ sandbox, timeout: Number.NaN }), + ).toThrow(/timeout must be a finite positive number/) + expect(() => + createDaytonaIsolateDriver({ sandbox, maxToolRounds: -1 }), + ).toThrow(/maxToolRounds must be a finite non-negative integer/) + expect(() => + createDaytonaIsolateDriver({ sandbox, maxToolRounds: 1.5 }), + ).toThrow(/maxToolRounds must be a finite non-negative integer/) + }) + + it('rejects invalid per-context timeout config', async () => { + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(vi.fn()), + }) + + expect(() => + driver.createContext({ + bindings: {}, + timeout: -1, + }), + ).toThrow(/timeout must be a finite positive number/) + }) + + it('returns a context with execute and dispose', async () => { + const codeRun = vi.fn().mockResolvedValue( + envelope({ + status: 'done', + success: true, + value: 42, + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + expect(typeof context.execute).toBe('function') + expect(typeof context.dispose).toBe('function') + + const result = await context.execute('return 42') + expect(result.success).toBe(true) + expect(result.value).toBe(42) + }) + + it('wraps code, sends no params, and converts timeout from ms to seconds', async () => { + const codeRun = vi.fn().mockResolvedValue( + envelope({ + status: 'done', + success: true, + value: { sum: 7 }, + logs: ['hello'], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + timeout: 1500, + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('return { sum: 3 + 4 }') + + expect(result.success).toBe(true) + expect(result.value).toEqual({ sum: 7 }) + expect(result.logs).toEqual(['hello']) + expect(codeRun).toHaveBeenCalledTimes(1) + + const [code, params, timeoutSeconds] = codeRun.mock.calls[0]! + expect(code).toContain('return { sum: 3 + 4 }') + expect(code).toContain(DAYTONA_RESULT_MARKER) + expect(params).toBeUndefined() + expect(timeoutSeconds).toBe(2) + }) + + it('parses only line-prefixed result markers when values contain marker text', async () => { + const value = `before ${DAYTONA_RESULT_MARKER} after` + const codeRun = vi.fn().mockResolvedValue( + stdoutWithEnvelope('ordinary stdout', { + status: 'done', + success: true, + value, + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('return markerText') + + expect(result.success).toBe(true) + expect(result.value).toBe(value) + }) + + it('parses only line-prefixed result markers when logs contain marker text', async () => { + const log = `log ${DAYTONA_RESULT_MARKER} text` + const codeRun = vi.fn().mockResolvedValue( + stdoutWithEnvelope('ordinary stdout', { + status: 'done', + success: true, + value: 'ok', + logs: [log], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('console.log(markerText); return "ok"') + + expect(result.success).toBe(true) + expect(result.logs).toEqual([log]) + }) + + it('ignores static marker spoofing after the real per-execution marker', async () => { + const codeRun = vi.fn(async (wrappedCode: string) => { + const resultMarker = resultMarkerFromCode(wrappedCode) + const realEnvelope = JSON.stringify({ + status: 'done', + success: true, + value: 'real', + logs: [], + }) + const spoofEnvelope = JSON.stringify({ + status: 'done', + success: true, + value: 'spoofed', + logs: [], + }) + const stdout = [ + `${resultMarker}${realEnvelope}`, + `${DAYTONA_RESULT_MARKER}${spoofEnvelope}`, + ].join('\n') + + return { + exitCode: 0, + result: stdout, + artifacts: { stdout }, + } + }) + + const driver = createDaytonaIsolateDriver({ + sandbox: { process: { codeRun } }, + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('return "real"') + + expect(result.success).toBe(true) + expect(result.value).toBe('real') + }) + + it('uses per-context timeout over the driver default', async () => { + const codeRun = vi.fn().mockResolvedValue( + envelope({ + status: 'done', + success: true, + value: null, + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + timeout: 10_000, + }) + const context = await driver.createContext({ + bindings: {}, + timeout: 2500, + }) + + await context.execute('return 1') + + expect(codeRun.mock.calls[0]![2]).toBe(3) + }) + + it('executes host tools locally and replays accumulated tool results', async () => { + const add = makeBinding('add', async (args: unknown) => { + const { a, b } = args as { a: number; b: number } + return a + b + }) + const getLabel = makeBinding('getLabel', async () => 'total') + const codeRun = vi + .fn() + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'add', args: { a: 2, b: 3 } }], + logs: ['before add'], + }), + ) + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_1', name: 'getLabel', args: {} }], + logs: ['before add', 'before label'], + }), + ) + .mockResolvedValueOnce( + envelope({ + status: 'done', + success: true, + value: { label: 'total', value: 5 }, + logs: ['before add', 'before label', 'done'], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ + bindings: { add, getLabel }, + }) + + const result = await context.execute( + 'const value = await add({ a: 2, b: 3 }); const label = await getLabel({}); return { label, value }', + ) + + expect(result.success).toBe(true) + expect(result.value).toEqual({ label: 'total', value: 5 }) + expect(result.logs).toEqual(['before add', 'before label', 'done']) + expect(codeRun).toHaveBeenCalledTimes(3) + + const secondRoundCode = codeRun.mock.calls[1]![0] + const thirdRoundCode = codeRun.mock.calls[2]![0] + expect(secondRoundCode).toContain('"tc_0":{"success":true,"value":5}') + expect(thirdRoundCode).toContain('"tc_0":{"success":true,"value":5}') + expect(thirdRoundCode).toContain('"tc_1":{"success":true,"value":"total"}') + }) + + it('returns tool errors to the sandbox protocol', async () => { + const failTool = makeBinding('failTool', async () => { + throw new Error('Tool failed') + }) + const codeRun = vi + .fn() + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'failTool', args: {} }], + logs: [], + }), + ) + .mockResolvedValueOnce( + envelope({ + status: 'done', + success: false, + error: { name: 'Error', message: 'Tool call failed' }, + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ + bindings: { failTool }, + }) + + const result = await context.execute('return await failTool({})') + + expect(result.success).toBe(false) + expect(result.error?.message).toBe('Tool call failed') + expect(codeRun.mock.calls[1]![0]).toContain( + '"tc_0":{"success":false,"error":"Tool failed"}', + ) + }) + + it('returns unknown tool names to the sandbox protocol', async () => { + const codeRun = vi + .fn() + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'unknownTool', args: {} }], + logs: [], + }), + ) + .mockResolvedValueOnce( + envelope({ + status: 'done', + success: false, + error: { name: 'Error', message: 'Tool result not found' }, + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + await context.execute('return await unknownTool({})') + + expect(codeRun.mock.calls[1]![0]).toContain( + '"tc_0":{"success":false,"error":"Unknown tool: unknownTool"}', + ) + }) + + it('executes same-round tool calls concurrently and merges results atomically', async () => { + const events: Array = [] + let resolveSlow: (value: string) => void = () => {} + const slowReady = new Promise((resolve) => { + resolveSlow = resolve + }) + const slow = makeBinding('slow', async () => { + events.push('slow:start') + return slowReady + }) + const fast = makeBinding('fast', async () => { + events.push('fast:start') + return 'fast' + }) + const codeRun = vi + .fn() + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [ + { id: 'tc_0', name: 'slow', args: {} }, + { id: 'tc_1', name: 'fast', args: {} }, + ], + logs: [], + }), + ) + .mockResolvedValueOnce( + envelope({ + status: 'done', + success: true, + value: 'done', + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ + bindings: { slow, fast }, + }) + + const resultPromise = context.execute( + 'return await Promise.all([slow({}), fast({})])', + ) + + for (let index = 0; index < 10 && events.length < 2; index++) { + await Promise.resolve() + } + expect(events).toEqual(['slow:start', 'fast:start']) + + resolveSlow('slow') + const result = await resultPromise + + expect(result.success).toBe(true) + expect(codeRun.mock.calls[1]![0]).toContain( + '"tc_0":{"success":true,"value":"slow"}', + ) + expect(codeRun.mock.calls[1]![0]).toContain( + '"tc_1":{"success":true,"value":"fast"}', + ) + }) + + it('treats prototype property tool names as unknown tools', async () => { + const codeRun = vi + .fn() + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'toString', args: {} }], + logs: [], + }), + ) + .mockResolvedValueOnce( + envelope({ + status: 'done', + success: false, + error: { name: 'Error', message: 'Tool result not found' }, + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + await context.execute('return await toString({})') + + expect(codeRun.mock.calls[1]![0]).toContain( + '"tc_0":{"success":false,"error":"Unknown tool: toString"}', + ) + }) + + it('rejects invalid tool call ids from the sandbox boundary', async () => { + const add = makeBinding('add', async () => 1) + const codeRun = vi.fn().mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: '__proto__', name: 'add', args: {} }], + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ + bindings: { add }, + }) + + const result = await context.execute('return await add({})') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain('Invalid Daytona tool call id') + expect(codeRun).toHaveBeenCalledTimes(1) + }) + + it('rejects duplicate tool call ids in one sandbox response', async () => { + const add = makeBinding('add', async () => 1) + const codeRun = vi.fn().mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [ + { id: 'tc_0', name: 'add', args: {} }, + { id: 'tc_0', name: 'add', args: {} }, + ], + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ + bindings: { add }, + }) + + const result = await context.execute('return await add({})') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain('Duplicate Daytona tool call id') + expect(codeRun).toHaveBeenCalledTimes(1) + }) + + it('rejects empty need_tools responses before executing host tools', async () => { + const execute = vi.fn().mockResolvedValue(1) + const add = makeBinding('add', execute) + const codeRun = vi.fn().mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [], + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ + bindings: { add }, + }) + + const result = await context.execute('return await add({})') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain( + 'Daytona need_tools response must include tool calls', + ) + expect(execute).not.toHaveBeenCalled() + }) + + it('rejects gapped tool call ids before executing host tools', async () => { + const execute = vi.fn().mockResolvedValue(1) + const add = makeBinding('add', execute) + const codeRun = vi.fn().mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_1', name: 'add', args: {} }], + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ + bindings: { add }, + }) + + const result = await context.execute('return await add({})') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain( + 'Daytona tool call ids must be contiguous from tc_0', + ) + expect(execute).not.toHaveBeenCalled() + }) + + it('rejects out-of-order tool call ids before executing host tools', async () => { + const execute = vi.fn().mockResolvedValue(1) + const add = makeBinding('add', execute) + const codeRun = vi.fn().mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [ + { id: 'tc_1', name: 'add', args: {} }, + { id: 'tc_0', name: 'add', args: {} }, + ], + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ + bindings: { add }, + }) + + const result = await context.execute( + 'return await Promise.all([add({}), add({})])', + ) + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain( + 'Daytona tool call ids must be contiguous from tc_0', + ) + expect(execute).not.toHaveBeenCalled() + }) + + it('rejects tool call ids that already have cached results', async () => { + const add = makeBinding('add', async () => 1) + const codeRun = vi + .fn() + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'add', args: {} }], + logs: [], + }), + ) + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'add', args: {} }], + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ + bindings: { add }, + }) + + const result = await context.execute('return await add({})') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain( + 'Daytona tool call id already has a cached result', + ) + expect(codeRun).toHaveBeenCalledTimes(2) + }) + + it('allows one tool callback round plus final replay when maxToolRounds is 1', async () => { + const add = makeBinding('add', async () => 5) + const codeRun = vi + .fn() + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'add', args: {} }], + logs: ['need add'], + }), + ) + .mockResolvedValueOnce( + envelope({ + status: 'done', + success: true, + value: 5, + logs: ['need add', 'done'], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + maxToolRounds: 1, + }) + const context = await driver.createContext({ + bindings: { add }, + }) + + const result = await context.execute('return await add({})') + + expect(result.success).toBe(true) + expect(result.value).toBe(5) + expect(result.logs).toEqual(['need add', 'done']) + expect(codeRun).toHaveBeenCalledTimes(2) + }) + + it('returns MaxRoundsExceeded when sandbox keeps requesting tools', async () => { + const add = makeBinding('add', async () => 1) + const codeRun = vi + .fn() + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'add', args: {} }], + logs: [], + }), + ) + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_1', name: 'add', args: {} }], + logs: [], + }), + ) + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_2', name: 'add', args: {} }], + logs: [], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + maxToolRounds: 2, + }) + const context = await driver.createContext({ + bindings: { add }, + }) + + const result = await context.execute('return await add({})') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('MaxRoundsExceeded') + expect(result.error?.message).toContain('2') + expect(codeRun).toHaveBeenCalledTimes(3) + }) + + it('uses the latest replay log snapshot instead of appending duplicates', async () => { + const add = makeBinding('add', async () => 1) + const codeRun = vi + .fn() + .mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'add', args: {} }], + logs: ['before'], + }), + ) + .mockResolvedValueOnce( + envelope({ + status: 'done', + success: true, + value: 1, + logs: ['before', 'after'], + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ + bindings: { add }, + }) + + const result = await context.execute('return await add({})') + + expect(result.success).toBe(true) + expect(result.logs).toEqual(['before', 'after']) + }) + + it('does not execute tools or replay when disposed after codeRun resolves', async () => { + let resolveCodeRun: (value: DaytonaCodeRunResponse) => void = () => {} + const firstCodeRun = new Promise((resolve) => { + resolveCodeRun = resolve + }) + const codeRun = vi.fn().mockReturnValueOnce(firstCodeRun) + const execute = vi.fn().mockResolvedValue(1) + const add = makeBinding('add', execute) + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ + bindings: { add }, + }) + + const executePromise = context.execute('return await add({})') + await context.dispose() + resolveCodeRun( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'add', args: {} }], + logs: ['before add'], + }), + ) + + const result = await executePromise + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DisposedError') + expect(result.logs).toEqual(['before add']) + expect(execute).not.toHaveBeenCalled() + expect(codeRun).toHaveBeenCalledTimes(1) + }) + + it('returns timeout instead of replaying after host tools exceed the budget', async () => { + let resolveTool: (value: number) => void = () => {} + const toolResult = new Promise((resolve) => { + resolveTool = resolve + }) + const add = makeBinding('add', async () => toolResult) + const codeRun = vi.fn().mockResolvedValueOnce( + envelope({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'add', args: {} }], + logs: ['before'], + }), + ) + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + timeout: 1, + }) + const context = await driver.createContext({ + bindings: { add }, + }) + + const result = await context.execute('return await add({})') + resolveTool(1) + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('TimeoutError') + expect(codeRun).toHaveBeenCalledTimes(1) + }) + + it('returns timeout when codeRun exceeds the millisecond execution budget', async () => { + let resolveCodeRun: (value: DaytonaCodeRunResponse) => void = () => {} + const slowCodeRun = new Promise((resolve) => { + resolveCodeRun = resolve + }) + const codeRun = vi.fn().mockReturnValueOnce(slowCodeRun) + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + timeout: 1, + }) + const context = await driver.createContext({ + bindings: {}, + }) + + const result = await context.execute('return 1') + resolveCodeRun( + envelope({ + status: 'done', + success: true, + value: 1, + logs: [], + }), + ) + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('TimeoutError') + expect(codeRun).toHaveBeenCalledTimes(1) + }) + + it('returns wrapper status errors as execution errors', async () => { + const codeRun = vi.fn().mockResolvedValue( + envelope({ + status: 'error', + error: { + name: 'WrapperError', + message: 'wrapper failed', + }, + }), + ) + + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('return 1') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('WrapperError') + expect(result.error?.message).toBe('wrapper failed') + }) + + it('rejects success envelopes that include errors', async () => { + const codeRun = vi.fn().mockResolvedValue({ + exitCode: 0, + result: `${DAYTONA_RESULT_MARKER}${JSON.stringify({ + status: 'done', + success: true, + value: 1, + error: { name: 'Error', message: 'impossible' }, + logs: [], + })}`, + }) + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('return 1') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain( + 'Daytona success envelope must not include error', + ) + }) + + it('rejects failure envelopes without errors', async () => { + const codeRun = vi.fn().mockResolvedValue({ + exitCode: 0, + result: `${DAYTONA_RESULT_MARKER}${JSON.stringify({ + status: 'done', + success: false, + logs: [], + })}`, + }) + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('return 1') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain( + "Daytona envelope field 'error' must be an object", + ) + }) + + it('rejects failure envelopes that include values', async () => { + const codeRun = vi.fn().mockResolvedValue({ + exitCode: 0, + result: `${DAYTONA_RESULT_MARKER}${JSON.stringify({ + status: 'done', + success: false, + value: 1, + error: { name: 'Error', message: 'failed' }, + logs: [], + })}`, + }) + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('return 1') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain( + 'Daytona failure envelope must not include value', + ) + }) + + it('returns DaytonaExecutionError when codeRun throws', async () => { + const codeRun = vi.fn().mockRejectedValue(new Error('sandbox unavailable')) + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('return 1') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain('sandbox unavailable') + }) + + it('normalizes thrown circular objects without throwing again', async () => { + const circular: { self?: unknown } = {} + circular.self = circular + const codeRun = vi.fn().mockRejectedValue(circular) + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('return 1') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain( + 'Failed to execute code in Daytona sandbox: Error', + ) + }) + + it('returns DaytonaExecutionError when the marker is missing', async () => { + const codeRun = vi.fn().mockResolvedValue({ + exitCode: 0, + result: 'ordinary stdout', + artifacts: { stdout: 'ordinary stdout' }, + }) + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('return 1') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DaytonaExecutionError') + expect(result.error?.message).toContain('Code Mode marker') + }) + + it('does not call Daytona after dispose', async () => { + const codeRun = vi.fn() + const driver = createDaytonaIsolateDriver({ + sandbox: makeSandbox(codeRun), + }) + const context = await driver.createContext({ bindings: {} }) + + await context.dispose() + const result = await context.execute('return 1') + + expect(result.success).toBe(false) + expect(result.error?.name).toBe('DisposedError') + expect(codeRun).not.toHaveBeenCalled() + }) +}) diff --git a/packages/ai-isolate-daytona/tests/live.test.ts b/packages/ai-isolate-daytona/tests/live.test.ts new file mode 100644 index 000000000..4e10526b0 --- /dev/null +++ b/packages/ai-isolate-daytona/tests/live.test.ts @@ -0,0 +1,537 @@ +import { CodeLanguage, Daytona } from '@daytona/sdk' +import { describe, expect, it } from 'vitest' +import { createDaytonaIsolateDriver } from '../src/isolate-driver' +import { DAYTONA_RESULT_MARKER } from '../src/wrap-code' +import type { ToolBinding } from '@tanstack/ai-code-mode' +import type { + DaytonaCodeRunParams, + DaytonaCodeRunResponse, + DaytonaExecutionEnvelope, + DaytonaSandboxLike, +} from '../src/types' + +const liveEnabled = + process.env.DAYTONA_LIVE_TEST === '1' && + process.env.DAYTONA_API_KEY !== undefined && + process.env.DAYTONA_API_KEY.length > 0 + +const CREATE_TIMEOUT_SECONDS = 90 +const DELETE_TIMEOUT_SECONDS = 60 +const CODE_RUN_TIMEOUT_MS = 30_000 + +type LiveSandbox = Awaited> + +interface RawCodeRunCall { + code: string + params?: DaytonaCodeRunParams | undefined + timeoutSeconds?: number | undefined + response?: DaytonaCodeRunResponse | undefined +} + +interface InstrumentedSandbox { + sandbox: DaytonaSandboxLike + calls: Array +} + +interface CleanupReport { + attempted: boolean + succeeded: boolean +} + +interface SandboxRunReport { + result?: T | undefined + error?: unknown + cleanup: CleanupReport +} + +function outputFromResponse(response: DaytonaCodeRunResponse): string { + return response.artifacts?.stdout ?? response.result ?? '' +} + +function parseRawEnvelope( + response: DaytonaCodeRunResponse, +): DaytonaExecutionEnvelope { + const markerLine = outputFromResponse(response) + .split(/\r?\n/) + .reverse() + .find((line) => line.startsWith(DAYTONA_RESULT_MARKER)) + + if (!markerLine) { + throw new Error('raw Daytona response did not include the marker envelope') + } + + const jsonStart = markerLine.indexOf('{', DAYTONA_RESULT_MARKER.length) + if (jsonStart === -1) { + throw new Error('raw Daytona marker line did not include a JSON envelope') + } + + return JSON.parse(markerLine.slice(jsonStart)) as DaytonaExecutionEnvelope +} + +function hasMarker(response: DaytonaCodeRunResponse): boolean { + return [response.artifacts?.stdout, response.result].some( + (value) => value?.includes(DAYTONA_RESULT_MARKER) === true, + ) +} + +function instrumentSandbox(sandbox: LiveSandbox): InstrumentedSandbox { + const calls: Array = [] + + return { + calls, + sandbox: { + process: { + codeRun: async (code, params, timeoutSeconds) => { + const call: RawCodeRunCall = { code, params, timeoutSeconds } + calls.push(call) + const response = (await sandbox.process.codeRun( + code, + params, + timeoutSeconds, + )) as DaytonaCodeRunResponse + call.response = response + return response + }, + }, + }, + } +} + +function makeBinding( + name: string, + execute: (args: unknown) => Promise, +): ToolBinding { + return { + name, + description: `${name} live test tool`, + inputSchema: { type: 'object', additionalProperties: true }, + execute, + } +} + +function expectSuccess(result: { + success: boolean + value?: T + error?: { name: string; message: string } +}): T { + expect(result.error?.message).toBeUndefined() + expect(result.success).toBe(true) + return result.value as T +} + +function uniqueSandboxName(language: CodeLanguage): string { + const suffix = Math.random().toString(36).slice(2, 8) + return `tanstack-ai-live-${language}-${Date.now()}-${suffix}` +} + +async function captureWithLiveSandbox( + language: CodeLanguage, + callback: (sandbox: LiveSandbox) => Promise, +): Promise> { + const daytona = new Daytona() + const cleanup: CleanupReport = { attempted: false, succeeded: false } + let sandbox: LiveSandbox | undefined + let result: T | undefined + let error: unknown + + try { + sandbox = await daytona.create( + { + language, + name: uniqueSandboxName(language), + labels: { + package: 'tanstack-ai-isolate-daytona', + test: 'live-harness', + }, + ephemeral: true, + autoStopInterval: 5, + }, + { timeout: CREATE_TIMEOUT_SECONDS }, + ) + result = await callback(sandbox) + } catch (caught) { + error = caught + } finally { + if (sandbox !== undefined) { + cleanup.attempted = true + await sandbox.delete(DELETE_TIMEOUT_SECONDS) + cleanup.succeeded = true + } + } + + return { result, error, cleanup } +} + +async function withLiveSandbox( + language: CodeLanguage, + callback: (sandbox: LiveSandbox) => Promise, +): Promise<{ result: T; cleanup: CleanupReport }> { + const report = await captureWithLiveSandbox(language, callback) + expect(report.cleanup.attempted).toBe(true) + expect(report.cleanup.succeeded).toBe(true) + if (report.error !== undefined) { + throw report.error + } + return { result: report.result as T, cleanup: report.cleanup } +} + +async function runLanguageSmoke(language: CodeLanguage): Promise { + await withLiveSandbox(language, async (liveSandbox) => { + const instrumented = instrumentSandbox(liveSandbox) + const add = makeBinding('external_add', (args) => { + const input = args as { a: number; b: number } + return Promise.resolve(input.a + input.b) + }) + const driver = createDaytonaIsolateDriver({ + sandbox: instrumented.sandbox, + timeout: CODE_RUN_TIMEOUT_MS, + }) + const context = await driver.createContext({ + bindings: { external_add: add }, + }) + + const smoke = await context.execute('return 42') + expectSuccess(smoke) + expect(smoke.value).toBe(42) + expect(instrumented.calls[0]?.response).toBeDefined() + expect(hasMarker(instrumented.calls[0]!.response!)).toBe(true) + + const toolResult = await context.execute( + 'return await external_add({ a: 20, b: 22 })', + ) + expectSuccess(toolResult) + expect(toolResult.value).toBe(42) + expect(instrumented.calls.at(-1)?.code).toContain('"tc_0"') + }) +} + +describe('Daytona live harness gate', () => { + it.skipIf(liveEnabled)( + 'does not run live Daytona scenarios without explicit credentials', + () => { + expect(liveEnabled).toBe(false) + }, + ) +}) + +describe.skipIf(!liveEnabled)( + 'Daytona live Code Mode harness', + () => { + it('executes TypeScript Code Mode programs and tool replay against real Daytona', async () => { + await withLiveSandbox(CodeLanguage.TYPESCRIPT, async (liveSandbox) => { + const instrumented = instrumentSandbox(liveSandbox) + const capturedArgs: Array = [] + const externalAdd = makeBinding('external_add', (args) => { + const input = args as { a: number; b: number } + return Promise.resolve(input.a + input.b) + }) + const externalA = makeBinding('external_a', (args) => { + capturedArgs.push(args) + return Promise.resolve('A') + }) + const externalB = makeBinding('external_b', () => Promise.resolve('B')) + const externalEchoArgs = makeBinding('external_echoArgs', (args) => { + capturedArgs.push(args) + return Promise.resolve(args) + }) + const externalPayload = makeBinding('external_payload', () => + Promise.resolve({ + nested: { ok: true, list: [1, 'two', null] }, + text: 'line 1\nline 2 "quoted" unicode snowman', + }), + ) + const externalFail = makeBinding('external_fail', () => + Promise.reject(new Error('host tool exploded')), + ) + const bindings = { + external_add: externalAdd, + external_a: externalA, + external_b: externalB, + external_echoArgs: externalEchoArgs, + external_payload: externalPayload, + external_fail: externalFail, + } + const driver = createDaytonaIsolateDriver({ + sandbox: instrumented.sandbox, + timeout: CODE_RUN_TIMEOUT_MS, + }) + const context = await driver.createContext({ bindings }) + + const simple = await context.execute('return 42') + expect(simple.success).toBe(true) + expect(simple.value).toBe(42) + + const firstRawResponse = instrumented.calls[0]?.response + expect(firstRawResponse).toBeDefined() + expect(hasMarker(firstRawResponse!)).toBe(true) + expect(parseRawEnvelope(firstRawResponse!).status).toBe('done') + + const consoleResult = await context.execute(` + console.log('log line', { count: 1 }); + console.warn('warn line'); + console.error('error line'); + return 'console-ok'; + `) + expect(consoleResult.success).toBe(true) + expect(consoleResult.value).toBe('console-ok') + expect(consoleResult.logs).toEqual([ + 'log line {"count":1}', + 'WARN: warn line', + 'ERROR: error line', + ]) + + const asyncResult = await context.execute>(` + const one = await Promise.resolve(1); + const two = await new Promise((resolve) => setTimeout(() => resolve(2), 10)); + const rest = await Promise.all([Promise.resolve(3), Promise.resolve(4)]); + return [one, two, ...rest]; + `) + expect(asyncResult.success).toBe(true) + expect(asyncResult.value).toEqual([1, 2, 3, 4]) + + const oneTool = await context.execute( + 'return await external_add({ a: 19, b: 23 })', + ) + expect(oneTool.success).toBe(true) + expect(oneTool.value).toBe(42) + + const beforeSequential = instrumented.calls.length + const sequential = await context.execute(` + const first = await external_add({ a: 1, b: 2 }); + const second = await external_add({ a: first, b: 4 }); + return second; + `) + expect(sequential.success).toBe(true) + expect(sequential.value).toBe(7) + const sequentialCalls = instrumented.calls.slice(beforeSequential) + expect(sequentialCalls).toHaveLength(3) + expect(sequentialCalls[1]?.code).toContain('"tc_0"') + expect(sequentialCalls[1]?.code).not.toContain('"tc_1"') + expect(sequentialCalls[2]?.code).toContain('"tc_0"') + expect(sequentialCalls[2]?.code).toContain('"tc_1"') + + const beforeBatch = instrumented.calls.length + const batch = await context.execute>(` + return await Promise.all([ + external_a({ label: 'left' }), + external_b({ label: 'right' }), + ]); + `) + expect(batch.success).toBe(true) + expect(batch.value).toEqual(['A', 'B']) + const batchEnvelope = parseRawEnvelope( + instrumented.calls[beforeBatch]!.response!, + ) + expect(batchEnvelope.status).toBe('need_tools') + if (batchEnvelope.status === 'need_tools') { + expect(batchEnvelope.toolCalls.map((call) => call.id)).toEqual([ + 'tc_0', + 'tc_1', + ]) + expect(batchEnvelope.toolCalls.map((call) => call.name)).toEqual([ + 'external_a', + 'external_b', + ]) + } + expect(instrumented.calls[beforeBatch + 1]?.code).toContain('"tc_0"') + expect(instrumented.calls[beforeBatch + 1]?.code).toContain('"tc_1"') + + const serializedArgs = { + nested: { quotes: '"hello"', newline: 'a\nb', unicode: 'snowman' }, + array: [1, true, null, { ok: false }], + } + const argsResult = await context.execute( + `return await external_echoArgs(${JSON.stringify(serializedArgs)})`, + ) + expect(argsResult.success).toBe(true) + expect(argsResult.value).toEqual(serializedArgs) + expect(capturedArgs).toContainEqual(serializedArgs) + + const payloadResult = await context.execute<{ + nested: { ok: boolean; list: Array } + text: string + }>('return await external_payload({})') + expect(payloadResult.success).toBe(true) + expect(payloadResult.value).toEqual({ + nested: { ok: true, list: [1, 'two', null] }, + text: 'line 1\nline 2 "quoted" unicode snowman', + }) + + const beforeToolError = instrumented.calls.length + const toolError = await context.execute( + 'return await external_fail({})', + ) + expect(toolError.success).toBe(false) + expect(toolError.error?.message).toContain('host tool exploded') + expect(instrumented.calls[beforeToolError + 1]?.code).toContain( + '"success":false', + ) + expect(instrumented.calls[beforeToolError + 1]?.code).toContain( + 'host tool exploded', + ) + + const stdoutNoise = await context.execute(` + globalThis.console.log('stdout noise before marker'); + return 'noise-ok'; + `) + expect(stdoutNoise.success).toBe(true) + expect(stdoutNoise.value).toBe('noise-ok') + + const markerValue = `${DAYTONA_RESULT_MARKER} inside returned value` + const markerResult = await context.execute( + `return ${JSON.stringify(markerValue)}`, + ) + expect(markerResult.success).toBe(true) + expect(markerResult.value).toBe(markerValue) + + const runtimeError = await context.execute(` + console.log('before boom'); + throw new TypeError('boom'); + `) + expect(runtimeError.success).toBe(false) + expect(runtimeError.error?.name).toBe('TypeError') + expect(runtimeError.error?.message).toBe('boom') + expect(runtimeError.logs).toEqual(['before boom']) + + const syntaxError = await context.execute('const broken = ;') + expect(syntaxError.success).toBe(false) + expect(syntaxError.error?.message).toMatch( + /Code Mode marker|Failed to execute code in Daytona sandbox/, + ) + + const beforeFreshExecute = instrumented.calls.length + const firstFresh = await context.execute( + 'return await external_add({ a: 1, b: 1 })', + ) + const secondFresh = await context.execute( + 'return await external_add({ a: 2, b: 2 })', + ) + expect(firstFresh.success).toBe(true) + expect(secondFresh.success).toBe(true) + const freshCalls = instrumented.calls.slice(beforeFreshExecute) + expect(freshCalls[0]?.code).toContain('const __toolResults = {};') + const firstFreshEnvelope = parseRawEnvelope(freshCalls[0]!.response!) + expect(firstFreshEnvelope.status).toBe('need_tools') + if (firstFreshEnvelope.status === 'need_tools') { + expect(firstFreshEnvelope.toolCalls.map((call) => call.id)).toEqual([ + 'tc_0', + ]) + } + expect(freshCalls[2]?.code).toContain('const __toolResults = {};') + expect(freshCalls[2]?.code).not.toContain('"tc_0"') + const secondFreshEnvelope = parseRawEnvelope(freshCalls[2]!.response!) + expect(secondFreshEnvelope.status).toBe('need_tools') + if (secondFreshEnvelope.status === 'need_tools') { + expect(secondFreshEnvelope.toolCalls.map((call) => call.id)).toEqual([ + 'tc_0', + ]) + } + + const beforeDispose = instrumented.calls.length + await context.dispose() + const disposed = await context.execute('return 1') + expect(disposed.success).toBe(false) + expect(disposed.error?.name).toBe('DisposedError') + expect(instrumented.calls).toHaveLength(beforeDispose) + }) + }, 180_000) + + it('counts maxToolRounds as callback rounds, not total codeRun calls', async () => { + await withLiveSandbox(CodeLanguage.TYPESCRIPT, async (liveSandbox) => { + const instrumented = instrumentSandbox(liveSandbox) + const externalAdd = makeBinding('external_add', (args) => { + const input = args as { a: number; b: number } + return Promise.resolve(input.a + input.b) + }) + const driver = createDaytonaIsolateDriver({ + sandbox: instrumented.sandbox, + timeout: CODE_RUN_TIMEOUT_MS, + maxToolRounds: 1, + }) + const context = await driver.createContext({ + bindings: { external_add: externalAdd }, + }) + + const oneRound = await context.execute( + 'return await external_add({ a: 20, b: 22 })', + ) + expect(oneRound.success).toBe(true) + expect(oneRound.value).toBe(42) + + const beforeTwoRound = instrumented.calls.length + const twoRounds = await context.execute(` + const first = await external_add({ a: 1, b: 1 }); + return await external_add({ a: first, b: 1 }); + `) + expect(twoRounds.success).toBe(false) + expect(twoRounds.error?.name).toBe('MaxRoundsExceeded') + expect(instrumented.calls.slice(beforeTwoRound)).toHaveLength(2) + }) + }, 120_000) + + it('returns a clear failure when Daytona codeRun times out', async () => { + await withLiveSandbox(CodeLanguage.TYPESCRIPT, async (liveSandbox) => { + const instrumented = instrumentSandbox(liveSandbox) + const driver = createDaytonaIsolateDriver({ + sandbox: instrumented.sandbox, + timeout: 1000, + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute(` + await new Promise((resolve) => setTimeout(resolve, 10_000)); + return 'late'; + `) + + expect(instrumented.calls[0]?.timeoutSeconds).toBe(1) + expect(result.success).toBe(false) + expect(result.error?.name).toBe('TimeoutError') + expect(result.error?.message).toMatch(/timeout|timed out|execute/i) + }) + }, 90_000) + + it('reports wrong sandbox language execution without a marker-shaped success', async () => { + await withLiveSandbox(CodeLanguage.PYTHON, async (liveSandbox) => { + const instrumented = instrumentSandbox(liveSandbox) + const driver = createDaytonaIsolateDriver({ + sandbox: instrumented.sandbox, + timeout: CODE_RUN_TIMEOUT_MS, + }) + const context = await driver.createContext({ bindings: {} }) + + const result = await context.execute('return 42') + + expect(result.success).toBe(false) + expect(result.error?.message).toMatch( + /Code Mode marker|Failed to execute code in Daytona sandbox/, + ) + }) + }, 120_000) + + it('always deletes live sandboxes after passing and failing callbacks', async () => { + const passing = await captureWithLiveSandbox( + CodeLanguage.TYPESCRIPT, + async (sandbox) => { + await sandbox.process.codeRun('console.log("cleanup pass")') + return 'passed' + }, + ) + expect(passing.error).toBeUndefined() + expect(passing.result).toBe('passed') + expect(passing.cleanup).toEqual({ attempted: true, succeeded: true }) + + const failing = await captureWithLiveSandbox( + CodeLanguage.TYPESCRIPT, + () => Promise.reject(new Error('forced cleanup failure path')), + ) + expect(failing.error).toBeInstanceOf(Error) + expect(failing.cleanup).toEqual({ attempted: true, succeeded: true }) + }, 180_000) + + it('keeps the README language claims honest for TypeScript and JavaScript', async () => { + await runLanguageSmoke(CodeLanguage.TYPESCRIPT) + await runLanguageSmoke(CodeLanguage.JAVASCRIPT) + }, 180_000) + }, + 300_000, +) diff --git a/packages/ai-isolate-daytona/tests/wrap-code.test.ts b/packages/ai-isolate-daytona/tests/wrap-code.test.ts new file mode 100644 index 000000000..b82c38d71 --- /dev/null +++ b/packages/ai-isolate-daytona/tests/wrap-code.test.ts @@ -0,0 +1,275 @@ +import { createContext, runInContext } from 'node:vm' +import { describe, expect, it } from 'vitest' +import { + DAYTONA_RESULT_MARKER, + generateToolWrappers, + wrapCode, +} from '../src/wrap-code' +import type { + DaytonaExecutionEnvelope, + ToolResultPayload, + ToolSchema, +} from '../src/types' + +function isPromiseLike(value: unknown): value is PromiseLike { + return ( + typeof value === 'object' && + value !== null && + 'then' in value && + typeof value.then === 'function' + ) +} + +async function runWrappedCode( + code: string, + tools: Array = [], + toolResults?: Record, +): Promise { + const output: Array = [] + const context = createContext({ + console: { + log: (value: unknown) => output.push(String(value)), + }, + }) + + const result: unknown = runInContext( + wrapCode(code, tools, toolResults), + context, + ) + if (isPromiseLike(result)) { + await result + } + + const markedOutput = output.find((line) => + line.startsWith(DAYTONA_RESULT_MARKER), + ) + if (!markedOutput) { + throw new Error('wrapped code did not emit Daytona marker') + } + + return JSON.parse( + markedOutput.slice(DAYTONA_RESULT_MARKER.length), + ) as DaytonaExecutionEnvelope +} + +describe('generateToolWrappers', () => { + const tools: Array = [ + { name: 'add', description: 'Add numbers', inputSchema: {} }, + { name: 'fetchData', description: 'Fetch data', inputSchema: {} }, + ] + + it('generates first-pass wrappers that collect missing tool calls', () => { + const code = generateToolWrappers(tools) + expect(code).toContain('async function add(input)') + expect(code).toContain("__pendingToolCalls.push({ id: callId, name: 'add'") + expect(code).toContain('__ToolCallNeeded') + expect(code).toContain('async function fetchData(input)') + }) + + it('generates wrappers that return cached results when present', () => { + const code = generateToolWrappers(tools) + expect(code).toContain('const result = __toolResults[callId]') + expect(code).toContain('result.success') + expect(code).toContain('return result.value') + }) + + it('rejects unsafe tool names', () => { + const invalid = [ + 'has space', + 'with`backtick', + "with'quote", + 'with"quote', + 'with;semi', + 'with\nnewline', + '123tool', + 'return', + 'class', + 'await', + ] + + for (const name of invalid) { + expect(() => + generateToolWrappers([{ name, description: '', inputSchema: {} }]), + ).toThrow(/Invalid tool name/) + } + }) + + it('accepts conventional JavaScript identifiers', () => { + const valid = ['camelCase', 'snake_case', '_leading', '$dollar'] + + for (const name of valid) { + expect(() => + generateToolWrappers([{ name, description: '', inputSchema: {} }]), + ).not.toThrow() + } + }) +}) + +describe('wrapCode', () => { + it('prints a marked JSON envelope instead of relying on codeRun return value', () => { + const wrapped = wrapCode('return 1 + 1', []) + expect(wrapped).toContain(DAYTONA_RESULT_MARKER) + expect(wrapped).toContain('__hostConsole.log') + expect(wrapped).toContain("status: 'done'") + expect(wrapped).toContain('return 1 + 1') + }) + + it('includes cached tool results for replay rounds', () => { + const wrapped = wrapCode( + 'return await add({ a: 2, b: 3 })', + [{ name: 'add', description: 'Add numbers', inputSchema: {} }], + { tc_0: { success: true, value: 5 } }, + ) + + expect(wrapped).toContain('"tc_0"') + expect(wrapped).toContain('"success":true') + expect(wrapped).toContain('"value":5') + }) + + it('captures user console output in the protocol logs', () => { + const wrapped = wrapCode('console.log("hello")', []) + expect(wrapped).toContain('const console =') + expect(wrapped).toContain('__logs.push') + expect(wrapped).toContain('logs: __logs') + }) + + it('executes wrapped code and emits a done envelope', async () => { + const envelope = await runWrappedCode('return 1 + 1') + + expect(envelope).toEqual({ + status: 'done', + success: true, + value: 2, + logs: [], + }) + }) + + it('captures console output in an executable wrapper', async () => { + const envelope = await runWrappedCode(` + console.log("hello", { target: "world" }); + console.warn("careful"); + return "ok"; + `) + + expect(envelope.status).toBe('done') + if (envelope.status === 'done') { + expect(envelope.logs).toEqual([ + 'hello {"target":"world"}', + 'WARN: careful', + ]) + } + }) + + it('does not fail execution when console arguments cannot JSON serialize', async () => { + const envelope = await runWrappedCode(` + const circular = {}; + circular.self = circular; + console.log("circular", circular); + console.info("bigint", 1n); + return "ok"; + `) + + expect(envelope.status).toBe('done') + if (envelope.status === 'done') { + expect(envelope.success).toBe(true) + expect(envelope.logs).toEqual([ + 'circular [object Object]', + 'INFO: bigint 1', + ]) + } + }) + + it('normalizes non-Error thrown values in the failure envelope', async () => { + const nullEnvelope = await runWrappedCode('throw null') + const undefinedEnvelope = await runWrappedCode('throw undefined') + const stringEnvelope = await runWrappedCode('throw "boom"') + + expect(nullEnvelope).toMatchObject({ + status: 'done', + success: false, + error: { name: 'Error', message: 'null' }, + }) + expect(undefinedEnvelope).toMatchObject({ + status: 'done', + success: false, + error: { name: 'Error', message: 'undefined' }, + }) + expect(stringEnvelope).toMatchObject({ + status: 'done', + success: false, + error: { name: 'Error', message: 'boom' }, + }) + }) + + it('emits need_tools for missing tool results', async () => { + const envelope = await runWrappedCode('return await add({ a: 2, b: 3 })', [ + { name: 'add', description: 'Add numbers', inputSchema: {} }, + ]) + + expect(envelope).toEqual({ + status: 'need_tools', + toolCalls: [{ id: 'tc_0', name: 'add', args: { a: 2, b: 3 } }], + logs: [], + }) + }) + + it('replays successful cached tool results', async () => { + const envelope = await runWrappedCode( + 'return await add({ a: 2, b: 3 })', + [{ name: 'add', description: 'Add numbers', inputSchema: {} }], + { tc_0: { success: true, value: 5 } }, + ) + + expect(envelope).toEqual({ + status: 'done', + success: true, + value: 5, + logs: [], + }) + }) + + it('replays failed cached tool results as execution errors', async () => { + const envelope = await runWrappedCode( + 'return await add({ a: 2, b: 3 })', + [{ name: 'add', description: 'Add numbers', inputSchema: {} }], + { tc_0: { success: false, error: 'Tool failed' } }, + ) + + expect(envelope.status).toBe('done') + if (envelope.status === 'done') { + expect(envelope.success).toBe(false) + expect(envelope.error?.message).toBe('Tool failed') + } + }) + + it('emits an outer error envelope when the result marker cannot serialize', async () => { + const envelope = await runWrappedCode(` + const value = {}; + value.self = value; + return value; + `) + + expect(envelope.status).toBe('error') + if (envelope.status === 'error') { + expect(envelope.error.message).toContain('circular') + } + }) + + it('normalizes non-Error outer serialization failures', async () => { + const envelope = await runWrappedCode(` + return { + toJSON() { + throw null; + } + }; + `) + + expect(envelope).toEqual({ + status: 'error', + error: { + name: 'Error', + message: 'null', + }, + }) + }) +}) diff --git a/packages/ai-isolate-daytona/tsconfig.json b/packages/ai-isolate-daytona/tsconfig.json new file mode 100644 index 000000000..c38689f4e --- /dev/null +++ b/packages/ai-isolate-daytona/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": ["src", "tests"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/ai-isolate-daytona/vite.config.ts b/packages/ai-isolate-daytona/vite.config.ts new file mode 100644 index 000000000..77bcc2e60 --- /dev/null +++ b/packages/ai-isolate-daytona/vite.config.ts @@ -0,0 +1,36 @@ +import { defineConfig, mergeConfig } from 'vitest/config' +import { tanstackViteConfig } from '@tanstack/vite-config' +import packageJson from './package.json' + +const config = defineConfig({ + test: { + name: packageJson.name, + dir: './', + watch: false, + globals: true, + environment: 'node', + include: ['tests/**/*.test.ts'], + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html', 'lcov'], + exclude: [ + 'node_modules/', + 'dist/', + 'tests/', + '**/*.test.ts', + '**/*.config.ts', + '**/types.ts', + ], + include: ['src/**/*.ts'], + }, + }, +}) + +export default mergeConfig( + config, + tanstackViteConfig({ + entry: ['./src/index.ts'], + srcDir: './src', + cjs: false, + }), +) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 65bf21afb..960542f5d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1280,6 +1280,18 @@ importers: specifier: ^4.88.0 version: 4.88.0(@cloudflare/workers-types@4.20260317.1) + packages/ai-isolate-daytona: + devDependencies: + '@daytona/sdk': + specifier: ^0.180.0 + version: 0.180.0(ws@8.19.0) + '@tanstack/ai-code-mode': + specifier: workspace:* + version: link:../ai-code-mode + '@vitest/coverage-v8': + specifier: 4.0.14 + version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.1)(@types/node@24.10.3)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.9))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + packages/ai-isolate-node: dependencies: '@tanstack/ai-code-mode': @@ -2003,6 +2015,131 @@ packages: '@asamuzakjp/nwsapi@2.3.9': resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/crc32c@5.2.0': + resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} + + '@aws-crypto/sha1-browser@5.2.0': + resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-s3@3.1053.0': + resolution: {integrity: sha512-/oGxoB6p1Nqs935Blt+v1o+anSCEf2n3RjIrcLz84i4cn2Gr+Z7JpDdUkG5+74r5ctqEPG7k/phTGbJ9fNKnHg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.974.13': + resolution: {integrity: sha512-+Y5/4tHki0uYgyx8eun146DegRVQBpdKGK5RbV0FTKJPpaKTchvqVxrrRFK6Wk0JksO4iAZKw3eqxGEIwtO98w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/crc64-nvme@3.972.9': + resolution: {integrity: sha512-P+QGozmXn2mZZI7sDgk+aUm+RTI61MPSFB+Ir2vjEjEbEsE4e7hYtzrDvAUxZy9ko81h53e11+F/GYlvwDkaOQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.39': + resolution: {integrity: sha512-29wX9zpAvEt1vcj0psha+y6ygBHy2V/S72mp6e7q0KARLWXq+pwE/lR6qGkwknQvruh52lXvlqZIga8Hdxkucw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.41': + resolution: {integrity: sha512-IA3CQTjtJkb6u1H4mE4936c8OPBMa9Jggtwe8U2Mqw/vvb/tZ5Ebd0mcZcX0uKWQhOyYo/+qNIwkV5Xh+FeJJA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.972.43': + resolution: {integrity: sha512-4mzII+3mZEVXXE1xzrLQrCJL7/r62A63bA6SVzZoNL5rqCJghpf+xgGltVrIBBs0n+mOZBKrQl2tRREtvZ5l6A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.43': + resolution: {integrity: sha512-HG7kQCwXtbv3oBV61Ins0oNX8KKyvrMqqRkb6ZiAfQHbMuHaiNaEb2KnpKLPkNpqImSBK82UkVE/kaY6IfWikA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.44': + resolution: {integrity: sha512-sDaBIT0yrNNIPfvlsiTCmANm07zKju+ipWODjEXgZlsjMeIJR3LVp7RDyAOzUoAsTbDfYKDWp+i5WrFiQP6rmQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.39': + resolution: {integrity: sha512-2k/amBifLd75eXNwgvPw/2lKYSQ3NhvHQgkVKVjfUq13/eJ3JRtHmznuFenn74OK3sSfp4SMy1YB2w+UVXoKqA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.972.43': + resolution: {integrity: sha512-LPc3+Y4vhH1T4x6CMqwCM6hk5+SRf/Lwmgm8INm95wxTtIRHcMwQUVkDzWu4Iw/RSncxYM2BC01OrYbxOPZvyg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.43': + resolution: {integrity: sha512-wQtL34lUD/09VXjwAUo2T+I3aEXRDxMB3DKmTJL/Zj0Gi6sLDTrVhae1XVt01yzkquOWajI/sZW72JGDZ1ciTw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/lib-storage@3.1053.0': + resolution: {integrity: sha512-Y5fyrJ2Qln3lmU0I335no+zdyytpM7svvYOYadZiV2bXGDXEO26A8B+4iGW264GvBO4jnl/iPHVZ/hJIqXekAA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@aws-sdk/client-s3': ^3.1053.0 + + '@aws-sdk/middleware-bucket-endpoint@3.972.15': + resolution: {integrity: sha512-O2HDANa+MrvbxpaRVQDiH3T13uAa9AkMjKyZmDygwauAmmvqZ5B0iRmKW+fuVGW6NPXuyXurFgIx69lSvmAWGA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-expect-continue@3.972.13': + resolution: {integrity: sha512-sHiqIFg8o2ipT7t40B89Vj0ubSUtY6OSt/+Ee/OXhHch5K4+81zP2+QX8Lkc/nJ2QSmCySxOke7TEbmX69fe2g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-flexible-checksums@3.974.21': + resolution: {integrity: sha512-alAu9heyiBK/OmRNXVxq8mmPTgeW2AQ6EYjRsI38kPZa1MZvt2Jh+BlGq7/GG9OVXOaEgD7DlGj/Lzfy5OmuEg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-location-constraint@3.972.11': + resolution: {integrity: sha512-hkfspNUP4criAH6ton6BGKgnm5dZx+7bUOy1YqlTfejDeUPAM23D81q/IX+hdlS3KUsfwGz5ADTqZWKBEUpf4A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-sdk-s3@3.972.42': + resolution: {integrity: sha512-/xNqNGXv9LaxZd25L9VV4pnSOw9OdDNO4rAHamM+h3KQBSITljIH9vk3dveGga1I2j36lQd0rdG3gjNEXvtNew==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-ssec@3.972.11': + resolution: {integrity: sha512-7PQvGNhtveKlvVqNahqWx5yrwxP7ecwAoB1dYBf8eKwfo2tzzCbNnW+q2nO3N066ktQaB4iBQbDRWtizm+amoQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/nested-clients@3.997.11': + resolution: {integrity: sha512-nWXXJ1r/r8N2Gw1pWolRgED38/A9A8DHR2ETWIv220zh4PZHcybbR4hUVWWktmNXTRHzDJwRluapHn0rZxuoqA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.996.28': + resolution: {integrity: sha512-qs9z5LqXO/CZC2Lg9SGKpoLU8Rhi+m2pFKZqfO9pytX1clc0katqtsDNupJxFy0xT9wsZSPzM2v1y+/H/zfp5Q==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1052.0': + resolution: {integrity: sha512-QqZNB3so7UIDxZtroc85TQaLVxdZRFm0eWM1CSR2N+b06as9TOrilvrlTZuj3guYlxMs6yLOgGxnklJ5qMYtTw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.973.9': + resolution: {integrity: sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.5': + resolution: {integrity: sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/xml-builder@3.972.25': + resolution: {integrity: sha512-GH+Kjz4nPKWKHnsiQpnhP1MJdTGIcK4rAka6tzakgjjUkVgNsmPeEbbRAf09SzS1hjGu6duGHCBsxYke0BhHjQ==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.2.4': + resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} + engines: {node: '>=18.0.0'} + '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} @@ -2424,6 +2561,15 @@ packages: '@date-fns/tz@1.4.1': resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} + '@daytona/api-client@0.180.0': + resolution: {integrity: sha512-zjvyYdGE8KXS66A6HVH4vuRa+rjoqVkOdOLHg9OduPw+6xnqYMQF8pKm0r5i5R2U0m0OFE5j4l/yENjNLjMoWw==} + + '@daytona/sdk@0.180.0': + resolution: {integrity: sha512-aGXheZKQnaNVKREAq4/0dNAna7Cs0x74bRf1TBBlIHUzL/7ayGRguhRsBmCia5ve4Urscj3bQ9lmvXCoHHb1gQ==} + + '@daytona/toolbox-api-client@0.180.0': + resolution: {integrity: sha512-JO6bDKi9XlV4s+3aWD/Jp7P5mmtAlAcd6AGSLQiht/PUQKM9RChRB4oQC40P6p5pqwQVa11VBAqfYvQI+mUe+w==} + '@deno/shim-deno-test@0.5.0': resolution: {integrity: sha512-4nMhecpGlPi0cSzT67L+Tm+GOJqvuk8gqHBziqcUQOarnuIax1z96/gJHCSIz2Z0zhxE6Rzwb3IZXPtFh51j+w==} @@ -3320,6 +3466,15 @@ packages: '@modelcontextprotocol/sdk': optional: true + '@grpc/grpc-js@1.14.4': + resolution: {integrity: sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ==} + engines: {node: '>=12.10.0'} + + '@grpc/proto-loader@0.8.1': + resolution: {integrity: sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg==} + engines: {node: '>=6'} + hasBin: true + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -3348,6 +3503,9 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@iarna/toml@2.2.5': + resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} + '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} @@ -3581,6 +3739,9 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@js-sdsl/ordered-map@4.4.2': + resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + '@livekit/mutex@1.1.1': resolution: {integrity: sha512-EsshAucklmpuUAfkABPxJNhzj9v2sG7JuzFDL4ML1oJQSV14sqrpTYnsaOudMAw9yOaW53NU3QQTlUQoRs4czw==} @@ -3633,6 +3794,9 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@nodable/entities@2.1.0': + resolution: {integrity: sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -3740,10 +3904,180 @@ packages: '@openrouter/sdk@0.12.35': resolution: {integrity: sha512-s4QVLLnG1AmfW3TjnnHUqGfsCkzwVK+kboGcZmKbde09m1DPqgzl4RUFt/HJ5v97MX8aEaN0UG3mKv2S+qj2Gw==} + '@opentelemetry/api-logs@0.217.0': + resolution: {integrity: sha512-Cdq0jW2lknrNfrAm92MyEAvpe2cRsKjdnQLHUL6xRA4IVUnsWx6P65E7NcUO0Y+L4w1Aee5iV8FvjSwd+lrs9A==} + engines: {node: '>=8.0.0'} + '@opentelemetry/api@1.9.1': resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} + '@opentelemetry/configuration@0.217.0': + resolution: {integrity: sha512-xCtrYOhBqdy6ZOMfe0Oa73ZKF+2LMhoOv4L5vmwAHVvOXUg+V3fvKuEIr9ZyD0Ow+vxllEjWO6PV1wd0DOtyvw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + + '@opentelemetry/context-async-hooks@2.7.1': + resolution: {integrity: sha512-OPFBYuXEn1E4ja3Y6eeA7O+ZnLBNcXTV5Cgsn1VaqBZ6hC5FnpZPLBNme1LJY8ZtF4aOujPKFoeWN4ik487KuQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@2.7.1': + resolution: {integrity: sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/exporter-logs-otlp-grpc@0.217.0': + resolution: {integrity: sha512-vC5S0Dc+noxD86CVtNu1+awCHPA5Kewi1Sg23ps+9lh4YifwsKXh3pe4XTNEKtUJiAcjpJ5dqStGakLbrSE+YQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-logs-otlp-http@0.217.0': + resolution: {integrity: sha512-KfLAdt1uilVE+3FxbgVnp2ZrzqbIawzcesnRoi+Kh9ckB5Ld5D8btUgoBvwTbdmuNx1j6b132Wsh72azq+pPNQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-logs-otlp-proto@0.217.0': + resolution: {integrity: sha512-Se0GG/ZO24mQTlQj7zprR4pNI0nKe4lPDPBsuJmi6508b9TlZEuUd3EfyuHk6oJxzL7fGyDFYAbxNigQvRP2ZQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-metrics-otlp-grpc@0.217.0': + resolution: {integrity: sha512-0GpJKnCoVaVA1rKBMVPHziznfOQlXgH72S9ktjBAF1AnAVPzX7vVEBGrhwiSxxHDAiefXk+J8znApsMb/K6Z3w==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-metrics-otlp-http@0.217.0': + resolution: {integrity: sha512-1zkMzzhiNJdVmLxuwkltqWGw4fOOam47bqRxmuQNjyKJe/9NmY5cIrZ4kiQV7sVGxoOgT0ZvGUfLcjvtpC/b9Q==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-metrics-otlp-proto@0.217.0': + resolution: {integrity: sha512-nfxt/KxVGFkjkO/M+58y1ugHu/dwPtxG4eYq0KApcQ7xk5CHzhdn+IuLZfDSvNDrJ3Uy5q++Fj/wbK7i8yryfQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-prometheus@0.217.0': + resolution: {integrity: sha512-U9MCXxJu0sBCh5aEkylYRR4xVIL8D1CW6dGwvYXbfFr0qveSorfD0XJchCAWoW6QfAAIcY/yxjf4Dj8OgkHBPw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-trace-otlp-grpc@0.217.0': + resolution: {integrity: sha512-fPZs2fw7veLH3pEKu8vSepUa2fQpAE2P7al6qU10aH9GrEJJ8YaPgsd5xON7by5rbcEVS71FOU2aWyK6nzB7VQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-trace-otlp-http@0.217.0': + resolution: {integrity: sha512-38YQoqtYjglz2GV94LGUN/djLvxtvGIQO68o6qAFPVshjmwSdX1F2i0c7vn3lEl1L5B/YqjB/bgKXaVx7KO+RQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-trace-otlp-proto@0.217.0': + resolution: {integrity: sha512-nPV8gKHUiSuTZpQcnZU3/pBlK7crSyEGpZuh5MtWySB0vv6NNG0QvvfKitQt+Fc2Mc6qfyU54KlZcurwoTbrVg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/exporter-zipkin@2.7.1': + resolution: {integrity: sha512-mfsD9bKAxcKrh5+y08TPodvClBO0CznBE3p79YAGnO81WI4LrdsGA65T53e4iTSbCalW4WaUpkbeJcbpyIUHfg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + + '@opentelemetry/instrumentation-http@0.217.0': + resolution: {integrity: sha512-B88Y7k5A9a60pHUboFoeJlgVwXq2T0rsZKj6dTwzSMKSOsNXR4Jz5ovwprVn3kHLAZrkyLEjQtBJ34DYHs1U4Q==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation@0.217.0': + resolution: {integrity: sha512-24ucQMjz7Y34Kw3trbxL2ZrssbtgWnR+Clpaa+YdeWuuyH3Cvk23Q03PcQvqiZrDvt8AmQmjgg9v6Y9PHoxG7w==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-exporter-base@0.217.0': + resolution: {integrity: sha512-eYfqnB3UhKu/5frhd1R6+FprKygbhkomuaceMXDyzxbfXB9tKgZOVmjaJ02CkLA6Tdzumxl+e2H+vo2a8jiMPQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-grpc-exporter-base@0.217.0': + resolution: {integrity: sha512-7RTAdZuOsCDnsyqTCG4+bDzrfnsWdzkRs7z0AVi/V3tEQx0oKeyc+OuRWYxnRsmaJXgxcmB8vb/lfxn58Dj6Ag==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-transformer@0.217.0': + resolution: {integrity: sha512-MKK8UHKFUOGAvbZRWh90MhwHG+Fxm6OROBdjKPCF+HQobjuJ/Kuf8Chs8CR45X1aqotxrMj7OxTdsXe8sXuGVA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/propagator-b3@2.7.1': + resolution: {integrity: sha512-RJid6E2CKyeGfKBzXKF21ejabGMHypFkPAh3qZ+NvI+SGjuIye79t3PmiqcDgtRzdKH6ynXzbfslQ8DfpRUg2A==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/propagator-jaeger@2.7.1': + resolution: {integrity: sha512-KMjVBHzP4N60bOzxja76M1F1hZZ43lGPga5ix+mkv9+kk1nx9SbkxSvJsMbuVUxdPQmsPTqGShmhN8ulrMOg6Q==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/resources@2.7.1': + resolution: {integrity: sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-logs@0.217.0': + resolution: {integrity: sha512-BB+PcHItcZDL63dPMW+mJvwN9rk37wuIDjRxbVlg6pPDvDR/7GL7UJHbGsllgoggOoTimsKgENaWPoGch/oE1A==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.4.0 <1.10.0' + + '@opentelemetry/sdk-metrics@2.7.1': + resolution: {integrity: sha512-MpDJdkiFDs3Pm1RHO3KByuZbuBdJEXEAkiC0+yJdsZGVCdf1RpHR6n+LHDcS7ffmfrt5kVCzJSCfm4z2C7v0uQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.9.0 <1.10.0' + + '@opentelemetry/sdk-node@0.217.0': + resolution: {integrity: sha512-K/60pSv42+NQiZKy1pAH18nYDkxltsDV4O3SJ233J0E9raU1ksyL9gsKuS8p30bYBb4AMPCfDuutHQaHYpcv0Q==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@2.7.1': + resolution: {integrity: sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-node@2.7.1': + resolution: {integrity: sha512-pCpQxU68lV+I9s9svqMyVu5iHdDDUnqUpSxqwyCU8A9ejEsSnMPCbearwsUO4yk08ZJzAIUCFuReMdVQvHrdvg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/semantic-conventions@1.41.1': + resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==} + engines: {node: '>=14'} + '@oxc-minify/binding-android-arm-eabi@0.110.0': resolution: {integrity: sha512-43fMTO8/5bMlqfOiNSZNKUzIqeLIYuB9Hr1Ohyf58B1wU11S2dPGibTXOGNaWsfgHy99eeZ1bSgeIHy/fEYqbw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4242,18 +4576,30 @@ packages: '@protobufjs/codegen@2.0.4': resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + '@protobufjs/eventemitter@1.1.0': resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + '@protobufjs/fetch@1.1.0': resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + '@protobufjs/float@1.0.2': resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} '@protobufjs/inquire@1.1.0': resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + '@protobufjs/inquire@1.1.2': + resolution: {integrity: sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==} + '@protobufjs/path@1.1.2': resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} @@ -4263,6 +4609,9 @@ packages: '@protobufjs/utf8@1.1.0': resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@protobufjs/utf8@1.1.1': + resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} + '@publint/pack@0.1.2': resolution: {integrity: sha512-S+9ANAvUmjutrshV4jZjaiG8XQyuJIZ8a4utWmN/vW1sgQ9IfBnPndwkmQYw53QmouOIytT874u65HEmu6H5jw==} engines: {node: '>=18'} @@ -5576,6 +5925,42 @@ packages: resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} + '@smithy/core@3.24.4': + resolution: {integrity: sha512-3UNRKEyQyAgVgM0LGlerCLm+ChZWZ1GPfde+jBEW6bm6bSBGU1p0EbblaUV3unbhwvidjLA5Zs3sOs7mnZwvAw==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.3.4': + resolution: {integrity: sha512-vKW0MEFRU4Y3MkVZUkpJm+g9qyPGLCXhc0YLggUdSdBB4g7IaSSsCE75P9rBXyWHrXY1UYSQUl8/DwsTR7QciA==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.4.4': + resolution: {integrity: sha512-qM7AUKI4G6d7lNgaZD3lA1tWSolh5r6gcixfTZAPstVURfjIbvreVTPz+994M0yC3HbX4YYhDRgr31Xy3XwWOQ==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/node-http-handler@4.7.4': + resolution: {integrity: sha512-HIeF+1vrDGzPkkv39Hj2vlHSXHY3p958jd/8ZnePIY6+ZOsQX8coyEUKO5yQu4r0bQIVsbpotVIrXXwyycMStQ==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.4.4': + resolution: {integrity: sha512-e5UtkMvsatzBfbeBZjEOt0k0Z3BEsjTFL/n6fdO5vtBLe67tdy0dX7xw2DU7uZ3acwoHyeCqpU2Fzb7pxwHb6Q==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.14.2': + resolution: {integrity: sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + '@solid-devtools/debugger@0.28.1': resolution: {integrity: sha512-6qIUI6VYkXoRnL8oF5bvh2KgH71qlJ18hNw/mwSyY6v48eb80ZR48/5PDXufUa3q+MBSuYa1uqTMwLewpay9eg==} peerDependencies: @@ -7016,6 +7401,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -7167,6 +7556,9 @@ packages: axios@1.13.2: resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + axios@1.16.1: + resolution: {integrity: sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==} + axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -7292,6 +7684,9 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + boxen@7.1.1: resolution: {integrity: sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==} engines: {node: '>=14.16'} @@ -7331,6 +7726,9 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.6.0: + resolution: {integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==} + buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} @@ -7343,6 +7741,10 @@ packages: peerDependencies: esbuild: '>=0.18' + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -7458,6 +7860,9 @@ packages: citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -8268,6 +8673,10 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + expand-tilde@2.0.2: + resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} + engines: {node: '>=0.10.0'} + expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} @@ -8313,6 +8722,13 @@ packages: fast-sha256@1.3.0: resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} + fast-xml-builder@1.2.0: + resolution: {integrity: sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==} + + fast-xml-parser@5.7.3: + resolution: {integrity: sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==} + hasBin: true + fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} @@ -8400,6 +8816,15 @@ packages: debug: optional: true + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} @@ -8421,6 +8846,9 @@ packages: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} + forwarded-parse@2.1.2: + resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -8710,6 +9138,10 @@ packages: resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} engines: {node: '>=12.0.0'} + homedir-polyfill@1.0.3: + resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} + engines: {node: '>=0.10.0'} + hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} @@ -8762,6 +9194,10 @@ packages: resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} @@ -8803,6 +9239,10 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} + import-in-the-middle@3.0.1: + resolution: {integrity: sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==} + engines: {node: '>=18'} + import-lazy@4.0.0: resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} engines: {node: '>=8'} @@ -9067,6 +9507,11 @@ packages: resolution: {integrity: sha512-GGfsHqtlZiiurZaxB/3kY7LLAXR3sgzDul0fom4cSyBjx6ZbjpTrFWiH3z/nUfLJGJ8PIq9LQmQFiAxu24+I7A==} engines: {node: '>=22.0.0'} + isomorphic-ws@5.0.0: + resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} + peerDependencies: + ws: '*' + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -9371,6 +9816,9 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} @@ -9761,6 +10209,9 @@ packages: mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + module-details-from-path@1.0.4: + resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} + motion-dom@11.18.1: resolution: {integrity: sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==} @@ -10132,6 +10583,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-passwd@1.0.0: + resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} + engines: {node: '>=0.10.0'} + parse5-htmlparser2-tree-adapter@7.1.0: resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} @@ -10162,6 +10617,10 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-expression-matcher@1.5.0: + resolution: {integrity: sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==} + engines: {node: '>=14.0.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -10353,6 +10812,14 @@ packages: resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} engines: {node: '>=12.0.0'} + protobufjs@7.6.1: + resolution: {integrity: sha512-4K0myLaWL5EteuSAro91EGFgcfVgxb64Jx+7oDAY6GOkXD4M69yuSEljNcInGVCA5sOPxmZ/EqDLj2x0Q0+Ygg==} + engines: {node: '>=12.0.0'} + + protobufjs@8.0.1: + resolution: {integrity: sha512-NWWCCscLjs+cOKF/s/XVNFRW7Yih0fdH+9brffR5NZCy8k42yRdl5KlWKMVXuI1vfCoy4o1z80XR/W/QUb3V3w==} + engines: {node: '>=12.0.0'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -10364,6 +10831,10 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + publint@0.3.16: resolution: {integrity: sha512-MFqyfRLAExPVZdTQFwkAQELzA8idyXzROVOytg6nEJ/GEypXBUmMGrVaID8cTuzRS1U5L8yTOdOJtMXgFUJAeA==} engines: {node: '>=18'} @@ -10614,6 +11085,10 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-in-the-middle@8.0.1: + resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} + engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} + requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -11069,6 +11544,13 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} + stream-browserify@3.0.0: + resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + streamx@2.23.0: resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} @@ -11120,6 +11602,9 @@ packages: strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + strnum@2.3.0: + resolution: {integrity: sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==} + style-to-js@1.1.21: resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} @@ -11199,6 +11684,10 @@ packages: tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + tar@7.5.15: + resolution: {integrity: sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==} + engines: {node: '>=18'} + tar@7.5.2: resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} engines: {node: '>=18'} @@ -12341,6 +12830,10 @@ packages: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} + xml-naming@0.1.0: + resolution: {integrity: sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==} + engines: {node: '>=16.0.0'} + xmlbuilder2@3.1.1: resolution: {integrity: sha512-WCSfbfZnQDdLQLiMdGUQpMxxckeQ4oZNMNhLVkcekTu7xhD4tuUDyAPoY8CwXvBYE6LwBHd6QW2WZXlOWr1vCw==} engines: {node: '>=12.0'} @@ -12437,15 +12930,290 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 lru-cache: 11.2.4 - '@asamuzakjp/dom-selector@6.7.6': + '@asamuzakjp/dom-selector@6.7.6': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.1.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.2.4 + + '@asamuzakjp/nwsapi@2.3.9': {} + + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.9 + tslib: 2.8.1 + + '@aws-crypto/crc32c@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.9 + tslib: 2.8.1 + + '@aws-crypto/sha1-browser@5.2.0': + dependencies: + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.9 + '@aws-sdk/util-locate-window': 3.965.5 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.9 + '@aws-sdk/util-locate-window': 3.965.5 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.9 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.9 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-s3@3.1053.0': + dependencies: + '@aws-crypto/sha1-browser': 5.2.0 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.13 + '@aws-sdk/credential-provider-node': 3.972.44 + '@aws-sdk/middleware-bucket-endpoint': 3.972.15 + '@aws-sdk/middleware-expect-continue': 3.972.13 + '@aws-sdk/middleware-flexible-checksums': 3.974.21 + '@aws-sdk/middleware-location-constraint': 3.972.11 + '@aws-sdk/middleware-sdk-s3': 3.972.42 + '@aws-sdk/middleware-ssec': 3.972.11 + '@aws-sdk/signature-v4-multi-region': 3.996.28 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/fetch-http-handler': 5.4.4 + '@smithy/node-http-handler': 4.7.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/core@3.974.13': + dependencies: + '@aws-sdk/types': 3.973.9 + '@aws-sdk/xml-builder': 3.972.25 + '@aws/lambda-invoke-store': 0.2.4 + '@smithy/core': 3.24.4 + '@smithy/signature-v4': 5.4.4 + '@smithy/types': 4.14.2 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/crc64-nvme@3.972.9': + dependencies: + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.39': + dependencies: + '@aws-sdk/core': 3.974.13 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.41': + dependencies: + '@aws-sdk/core': 3.974.13 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/fetch-http-handler': 5.4.4 + '@smithy/node-http-handler': 4.7.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.972.43': + dependencies: + '@aws-sdk/core': 3.974.13 + '@aws-sdk/credential-provider-env': 3.972.39 + '@aws-sdk/credential-provider-http': 3.972.41 + '@aws-sdk/credential-provider-login': 3.972.43 + '@aws-sdk/credential-provider-process': 3.972.39 + '@aws-sdk/credential-provider-sso': 3.972.43 + '@aws-sdk/credential-provider-web-identity': 3.972.43 + '@aws-sdk/nested-clients': 3.997.11 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/credential-provider-imds': 4.3.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-login@3.972.43': + dependencies: + '@aws-sdk/core': 3.974.13 + '@aws-sdk/nested-clients': 3.997.11 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-node@3.972.44': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.39 + '@aws-sdk/credential-provider-http': 3.972.41 + '@aws-sdk/credential-provider-ini': 3.972.43 + '@aws-sdk/credential-provider-process': 3.972.39 + '@aws-sdk/credential-provider-sso': 3.972.43 + '@aws-sdk/credential-provider-web-identity': 3.972.43 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/credential-provider-imds': 4.3.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.972.39': + dependencies: + '@aws-sdk/core': 3.974.13 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.972.43': + dependencies: + '@aws-sdk/core': 3.974.13 + '@aws-sdk/nested-clients': 3.997.11 + '@aws-sdk/token-providers': 3.1052.0 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.972.43': + dependencies: + '@aws-sdk/core': 3.974.13 + '@aws-sdk/nested-clients': 3.997.11 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/lib-storage@3.1053.0(@aws-sdk/client-s3@3.1053.0)': + dependencies: + '@aws-sdk/client-s3': 3.1053.0 + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + buffer: 5.6.0 + events: 3.3.0 + stream-browserify: 3.0.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-bucket-endpoint@3.972.15': + dependencies: + '@aws-sdk/core': 3.974.13 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-expect-continue@3.972.13': + dependencies: + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-flexible-checksums@3.974.21': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@aws-crypto/crc32c': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/core': 3.974.13 + '@aws-sdk/crc64-nvme': 3.972.9 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-location-constraint@3.972.11': + dependencies: + '@aws-sdk/types': 3.973.9 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-sdk-s3@3.972.42': + dependencies: + '@aws-sdk/core': 3.974.13 + '@aws-sdk/signature-v4-multi-region': 3.996.28 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/signature-v4': 5.4.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-ssec@3.972.11': + dependencies: + '@aws-sdk/types': 3.973.9 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.997.11': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.13 + '@aws-sdk/signature-v4-multi-region': 3.996.28 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/fetch-http-handler': 5.4.4 + '@smithy/node-http-handler': 4.7.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.996.28': + dependencies: + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/signature-v4': 5.4.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1052.0': + dependencies: + '@aws-sdk/core': 3.974.13 + '@aws-sdk/nested-clients': 3.997.11 + '@aws-sdk/types': 3.973.9 + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/types@3.973.9': + dependencies: + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.5': dependencies: - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.1.0 - is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.4 + tslib: 2.8.1 - '@asamuzakjp/nwsapi@2.3.9': {} + '@aws-sdk/xml-builder@3.972.25': + dependencies: + '@nodable/entities': 2.1.0 + '@smithy/types': 4.14.2 + fast-xml-parser: 5.7.3 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.4': {} '@babel/code-frame@7.26.2': dependencies: @@ -13005,6 +13773,48 @@ snapshots: '@date-fns/tz@1.4.1': {} + '@daytona/api-client@0.180.0': + dependencies: + axios: 1.13.2 + transitivePeerDependencies: + - debug + + '@daytona/sdk@0.180.0(ws@8.19.0)': + dependencies: + '@aws-sdk/client-s3': 3.1053.0 + '@aws-sdk/lib-storage': 3.1053.0(@aws-sdk/client-s3@3.1053.0) + '@daytona/api-client': 0.180.0 + '@daytona/toolbox-api-client': 0.180.0 + '@iarna/toml': 2.2.5 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/exporter-trace-otlp-http': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-http': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-node': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + axios: 1.16.1 + busboy: 1.6.0 + dotenv: 17.2.3 + expand-tilde: 2.0.2 + fast-glob: 3.3.3 + form-data: 4.0.5 + isomorphic-ws: 5.0.0(ws@8.19.0) + pathe: 2.0.3 + shell-quote: 1.8.3 + tar: 7.5.15 + transitivePeerDependencies: + - debug + - supports-color + - ws + + '@daytona/toolbox-api-client@0.180.0': + dependencies: + axios: 1.13.2 + transitivePeerDependencies: + - debug + '@deno/shim-deno-test@0.5.0': {} '@deno/shim-deno@0.19.2': @@ -13574,6 +14384,18 @@ snapshots: - supports-color - utf-8-validate + '@grpc/grpc-js@1.14.4': + dependencies: + '@grpc/proto-loader': 0.8.1 + '@js-sdsl/ordered-map': 4.4.2 + + '@grpc/proto-loader@0.8.1': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.2 + protobufjs: 7.6.1 + yargs: 17.7.2 + '@humanfs/core@0.19.1': {} '@humanfs/core@0.19.2': @@ -13597,6 +14419,8 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@iarna/toml@2.2.5': {} + '@img/colour@1.1.0': {} '@img/sharp-darwin-arm64@0.34.5': @@ -13778,6 +14602,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@js-sdsl/ordered-map@4.4.2': {} + '@livekit/mutex@1.1.1': {} '@livekit/protocol@1.44.0': @@ -13884,6 +14710,8 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@nodable/entities@2.1.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -13968,8 +14796,254 @@ snapshots: dependencies: zod: 4.3.6 + '@opentelemetry/api-logs@0.217.0': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api@1.9.1': {} + '@opentelemetry/configuration@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + yaml: 2.8.2 + + '@opentelemetry/context-async-hooks@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + + '@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/exporter-logs-otlp-grpc@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@grpc/grpc-js': 1.14.4 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-grpc-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.217.0(@opentelemetry/api@1.9.1) + + '@opentelemetry/exporter-logs-otlp-http@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.217.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.217.0(@opentelemetry/api@1.9.1) + + '@opentelemetry/exporter-logs-otlp-proto@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.217.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/exporter-metrics-otlp-grpc@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@grpc/grpc-js': 1.14.4 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-metrics-otlp-http': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-grpc-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/exporter-metrics-otlp-http@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/exporter-metrics-otlp-proto@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-metrics-otlp-http': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/exporter-prometheus@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/exporter-trace-otlp-grpc@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@grpc/grpc-js': 1.14.4 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-grpc-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/exporter-trace-otlp-http@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/exporter-trace-otlp-proto@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/exporter-zipkin@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/instrumentation-http@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + forwarded-parse: 2.1.2 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.217.0 + import-in-the-middle: 3.0.1 + require-in-the-middle: 8.0.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/otlp-exporter-base@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.1) + + '@opentelemetry/otlp-grpc-exporter-base@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@grpc/grpc-js': 1.14.4 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.217.0(@opentelemetry/api@1.9.1) + + '@opentelemetry/otlp-transformer@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.217.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + protobufjs: 8.0.1 + + '@opentelemetry/propagator-b3@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/propagator-jaeger@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/sdk-logs@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.217.0 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/sdk-metrics@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/sdk-node@0.217.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.217.0 + '@opentelemetry/configuration': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/context-async-hooks': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-logs-otlp-grpc': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-logs-otlp-http': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-logs-otlp-proto': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-metrics-otlp-grpc': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-metrics-otlp-http': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-metrics-otlp-proto': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-prometheus': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-trace-otlp-grpc': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-trace-otlp-http': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-trace-otlp-proto': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-zipkin': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/propagator-b3': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/propagator-jaeger': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.217.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-node': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/sdk-trace-node@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/context-async-hooks': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + + '@opentelemetry/semantic-conventions@1.41.1': {} + '@oxc-minify/binding-android-arm-eabi@0.110.0': optional: true @@ -14257,23 +15331,35 @@ snapshots: '@protobufjs/codegen@2.0.4': {} + '@protobufjs/codegen@2.0.5': {} + '@protobufjs/eventemitter@1.1.0': {} + '@protobufjs/eventemitter@1.1.1': {} + '@protobufjs/fetch@1.1.0': dependencies: '@protobufjs/aspromise': 1.1.2 '@protobufjs/inquire': 1.1.0 + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/float@1.0.2': {} '@protobufjs/inquire@1.1.0': {} + '@protobufjs/inquire@1.1.2': {} + '@protobufjs/path@1.1.2': {} '@protobufjs/pool@1.1.0': {} '@protobufjs/utf8@1.1.0': {} + '@protobufjs/utf8@1.1.1': {} + '@publint/pack@0.1.2': {} '@puppeteer/browsers@2.13.0': @@ -15483,6 +16569,54 @@ snapshots: '@sindresorhus/merge-streams@4.0.0': {} + '@smithy/core@3.24.4': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.3.4': + dependencies: + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.4.4': + dependencies: + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/node-http-handler@4.7.4': + dependencies: + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@smithy/signature-v4@5.4.4': + dependencies: + '@smithy/core': 3.24.4 + '@smithy/types': 4.14.2 + tslib: 2.8.1 + + '@smithy/types@4.14.2': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + '@solid-devtools/debugger@0.28.1(solid-js@1.9.10)': dependencies: '@nothing-but/utils': 0.17.0 @@ -17850,6 +18984,12 @@ snapshots: acorn@8.15.0: {} + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + agent-base@7.1.4: {} ajv-draft-04@1.0.0(ajv@8.13.0): @@ -18016,6 +19156,16 @@ snapshots: transitivePeerDependencies: - debug + axios@1.16.1: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.5 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + axobject-query@4.1.0: {} b4a@1.7.3: {} @@ -18146,6 +19296,8 @@ snapshots: boolbase@1.0.0: {} + bowser@2.14.1: {} + boxen@7.1.1: dependencies: ansi-align: 3.0.1 @@ -18195,6 +19347,11 @@ snapshots: buffer-from@1.1.2: {} + buffer@5.6.0: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + buffer@5.7.1: dependencies: base64-js: 1.5.1 @@ -18210,6 +19367,10 @@ snapshots: esbuild: 0.27.3 load-tsconfig: 0.2.5 + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + bytes@3.1.2: {} c12@3.3.2(magicast@0.5.2): @@ -18351,6 +19512,8 @@ snapshots: dependencies: consola: 3.4.2 + cjs-module-lexer@2.2.0: {} + class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 @@ -19251,6 +20414,10 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + expand-tilde@2.0.2: + dependencies: + homedir-polyfill: 1.0.3 + expect-type@1.3.0: {} express@5.2.1: @@ -19322,6 +20489,18 @@ snapshots: fast-sha256@1.3.0: {} + fast-xml-builder@1.2.0: + dependencies: + path-expression-matcher: 1.5.0 + xml-naming: 0.1.0 + + fast-xml-parser@5.7.3: + dependencies: + '@nodable/entities': 2.1.0 + fast-xml-builder: 1.2.0 + path-expression-matcher: 1.5.0 + strnum: 2.3.0 + fastq@1.19.1: dependencies: reusify: 1.1.0 @@ -19413,6 +20592,8 @@ snapshots: follow-redirects@1.15.11: {} + follow-redirects@1.16.0: {} + for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -19438,6 +20619,8 @@ snapshots: dependencies: fetch-blob: 3.2.0 + forwarded-parse@2.1.2: {} + forwarded@0.2.0: {} fraction.js@5.3.4: {} @@ -19821,6 +21004,10 @@ snapshots: highlight.js@11.11.1: {} + homedir-polyfill@1.0.3: + dependencies: + parse-passwd: 1.0.0 + hookable@5.5.3: {} hookable@6.1.1: {} @@ -19883,6 +21070,13 @@ snapshots: http-shutdown@1.2.2: {} + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 @@ -19917,6 +21111,13 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + import-in-the-middle@3.0.1: + dependencies: + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) + cjs-module-lexer: 2.2.0 + module-details-from-path: 1.0.4 + import-lazy@4.0.0: {} import-meta-resolve@4.2.0: {} @@ -20149,6 +21350,10 @@ snapshots: dependencies: node-gyp-build: 4.8.4 + isomorphic-ws@5.0.0(ws@8.19.0): + dependencies: + ws: 8.19.0 + istanbul-lib-coverage@3.2.2: {} istanbul-lib-report@3.0.1: @@ -20485,6 +21690,8 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.camelcase@4.3.0: {} + lodash.defaults@4.2.0: {} lodash.isarguments@3.1.0: {} @@ -21062,6 +22269,8 @@ snapshots: pkg-types: 1.3.1 ufo: 1.6.1 + module-details-from-path@1.0.4: {} + motion-dom@11.18.1: dependencies: motion-utils: 11.18.1 @@ -21755,6 +22964,8 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-passwd@1.0.0: {} + parse5-htmlparser2-tree-adapter@7.1.0: dependencies: domhandler: 5.0.3 @@ -21782,6 +22993,8 @@ snapshots: path-exists@4.0.0: {} + path-expression-matcher@1.5.0: {} + path-key@3.1.1: {} path-key@4.0.0: {} @@ -21939,6 +23152,36 @@ snapshots: '@types/node': 24.10.3 long: 5.3.2 + protobufjs@7.6.1: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.1 + '@types/node': 24.10.3 + long: 5.3.2 + + protobufjs@8.0.1: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 24.10.3 + long: 5.3.2 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -21959,6 +23202,8 @@ snapshots: proxy-from-env@1.1.0: {} + proxy-from-env@2.1.0: {} + publint@0.3.16: dependencies: '@publint/pack': 0.1.2 @@ -22351,6 +23596,13 @@ snapshots: require-from-string@2.0.2: {} + require-in-the-middle@8.0.1: + dependencies: + debug: 4.4.3 + module-details-from-path: 1.0.4 + transitivePeerDependencies: + - supports-color + requires-port@1.0.0: {} resolve-from@4.0.0: {} @@ -22921,6 +24173,13 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 + stream-browserify@3.0.0: + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + + streamsearch@1.1.0: {} + streamx@2.23.0: dependencies: events-universal: 1.0.1 @@ -22977,6 +24236,8 @@ snapshots: dependencies: js-tokens: 9.0.1 + strnum@2.3.0: {} + style-to-js@1.1.21: dependencies: style-to-object: 1.0.14 @@ -23089,6 +24350,14 @@ snapshots: - bare-abort-controller - react-native-b4a + tar@7.5.15: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.1.0 + yallist: 5.0.0 + tar@7.5.2: dependencies: '@isaacs/fs-minipass': 4.0.1 @@ -24149,6 +25418,8 @@ snapshots: xml-name-validator@5.0.0: {} + xml-naming@0.1.0: {} + xmlbuilder2@3.1.1: dependencies: '@oozcitak/dom': 1.15.10