diff --git a/README.md b/README.md index ae650e2..0767f06 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,10 @@ Production runtime substrate for domain agents. Owns the task lifecycle (knowledge readiness, control loop, session resume, sanitized telemetry, -canonical `RuntimeRunRow` persistence + cost ledger) so domain repos stop -inventing their own. +durable runs across worker / DO crashes, canonical `RuntimeRunRow` +persistence + cost ledger), the chat-model catalog + admission, and the +declarative `defineAgent` manifest — so domain repos stop inventing their +own. ```bash pnpm add @tangle-network/agent-runtime @tangle-network/agent-eval @@ -15,12 +17,20 @@ pnpm add @tangle-network/agent-runtime @tangle-network/agent-eval |---|---| | `runAgentTask` | Single-shot adapter-driven task with eval/verification | | `runAgentTaskStream` | Streaming product loop with session resume + backends | +| `runDurableTurn` | Checkpoint+replay chat turn — survives a worker crash *after* completion | +| `runSupervisedTurn` | Always-attached durable turn — re-attaches an in-flight sandbox run *during* a crash | +| `SessionSupervisorDO` | Cloudflare Durable Object host for `runSupervisedTurn` (with alarm-driven orphan re-attach) | +| `DurableChatTurnEngine` | Framework-neutral chat-turn orchestrator (durable turn + NDJSON + session lifecycle + product hooks) | | `startRuntimeRun` | Canonical production-run row + cost ledger | +| `runDurable` + `*DurableRunStore` | General durable-step substrate (in-memory / file-system / D1) | +| `defineAgent` | Declarative per-vertical agent manifest — surfaces, knowledge, rubric, run fn | +| `resolveChatModel` / `validateChatModelId` / `getModels` | Router catalog fetch + fail-closed admission + precedence resolver | | `createTraceBridge` | Map `RuntimeStreamEvent` → `agent-eval` `TraceEvent` | | `decideKnowledgeReadiness` | `ready` / `blocked` / `caveat` branch for routes / UI | | `createOpenAICompatibleBackend` | OpenAI-compatible streaming backend (TCloud / cli-bridge) | | `createSandboxPromptBackend` | Sandbox / sidecar `streamPrompt` clients | | `createRuntimeStreamEventCollector` | Default-redacted sanitized telemetry over a stream | +| `PlatformAuthClient` + `PlatformHubClient` (`/platform`) | Cross-site SSO + integrations hub | Every public export is annotated `@stable` or `@experimental`. `@stable` exports do not change shape inside a minor; `@experimental` exports may @@ -32,55 +42,147 @@ change inside a minor and require a deliberate consumer bump. import { runAgentTask } from '@tangle-network/agent-runtime' const result = await runAgentTask({ - task: { - id: 'review-2026-return', - intent: 'Review the return for missing evidence', - domain: 'tax', - }, + task: { id: 'review-2026-return', intent: 'Review the return', domain: 'tax' }, adapter: { async observe() { return { /* domain state */ } }, async validate({ state }) { return [/* eval results */] }, - async decide({ state }) { - return { type: 'stop', pass: true, score: 1, reason: 'review complete' } - }, + async decide({ state }) { return { type: 'stop', pass: true, score: 1, reason: 'done' } }, async act() { return undefined }, }, }) - console.log(result.status, result.runRecords) ``` +## Durable chat turns + +A 15-minute agentic turn must survive a Cloudflare worker isolate dying. +`runDurableTurn` replays a *completed* turn from cache (worker died after +the turn finished). `runSupervisedTurn` closes the harder gap — a turn +interrupted *mid-stream* — by relocating the durability boundary off the +ephemeral worker: + +- The supervisor drains every event into the substrate's own ordered log + (`appendStreamEvent`, idempotent on `eventId`). +- It persists the substrate `RunHandle` the instant the sandbox yields it. +- A fresh supervisor reads the log for its cursor and resumes via + `adapter.attach(handle, cursor)` — no event lost, none delivered twice. + +The reconnect glue is one typed contract — `SandboxReconnectAdapter` — +implemented once per substrate, not per product. + +```ts +import { runSupervisedTurn, InMemoryDurableRunStore } from '@tangle-network/agent-runtime' + +const store = new InMemoryDurableRunStore() +const supervised = runSupervisedTurn({ + store, runId: `chat:${threadId}:${turnIndex}`, manifest, workerId, + adapter: mySandboxAdapter, +}) +for await (const event of supervised.stream) sendToClient(event) +// supervised.mode() === 'fresh' | 'resumed' | 'replayed' +``` + +Full runnable: [`examples/durable-supervisor/`](./examples/durable-supervisor/). + +### Cloudflare Durable Object host + +`SessionSupervisorDO` hosts the supervisor on a real DO — `fetch` streams the +turn, `alarm()` re-attaches a run a dropped response stream abandoned. + +```ts +import { createSessionSupervisorDO } from '@tangle-network/agent-runtime' + +export const SessionSupervisor = createSessionSupervisorDO({ + resolveRun(request, env, state) { /* return RunSupervisorOptions */ }, + resolveOrphan(runId, env, state) { /* same, for the alarm path */ }, + encodeEvent(event) { return `data: ${JSON.stringify(event)}\n\n` }, +}) +``` + +```toml +# wrangler.toml +[[durable_objects.bindings]] +name = "SESSION_SUPERVISOR" +class_name = "SessionSupervisor" +[[migrations]] +tag = "v1" +new_classes = ["SessionSupervisor"] +``` + +CF types are structural (`DurableObjectStateLike`) — no +`@cloudflare/workers-types` runtime dep. + +## Chat-model resolution + +One primitive every chat handler needs and was hand-rolling per repo: +router catalog fetch, malformed-id guard, fail-closed catalog admission, +precedence resolver. Policy-free — the caller passes its own precedence +order and known-good allowlist. + +```ts +import { + resolveChatModel, resolveRouterBaseUrl, validateChatModelId, getModels, +} from '@tangle-network/agent-runtime' + +const routerBaseUrl = resolveRouterBaseUrl(env) +const { model, source } = resolveChatModel( + [ + { source: 'request', model: requestBody.model }, + { source: 'workspace', model: workspace.pinnedModel }, + { source: 'env', model: env.TCLOUD_CHAT_MODEL }, + ], + { source: 'default', model: 'claude-sonnet-4-6' }, +) +const validation = await validateChatModelId(model, { + routerBaseUrl, + allowlist: ['claude-sonnet-4-6'], +}) +if (!validation.succeeded) throw new ConfigError(validation.error) +``` + +Full runnable: [`examples/model-resolution/`](./examples/model-resolution/). + +## Define an agent — declarative manifest + +`defineAgent` is the per-vertical layer that pairs a runtime adapter with +the surfaces / knowledge / rubric / outcome contract `agent-eval`'s analyst +loop drives improvement against. + +```ts +import { defineAgent } from '@tangle-network/agent-runtime/agent' + +export const myAgent = defineAgent({ + id: 'legal-agent', + surfaces: { /* prompt, tools, skills — the levers an analyst can edit */ }, + knowledge: { /* requirements + provider */ }, + rubric: { /* dimensions + weights */ }, + run: async (ctx) => { + /* product-specific run — typically wraps runSupervisedTurn or runAgentTaskStream */ + }, +}) +``` + ## Canonical production-run lifecycle -`startRuntimeRun` records what the agent did on behalf of a customer, -what it cost, and how it ended. Replaces bespoke `agentRuns`-row helpers -across consumer repos with a single contract. +`startRuntimeRun` records what the agent did for a customer, what it +cost, and how it ended. Replaces bespoke `agentRuns` helpers across +consumer repos. ```ts import { startRuntimeRun, runAgentTaskStream } from '@tangle-network/agent-runtime' const run = startRuntimeRun({ - workspaceId: 'ws-1', - sessionId: threadId, - agentId: 'legal-chat-runtime', - taskSpec, - scenarioId: `legal-chat:${threadId}`, + workspaceId: 'ws-1', sessionId: threadId, agentId: 'legal-chat-runtime', + taskSpec, scenarioId: `legal-chat:${threadId}`, adapter: { upsert: (row) => db.insert(agentRuns).values(row) }, }) - for await (const event of runAgentTaskStream({ task: taskSpec, backend, input })) { - run.observe(event) // llm_call events update the cost ledger + run.observe(event) if (event.type === 'final') { - run.complete({ - status: event.status === 'completed' ? 'completed' : 'failed', - resultSummary: event.text ?? '', - error: event.status === 'failed' ? event.reason : undefined, - }) + run.complete({ status: event.status === 'completed' ? 'completed' : 'failed', resultSummary: event.text ?? '' }) } } - await run.persist({ runtimeEvents: telemetry.events }) -console.log(run.cost()) // { tokensIn, tokensOut, costUsd, wallMs, llmCalls } ``` Full runnable: [`examples/runtime-run/`](./examples/runtime-run/). @@ -89,7 +191,7 @@ Full runnable: [`examples/runtime-run/`](./examples/runtime-run/). If you persist traces in agent-eval's `TraceStore`, the bridge maps runtime stream events to `TraceEvent` so consumer repos don't hand-roll -the adapter: +the adapter. ```ts import { createTraceBridge } from '@tangle-network/agent-runtime' @@ -103,8 +205,6 @@ for await (const event of runAgentTaskStream({ task, backend, input })) { ## Error taxonomy -Every public function throws one of: - | Error | When | |---|---| | `ValidationError` | Caller passed invalid arguments | @@ -113,85 +213,65 @@ Every public function throws one of: | `BackendTransportError` | Backend HTTP / IPC call returned non-success | | `SessionMismatchError` | Resume requested against a different backend | | `RuntimeRunStateError` | `RuntimeRunHandle` lifecycle methods called out of order | +| `DurableRunLeaseHeldError` | Another worker holds a live lease on the run | +| `DurableRunInputMismatchError` | A `runId` exists with a different manifest hash | +| `DurableRunDivergenceError` | A step's intent changed across replays | All extend `AgentEvalError` (re-exported from `@tangle-network/agent-eval`) -and carry a stable `code` so cross-package handlers can pattern-match +and carry a stable `code` so cross-package handlers pattern-match without importing the runtime. ## Sanitized telemetry `task.intent` flows through sanitized telemetry on every event. **Never set it to user input** — use a fixed string describing the operation -kind (e.g. `"Run a chat turn"`, `"Score a tax return"`). Route user- -visible content through `task.inputs` (redacted by default). +kind (e.g. `"Run a chat turn"`, `"Score a tax return"`). Route +user-visible content through `task.inputs` (redacted by default). ```ts import { createRuntimeStreamEventCollector, runAgentTaskStream } from '@tangle-network/agent-runtime' const telemetry = createRuntimeStreamEventCollector() -for await (const event of runAgentTaskStream({ task, backend })) { - telemetry.onEvent(event) -} +for await (const event of runAgentTaskStream({ task, backend })) telemetry.onEvent(event) console.log(telemetry.events, telemetry.summary()) ``` -By default the collector redacts task inputs, user answers, credential -questions, control payloads, evidence IDs, task metadata, and eval -details. Private diagnostics opt-in via `RuntimeTelemetryOptions`. - ## Package boundaries | Package | Owns | |---|---| -| `agent-runtime` | Lifecycle, adapters, backends, `RuntimeRunHandle`, trace bridge | -| `agent-runtime/platform` | Server-side clients for the Tangle platform: cross-site SSO (`PlatformAuthClient`) and integrations hub (`PlatformHubClient`) | -| `agent-eval` | Control loops, readiness scoring, traces, evals, failure classes, release evidence | -| `agent-knowledge` | Evidence, claims, wiki pages, retrieval, knowledge bundle builders | +| `agent-runtime` | Lifecycle, adapters, backends, durable substrate, supervisor + DO, model resolution, trace bridge, `defineAgent` | +| `agent-runtime/platform` | Cross-site SSO (`PlatformAuthClient`) + integrations hub (`PlatformHubClient`) | +| `agent-runtime/agent` | `defineAgent` + surfaces / outcome adapters | +| `agent-runtime/analyst-loop` | `runAnalystLoop` — analyst registry driver | +| `agent-eval` | Control loops, readiness scoring, traces, evals, judges, RL, release evidence | +| `agent-knowledge` | Evidence, claims, wiki pages, retrieval | | Domain packages | Domain tools, policies, credentials, UI text, rubrics | -### `agent-runtime/platform` — Login with Tangle + integrations hub - -```ts -import { - PlatformAuthClient, - PlatformHubClient, -} from '@tangle-network/agent-runtime/platform' - -// Login with Tangle (cross-site SSO bridge). -const auth = new PlatformAuthClient({ - baseUrl: process.env.TANGLE_PLATFORM_URL!, // https://id.tangle.tools - appId: 'gtm-agent', // must be registered in TRUSTED_APPS -}) -const url = auth.authorizeUrl({ state: csrfToken, redirectUri: callbackUrl }) -// …user redirected to `url`, returns to callbackUrl with ?code=… -const { apiKey, user } = await auth.exchange(code) - -// Integrations hub (uses the user's apiKey from cross-site exchange). -const hub = new PlatformHubClient({ - baseUrl: process.env.TANGLE_PLATFORM_URL!, - bearer: apiKey, -}) -const connections = await hub.listConnections() -const { authorizationUrl } = await hub.startAuth({ - providerId: 'google', - connectorId: 'gmail', - returnUrl: 'https://gtm.tangle.tools/integrations', -}) -``` - -The API uses `runAgentTask`, not `runVerticalAgentTask`. `domain` is -metadata on the task because the runtime is reusable across many kinds of -agents without baking taxonomy into type names. +See [`docs/concepts.md`](./docs/concepts.md) for the mental model. ## Examples -Runnable in [`examples/`](./examples/): +Runnable in [`examples/`](./examples/). Every example imports from +`@tangle-network/agent-runtime` (the same surface consumers use): - [`basic-task/`](./examples/basic-task/) — smallest `runAgentTask` -- [`with-knowledge-readiness/`](./examples/with-knowledge-readiness/) — readiness gating + `onKnowledgeBlocked` -- [`sanitized-telemetry/`](./examples/sanitized-telemetry/) — `createRuntimeEventCollector` + redaction -- [`sanitized-telemetry-streaming/`](./examples/sanitized-telemetry-streaming/) — streaming collector + redaction -- [`sse-stream/`](./examples/sse-stream/) — Server-Sent Events for browser clients +- [`with-knowledge-readiness/`](./examples/with-knowledge-readiness/) — readiness gating +- [`sanitized-telemetry/`](./examples/sanitized-telemetry/) + [`-streaming/`](./examples/sanitized-telemetry-streaming/) — redaction +- [`sse-stream/`](./examples/sse-stream/) — SSE helpers for browser clients - [`sandbox-stream-backend/`](./examples/sandbox-stream-backend/) — `createSandboxPromptBackend` - [`openai-stream-backend/`](./examples/openai-stream-backend/) — `createOpenAICompatibleBackend` -- [`runtime-run/`](./examples/runtime-run/) — `startRuntimeRun` + cost ledger + persistence adapter +- [`runtime-run/`](./examples/runtime-run/) — production-run row + cost ledger +- [`model-resolution/`](./examples/model-resolution/) — router catalog + fail-closed admission +- [`durable-supervisor/`](./examples/durable-supervisor/) — cross-worker resume keystone +- [`agent-into-reviewer/`](./examples/agent-into-reviewer/) — pipe one runtime's stream into a reviewer agent + +## Tests + +```bash +pnpm test # full Node suite (251 tests) +pnpm test:workers # real workerd DO integration test +pnpm typecheck +pnpm lint +pnpm build +``` diff --git a/docs/concepts.md b/docs/concepts.md new file mode 100644 index 0000000..9857797 --- /dev/null +++ b/docs/concepts.md @@ -0,0 +1,157 @@ +# Concepts + +agent-runtime is a thin substrate. It owns five things and delegates the +rest. Read this file once and the rest of the API falls into place. + +## The five layers + +``` + ┌──────────────────────────┐ + │ Domain code (yours) │ + │ tools, rubric, prompts │ + └────────────┬─────────────┘ + │ + ┌───────────────────────────────────────┴─────────────────┐ + │ Agent manifest ─ defineAgent({ surfaces, run, … }) │ + └───────────────────────────────────────┬─────────────────┘ + │ + ┌───────────────────────────────────────┴─────────────────┐ + │ Task lifecycle ─ runAgentTask / runAgentTaskStream │ + │ observe → validate → decide → act → eval │ + └───────────────────────────────────────┬─────────────────┘ + │ + ┌───────────────────────────────────────┴─────────────────┐ + │ Durability ─ runDurableTurn / runSupervisedTurn │ + │ + DurableRunStore + stream-event log + RunHandle │ + └───────────────────────────────────────┬─────────────────┘ + │ + ┌───────────────────────────────────────┴─────────────────┐ + │ Backends + catalog │ + │ createOpenAICompatibleBackend, createSandboxPromptBackend, + │ getModels / resolveChatModel / validateChatModelId │ + └─────────────────────────────────────────────────────────┘ +``` + +Each layer composes the one below it. You can use the bottom layers +alone (a raw backend + the model catalog), or the whole stack +(`defineAgent` → `runSupervisedTurn`) — they're the same primitives +nested. + +## The task lifecycle + +Every `runAgentTask` is a small state machine over an `AgentAdapter`: + +- **observe** → snapshot domain state (read-only). +- **validate** → score the snapshot against the eval rubric. +- **decide** → `act` (perform a domain action) | `ask` (ask the user + something) | `stop` (this turn is done, here's the outcome). +- **act** → effect the action; loop. + +The adapter is *yours*. The lifecycle, the eval lift, the stop semantics, +the cost ledger — all substrate. Streaming is the same shape: +`runAgentTaskStream` yields `RuntimeStreamEvent`s as the loop progresses. + +## Durability — three levels + +A turn that "completes" means the response reached the client AND the +side effects landed. A worker isolate can die anywhere in between. Pick +the level that matches your turn length and substrate: + +| Level | Survives | When to reach for it | +|---|---|---| +| `runAgentTask` / `runAgentTaskStream` | nothing — a worker crash re-runs from the top | sub-second turns, no sandbox | +| `runDurableTurn` | a worker crash *after* the turn finished (cached replay) | medium turns, no sandbox-reconnect | +| `runSupervisedTurn` + `SessionSupervisorDO` | a worker crash *during* the turn — a fresh supervisor re-attaches to the in-flight sandbox run | long sandbox-backed turns | + +`runSupervisedTurn` works because the sandbox container is +orchestrator-managed and **outlives** the worker. The supervisor: + +1. Drains every event into the substrate's own ordered log + (`appendStreamEvent`, idempotent on `eventId`). +2. Persists a `RunHandle` (`setRunHandle`) the moment the substrate + yields a run id. +3. Heartbeats the lease while attached. + +A fresh supervisor reads the log for its cursor and calls +`adapter.attach(handle, cursor)` to resume past it — events through +`cursor` are not re-delivered (the log's idempotency dedups the seam). + +## The reconnect adapter contract + +`SandboxReconnectAdapter` is one typed interface. Implement it **once +per substrate** (the Tangle sandbox SDK, an OpenAI Assistants thread, +whatever), never per product. + +```ts +interface SandboxReconnectAdapter { + start(): AsyncIterable> + attach(handle: RunHandle, afterEventId: string | undefined): + AsyncIterable> +} +``` + +`SupervisedEvent` carries an `eventId` (cursor + dedup key), a `payload` +(your event type), and an optional `handle` (carried on the first frame +once the substrate yields the run id). + +Conformance assertions live in `src/durable/tests/supervisor.test.ts` — +copy them into your adapter's tests so substrate quirks surface there, +not in a 15-minute production turn. + +## The agent manifest + +`defineAgent(...)` is how a vertical declares the **surfaces** (prompt, +skills, tools — the levers `agent-eval`'s analyst loop can edit), the +**knowledge** requirements, the **rubric**, and the **run** function +that ties it all together. The manifest is what the eval harness +benchmarks, what the analyst loop improves, and (in time) what the +generated scaffold produces. + +Keep `defineAgent` *declarative*. Domain logic — the actual tool calls, +the actual rubric scoring — lives in functions the manifest references, +not inline. + +## Model resolution + +Every product chat handler asks the same questions and gets the same +answers wrong (or differently). Substrate primitive: + +- **`resolveChatModel(candidates, fallback)`** — first-non-blank + precedence over caller-supplied candidates (`request → workspace → + env`, in whatever order *you* want). Policy-free. +- **`validateChatModelId(modelId, { allowlist?, routerBaseUrl? })`** — + rejects malformed ids and ids absent from both the caller's + `allowlist` and the live router catalog. **Fails closed**: when the + catalog can't be fetched, an unverifiable id is rejected. +- **`getModels` / `resolveRouterBaseUrl` / `withConfiguredModels`** — + the catalog fetch + base-URL + injection helpers. + +This module has **no React, no `process.env` assumption** — it runs +unchanged in Node and in Cloudflare Workers. + +## Backends + +`createOpenAICompatibleBackend({ baseUrl, model, apiKey })` and +`createSandboxPromptBackend({ ... })` are the two production backends. +Both stream. `policy.fallbackModels: [...]` rotates through a named list +on transient failure — that's the only fallback you should ever wire, +and it's explicit. + +The doctrine is in `AGENTS.md`: **no silent fallbacks**. Required fields +fail loud; named rotations are opt-in. + +## What this package does NOT own + +Domain policy. Models. Tools. Connectors. UI. Prompts. Rubrics. Those +live in your vertical. The runtime is reusable across many kinds of +agents because nothing in this list is baked into it. + +## Reading order for a new consumer + +1. `examples/basic-task/` — the smallest end-to-end. +2. `examples/sandbox-stream-backend/` — what streaming looks like. +3. `examples/runtime-run/` — the production-run row + cost ledger. +4. `examples/model-resolution/` — pick + validate a model. +5. `examples/durable-supervisor/` — the cross-worker resume keystone. +6. `examples/agent-into-reviewer/` — pipe one runtime's stream into a reviewer agent. +7. The `README.md` entry-point table — every other primitive, one row each. diff --git a/examples/README.md b/examples/README.md index 69d6fe5..2a02019 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,9 +1,8 @@ # agent-runtime examples -Each example is a single runnable `.ts` file plus a short README. The -synthetic ones (`basic-task`, `with-knowledge-readiness`, `sse-stream`, -`sandbox-stream-backend`, `sanitized-telemetry`, `sanitized-telemetry-streaming`) -need no credentials; `openai-stream-backend` needs an `OPENAI_API_KEY`. +Each example is a single runnable `.ts` file plus a short README. All +ten are synthetic — no credentials required, except `openai-stream-backend` +which needs an `OPENAI_API_KEY`. | Example | What it covers | |---|---| @@ -14,6 +13,10 @@ need no credentials; `openai-stream-backend` needs an `OPENAI_API_KEY`. | [`sse-stream/`](./sse-stream/) | Server-Sent Events helpers for browser routes | | [`sandbox-stream-backend/`](./sandbox-stream-backend/) | `runAgentTaskStream` with `createSandboxPromptBackend` (synthetic sandbox client) | | [`openai-stream-backend/`](./openai-stream-backend/) | `runAgentTaskStream` with `createOpenAICompatibleBackend` (real endpoint required) | +| [`runtime-run/`](./runtime-run/) | `startRuntimeRun` + cost ledger + persistence adapter | +| [`model-resolution/`](./model-resolution/) | `resolveChatModel` + `validateChatModelId` (fail-closed) + `getModels` | +| [`durable-supervisor/`](./durable-supervisor/) | `runSupervisedTurn` — cross-worker resume keystone (fresh / resumed / replayed) | +| [`agent-into-reviewer/`](./agent-into-reviewer/) | Pipe one runtime's stream into a reviewer agent (the "2-runtime" pattern) | ## Conventions @@ -38,6 +41,10 @@ pnpm tsx examples/sanitized-telemetry/sanitized-telemetry.ts pnpm tsx examples/sanitized-telemetry-streaming/sanitized-telemetry-streaming.ts pnpm tsx examples/sse-stream/sse-stream.ts pnpm tsx examples/sandbox-stream-backend/sandbox-stream-backend.ts +pnpm tsx examples/runtime-run/runtime-run.ts +pnpm tsx examples/model-resolution/model-resolution.ts +pnpm tsx examples/durable-supervisor/durable-supervisor.ts +pnpm tsx examples/agent-into-reviewer/agent-into-reviewer.ts # requires creds OPENAI_API_KEY=... pnpm tsx examples/openai-stream-backend/openai-stream-backend.ts diff --git a/examples/agent-into-reviewer/README.md b/examples/agent-into-reviewer/README.md new file mode 100644 index 0000000..9e34505 --- /dev/null +++ b/examples/agent-into-reviewer/README.md @@ -0,0 +1,23 @@ +# Agent into reviewer + +Two runtimes, one driving the other. Agent A produces a draft as a +stream; Agent B is a reviewer — a normal `AgentAdapter` that scores the +collected draft against a rubric and stops with a verdict. + +The pattern is the point: + +1. **Collect** A's stream (any async iterable: `runAgentTaskStream`, a + sandbox client, an OpenAI stream, a synthetic chunked generator). +2. **Pipe** the collected output into B's `task.inputs`. +3. **Run** B through the same task lifecycle every other agent-runtime + call uses. B's adapter *is* the bridge — no separate "reviewer + framework" needed. + +The example uses a synthetic streaming generator for A so it runs +offline. In production, swap that generator for `runAgentTaskStream({ +task, backend, input })` with the same shape — an async iterable of +events. The reviewer adapter is unchanged. + +```bash +pnpm tsx examples/agent-into-reviewer/agent-into-reviewer.ts +``` diff --git a/examples/agent-into-reviewer/agent-into-reviewer.ts b/examples/agent-into-reviewer/agent-into-reviewer.ts new file mode 100644 index 0000000..3e0ec53 --- /dev/null +++ b/examples/agent-into-reviewer/agent-into-reviewer.ts @@ -0,0 +1,105 @@ +/** + * Two runtimes, one driving the other. Agent A produces a draft (here + * a synthetic chunked stream — swap in `runAgentTaskStream` + a real + * backend in production with no shape change). Agent B is a reviewer: + * an `AgentAdapter` that scores the collected draft against a rubric + * and stops with a verdict. + * + * The pattern: collect A's stream into a buffer, hand it to B as + * `task.inputs`. B's adapter is the bridge — same task lifecycle every + * other agent-runtime call uses. + * + * Run with: + * pnpm tsx examples/agent-into-reviewer/agent-into-reviewer.ts + */ + +import type { AgentAdapter } from '@tangle-network/agent-runtime' +import { runAgentTask } from '@tangle-network/agent-runtime' + +// ── Agent A — a "model" that streams a draft. In production this is +// `runAgentTaskStream({ task, backend, input })` with the same shape: +// an async iterable of textual events. ───────────────────────────────── +async function* draftStream(): AsyncGenerator { + const chunks = [ + 'The 2026 return ', + 'is mostly complete. ', + 'Missing: Schedule B (interest income) ', + 'and one W-2.', + ] + for (const chunk of chunks) { + await new Promise((r) => setTimeout(r, 5)) + yield chunk + } +} + +// ── Agent B — the reviewer. Same agent-runtime task lifecycle: observe, +// validate, decide. The reviewer's input is A's collected draft. ──────── +interface ReviewerState { + draftLength: number + mentionsMissing: boolean +} +type ReviewerAction = { kind: 'noop' } + +function buildReviewer(draft: string): AgentAdapter { + return { + observe: () => ({ + draftLength: draft.length, + mentionsMissing: /missing/i.test(draft), + }), + validate({ state }) { + // The rubric: a draft is acceptable if it is non-trivially long AND + // it surfaces missing items rather than fabricating completeness. + return [ + { id: 'length', score: state.draftLength >= 60 ? 1 : 0, passed: state.draftLength >= 60 }, + { + id: 'surfaces-missing', + score: state.mentionsMissing ? 1 : 0, + passed: state.mentionsMissing, + }, + ] + }, + decide({ state }) { + const pass = state.draftLength >= 60 && state.mentionsMissing + return { + type: 'stop', + pass, + score: pass ? 1 : 0, + reason: pass ? 'draft surfaces missing evidence' : 'draft fails rubric', + } + }, + act() { + /* reviewer takes no domain actions */ + }, + } +} + +async function main() { + // 1. Collect agent A's stream — this is the "pipe" between the two. + let draft = '' + process.stdout.write('[A] ') + for await (const chunk of draftStream()) { + draft += chunk + process.stdout.write(chunk) + } + process.stdout.write('\n') + + // 2. Hand the draft to agent B as input; run B through the runtime. + const result = await runAgentTask({ + task: { + id: 'review-2026-return', + intent: 'Review a draft return for missing evidence', + domain: 'review', + inputs: { draft }, + }, + adapter: buildReviewer(draft), + }) + + console.log('\n[B] status: ', result.status) + console.log('[B] pass: ', result.control.pass) + console.log('[B] reason: ', result.control.reason) +} + +main().catch((err) => { + console.error(err) + process.exit(1) +}) diff --git a/examples/durable-supervisor/README.md b/examples/durable-supervisor/README.md new file mode 100644 index 0000000..589b47f --- /dev/null +++ b/examples/durable-supervisor/README.md @@ -0,0 +1,22 @@ +# Durable run supervisor + +The cross-worker resume keystone. Worker 1 drains part of a long turn, +its isolate "dies" mid-stream, Worker 2 picks the same `runId` up and +resumes from the substrate's event log + cursor — the caller sees the +complete sequence exactly once. + +What the example shows: + +- `runSupervisedTurn` — the platform-agnostic supervisor (drains into + the durable log, persists the `RunHandle`, heartbeats the lease). +- A toy `SandboxReconnectAdapter` — one typed contract: `start()` for a + fresh run, `attach(handle, afterEventId)` to resume past a cursor. +- The three resolution modes — `fresh` / `resumed` / `replayed` — and + the idempotent `appendStreamEvent` that dedups the reconnect seam. + +For the Cloudflare Durable Object host — `createSessionSupervisorDO` — +see the README; it's a ~100-line glue layer around this same primitive. + +```bash +pnpm tsx examples/durable-supervisor/durable-supervisor.ts +``` diff --git a/examples/durable-supervisor/durable-supervisor.ts b/examples/durable-supervisor/durable-supervisor.ts new file mode 100644 index 0000000..58b99dc --- /dev/null +++ b/examples/durable-supervisor/durable-supervisor.ts @@ -0,0 +1,96 @@ +/** + * Durable run supervisor — the cross-worker resume keystone. + * + * Worker 1 drains a few events of a long turn, then its isolate "dies" + * (we stop pulling the generator and expire the lease). Worker 2 picks + * the same `runId` up: it re-yields the logged prefix from the substrate + * and resumes via `adapter.attach(handle, cursor)`. The caller sees the + * complete event sequence exactly once — no gap, no duplicate. + * + * Run with: + * pnpm tsx examples/durable-supervisor/durable-supervisor.ts + */ + +import { + type DurableRunManifest, + InMemoryDurableRunStore, + type RunHandle, + runSupervisedTurn, + type SandboxReconnectAdapter, + type SupervisedEvent, +} from '@tangle-network/agent-runtime' + +// ── Your scripted "sandbox" — pretend the events are streaming from +// somewhere durable (a sandbox container that outlives the worker). ──── +function scriptedAdapter(): SandboxReconnectAdapter { + const script = ['intro', 'analysis', 'finding-1', 'finding-2', 'conclusion'] + return { + async *start(): AsyncGenerator> { + for (const [i, payload] of script.entries()) { + // The first frame carries the handle — that is what the substrate + // uses to re-attach. + const handle: RunHandle | undefined = + i === 0 ? { kind: 'sandbox', runId: 'sbx-1', status: 'running' } : undefined + yield { eventId: `e${i}`, payload, handle } + } + }, + async *attach(_handle, afterEventId) { + const idx = afterEventId ? script.findIndex((_, i) => `e${i}` === afterEventId) : -1 + for (let i = idx + 1; i < script.length; i++) { + yield { eventId: `e${i}`, payload: script[i]! } + } + }, + } +} + +const manifest = { + projectId: 'demo', + scenarioId: 'persona-1', + task: { id: 'long-turn', intent: 'chat', domain: 'demo' }, + input: { q: 'analyse the brief' }, +} as unknown as DurableRunManifest + +async function main() { + const store = new InMemoryDurableRunStore() + const runId = 'turn-1' + + // ── Worker 1 — drains 2 of 5 events, then dies mid-stream ──────────── + const w1 = runSupervisedTurn({ + store, + runId, + manifest, + workerId: 'w1', + adapter: scriptedAdapter(), + }) + const partial: string[] = [] + for await (const event of w1.stream) { + partial.push(event) + if (partial.length >= 2) break // worker 1's isolate "dies" + } + console.log('worker 1 saw: ', partial) // ['intro', 'analysis'] + console.log('store has: ', (await store.readStreamEvents(runId)).length, 'events') // 2 + + // Worker 1 stopped heartbeating; its lease lapses. + store._expireLease(runId) + + // ── Worker 2 picks up the same runId ───────────────────────────────── + const w2 = runSupervisedTurn({ + store, + runId, + manifest, + workerId: 'w2', + adapter: scriptedAdapter(), + }) + const full: string[] = [] + for await (const event of w2.stream) full.push(event) + + console.log('worker 2 saw: ', full) // complete sequence, exactly once + console.log('worker 2 mode: ', w2.mode()) // 'resumed' + console.log('store has: ', (await store.readStreamEvents(runId)).length, 'events') // 5 + console.log('record status: ', w2.record()?.status) // 'completed' +} + +main().catch((err) => { + console.error(err) + process.exit(1) +}) diff --git a/examples/model-resolution/README.md b/examples/model-resolution/README.md new file mode 100644 index 0000000..8c7f6f0 --- /dev/null +++ b/examples/model-resolution/README.md @@ -0,0 +1,20 @@ +# Model resolution + +Demonstrates the four chat-model primitives every product chat handler +needs and was hand-rolling per repo: + +- `resolveRouterBaseUrl(env)` — normalised router base URL. +- `resolveChatModel(candidates, fallback)` — first-non-blank precedence; + caller owns the order (`request → workspace → env`, etc.). +- `validateChatModelId(modelId, { allowlist?, loadModels? })` — rejects + malformed ids and ids absent from both the allowlist and the live + catalog. **Fail-closed**: a failed catalog fetch rejects. +- `withConfiguredModels(catalog, extraIds)` — inject env-pinned ids + into the picker without duplicating catalog entries. + +Runs offline (the example injects `loadModels` instead of calling +`getModels` against a real router). + +```bash +pnpm tsx examples/model-resolution/model-resolution.ts +``` diff --git a/examples/model-resolution/model-resolution.ts b/examples/model-resolution/model-resolution.ts new file mode 100644 index 0000000..6a652f4 --- /dev/null +++ b/examples/model-resolution/model-resolution.ts @@ -0,0 +1,68 @@ +/** + * Chat-model resolution + catalog admission — the one primitive every + * product chat handler needs and was hand-rolling per repo. Runs offline + * via an injected `loadModels`. + * + * Run with: + * pnpm tsx examples/model-resolution/model-resolution.ts + */ + +import { + cleanModelId, + type ModelInfo, + resolveChatModel, + resolveRouterBaseUrl, + validateChatModelId, + withConfiguredModels, +} from '@tangle-network/agent-runtime' + +// Imagine this came from the Tangle Router. A real product calls `getModels`. +const catalog: ModelInfo[] = [ + { id: 'claude-sonnet-4-6', name: 'Sonnet 4.6' }, + { id: 'gpt-4o', name: 'GPT-4o', provider: 'openai' }, +] +const loadModels = async () => catalog + +async function main() { + // 1. Router base URL — env-driven, normalised (no trailing /v1 or /). + const env = { TANGLE_ROUTER_URL: 'https://router.tangle.tools/v1/' } + console.log('routerBaseUrl:', resolveRouterBaseUrl(env)) + + // 2. Precedence resolution — first non-blank wins; caller owns the order. + const resolved = resolveChatModel( + [ + { source: 'request', model: undefined }, // user did not pin one + { source: 'workspace', model: ' ' }, // workspace pin is blank + { source: 'env', model: 'claude-sonnet-4-6' }, // env wins + ], + { source: 'default', model: 'claude-sonnet-4-6' }, + ) + console.log('resolved: ', resolved) // { source: 'env', model: 'claude-sonnet-4-6' } + + // 3. Catalog admission — fail-closed: malformed ids, unknown ids, and a + // failed router fetch all reject. An allowlist (your default + any + // env-configured ids) short-circuits the catalog round-trip. + const accepted = await validateChatModelId(resolved.model, { + allowlist: ['claude-sonnet-4-6'], + loadModels, + }) + console.log('accepted: ', accepted) // { succeeded: true, value: '...' } + + const rejected = await validateChatModelId('not in catalog', { loadModels }) + console.log('rejected: ', rejected) // { succeeded: false, error: '...' } + + const malformed = await validateChatModelId('has spaces!', { loadModels }) + console.log('malformed: ', malformed) // { succeeded: false, error: 'malformed' } + + // 4. Inject env-configured ids into the catalog the picker shows the user. + const picker = withConfiguredModels(catalog, ['private/internal-model']) + console.log('picker first: ', picker[0]?.id) // 'private/internal-model' + + // 5. Helpers + console.log('cleanModelId: ', cleanModelId(' gpt-4o ')) // 'gpt-4o' +} + +main().catch((err) => { + console.error(err) + process.exit(1) +}) diff --git a/package.json b/package.json index 8539602..be942f4 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "prepare": "tsup", "test": "vitest run", "test:watch": "vitest", + "test:workers": "vitest run -c vitest.workers.config.ts", "lint": "biome check src tests examples", "lint:fix": "biome check --write src tests examples", "typecheck": "tsc --noEmit" @@ -57,13 +58,16 @@ }, "devDependencies": { "@biomejs/biome": "^2.4.0", + "@cloudflare/vitest-pool-workers": "^0.8.71", + "@cloudflare/workers-types": "^4.20260522.1", "@tangle-network/sandbox": "0.1.2", "@types/better-sqlite3": "^7.6.13", "@types/node": "^25.6.0", "better-sqlite3": "^12.10.0", "tsup": "^8.0.0", "typescript": "^5.7.0", - "vitest": "^3.0.0" + "vitest": "^3.0.0", + "wrangler": "^4.94.0" }, "pnpm": { "minimumReleaseAge": 4320, @@ -72,7 +76,8 @@ ], "onlyBuiltDependencies": [ "better-sqlite3", - "esbuild" + "esbuild", + "workerd" ] }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dd193fb..cdee100 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,6 +15,12 @@ importers: '@biomejs/biome': specifier: ^2.4.0 version: 2.4.15 + '@cloudflare/vitest-pool-workers': + specifier: ^0.8.71 + version: 0.8.71(@cloudflare/workers-types@4.20260522.1)(@vitest/runner@3.2.4)(@vitest/snapshot@3.2.4)(vitest@3.2.4(@types/node@25.6.0)(yaml@2.8.4)) + '@cloudflare/workers-types': + specifier: ^4.20260522.1 + version: 4.20260522.1 '@tangle-network/sandbox': specifier: 0.1.2 version: 0.1.2(viem@2.48.8(typescript@5.9.3)(zod@4.4.2)) @@ -36,6 +42,9 @@ importers: vitest: specifier: ^3.0.0 version: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + wrangler: + specifier: ^4.94.0 + version: 4.94.0(@cloudflare/workers-types@4.20260522.1) packages: @@ -109,156 +118,565 @@ packages: cpu: [x64] os: [win32] + '@cloudflare/kv-asset-handler@0.4.0': + resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} + engines: {node: '>=18.0.0'} + + '@cloudflare/kv-asset-handler@0.5.0': + resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==} + engines: {node: '>=22.0.0'} + + '@cloudflare/unenv-preset@2.16.1': + resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==} + peerDependencies: + unenv: 2.0.0-rc.24 + workerd: '>1.20260305.0 <2.0.0-0' + peerDependenciesMeta: + workerd: + optional: true + + '@cloudflare/unenv-preset@2.7.3': + resolution: {integrity: sha512-tsQQagBKjvpd9baa6nWVIv399ejiqcrUBBW6SZx6Z22+ymm+Odv5+cFimyuCsD/fC1fQTwfRmwXBNpzvHSeGCw==} + peerDependencies: + unenv: 2.0.0-rc.21 + workerd: ^1.20250828.1 + peerDependenciesMeta: + workerd: + optional: true + + '@cloudflare/vitest-pool-workers@0.8.71': + resolution: {integrity: sha512-keu2HCLQfRNwbmLBCDXJgCFpANTaYnQpE01fBOo4CNwiWHUT7SZGN7w64RKiSWRHyYppStXBuE5Ng7F42+flpg==} + peerDependencies: + '@vitest/runner': 2.0.x - 3.2.x + '@vitest/snapshot': 2.0.x - 3.2.x + vitest: 2.0.x - 3.2.x + + '@cloudflare/workerd-darwin-64@1.20250906.0': + resolution: {integrity: sha512-E+X/YYH9BmX0ew2j/mAWFif2z05NMNuhCTlNYEGLkqMe99K15UewBqajL9pMcMUKxylnlrEoK3VNxl33DkbnPA==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + + '@cloudflare/workerd-darwin-64@1.20260521.1': + resolution: {integrity: sha512-aiNdXmxlhwGjTSajL3I7uQPpN4lAOcXjvg5ZOlJKIywnevr798n9XCS6lvuqgniM3KjurBNWRRypMJntg/eSLg==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + + '@cloudflare/workerd-darwin-arm64@1.20250906.0': + resolution: {integrity: sha512-X5apsZ1SFW4FYTM19ISHf8005FJMPfrcf4U5rO0tdj+TeJgQgXuZ57IG0WeW7SpLVeBo8hM6WC8CovZh41AfnA==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + + '@cloudflare/workerd-darwin-arm64@1.20260521.1': + resolution: {integrity: sha512-ikN8aKSi4Ak28ndOkuSO5rq6lmV6wwDQu9F9Vu6J7EkwAOth74J/Hjn4j4EuFceW/npw2Ws0Y/muzA6WKHl4TA==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + + '@cloudflare/workerd-linux-64@1.20250906.0': + resolution: {integrity: sha512-rlKzWgsLnlQ5Nt9W69YBJKcmTmZbOGu0edUsenXPmc6wzULUxoQpi7ZE9k3TfTonJx4WoQsQlzCUamRYFsX+0Q==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + + '@cloudflare/workerd-linux-64@1.20260521.1': + resolution: {integrity: sha512-D/gUhvQcG0pJr5aJl6yUoi2JxbFpjVtDq9xUJHPjfkAjL28TUVgCR/e5r8YGirepv4I1DK7ihuii9LZ2GGMJbw==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + + '@cloudflare/workerd-linux-arm64@1.20250906.0': + resolution: {integrity: sha512-DdedhiQ+SeLzpg7BpcLrIPEZ33QKioJQ1wvL4X7nuLzEB9rWzS37NNNahQzc1+44rhG4fyiHbXBPOeox4B9XVA==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + + '@cloudflare/workerd-linux-arm64@1.20260521.1': + resolution: {integrity: sha512-vhjWPIHenczegTakhRPwEmTeaavCpNqsuo3RlLCkUdU47HrwLvy/4QersGggs4+kF4Do+IE/EznCGyT40xYcLA==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + + '@cloudflare/workerd-windows-64@1.20250906.0': + resolution: {integrity: sha512-Q8Qjfs8jGVILnZL6vUpQ90q/8MTCYaGR3d1LGxZMBqte8Vr7xF3KFHPEy7tFs0j0mMjnqCYzlofmPNY+9ZaDRg==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + + '@cloudflare/workerd-windows-64@1.20260521.1': + resolution: {integrity: sha512-wBolYC/+lnGIEbkkPdzFtjTOWip2uQH6maeAP1ZV0kyxi5SGpsa83+wD5rH5OOle+sHE5qJMdwCKjwRwj+FKJg==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + + '@cloudflare/workers-types@4.20260522.1': + resolution: {integrity: sha512-UjKZprpYHAaBVipLfZA2GzTuWSTHyPXWRsaedwVEqyDe+VHwFi8RVtxGr1lceBDCwLDGRjlUwuwokX6O9GZY2A==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@esbuild/aix-ppc64@0.25.4': + resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.27.7': resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.25.4': + resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.27.7': resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm@0.25.4': + resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.27.7': resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-x64@0.25.4': + resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.27.7': resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.25.4': + resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.27.7': resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.25.4': + resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.27.7': resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.25.4': + resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.27.7': resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.25.4': + resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.27.7': resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.25.4': + resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.27.7': resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.25.4': + resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.27.7': resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.25.4': + resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.27.7': resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.25.4': + resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.27.7': resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.25.4': + resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.27.7': resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-ppc64@0.25.4': + resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.27.7': resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-riscv64@0.25.4': + resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.27.7': resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.25.4': + resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.27.7': resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.25.4': + resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.27.7': resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/netbsd-arm64@0.25.4': + resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-arm64@0.27.7': resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.25.4': + resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.27.7': resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/openbsd-arm64@0.25.4': + resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-arm64@0.27.7': resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.25.4': + resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.27.7': resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/openharmony-arm64@0.27.7': resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/sunos-x64@0.25.4': + resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.27.7': resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.25.4': + resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.27.7': resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.25.4': + resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.27.7': resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.25.4': + resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.27.7': resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} @@ -271,12 +689,254 @@ packages: peerDependencies: hono: ^4 - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + '@img/sharp-darwin-arm64@0.33.5': + resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.33.5': + resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.0.4': + resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.0.4': + resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.0.4': + resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.0.5': + resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.0.4': + resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.0.4': + resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.33.5': + resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.33.5': + resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.33.5': + resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.33.5': + resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.33.5': + resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.33.5': + resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.33.5': + resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.33.5': + resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.33.5': + resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -284,6 +944,9 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@noble/ciphers@1.3.0': resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} engines: {node: ^14.21.3 || >=16} @@ -308,6 +971,15 @@ packages: resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + + '@poppinss/dumper@0.6.5': + resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + '@rollup/rollup-android-arm-eabi@4.60.2': resolution: {integrity: sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==} cpu: [arm] @@ -451,6 +1123,13 @@ packages: '@scure/bip39@2.2.0': resolution: {integrity: sha512-T/Bj/YvYMNkIPq6EENO6/rcs2e7qTNuyoUXf0KBFDmp0ZDu0H2X4Lq6yC3i0c8PcWkov5EbW+yQZZbdMmk154A==} + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + + '@speed-highlight/core@1.2.15': + resolution: {integrity: sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw==} + '@tangle-network/agent-eval@0.30.0': resolution: {integrity: sha512-PggTJ2wOLm3wt5MUSRLet5su5UxNkq+Of70L3bkS5uO/crZedULbYg2I9EdZ0a5u3v4HXAy5aCbfMgzTh6oJag==} engines: {node: '>=20'} @@ -528,6 +1207,15 @@ packages: zod: optional: true + acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} @@ -550,9 +1238,15 @@ packages: bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + birpc@0.2.14: + resolution: {integrity: sha512-37FHE8rqsYM5JEKCnXFyHpBCzvgHEExwVVTq+nUmloInU7l8ezD1TpOhKpS8oe1DTYFqEK27rFZVKG43oTqXRA==} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + blake3-wasm@2.1.5: + resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} + buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} @@ -581,6 +1275,23 @@ packages: chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + commander@14.0.3: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} @@ -596,6 +1307,10 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + dayjs@1.11.20: resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} @@ -620,16 +1335,35 @@ packages: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + devalue@5.8.1: + resolution: {integrity: sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==} + end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + esbuild@0.25.4: + resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + esbuild@0.27.7: resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} @@ -641,6 +1375,10 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + exit-hook@2.2.1: + resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} + engines: {node: '>=6'} + expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} @@ -649,6 +1387,9 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -675,6 +1416,9 @@ packages: github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + hono@4.12.16: resolution: {integrity: sha512-jN0ZewiNAWSe5khM3EyCmBb250+b40wWbwNILNfEvq84VREWwOIkuUsFONk/3i3nqkz7Oe1PcpM2mwQEK2L9Kg==} engines: {node: '>=16.9.0'} @@ -688,6 +1432,9 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + is-arrayish@0.3.4: + resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} + isows@1.0.7: resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} peerDependencies: @@ -700,6 +1447,10 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -717,10 +1468,25 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} + miniflare@4.20250906.0: + resolution: {integrity: sha512-T/RWn1sa0ien80s6NjU+Un/tj12gR6wqScZoiLeMJDD4/fK0UXfnbWXJDubnUED8Xjm7RPQ5ESYdE+mhPmMtuQ==} + engines: {node: '>=18.0.0'} + hasBin: true + + miniflare@4.20260521.0: + resolution: {integrity: sha512-roRfxPq49OkuSeQsc43hRjSB1+HdHtDNKRwDEVk2hCjCBuBWxb5Wvwq88b0ULj6QVEJLN/+ZqF19M+h4VYJ/zg==} + engines: {node: '>=22.0.0'} + hasBin: true + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -752,6 +1518,9 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -766,6 +1535,9 @@ packages: typescript: optional: true + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -839,6 +1611,26 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rosie-skills-darwin-arm64@0.6.4: + resolution: {integrity: sha512-rn1s5hqFKcxeiDEWWoFa1hdGPshR8TkwHLzy/cBavb9XJNAaUxbe3oQ78W9sQkRHAgRyzJYyk9tw68Qrdnizgg==} + cpu: [arm64] + os: [darwin] + + rosie-skills-freebsd-x64@0.6.4: + resolution: {integrity: sha512-SxCRduPBMtfjkQ+q56Yw9OLA3PyaqoALzt7kER7IDKuUVfM2O/1w8sa5xhTDiCvWkZJixnH5d5Ya6KT+/Mwcng==} + cpu: [x64] + os: [freebsd] + + rosie-skills-linux-x64@0.6.4: + resolution: {integrity: sha512-D9Y9mfu7goB0s0X59uU3hcFeUTef3VbpCIDwFMzyvJrAq3XhRACWBDMHQsHlyWdHxTXPX/ILyW65RXyrJlgqng==} + cpu: [x64] + os: [linux] + + rosie-skills@0.6.4: + resolution: {integrity: sha512-ojfhSiQRdZ2QyWbmKAHOSAUbaLYrTc5zIH7mS1jKoP8KCFSQddwVhMyFqldckTeybTfW3zNcsZzyOTzGTN1SBA==} + engines: {node: '>=18'} + hasBin: true + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -847,6 +1639,14 @@ packages: engines: {node: '>=10'} hasBin: true + sharp@0.33.5: + resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -856,6 +1656,9 @@ packages: simple-get@4.0.1: resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + simple-swizzle@0.2.4: + resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -870,6 +1673,10 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + stoppable@1.1.0: + resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} + engines: {node: '>=4', npm: '>=6'} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -885,6 +1692,10 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + tar-fs@2.1.4: resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} @@ -928,6 +1739,9 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsup@8.5.1: resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} engines: {node: '>=18'} @@ -961,6 +1775,16 @@ packages: undici-types@7.19.2: resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} + undici@7.24.8: + resolution: {integrity: sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==} + engines: {node: '>=20.18.1'} + + unenv@2.0.0-rc.21: + resolution: {integrity: sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A==} + + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -1017,194 +1841,660 @@ packages: yaml: optional: true - vitest@3.2.4: - resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.4 - '@vitest/ui': 3.2.4 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/debug': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true + vitest@3.2.4: + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + workerd@1.20250906.0: + resolution: {integrity: sha512-ryVyEaqXPPsr/AxccRmYZZmDAkfQVjhfRqrNTlEeN8aftBk6Ca1u7/VqmfOayjCXrA+O547TauebU+J3IpvFXw==} + engines: {node: '>=16'} + hasBin: true + + workerd@1.20260521.1: + resolution: {integrity: sha512-HzIThcZ0ZVEuzVxpY2IYZ3yssSrTjtrWXAVfmOl5rVwyqcu7aeZXGMiwrEmi9MOcC3wjy+BNv+hFrMMY5OrjQQ==} + engines: {node: '>=16'} + hasBin: true + + wrangler@4.35.0: + resolution: {integrity: sha512-HbyXtbrh4Fi3mU8ussY85tVdQ74qpVS1vctUgaPc+bPrXBTqfDLkZ6VRtHAVF/eBhz4SFmhJtCQpN1caY2Ak8A==} + engines: {node: '>=18.0.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^4.20250906.0 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + + wrangler@4.94.0: + resolution: {integrity: sha512-GsNw0DomGFfeXFtKVTwn2X69UKcCxcTB0CXykjsMineJIxOeyrw7LovlHQ/3JU8KJHH7repLB+kOHvfTBA/Eew==} + engines: {node: '>=22.0.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^4.20260521.1 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yaml@2.8.4: + resolution: {integrity: sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==} + engines: {node: '>= 14.6'} + hasBin: true + + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.0-beta.10: + resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} + + zod@3.22.3: + resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zod@4.4.2: + resolution: {integrity: sha512-IynmDyxsEsb9RKzO3J9+4SxXnl2FTFSzNBaKKaMV6tsSk0rw9gYw9gs+JFCq/qk2LCZ78KDwyj+Z289TijSkUw==} + +snapshots: + + '@adraffy/ens-normalize@1.11.1': {} + + '@asteasolutions/zod-to-openapi@8.5.0(zod@4.4.2)': + dependencies: + openapi3-ts: 4.5.0 + zod: 4.4.2 + + '@ax-llm/ax@19.0.45(zod@4.4.2)': + dependencies: + '@opentelemetry/api': 1.9.1 + dayjs: 1.11.20 + optionalDependencies: + zod: 4.4.2 + + '@biomejs/biome@2.4.15': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 2.4.15 + '@biomejs/cli-darwin-x64': 2.4.15 + '@biomejs/cli-linux-arm64': 2.4.15 + '@biomejs/cli-linux-arm64-musl': 2.4.15 + '@biomejs/cli-linux-x64': 2.4.15 + '@biomejs/cli-linux-x64-musl': 2.4.15 + '@biomejs/cli-win32-arm64': 2.4.15 + '@biomejs/cli-win32-x64': 2.4.15 + + '@biomejs/cli-darwin-arm64@2.4.15': + optional: true + + '@biomejs/cli-darwin-x64@2.4.15': + optional: true + + '@biomejs/cli-linux-arm64-musl@2.4.15': + optional: true + + '@biomejs/cli-linux-arm64@2.4.15': + optional: true + + '@biomejs/cli-linux-x64-musl@2.4.15': + optional: true + + '@biomejs/cli-linux-x64@2.4.15': + optional: true + + '@biomejs/cli-win32-arm64@2.4.15': + optional: true + + '@biomejs/cli-win32-x64@2.4.15': + optional: true + + '@cloudflare/kv-asset-handler@0.4.0': + dependencies: + mime: 3.0.0 + + '@cloudflare/kv-asset-handler@0.5.0': {} + + '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260521.1)': + dependencies: + unenv: 2.0.0-rc.24 + optionalDependencies: + workerd: 1.20260521.1 + + '@cloudflare/unenv-preset@2.7.3(unenv@2.0.0-rc.21)(workerd@1.20250906.0)': + dependencies: + unenv: 2.0.0-rc.21 + optionalDependencies: + workerd: 1.20250906.0 + + '@cloudflare/vitest-pool-workers@0.8.71(@cloudflare/workers-types@4.20260522.1)(@vitest/runner@3.2.4)(@vitest/snapshot@3.2.4)(vitest@3.2.4(@types/node@25.6.0)(yaml@2.8.4))': + dependencies: + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + birpc: 0.2.14 + cjs-module-lexer: 1.4.3 + devalue: 5.8.1 + miniflare: 4.20250906.0 + semver: 7.8.0 + vitest: 3.2.4(@types/node@25.6.0)(yaml@2.8.4) + wrangler: 4.35.0(@cloudflare/workers-types@4.20260522.1) + zod: 3.25.76 + transitivePeerDependencies: + - '@cloudflare/workers-types' + - bufferutil + - utf-8-validate + + '@cloudflare/workerd-darwin-64@1.20250906.0': + optional: true + + '@cloudflare/workerd-darwin-64@1.20260521.1': + optional: true + + '@cloudflare/workerd-darwin-arm64@1.20250906.0': + optional: true + + '@cloudflare/workerd-darwin-arm64@1.20260521.1': + optional: true + + '@cloudflare/workerd-linux-64@1.20250906.0': + optional: true + + '@cloudflare/workerd-linux-64@1.20260521.1': + optional: true + + '@cloudflare/workerd-linux-arm64@1.20250906.0': + optional: true + + '@cloudflare/workerd-linux-arm64@1.20260521.1': + optional: true + + '@cloudflare/workerd-windows-64@1.20250906.0': + optional: true + + '@cloudflare/workerd-windows-64@1.20260521.1': + optional: true + + '@cloudflare/workers-types@4.20260522.1': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.25.4': + optional: true + + '@esbuild/aix-ppc64@0.27.3': + optional: true + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.25.4': + optional: true + + '@esbuild/android-arm64@0.27.3': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.25.4': + optional: true + + '@esbuild/android-arm@0.27.3': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.25.4': + optional: true + + '@esbuild/android-x64@0.27.3': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.25.4': + optional: true + + '@esbuild/darwin-arm64@0.27.3': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.25.4': + optional: true + + '@esbuild/darwin-x64@0.27.3': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.25.4': + optional: true + + '@esbuild/freebsd-arm64@0.27.3': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.25.4': + optional: true + + '@esbuild/freebsd-x64@0.27.3': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.25.4': + optional: true + + '@esbuild/linux-arm64@0.27.3': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.25.4': + optional: true + + '@esbuild/linux-arm@0.27.3': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.25.4': + optional: true + + '@esbuild/linux-ia32@0.27.3': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.25.4': + optional: true + + '@esbuild/linux-loong64@0.27.3': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.25.4': + optional: true + + '@esbuild/linux-mips64el@0.27.3': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.25.4': + optional: true + + '@esbuild/linux-ppc64@0.27.3': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.25.4': + optional: true + + '@esbuild/linux-riscv64@0.27.3': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.25.4': + optional: true + + '@esbuild/linux-s390x@0.27.3': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.25.4': + optional: true + + '@esbuild/linux-x64@0.27.3': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.25.4': + optional: true + + '@esbuild/netbsd-arm64@0.27.3': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.25.4': + optional: true + + '@esbuild/netbsd-x64@0.27.3': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.25.4': + optional: true + + '@esbuild/openbsd-arm64@0.27.3': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.25.4': + optional: true + + '@esbuild/openbsd-x64@0.27.3': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.3': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.25.4': + optional: true + + '@esbuild/sunos-x64@0.27.3': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true + '@esbuild/win32-arm64@0.25.4': + optional: true - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + '@esbuild/win32-arm64@0.27.3': + optional: true - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true + '@esbuild/win32-arm64@0.27.7': + optional: true - yaml@2.8.4: - resolution: {integrity: sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==} - engines: {node: '>= 14.6'} - hasBin: true + '@esbuild/win32-ia32@0.25.4': + optional: true - zod@4.4.2: - resolution: {integrity: sha512-IynmDyxsEsb9RKzO3J9+4SxXnl2FTFSzNBaKKaMV6tsSk0rw9gYw9gs+JFCq/qk2LCZ78KDwyj+Z289TijSkUw==} + '@esbuild/win32-ia32@0.27.3': + optional: true -snapshots: + '@esbuild/win32-ia32@0.27.7': + optional: true - '@adraffy/ens-normalize@1.11.1': {} + '@esbuild/win32-x64@0.25.4': + optional: true - '@asteasolutions/zod-to-openapi@8.5.0(zod@4.4.2)': - dependencies: - openapi3-ts: 4.5.0 - zod: 4.4.2 + '@esbuild/win32-x64@0.27.3': + optional: true - '@ax-llm/ax@19.0.45(zod@4.4.2)': + '@esbuild/win32-x64@0.27.7': + optional: true + + '@hono/node-server@2.0.1(hono@4.12.16)': dependencies: - '@opentelemetry/api': 1.9.1 - dayjs: 1.11.20 + hono: 4.12.16 + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: - zod: 4.4.2 + '@img/sharp-libvips-darwin-arm64': 1.0.4 + optional: true - '@biomejs/biome@2.4.15': + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.4.15 - '@biomejs/cli-darwin-x64': 2.4.15 - '@biomejs/cli-linux-arm64': 2.4.15 - '@biomejs/cli-linux-arm64-musl': 2.4.15 - '@biomejs/cli-linux-x64': 2.4.15 - '@biomejs/cli-linux-x64-musl': 2.4.15 - '@biomejs/cli-win32-arm64': 2.4.15 - '@biomejs/cli-win32-x64': 2.4.15 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true - '@biomejs/cli-darwin-arm64@2.4.15': + '@img/sharp-darwin-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.0.4 optional: true - '@biomejs/cli-darwin-x64@2.4.15': + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - '@biomejs/cli-linux-arm64-musl@2.4.15': + '@img/sharp-libvips-darwin-arm64@1.0.4': optional: true - '@biomejs/cli-linux-arm64@2.4.15': + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@biomejs/cli-linux-x64-musl@2.4.15': + '@img/sharp-libvips-darwin-x64@1.0.4': optional: true - '@biomejs/cli-linux-x64@2.4.15': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@biomejs/cli-win32-arm64@2.4.15': + '@img/sharp-libvips-linux-arm64@1.0.4': optional: true - '@biomejs/cli-win32-x64@2.4.15': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@esbuild/aix-ppc64@0.27.7': + '@img/sharp-libvips-linux-arm@1.0.5': optional: true - '@esbuild/android-arm64@0.27.7': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@esbuild/android-arm@0.27.7': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@esbuild/android-x64@0.27.7': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@esbuild/darwin-arm64@0.27.7': + '@img/sharp-libvips-linux-s390x@1.0.4': optional: true - '@esbuild/darwin-x64@0.27.7': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@esbuild/freebsd-arm64@0.27.7': + '@img/sharp-libvips-linux-x64@1.0.4': optional: true - '@esbuild/freebsd-x64@0.27.7': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@esbuild/linux-arm64@0.27.7': + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': optional: true - '@esbuild/linux-arm@0.27.7': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - '@esbuild/linux-ia32@0.27.7': + '@img/sharp-libvips-linuxmusl-x64@1.0.4': optional: true - '@esbuild/linux-loong64@0.27.7': + '@img/sharp-libvips-linuxmusl-x64@1.2.4': optional: true - '@esbuild/linux-mips64el@0.27.7': + '@img/sharp-linux-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.0.4 optional: true - '@esbuild/linux-ppc64@0.27.7': + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - '@esbuild/linux-riscv64@0.27.7': + '@img/sharp-linux-arm@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.0.5 optional: true - '@esbuild/linux-s390x@0.27.7': + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@esbuild/linux-x64@0.27.7': + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@esbuild/netbsd-arm64@0.27.7': + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@esbuild/netbsd-x64@0.27.7': + '@img/sharp-linux-s390x@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.0.4 optional: true - '@esbuild/openbsd-arm64@0.27.7': + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@esbuild/openbsd-x64@0.27.7': + '@img/sharp-linux-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.0.4 optional: true - '@esbuild/openharmony-arm64@0.27.7': + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@esbuild/sunos-x64@0.27.7': + '@img/sharp-linuxmusl-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 optional: true - '@esbuild/win32-arm64@0.27.7': + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@esbuild/win32-ia32@0.27.7': + '@img/sharp-linuxmusl-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 optional: true - '@esbuild/win32-x64@0.27.7': + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 optional: true - '@hono/node-server@2.0.1(hono@4.12.16)': + '@img/sharp-wasm32@0.33.5': dependencies: - hono: 4.12.16 + '@emnapi/runtime': 1.10.0 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.10.0 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.33.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.33.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -1220,6 +2510,11 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@noble/ciphers@1.3.0': {} '@noble/curves@1.9.1': @@ -1236,6 +2531,18 @@ snapshots: '@opentelemetry/api@1.9.1': {} + '@poppinss/colors@4.1.6': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.6.5': + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 + + '@poppinss/exception@1.2.3': {} + '@rollup/rollup-android-arm-eabi@4.60.2': optional: true @@ -1337,6 +2644,10 @@ snapshots: '@noble/hashes': 2.2.0 '@scure/base': 2.2.0 + '@sindresorhus/is@7.2.0': {} + + '@speed-highlight/core@1.2.15': {} + '@tangle-network/agent-eval@0.30.0(typescript@5.9.3)': dependencies: '@asteasolutions/zod-to-openapi': 8.5.0(zod@4.4.2) @@ -1434,6 +2745,10 @@ snapshots: typescript: 5.9.3 zod: 4.4.2 + acorn-walk@8.3.2: {} + + acorn@8.14.0: {} + acorn@8.16.0: {} any-promise@1.3.0: {} @@ -1451,12 +2766,16 @@ snapshots: dependencies: file-uri-to-path: 1.0.0 + birpc@0.2.14: {} + bl@4.1.0: dependencies: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 + blake3-wasm@2.1.5: {} + buffer@5.7.1: dependencies: base64-js: 1.5.1 @@ -1485,6 +2804,24 @@ snapshots: chownr@1.1.4: {} + cjs-module-lexer@1.4.3: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.4 + + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + commander@14.0.3: {} commander@4.1.1: {} @@ -1493,6 +2830,8 @@ snapshots: consola@3.4.2: {} + cookie@1.1.1: {} + dayjs@1.11.20: {} debug@4.4.3: @@ -1507,14 +2846,77 @@ snapshots: deep-extend@0.6.0: {} + defu@6.1.7: {} + detect-libc@2.1.2: {} + devalue@5.8.1: {} + end-of-stream@1.4.5: dependencies: once: 1.4.0 + error-stack-parser-es@1.0.5: {} + es-module-lexer@1.7.0: {} + esbuild@0.25.4: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.4 + '@esbuild/android-arm': 0.25.4 + '@esbuild/android-arm64': 0.25.4 + '@esbuild/android-x64': 0.25.4 + '@esbuild/darwin-arm64': 0.25.4 + '@esbuild/darwin-x64': 0.25.4 + '@esbuild/freebsd-arm64': 0.25.4 + '@esbuild/freebsd-x64': 0.25.4 + '@esbuild/linux-arm': 0.25.4 + '@esbuild/linux-arm64': 0.25.4 + '@esbuild/linux-ia32': 0.25.4 + '@esbuild/linux-loong64': 0.25.4 + '@esbuild/linux-mips64el': 0.25.4 + '@esbuild/linux-ppc64': 0.25.4 + '@esbuild/linux-riscv64': 0.25.4 + '@esbuild/linux-s390x': 0.25.4 + '@esbuild/linux-x64': 0.25.4 + '@esbuild/netbsd-arm64': 0.25.4 + '@esbuild/netbsd-x64': 0.25.4 + '@esbuild/openbsd-arm64': 0.25.4 + '@esbuild/openbsd-x64': 0.25.4 + '@esbuild/sunos-x64': 0.25.4 + '@esbuild/win32-arm64': 0.25.4 + '@esbuild/win32-ia32': 0.25.4 + '@esbuild/win32-x64': 0.25.4 + + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + esbuild@0.27.7: optionalDependencies: '@esbuild/aix-ppc64': 0.27.7 @@ -1550,10 +2952,14 @@ snapshots: eventemitter3@5.0.1: {} + exit-hook@2.2.1: {} + expand-template@2.0.3: {} expect-type@1.3.0: {} + exsolve@1.0.8: {} + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -1573,6 +2979,8 @@ snapshots: github-from-package@0.0.0: {} + glob-to-regexp@0.4.1: {} + hono@4.12.16: {} ieee754@1.2.1: {} @@ -1581,6 +2989,8 @@ snapshots: ini@1.3.8: {} + is-arrayish@0.3.4: {} + isows@1.0.7(ws@8.18.3): dependencies: ws: 8.18.3 @@ -1589,6 +2999,8 @@ snapshots: js-tokens@9.0.1: {} + kleur@4.1.5: {} + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -1601,8 +3013,40 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + mime@3.0.0: {} + mimic-response@3.1.0: {} + miniflare@4.20250906.0: + dependencies: + '@cspotcode/source-map-support': 0.8.1 + acorn: 8.14.0 + acorn-walk: 8.3.2 + exit-hook: 2.2.1 + glob-to-regexp: 0.4.1 + sharp: 0.33.5 + stoppable: 1.1.0 + undici: 7.24.8 + workerd: 1.20250906.0 + ws: 8.18.0 + youch: 4.1.0-beta.10 + zod: 3.22.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + miniflare@4.20260521.0: + dependencies: + '@cspotcode/source-map-support': 0.8.1 + sharp: 0.34.5 + undici: 7.24.8 + workerd: 1.20260521.1 + ws: 8.20.1 + youch: 4.1.0-beta.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + minimist@1.2.8: {} mkdirp-classic@0.5.3: {} @@ -1632,6 +3076,8 @@ snapshots: object-assign@4.1.1: {} + ohash@2.0.11: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -1655,6 +3101,8 @@ snapshots: transitivePeerDependencies: - zod + path-to-regexp@6.3.0: {} + pathe@2.0.3: {} pathval@2.0.1: {} @@ -1752,10 +3200,82 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.60.2 fsevents: 2.3.3 + rosie-skills-darwin-arm64@0.6.4: + optional: true + + rosie-skills-freebsd-x64@0.6.4: + optional: true + + rosie-skills-linux-x64@0.6.4: + optional: true + + rosie-skills@0.6.4: + optionalDependencies: + rosie-skills-darwin-arm64: 0.6.4 + rosie-skills-freebsd-x64: 0.6.4 + rosie-skills-linux-x64: 0.6.4 + safe-buffer@5.2.1: {} semver@7.8.0: {} + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.1.2 + semver: 7.8.0 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.33.5 + '@img/sharp-darwin-x64': 0.33.5 + '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-linux-arm': 0.33.5 + '@img/sharp-linux-arm64': 0.33.5 + '@img/sharp-linux-s390x': 0.33.5 + '@img/sharp-linux-x64': 0.33.5 + '@img/sharp-linuxmusl-arm64': 0.33.5 + '@img/sharp-linuxmusl-x64': 0.33.5 + '@img/sharp-wasm32': 0.33.5 + '@img/sharp-win32-ia32': 0.33.5 + '@img/sharp-win32-x64': 0.33.5 + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.0 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + siginfo@2.0.0: {} simple-concat@1.0.1: {} @@ -1766,6 +3286,10 @@ snapshots: once: 1.4.0 simple-concat: 1.0.1 + simple-swizzle@0.2.4: + dependencies: + is-arrayish: 0.3.4 + source-map-js@1.2.1: {} source-map@0.7.6: {} @@ -1774,6 +3298,8 @@ snapshots: std-env@3.10.0: {} + stoppable@1.1.0: {} + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -1794,6 +3320,8 @@ snapshots: tinyglobby: 0.2.16 ts-interface-checker: 0.1.13 + supports-color@10.2.2: {} + tar-fs@2.1.4: dependencies: chownr: 1.1.4 @@ -1836,6 +3364,9 @@ snapshots: ts-interface-checker@0.1.13: {} + tslib@2.8.1: + optional: true + tsup@8.5.1(postcss@8.5.13)(typescript@5.9.3)(yaml@2.8.4): dependencies: bundle-require: 5.1.0(esbuild@0.27.7) @@ -1874,6 +3405,20 @@ snapshots: undici-types@7.19.2: {} + undici@7.24.8: {} + + unenv@2.0.0-rc.21: + dependencies: + defu: 6.1.7 + exsolve: 1.0.8 + ohash: 2.0.11 + pathe: 2.0.3 + ufo: 1.6.4 + + unenv@2.0.0-rc.24: + dependencies: + pathe: 2.0.3 + util-deprecate@1.0.2: {} viem@2.48.8(typescript@5.9.3)(zod@4.4.2): @@ -1973,10 +3518,82 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + workerd@1.20250906.0: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20250906.0 + '@cloudflare/workerd-darwin-arm64': 1.20250906.0 + '@cloudflare/workerd-linux-64': 1.20250906.0 + '@cloudflare/workerd-linux-arm64': 1.20250906.0 + '@cloudflare/workerd-windows-64': 1.20250906.0 + + workerd@1.20260521.1: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20260521.1 + '@cloudflare/workerd-darwin-arm64': 1.20260521.1 + '@cloudflare/workerd-linux-64': 1.20260521.1 + '@cloudflare/workerd-linux-arm64': 1.20260521.1 + '@cloudflare/workerd-windows-64': 1.20260521.1 + + wrangler@4.35.0(@cloudflare/workers-types@4.20260522.1): + dependencies: + '@cloudflare/kv-asset-handler': 0.4.0 + '@cloudflare/unenv-preset': 2.7.3(unenv@2.0.0-rc.21)(workerd@1.20250906.0) + blake3-wasm: 2.1.5 + esbuild: 0.25.4 + miniflare: 4.20250906.0 + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.21 + workerd: 1.20250906.0 + optionalDependencies: + '@cloudflare/workers-types': 4.20260522.1 + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + wrangler@4.94.0(@cloudflare/workers-types@4.20260522.1): + dependencies: + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260521.1) + blake3-wasm: 2.1.5 + esbuild: 0.27.3 + miniflare: 4.20260521.0 + path-to-regexp: 6.3.0 + rosie-skills: 0.6.4 + unenv: 2.0.0-rc.24 + workerd: 1.20260521.1 + optionalDependencies: + '@cloudflare/workers-types': 4.20260522.1 + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + wrappy@1.0.2: {} + ws@8.18.0: {} + ws@8.18.3: {} + ws@8.20.1: {} + yaml@2.8.4: {} + youch-core@0.3.3: + dependencies: + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + + youch@4.1.0-beta.10: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.6.5 + '@speed-highlight/core': 1.2.15 + cookie: 1.1.1 + youch-core: 0.3.3 + + zod@3.22.3: {} + + zod@3.25.76: {} + zod@4.4.2: {} diff --git a/tests/workers/entry.ts b/tests/workers/entry.ts new file mode 100644 index 0000000..502cac5 --- /dev/null +++ b/tests/workers/entry.ts @@ -0,0 +1,89 @@ +/** + * Test-only worker entry. Builds a `SessionSupervisorDO` over an in-memory + * store + a controllable scripted adapter, so a vitest-pool-workers test can + * drive the real Cloudflare DO host under real `workerd`. Not a deployable + * Worker — referenced only by `wrangler.workers.toml`. + * + * The adapter is parameterised through the request URL (`?events=N&runId=…`) + * so the test injects different scenarios without recompiling. The in-memory + * store + scripted-adapter factory live at module scope; they survive across + * requests inside one workerd run, matching how a real product's DO would + * share a substrate binding across requests. + */ + +import { + createSessionSupervisorDO, + type DurableRunManifest, + InMemoryDurableRunStore, + type RunHandle, + type SandboxReconnectAdapter, + type SupervisedEvent, +} from '../../src/durable' + +interface TestEnv { + SESSION_SUPERVISOR: DurableObjectNamespace +} + +const store = new InMemoryDurableRunStore() + +const manifest = { + projectId: 'test', + scenarioId: 'persona-1', + task: { id: 'task-1', intent: 'chat', domain: 'test' }, + input: { q: 'hello' }, +} as unknown as DurableRunManifest + +function scriptedAdapter(n: number): SandboxReconnectAdapter { + const ids = Array.from({ length: n }, (_, i) => i) + return { + async *start(): AsyncGenerator> { + for (const i of ids) { + const handle: RunHandle | undefined = + i === 0 ? { kind: 'sandbox', runId: 'sbx-test', status: 'running' } : undefined + yield { eventId: `e${i}`, payload: i, handle } + } + }, + async *attach( + _handle: RunHandle, + afterEventId: string | undefined, + ): AsyncGenerator> { + const found = afterEventId ? ids.findIndex((i) => `e${i}` === afterEventId) : -1 + for (let i = found + 1; i < ids.length; i++) yield { eventId: `e${i}`, payload: i } + }, + } +} + +export const TestSessionSupervisor = createSessionSupervisorDO({ + async resolveRun(request) { + const url = new URL(request.url) + const runId = url.searchParams.get('runId') ?? 'r1' + const events = Number(url.searchParams.get('events') ?? '4') + return { + store, + runId, + manifest, + workerId: 'w-fetch', + adapter: scriptedAdapter(events), + } + }, + async resolveOrphan(runId) { + return { + store, + runId, + manifest, + workerId: 'w-alarm', + adapter: scriptedAdapter(4), + } + }, + encodeEvent: (event) => `data: ${event}\n`, +}) + +export default { + async fetch(request: Request, env: TestEnv): Promise { + const url = new URL(request.url) + const sessionId = url.searchParams.get('session') ?? 'default' + const id = env.SESSION_SUPERVISOR.idFromName(sessionId) + const stub = env.SESSION_SUPERVISOR.get(id) + return stub.fetch(request) + }, +} satisfies ExportedHandler diff --git a/tests/workers/session-supervisor-do.workers.test.ts b/tests/workers/session-supervisor-do.workers.test.ts new file mode 100644 index 0000000..af9f1d7 --- /dev/null +++ b/tests/workers/session-supervisor-do.workers.test.ts @@ -0,0 +1,31 @@ +import { SELF } from 'cloudflare:test' +import { describe, expect, it } from 'vitest' + +/** + * Test the SessionSupervisorDO end-to-end under real workerd: real + * `DurableObjectState`, real `ReadableStream`, real `Response`. The + * fake-state suite in `src/durable/tests/session-supervisor-do.test.ts` + * exercises the supervisor logic exhaustively (fresh / resumed / replayed / + * orphan re-attach via `alarm()`); this file's job is to prove the same DO + * host works against the actual Cloudflare runtime, catching any platform + * quirk the structural fakes miss. + */ +describe('SessionSupervisorDO under real workerd', () => { + it('streams a fresh supervised run end-to-end through a real DO', async () => { + const res = await SELF.fetch('http://test/?session=s-fresh&runId=r-fresh&events=4') + expect(res.status).toBe(200) + expect(res.headers.get('content-type')).toBe('text/event-stream') + const text = await res.text() + expect(text).toBe('data: 0\ndata: 1\ndata: 2\ndata: 3\n') + }) + + it('a second fetch for the same runId replays the same stream from the durable log', async () => { + await SELF.fetch('http://test/?session=s-replay&runId=r-replay&events=3').then((r) => r.text()) + // Second fetch — the run already completed, so the supervisor enters the + // replay path and re-yields the logged stream verbatim. + const replayed = await SELF.fetch('http://test/?session=s-replay&runId=r-replay&events=3').then( + (r) => r.text(), + ) + expect(replayed).toBe('data: 0\ndata: 1\ndata: 2\n') + }) +}) diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..0c08e07 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config' + +/** Default Node-pool vitest run. The workerd-only suite under + * `tests/workers/**` runs separately via `pnpm test:workers` against + * `vitest.workers.config.ts` — it imports `cloudflare:test`, which only + * resolves inside `@cloudflare/vitest-pool-workers`. */ +export default defineConfig({ + test: { + exclude: ['node_modules/**', 'dist/**', 'tests/workers/**'], + }, +}) diff --git a/vitest.workers.config.ts b/vitest.workers.config.ts new file mode 100644 index 0000000..ba9252e --- /dev/null +++ b/vitest.workers.config.ts @@ -0,0 +1,15 @@ +import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config' + +/** Separate vitest config used by `pnpm test:workers` so the main suite stays + * on the default Node pool; only the workerd-only `*.workers.test.ts` files + * run inside the real Cloudflare runtime via `@cloudflare/vitest-pool-workers`. */ +export default defineWorkersConfig({ + test: { + include: ['tests/workers/**/*.workers.test.ts'], + poolOptions: { + workers: { + wrangler: { configPath: './wrangler.workers.toml' }, + }, + }, + }, +}) diff --git a/wrangler.workers.toml b/wrangler.workers.toml new file mode 100644 index 0000000..68ff9c2 --- /dev/null +++ b/wrangler.workers.toml @@ -0,0 +1,17 @@ +# Wrangler config used ONLY by the `test:workers` vitest pool — it pins a +# real `workerd` runtime around the `SessionSupervisorDO` so the DO host is +# exercised under actual Cloudflare semantics (real DurableObjectState, real +# ReadableStream, real Response). Not a deployable Worker. + +name = "agent-runtime-workers-tests" +main = "tests/workers/entry.ts" +compatibility_date = "2025-05-01" +compatibility_flags = ["nodejs_compat"] + +[[durable_objects.bindings]] +name = "SESSION_SUPERVISOR" +class_name = "TestSessionSupervisor" + +[[migrations]] +tag = "v1" +new_classes = ["TestSessionSupervisor"]