diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9f3706a..73ede23 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -13,8 +13,11 @@ jobs:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- uses: denoland/setup-deno@v2
- - name: Install dependencies
+ - name: Install dependencies (API)
run: uv sync --directory api --dev
+ - name: Install dependencies (web)
+ run: deno install
+ working-directory: web
- uses: pre-commit/action@v3.0.1
check-web:
@@ -23,6 +26,9 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: denoland/setup-deno@v2
+ - name: Install dependencies
+ run: deno install
+ working-directory: web
- name: Check
run: deno task check
working-directory: web
diff --git a/web/README.md b/web/README.md
new file mode 100644
index 0000000..9532876
--- /dev/null
+++ b/web/README.md
@@ -0,0 +1,43 @@
+# Librarian — Web Frontend
+
+Fresh 2 frontend for the Librarian local AI research assistant.
+
+Built with [Deno](https://deno.com), [Fresh 2](https://fresh.deno.dev), [Preact](https://preactjs.com), [Vite](https://vite.dev), and [Tailwind CSS v4](https://tailwindcss.com).
+
+## Prerequisites
+
+- [Deno](https://deno.com) v2+
+
+## Commands
+
+```sh
+deno task dev # Start Vite dev server with HMR
+deno task build # Build for production → _fresh/
+deno task start # Run production build
+deno task check # Fmt check, lint, and typecheck
+```
+
+## Structure
+
+```
+web/
+├── routes/ # File-based pages and API handlers
+│ └── api/ # /api/config, /api/health
+├── islands/ # Client-hydrated interactive components
+│ ├── Chat.tsx # Main chat interface (SSE streaming)
+│ └── ControlsPanel.tsx # Collapsible settings sidebar
+├── components/ # Server-rendered static components
+├── utils/
+│ ├── appState.ts # Persisted signals (localStorage)
+│ └── bookmarks.ts # Bookmark group management
+└── assets/
+ └── styles.css # Tailwind + global CSS custom properties
+```
+
+## Architecture
+
+**Islands**: Only components in `islands/` run on the client. Everything in `components/` is server-rendered. This keeps the JS bundle small — interactivity is opt-in per component.
+
+**State**: Shared signals live in `utils/appState.ts`. Persistent state (bookmark groups, controls settings, message history) is synced to `localStorage` via `createPersistedSignal`.
+
+**Backend connection**: The frontend connects to the Python API on the port specified in `librarian.config.json` (read via `/api/config`). Queries stream over SSE.
diff --git a/web/assets/styles.css b/web/assets/styles.css
new file mode 100644
index 0000000..cb2d1c2
--- /dev/null
+++ b/web/assets/styles.css
@@ -0,0 +1,323 @@
+@import "tailwindcss";
+@plugin "@tailwindcss/typography";
+
+/* SVGs */
+:root {
+ --star-svg: url('data:image/svg+xml,');
+
+ /* Shared colors */
+ --color-muted: theme(--color-zinc-400);
+ --color-accent: theme(--color-green-300);
+ --color-text: color-mix(in srgb, theme(--color-green-200) 80%, transparent);
+
+ /* Backgrounds */
+ --bg-page: theme(--color-zinc-800);
+ --bg-panel: color-mix(in srgb, theme(--color-zinc-900) 50%, transparent);
+ --bg-panel-hover: color-mix(
+ in srgb,
+ theme(--color-zinc-900) 80%,
+ transparent
+ );
+
+ /* Content colors */
+ --color-answer: color-mix(in srgb, theme(--color-zinc-100) 90%, transparent);
+ --color-link: color-mix(in srgb, theme(--color-green-400) 90%, transparent);
+ --color-link-hover: theme(--color-green-300);
+ --color-danger: theme(--color-red-400);
+ --color-danger-muted: color-mix(
+ in srgb,
+ theme(--color-red-400) 50%,
+ transparent
+ );
+}
+
+/* Custom scrollbar styling */
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+::-webkit-scrollbar-track {
+ background: var(--bg-page);
+}
+
+::-webkit-scrollbar-thumb {
+ background: color-mix(in srgb, var(--color-accent) 30%, transparent);
+ border-radius: 4px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: color-mix(in srgb, var(--color-accent) 50%, transparent);
+}
+
+/* Firefox */
+* {
+ scrollbar-width: thin;
+ scrollbar-color: color-mix(in srgb, var(--color-accent) 30%, transparent)
+ var(--bg-page);
+}
+
+/* Controls panel */
+.controls-panel {
+ @apply border-zinc-700/50 text-green-200 transition-colors;
+ background-color: var(--bg-panel);
+
+ &:hover {
+ background-color: var(--bg-panel-hover);
+ }
+
+ @media (width >= 99rem) {
+ @apply absolute top-0 left-0 h-full z-10;
+ }
+
+ h1 {
+ @apply text-lg font-light mt-5;
+ color: var(--color-muted);
+ }
+
+ h2 {
+ @apply text-base font-light;
+ color: var(--color-accent);
+ }
+
+ h3 {
+ @apply text-sm font-light;
+ color: var(--color-muted);
+ }
+
+ .controls-action-btn {
+ @apply outline-1 w-9 h-7 rounded-full transition-colors cursor-pointer;
+ &:hover {
+ background-color: var(--color-accent);
+ }
+ &:active {
+ @apply scale-90;
+ }
+ }
+}
+
+/* Controls section: collapsible */
+.controls-section {
+ margin-bottom: 2rem;
+
+ &:not([open]) {
+ margin-bottom: 1rem;
+ }
+
+ summary {
+ @apply transition-opacity duration-300;
+ }
+
+ &:not([open]) summary {
+ @apply opacity-50;
+ }
+
+ .controls-section-chevron {
+ @apply transition-transform;
+ color: var(--color-muted);
+ }
+
+ &[open] .controls-section-chevron {
+ @apply rotate-90;
+ }
+
+ .controls-section-underline {
+ flex-basis: 100%;
+ height: 1px;
+ margin-top: 0.5rem;
+ background-color: var(--color-accent);
+ transform: scaleX(0);
+ transform-origin: left;
+ transition: transform 0.3s ease;
+ }
+
+ &[open] .controls-section-underline {
+ margin-bottom: 0.65rem;
+ transform: scaleX(1);
+ }
+
+ &[open] .controls-section-content {
+ animation: controls-fade-in 0.3s cubic-bezier(0.9, 0, 1, 1);
+ }
+}
+
+@keyframes controls-fade-in {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+/* Bookmark group: collapsible */
+.bookmark-group {
+ margin: 0.2rem 0.4rem 0 0.2rem;
+ @apply p-1;
+
+ summary {
+ @apply transition-opacity duration-300;
+ }
+
+ .bookmark-group-chevron {
+ @apply transition-transform;
+ color: var(--color-muted);
+ }
+
+ &[open] .bookmark-group-chevron {
+ @apply rotate-90;
+ }
+
+ input[type="checkbox"] {
+ appearance: none;
+ width: 11px;
+ height: 11px;
+ border-radius: 4px;
+ border: 1px solid var(--color-muted);
+ background-color: transparent;
+ cursor: pointer;
+ position: relative;
+ transition: border-color 0.15s;
+ flex-shrink: 0;
+ margin-left: 0.5px;
+ margin-top: 1.5px;
+
+ &:checked {
+ border-color: transparent;
+ }
+
+ &:checked::after {
+ content: "";
+ position: absolute;
+ bottom: 1px;
+ left: 2px;
+ width: 5px;
+ height: 9px;
+ border: solid var(--color-muted);
+ border-width: 0 2px 2px 0;
+ transform: rotate(45deg);
+ }
+
+ &.checkbox-active:checked::after {
+ border-color: var(--color-accent);
+ }
+ }
+
+ &[open] > div {
+ animation: controls-fade-in 0.1s cubic-bezier(0.3, 0, 1, 1);
+ }
+}
+
+.bookmark-url {
+ color: inherit;
+ text-decoration: none;
+}
+
+.bookmark-url-active {
+ color: var(--color-link);
+}
+
+/* Controls row: label + control on a shared grid */
+.controls-row {
+ display: grid;
+ grid-template-columns: 1fr auto;
+ align-items: center;
+ gap: 1rem;
+ padding: 0.5rem 0.2rem;
+}
+
+.controls-row.stacked {
+ grid-template-columns: 1fr;
+ gap: 0.1rem;
+ padding-bottom: 0.5rem;
+}
+
+/* Slider thumb */
+input[type="range"].slider-thumb-svg {
+ appearance: none;
+ background: transparent;
+}
+
+input[type="range"].slider-thumb-svg::-webkit-slider-runnable-track {
+ height: 4px;
+ border-radius: 2px;
+ background: var(--color-accent);
+}
+
+input[type="range"].slider-thumb-svg::-webkit-slider-thumb {
+ appearance: none;
+ width: 24px;
+ height: 24px;
+ margin-top: -10px;
+ border: none;
+ background-color: var(--color-accent);
+ -webkit-mask: var(--star-svg) no-repeat center / contain;
+}
+
+input[type="range"].slider-thumb-svg::-moz-range-track {
+ height: 1px;
+ border-radius: 2px;
+ background: color-mix(in srgb, var(--color-accent) 10%, transparent);
+}
+
+input[type="range"].slider-thumb-svg::-moz-range-thumb {
+ appearance: none;
+ width: 24px;
+ height: 24px;
+ border: none;
+ background-color: var(--color-accent);
+ mask: var(--star-svg) no-repeat center / contain;
+}
+
+/* Chat input */
+.chat-input {
+ @apply bg-transparent focus:outline-none font-light text-lg resize-none
+ w-full;
+ color: var(--color-text);
+ caret-color: var(--color-accent);
+}
+
+/* Loading indicator */
+.loading-indicator {
+ @apply my-5 px-5 py-3 rounded-lg;
+ background-color: var(--bg-panel);
+}
+
+/* Answer prose overrides */
+.answer-prose {
+ @apply font-light max-w-none mt-5 pl-5 prose prose-invert prose-sm
+ prose-p:my-2 prose-p:leading-normal prose-li:leading-normal;
+ color: var(--color-answer);
+
+ :where(a) {
+ color: var(--color-link);
+ }
+
+ :where(code) {
+ color: var(--color-accent);
+ }
+
+ :where(pre) {
+ background-color: var(--bg-page);
+ }
+}
+
+/* Shared link style */
+.link {
+ color: var(--color-link);
+ transition: color 0.15s;
+
+ &:hover {
+ color: var(--color-link-hover);
+ }
+}
+
+/* Danger button (delete actions) */
+.danger-btn {
+ color: var(--color-danger-muted);
+ transition: color 0.15s;
+
+ &:hover {
+ color: var(--color-danger);
+ }
+}
diff --git a/web/client.ts b/web/client.ts
new file mode 100644
index 0000000..016cb07
--- /dev/null
+++ b/web/client.ts
@@ -0,0 +1,2 @@
+// Import CSS files here for hot module reloading to work.
+import "./assets/styles.css";
diff --git a/web/components/Answer.tsx b/web/components/Answer.tsx
new file mode 100644
index 0000000..3f676da
--- /dev/null
+++ b/web/components/Answer.tsx
@@ -0,0 +1,38 @@
+import { marked } from "marked";
+
+export function Answer(props: { answer: string; references: string[] }) {
+ const html = marked.parse(props.answer) as string;
+
+ return (
+ <>
+
+ {props.references.length > 0 && (
+
+ )}
+ >
+ );
+}
diff --git a/web/components/BookmarkGroupRow.tsx b/web/components/BookmarkGroupRow.tsx
new file mode 100644
index 0000000..e9599eb
--- /dev/null
+++ b/web/components/BookmarkGroupRow.tsx
@@ -0,0 +1,87 @@
+import {
+ addBookmarkToGroup,
+ BookmarkGroup,
+ createBookmark,
+ deleteBookmarkGroup,
+} from "../utils/bookmarks.ts";
+import {
+ allowBookmarkFilterEnabled,
+ allowedBookmarkGroups,
+} from "../utils/appState.ts";
+import { BookmarkItem } from "./BookmarkItem.tsx";
+import { ControlInlineAdd } from "./Controls.tsx";
+
+export function BookmarkGroupRow({ group }: { group: BookmarkGroup }) {
+ return (
+
+
+
+
{
+ e.stopPropagation();
+ const next = new Set(allowedBookmarkGroups.value);
+ if (next.has(group.id)) {
+ next.delete(group.id);
+ } else next.add(group.id);
+ allowedBookmarkGroups.value = next;
+ }}
+ />
+
{group.name}
+
+
+
+
+
+
+
+ {group.bookmarks.map((bookmark) => (
+
+ ))}
+ addBookmarkToGroup(createBookmark(url), group)}
+ />
+
+
+ );
+}
diff --git a/web/components/BookmarkItem.tsx b/web/components/BookmarkItem.tsx
new file mode 100644
index 0000000..81ab4a3
--- /dev/null
+++ b/web/components/BookmarkItem.tsx
@@ -0,0 +1,51 @@
+import {
+ Bookmark,
+ BookmarkGroup,
+ removeBookmarkFromGroup,
+} from "../utils/bookmarks.ts";
+
+export function BookmarkItem(
+ props: { bookmark: Bookmark; group: BookmarkGroup; filterActive?: boolean },
+) {
+ return (
+
+
+ {props.bookmark.url.replace(/^https?:\/\/(www\.)?/, "").replace(
+ /\/$/,
+ "",
+ )}
+
+
+
+ );
+}
diff --git a/web/components/Controls.tsx b/web/components/Controls.tsx
new file mode 100644
index 0000000..d0263d8
--- /dev/null
+++ b/web/components/Controls.tsx
@@ -0,0 +1,269 @@
+import { Signal, useSignal } from "@preact/signals";
+import { ComponentChildren } from "preact";
+
+// ============================================================================
+// Layout Components
+// ============================================================================
+
+interface ControlSectionProps {
+ title?: string;
+ open: Signal;
+ children: ComponentChildren;
+}
+
+export function ControlSection({ title, open, children }: ControlSectionProps) {
+ return (
+ {
+ open.value = (e.target as HTMLDetailsElement).open;
+ }}
+ >
+ {title && (
+
+ {title}
+
+
+
+ )}
+ {children}
+
+ );
+}
+
+interface ControlRowProps {
+ label?: string;
+ description?: string;
+ stacked?: boolean;
+ children?: ComponentChildren;
+}
+
+export function ControlRow(
+ { label, description, stacked, children }: ControlRowProps,
+) {
+ return (
+
+ {label && (
+
+
+ {label}
+
+ {description && (
+
+ {description}
+
+ )}
+
+ )}
+ {children}
+
+ );
+}
+
+// ============================================================================
+// Input Components
+// ============================================================================
+
+interface ControlAddButtonProps {
+ onAdd: (name: string) => void;
+ placeholder?: string;
+}
+
+export function ControlAddButton(
+ { onAdd, placeholder = "Add group" }: ControlAddButtonProps,
+) {
+ const name = useSignal("");
+
+ const handleAdd = () => {
+ const value = name.value.trim() || placeholder;
+ onAdd(value);
+ name.value = "";
+ };
+
+ return (
+
+
{
+ name.value = (e.target as HTMLInputElement).value;
+ }}
+ onKeyDown={(e) => {
+ if (e.key === "Enter") handleAdd();
+ }}
+ class="flex-1 min-w-0 bg-transparent text-xs font-light px-3 focus:outline-none"
+ style="color: var(--color-text)"
+ />
+
+
+ );
+}
+
+interface ControlInlineAddProps {
+ onAdd: (value: string) => void;
+ placeholder?: string;
+}
+
+export function ControlInlineAdd(
+ { onAdd, placeholder = "Add URL" }: ControlInlineAddProps,
+) {
+ const name = useSignal("");
+
+ const handleAdd = () => {
+ const value = name.value.trim();
+ if (!value) return;
+ onAdd(value);
+ name.value = "";
+ };
+
+ return (
+
+ {
+ name.value = (e.target as HTMLInputElement).value;
+ }}
+ onKeyDown={(e) => {
+ if (e.key === "Enter") handleAdd();
+ }}
+ class="flex-1 bg-transparent text-xs font-light py-1 focus:outline-none placeholder:opacity-80"
+ style={`color: var(--color-text); border-bottom: 1px solid color-mix(in srgb, var(--color-muted) 10%, transparent)`}
+ />
+
+ );
+}
+
+interface ControlToggleProps {
+ value: Signal;
+ onChange?: (value: boolean) => void;
+}
+
+export function ControlToggle({ value, onChange }: ControlToggleProps) {
+ const handleToggle = () => {
+ const newValue = !value.value;
+ value.value = newValue;
+ onChange?.(newValue);
+ };
+
+ return (
+
+ );
+}
+
+interface ControlNumberInputProps {
+ value: Signal;
+ min?: number;
+ max?: number;
+ onChange?: (value: number) => void;
+}
+
+export function ControlNumberInput(
+ { value, min = 1, max = 10, onChange }: ControlNumberInputProps,
+) {
+ const options = Array.from({ length: max - min + 1 }, (_, i) => min + i);
+
+ return (
+
+ );
+}
+
+interface SliderStop {
+ label: string;
+ value: number;
+}
+
+interface ControlNumberSliderProps {
+ value: Signal;
+ stops: SliderStop[];
+ onInput?: (value: number) => void;
+}
+
+export function ControlNumberSlider(
+ { value, stops, onInput }: ControlNumberSliderProps,
+) {
+ const index = stops.findIndex((s) => s.value === value.value);
+ const currentIndex = index >= 0 ? index : 0;
+
+ return (
+
+
{
+ const idx = parseInt((e.target as HTMLInputElement).value, 10);
+ const newValue = stops[idx].value;
+ value.value = newValue;
+ onInput?.(newValue);
+ }}
+ class="mt-3 w-full slider-thumb-svg"
+ />
+
+
+ {stops[currentIndex].label}
+
+
+
+ );
+}
diff --git a/web/components/HealthStatus.tsx b/web/components/HealthStatus.tsx
new file mode 100644
index 0000000..5aa3c02
--- /dev/null
+++ b/web/components/HealthStatus.tsx
@@ -0,0 +1,286 @@
+import { useSignal } from "@preact/signals";
+import { useEffect } from "preact/hooks";
+import { backendPort } from "../utils/appState.ts";
+
+interface EnvVarStatus {
+ set: boolean;
+ required: boolean;
+ description: string;
+ link?: string;
+}
+
+interface ServiceHealth {
+ vllm: boolean;
+ vllm_url: string;
+}
+
+interface HealthState {
+ env: Record | null;
+ backendOk: boolean | null;
+ services: ServiceHealth | null;
+ model: string | null;
+}
+
+function Dot({ ok }: { ok: boolean | null }) {
+ const color = ok === true
+ ? "var(--color-accent)"
+ : ok === false
+ ? "var(--color-danger)"
+ : "var(--color-muted)";
+ return (
+
+ );
+}
+
+function computeOverallHealth(h: HealthState): boolean | null {
+ if (h.env === null || h.backendOk === null) return null;
+ const envOk = Object.values(h.env).every((v) => !v.required || v.set);
+ if (!envOk || !h.backendOk) return false;
+ if (h.services?.vllm === false) return false;
+ return true;
+}
+
+export function HealthStatus() {
+ const health = useSignal({
+ env: null,
+ backendOk: null,
+ services: null,
+ model: null,
+ });
+ const open = useSignal(false);
+
+ const fetchHealth = async () => {
+ health.value = { env: null, backendOk: null, services: null, model: null };
+
+ try {
+ const res = await fetch("/api/health");
+ if (res.ok) {
+ const data = await res.json();
+ health.value = {
+ ...health.value,
+ env: data.env,
+ model: data.model ?? null,
+ };
+ }
+ } catch { /* frontend health endpoint may not exist */ }
+
+ try {
+ const res = await fetch(
+ `http://localhost:${backendPort.value}/api/health`,
+ );
+ if (res.ok) {
+ health.value = {
+ ...health.value,
+ backendOk: true,
+ services: await res.json(),
+ };
+ } else {
+ health.value = { ...health.value, backendOk: false };
+ }
+ } catch {
+ health.value = { ...health.value, backendOk: false };
+ }
+ };
+
+ useEffect(() => {
+ fetchHealth();
+ }, []);
+
+ const overall = computeOverallHealth(health.value);
+
+ const vllmOk = health.value.backendOk === false
+ ? false
+ : health.value.services?.vllm ?? null;
+
+ const summary = overall === true
+ ? null
+ : overall === null
+ ? "checking…"
+ : health.value.backendOk === false
+ ? "backend unreachable"
+ : health.value.services?.vllm === false
+ ? "vLLM unreachable"
+ : "env error";
+
+ return (
+ <>
+
+ {summary && (
+
+ )}
+ {!summary && health.value.model && (
+
+ {health.value.model}
+
+ )}
+
+
+ {open.value && (
+ (open.value = false)}
+ >
+
e.stopPropagation()}
+ >
+ {/* Header */}
+
+
+ Health
+
+
+
+
+
+
+
+ {/* Services */}
+
+
+ Services
+
+
+
+
+ Backend
+
+ {health.value.backendOk === null
+ ? "checking…"
+ : health.value.backendOk
+ ? "reachable"
+ : "unreachable"}
+
+
+
+
+ vLLM
+ {health.value.services !== null && (
+
+ {health.value.services.vllm ? "reachable" : "unreachable"}
+
+ )}
+ {health.value.backendOk === false && (
+ unknown
+ )}
+ {health.value.backendOk === null &&
+ health.value.services === null && (
+ checking…
+ )}
+
+
+
+
+ {/* Environment */}
+
+
+ Environment
+
+ {health.value.env === null
+ ? (
+
+ checking…
+
+ )
+ : (
+
+ {Object.entries(health.value.env).map(([name, info]) => (
+
+
+ {!info.set && info.link
+ ? (
+
+ {name}
+
+ )
+ : (
+
+ {name}
+
+ )}
+
+ {info.set
+ ? "set"
+ : info.required
+ ? "missing"
+ : "not set"}
+
+
+ ))}
+
+ )}
+
+
+
+ )}
+ >
+ );
+}
diff --git a/web/components/LoadingIndicator.tsx b/web/components/LoadingIndicator.tsx
new file mode 100644
index 0000000..c9f81b7
--- /dev/null
+++ b/web/components/LoadingIndicator.tsx
@@ -0,0 +1,96 @@
+const NODE_ICONS: Record = {
+ CoderNode: (
+
+ ),
+ ResearchNode: (
+
+ ),
+};
+
+const DEFAULT_ICON = (
+
+);
+
+const NODE_LABELS: Record = {
+ RouterNode: "Analyzing",
+ ResearchNode: "Researching",
+ CoderNode: "Computing",
+};
+
+interface LoadingIndicatorProps {
+ node: string | null;
+ onStop: () => void;
+}
+
+export function LoadingIndicator({ node, onStop }: LoadingIndicatorProps) {
+ const icon = node ? (NODE_ICONS[node] ?? DEFAULT_ICON) : DEFAULT_ICON;
+ const label = node ? (NODE_LABELS[node] ?? node) : "";
+
+ return (
+
+
+
+ {icon}
+ {label}
+
+
+
+
+ );
+}
diff --git a/web/components/Query.tsx b/web/components/Query.tsx
new file mode 100644
index 0000000..274daf9
--- /dev/null
+++ b/web/components/Query.tsx
@@ -0,0 +1,11 @@
+export function Query(props: { query?: string | null }) {
+ return (
+
+ ⟩
+ {props.query && {props.query}}
+
+ );
+}
diff --git a/web/deno.json b/web/deno.json
index e28adf8..6e9640b 100644
--- a/web/deno.json
+++ b/web/deno.json
@@ -1,6 +1,65 @@
{
+ "nodeModulesDir": "manual",
"tasks": {
- "check": "deno fmt --check . && deno lint . && deno check main.ts"
+ "check": "deno fmt --check . && deno lint . && deno check main.ts",
+ "dev": "vite",
+ "build": "vite build",
+ "start": "deno serve -A _fresh/server.js",
+ "update": "deno run -A -r jsr:@fresh/update ."
},
- "exclude": ["**/_fresh/*"]
+ "lint": {
+ "rules": {
+ "tags": [
+ "fresh",
+ "recommended"
+ ]
+ }
+ },
+ "exclude": [
+ "**/_fresh/*"
+ ],
+ "fmt": {
+ "exclude": ["**/*.md"]
+ },
+ "imports": {
+ "@/": "./",
+ "fresh": "jsr:@fresh/core@^2.2.0",
+ "preact": "npm:preact@^10.28.4",
+ "@preact/signals": "npm:@preact/signals@^2.8.1",
+ "@fresh/plugin-vite": "jsr:@fresh/plugin-vite@^1.0.8",
+ "vite": "npm:vite@^7.3.1",
+ "tailwindcss": "npm:tailwindcss@^4.2.1",
+ "@tailwindcss/vite": "npm:@tailwindcss/vite@^4.2.1",
+ "marked": "npm:marked@^17.0.3",
+ "@tailwindcss/typography": "npm:@tailwindcss/typography@^0.5.19"
+ },
+ "compilerOptions": {
+ "lib": [
+ "dom",
+ "dom.asynciterable",
+ "dom.iterable",
+ "deno.ns"
+ ],
+ "jsx": "precompile",
+ "jsxImportSource": "preact",
+ "jsxPrecompileSkipElements": [
+ "a",
+ "img",
+ "source",
+ "body",
+ "html",
+ "head",
+ "title",
+ "meta",
+ "script",
+ "link",
+ "style",
+ "base",
+ "noscript",
+ "template"
+ ],
+ "types": [
+ "vite/client"
+ ]
+ }
}
diff --git a/web/deno.lock b/web/deno.lock
new file mode 100644
index 0000000..1b4222b
--- /dev/null
+++ b/web/deno.lock
@@ -0,0 +1,1876 @@
+{
+ "version": "5",
+ "specifiers": {
+ "jsr:@deno/esbuild-plugin@^1.2.0": "1.2.1",
+ "jsr:@deno/loader@~0.3.10": "0.3.11",
+ "jsr:@deno/loader@~0.3.2": "0.3.11",
+ "jsr:@fresh/build-id@1": "1.0.1",
+ "jsr:@fresh/core@2": "2.2.0",
+ "jsr:@fresh/core@^2.2.0": "2.2.0",
+ "jsr:@fresh/plugin-vite@^1.0.8": "1.0.8",
+ "jsr:@luca/esbuild-deno-loader@0.10.3": "0.10.3",
+ "jsr:@std/assert@~0.213.1": "0.213.1",
+ "jsr:@std/bytes@^1.0.6": "1.0.6",
+ "jsr:@std/dotenv@~0.225.5": "0.225.6",
+ "jsr:@std/encoding@0.213": "0.213.1",
+ "jsr:@std/encoding@^1.0.10": "1.0.10",
+ "jsr:@std/fmt@^1.0.7": "1.0.9",
+ "jsr:@std/fmt@^1.0.8": "1.0.9",
+ "jsr:@std/fs@^1.0.19": "1.0.22",
+ "jsr:@std/html@^1.0.5": "1.0.5",
+ "jsr:@std/http@^1.0.21": "1.0.23",
+ "jsr:@std/internal@^1.0.12": "1.0.12",
+ "jsr:@std/json@^1.0.2": "1.0.2",
+ "jsr:@std/json@~0.213.1": "0.213.1",
+ "jsr:@std/jsonc@0.213": "0.213.1",
+ "jsr:@std/jsonc@^1.0.2": "1.0.2",
+ "jsr:@std/media-types@^1.1.0": "1.1.0",
+ "jsr:@std/path@0.213": "0.213.1",
+ "jsr:@std/path@1": "1.1.4",
+ "jsr:@std/path@^1.1.1": "1.1.4",
+ "jsr:@std/path@^1.1.2": "1.1.4",
+ "jsr:@std/path@^1.1.4": "1.1.4",
+ "jsr:@std/semver@^1.0.6": "1.0.8",
+ "jsr:@std/uuid@^1.0.9": "1.1.0",
+ "npm:@babel/core@^7.28.0": "7.29.0",
+ "npm:@babel/preset-react@^7.27.1": "7.28.5_@babel+core@7.29.0",
+ "npm:@mjackson/node-fetch-server@0.7": "0.7.0",
+ "npm:@opentelemetry/api@^1.9.0": "1.9.0",
+ "npm:@preact/signals@^2.2.1": "2.8.1_preact@10.28.4",
+ "npm:@preact/signals@^2.8.1": "2.8.1_preact@10.28.4",
+ "npm:@prefresh/vite@^2.4.8": "2.4.12_preact@10.28.4_vite@7.3.1__@types+node@24.2.0__picomatch@4.0.3_@types+node@24.2.0",
+ "npm:@tailwindcss/typography@~0.5.19": "0.5.19_tailwindcss@4.2.1",
+ "npm:@tailwindcss/vite@^4.2.1": "4.2.1_vite@7.3.1__@types+node@24.2.0__picomatch@4.0.3_@types+node@24.2.0",
+ "npm:@types/node@*": "24.2.0",
+ "npm:esbuild-wasm@~0.25.11": "0.25.12",
+ "npm:esbuild@0.25.7": "0.25.7",
+ "npm:esbuild@~0.25.5": "0.25.12",
+ "npm:marked@^17.0.3": "17.0.3",
+ "npm:preact-render-to-string@^6.6.3": "6.6.6_preact@10.28.4",
+ "npm:preact@^10.27.0": "10.28.4",
+ "npm:preact@^10.27.2": "10.28.4",
+ "npm:preact@^10.28.4": "10.28.4",
+ "npm:rollup@^4.50.0": "4.59.0",
+ "npm:tailwindcss@^4.2.1": "4.2.1",
+ "npm:vite@^7.1.4": "7.3.1_@types+node@24.2.0_picomatch@4.0.3",
+ "npm:vite@^7.3.1": "7.3.1_@types+node@24.2.0_picomatch@4.0.3"
+ },
+ "jsr": {
+ "@deno/esbuild-plugin@1.2.1": {
+ "integrity": "df629467913adc1f960149fdfa3a3430ba8c20381c310fba096db244e6c3c9f6",
+ "dependencies": [
+ "jsr:@deno/loader@~0.3.10",
+ "jsr:@std/path@^1.1.1",
+ "npm:esbuild@~0.25.5"
+ ]
+ },
+ "@deno/loader@0.3.11": {
+ "integrity": "7c62f4f09cdfc34e66ba25b5a775a1830cbb5266b3e39f67b0f620c75484df8d"
+ },
+ "@fresh/build-id@1.0.1": {
+ "integrity": "12a2ec25fd52ae9ec68c26848a5696cd1c9b537f7c983c7e56e4fb1e7e816c20",
+ "dependencies": [
+ "jsr:@std/encoding@^1.0.10"
+ ]
+ },
+ "@fresh/core@2.2.0": {
+ "integrity": "b3c00f82288a2c4c8ec85e4abb67b080b366ec5971860f2f2898eb281ea1a80f",
+ "dependencies": [
+ "jsr:@deno/esbuild-plugin",
+ "jsr:@fresh/build-id",
+ "jsr:@std/encoding@^1.0.10",
+ "jsr:@std/fmt@^1.0.8",
+ "jsr:@std/fs",
+ "jsr:@std/html",
+ "jsr:@std/http",
+ "jsr:@std/jsonc@^1.0.2",
+ "jsr:@std/media-types",
+ "jsr:@std/path@^1.1.2",
+ "jsr:@std/semver",
+ "jsr:@std/uuid",
+ "npm:@opentelemetry/api",
+ "npm:@preact/signals@^2.2.1",
+ "npm:esbuild-wasm",
+ "npm:esbuild@0.25.7",
+ "npm:preact-render-to-string",
+ "npm:preact@^10.27.0",
+ "npm:preact@^10.27.2"
+ ]
+ },
+ "@fresh/plugin-vite@1.0.8": {
+ "integrity": "5780d842ed82e4cbccd93dd8ba2d54bf59dff5aee65921134aab15a4cd457c56",
+ "dependencies": [
+ "jsr:@deno/loader@~0.3.2",
+ "jsr:@fresh/core@2",
+ "jsr:@fresh/core@^2.2.0",
+ "jsr:@std/dotenv",
+ "jsr:@std/fmt@^1.0.7",
+ "jsr:@std/path@1",
+ "npm:@babel/core",
+ "npm:@babel/preset-react",
+ "npm:@mjackson/node-fetch-server",
+ "npm:@prefresh/vite",
+ "npm:rollup",
+ "npm:vite@^7.1.4"
+ ]
+ },
+ "@luca/esbuild-deno-loader@0.10.3": {
+ "integrity": "32fc93f7e7f78060234fd5929a740668aab1c742b808c6048b57f9aaea514921",
+ "dependencies": [
+ "jsr:@std/encoding@0.213",
+ "jsr:@std/jsonc@0.213",
+ "jsr:@std/path@0.213"
+ ]
+ },
+ "@std/assert@0.213.1": {
+ "integrity": "24c28178b30c8e0782c18e8e94ea72b16282207569cdd10ffb9d1d26f2edebfe"
+ },
+ "@std/bytes@1.0.6": {
+ "integrity": "f6ac6adbd8ccd99314045f5703e23af0a68d7f7e58364b47d2c7f408aeb5820a"
+ },
+ "@std/dotenv@0.225.6": {
+ "integrity": "1d6f9db72f565bd26790fa034c26e45ecb260b5245417be76c2279e5734c421b"
+ },
+ "@std/encoding@0.213.1": {
+ "integrity": "fcbb6928713dde941a18ca5db88ca1544d0755ec8fb20fe61e2dc8144b390c62"
+ },
+ "@std/encoding@1.0.10": {
+ "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1"
+ },
+ "@std/fmt@1.0.9": {
+ "integrity": "2487343e8899fb2be5d0e3d35013e54477ada198854e52dd05ed0422eddcabe0"
+ },
+ "@std/fs@1.0.22": {
+ "integrity": "de0f277a58a867147a8a01bc1b181d0dfa80bfddba8c9cf2bacd6747bcec9308",
+ "dependencies": [
+ "jsr:@std/path@^1.1.4"
+ ]
+ },
+ "@std/html@1.0.5": {
+ "integrity": "4e2d693f474cae8c16a920fa5e15a3b72267b94b84667f11a50c6dd1cb18d35e"
+ },
+ "@std/http@1.0.23": {
+ "integrity": "6634e9e034c589bf35101c1b5ee5bbf052a5987abca20f903e58bdba85c80dee",
+ "dependencies": [
+ "jsr:@std/encoding@^1.0.10"
+ ]
+ },
+ "@std/internal@1.0.12": {
+ "integrity": "972a634fd5bc34b242024402972cd5143eac68d8dffaca5eaa4dba30ce17b027"
+ },
+ "@std/json@0.213.1": {
+ "integrity": "f572b1de605d07c4a5602445dac54bfc51b1fb87a3710a17aed2608bfca54e68"
+ },
+ "@std/json@1.0.2": {
+ "integrity": "d9e5497801c15fb679f55a2c01c7794ad7a5dfda4dd1bebab5e409cb5e0d34d4"
+ },
+ "@std/jsonc@0.213.1": {
+ "integrity": "5578f21aa583b7eb7317eed077ffcde47b294f1056bdbb9aacec407758637bfe",
+ "dependencies": [
+ "jsr:@std/assert",
+ "jsr:@std/json@~0.213.1"
+ ]
+ },
+ "@std/jsonc@1.0.2": {
+ "integrity": "909605dae3af22bd75b1cbda8d64a32cf1fd2cf6efa3f9e224aba6d22c0f44c7",
+ "dependencies": [
+ "jsr:@std/json@^1.0.2"
+ ]
+ },
+ "@std/media-types@1.1.0": {
+ "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4"
+ },
+ "@std/path@0.213.1": {
+ "integrity": "f187bf278a172752e02fcbacf6bd78a335ed320d080a7ed3a5a59c3e88abc673",
+ "dependencies": [
+ "jsr:@std/assert"
+ ]
+ },
+ "@std/path@1.1.4": {
+ "integrity": "1d2d43f39efb1b42f0b1882a25486647cb851481862dc7313390b2bb044314b5",
+ "dependencies": [
+ "jsr:@std/internal"
+ ]
+ },
+ "@std/semver@1.0.8": {
+ "integrity": "dc830e8b8b6a380c895d53fbfd1258dc253704ca57bbe1629ac65fd7830179b7"
+ },
+ "@std/uuid@1.1.0": {
+ "integrity": "6268db2ccf172849c9be80763354ca305d49ef4af41fe995623d44fcc3f7457c",
+ "dependencies": [
+ "jsr:@std/bytes"
+ ]
+ }
+ },
+ "npm": {
+ "@babel/code-frame@7.29.0": {
+ "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
+ "dependencies": [
+ "@babel/helper-validator-identifier",
+ "js-tokens",
+ "picocolors"
+ ]
+ },
+ "@babel/compat-data@7.29.0": {
+ "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="
+ },
+ "@babel/core@7.29.0": {
+ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
+ "dependencies": [
+ "@babel/code-frame",
+ "@babel/generator",
+ "@babel/helper-compilation-targets",
+ "@babel/helper-module-transforms",
+ "@babel/helpers",
+ "@babel/parser",
+ "@babel/template",
+ "@babel/traverse",
+ "@babel/types",
+ "@jridgewell/remapping",
+ "convert-source-map",
+ "debug",
+ "gensync",
+ "json5",
+ "semver"
+ ]
+ },
+ "@babel/generator@7.29.1": {
+ "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
+ "dependencies": [
+ "@babel/parser",
+ "@babel/types",
+ "@jridgewell/gen-mapping",
+ "@jridgewell/trace-mapping",
+ "jsesc"
+ ]
+ },
+ "@babel/helper-annotate-as-pure@7.27.3": {
+ "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
+ "dependencies": [
+ "@babel/types"
+ ]
+ },
+ "@babel/helper-compilation-targets@7.28.6": {
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
+ "dependencies": [
+ "@babel/compat-data",
+ "@babel/helper-validator-option",
+ "browserslist",
+ "lru-cache",
+ "semver"
+ ]
+ },
+ "@babel/helper-globals@7.28.0": {
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="
+ },
+ "@babel/helper-module-imports@7.28.6": {
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
+ "dependencies": [
+ "@babel/traverse",
+ "@babel/types"
+ ]
+ },
+ "@babel/helper-module-transforms@7.28.6_@babel+core@7.29.0": {
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
+ "dependencies": [
+ "@babel/core",
+ "@babel/helper-module-imports",
+ "@babel/helper-validator-identifier",
+ "@babel/traverse"
+ ]
+ },
+ "@babel/helper-plugin-utils@7.28.6": {
+ "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="
+ },
+ "@babel/helper-string-parser@7.27.1": {
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="
+ },
+ "@babel/helper-validator-identifier@7.28.5": {
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="
+ },
+ "@babel/helper-validator-option@7.27.1": {
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="
+ },
+ "@babel/helpers@7.28.6": {
+ "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
+ "dependencies": [
+ "@babel/template",
+ "@babel/types"
+ ]
+ },
+ "@babel/parser@7.29.0": {
+ "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
+ "dependencies": [
+ "@babel/types"
+ ],
+ "bin": true
+ },
+ "@babel/plugin-syntax-jsx@7.28.6_@babel+core@7.29.0": {
+ "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==",
+ "dependencies": [
+ "@babel/core",
+ "@babel/helper-plugin-utils"
+ ]
+ },
+ "@babel/plugin-transform-react-display-name@7.28.0_@babel+core@7.29.0": {
+ "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==",
+ "dependencies": [
+ "@babel/core",
+ "@babel/helper-plugin-utils"
+ ]
+ },
+ "@babel/plugin-transform-react-jsx-development@7.27.1_@babel+core@7.29.0": {
+ "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==",
+ "dependencies": [
+ "@babel/core",
+ "@babel/plugin-transform-react-jsx"
+ ]
+ },
+ "@babel/plugin-transform-react-jsx@7.28.6_@babel+core@7.29.0": {
+ "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==",
+ "dependencies": [
+ "@babel/core",
+ "@babel/helper-annotate-as-pure",
+ "@babel/helper-module-imports",
+ "@babel/helper-plugin-utils",
+ "@babel/plugin-syntax-jsx",
+ "@babel/types"
+ ]
+ },
+ "@babel/plugin-transform-react-pure-annotations@7.27.1_@babel+core@7.29.0": {
+ "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==",
+ "dependencies": [
+ "@babel/core",
+ "@babel/helper-annotate-as-pure",
+ "@babel/helper-plugin-utils"
+ ]
+ },
+ "@babel/preset-react@7.28.5_@babel+core@7.29.0": {
+ "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==",
+ "dependencies": [
+ "@babel/core",
+ "@babel/helper-plugin-utils",
+ "@babel/helper-validator-option",
+ "@babel/plugin-transform-react-display-name",
+ "@babel/plugin-transform-react-jsx",
+ "@babel/plugin-transform-react-jsx-development",
+ "@babel/plugin-transform-react-pure-annotations"
+ ]
+ },
+ "@babel/template@7.28.6": {
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
+ "dependencies": [
+ "@babel/code-frame",
+ "@babel/parser",
+ "@babel/types"
+ ]
+ },
+ "@babel/traverse@7.29.0": {
+ "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
+ "dependencies": [
+ "@babel/code-frame",
+ "@babel/generator",
+ "@babel/helper-globals",
+ "@babel/parser",
+ "@babel/template",
+ "@babel/types",
+ "debug"
+ ]
+ },
+ "@babel/types@7.29.0": {
+ "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
+ "dependencies": [
+ "@babel/helper-string-parser",
+ "@babel/helper-validator-identifier"
+ ]
+ },
+ "@esbuild/aix-ppc64@0.25.12": {
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
+ "os": ["aix"],
+ "cpu": ["ppc64"]
+ },
+ "@esbuild/aix-ppc64@0.25.7": {
+ "integrity": "sha512-uD0kKFHh6ETr8TqEtaAcV+dn/2qnYbH/+8wGEdY70Qf7l1l/jmBUbrmQqwiPKAQE6cOQ7dTj6Xr0HzQDGHyceQ==",
+ "os": ["aix"],
+ "cpu": ["ppc64"]
+ },
+ "@esbuild/aix-ppc64@0.27.3": {
+ "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==",
+ "os": ["aix"],
+ "cpu": ["ppc64"]
+ },
+ "@esbuild/android-arm64@0.25.12": {
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "os": ["android"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/android-arm64@0.25.7": {
+ "integrity": "sha512-p0ohDnwyIbAtztHTNUTzN5EGD/HJLs1bwysrOPgSdlIA6NDnReoVfoCyxG6W1d85jr2X80Uq5KHftyYgaK9LPQ==",
+ "os": ["android"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/android-arm64@0.27.3": {
+ "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==",
+ "os": ["android"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/android-arm@0.25.12": {
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "os": ["android"],
+ "cpu": ["arm"]
+ },
+ "@esbuild/android-arm@0.25.7": {
+ "integrity": "sha512-Jhuet0g1k9rAJHrXGIh7sFknFuT4sfytYZpZpuZl7YKDhnPByVAm5oy2LEBmMbuYf3ejWVYCc2seX81Mk+madA==",
+ "os": ["android"],
+ "cpu": ["arm"]
+ },
+ "@esbuild/android-arm@0.27.3": {
+ "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==",
+ "os": ["android"],
+ "cpu": ["arm"]
+ },
+ "@esbuild/android-x64@0.25.12": {
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "os": ["android"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/android-x64@0.25.7": {
+ "integrity": "sha512-mMxIJFlSgVK23HSsII3ZX9T2xKrBCDGyk0qiZnIW10LLFFtZLkFD6imZHu7gUo2wkNZwS9Yj3mOtZD3ZPcjCcw==",
+ "os": ["android"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/android-x64@0.27.3": {
+ "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==",
+ "os": ["android"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/darwin-arm64@0.25.12": {
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "os": ["darwin"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/darwin-arm64@0.25.7": {
+ "integrity": "sha512-jyOFLGP2WwRwxM8F1VpP6gcdIJc8jq2CUrURbbTouJoRO7XCkU8GdnTDFIHdcifVBT45cJlOYsZ1kSlfbKjYUQ==",
+ "os": ["darwin"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/darwin-arm64@0.27.3": {
+ "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==",
+ "os": ["darwin"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/darwin-x64@0.25.12": {
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "os": ["darwin"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/darwin-x64@0.25.7": {
+ "integrity": "sha512-m9bVWqZCwQ1BthruifvG64hG03zzz9gE2r/vYAhztBna1/+qXiHyP9WgnyZqHgGeXoimJPhAmxfbeU+nMng6ZA==",
+ "os": ["darwin"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/darwin-x64@0.27.3": {
+ "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==",
+ "os": ["darwin"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/freebsd-arm64@0.25.12": {
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "os": ["freebsd"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/freebsd-arm64@0.25.7": {
+ "integrity": "sha512-Bss7P4r6uhr3kDzRjPNEnTm/oIBdTPRNQuwaEFWT/uvt6A1YzK/yn5kcx5ZxZ9swOga7LqeYlu7bDIpDoS01bA==",
+ "os": ["freebsd"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/freebsd-arm64@0.27.3": {
+ "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==",
+ "os": ["freebsd"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/freebsd-x64@0.25.12": {
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "os": ["freebsd"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/freebsd-x64@0.25.7": {
+ "integrity": "sha512-S3BFyjW81LXG7Vqmr37ddbThrm3A84yE7ey/ERBlK9dIiaWgrjRlre3pbG7txh1Uaxz8N7wGGQXmC9zV+LIpBQ==",
+ "os": ["freebsd"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/freebsd-x64@0.27.3": {
+ "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==",
+ "os": ["freebsd"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/linux-arm64@0.25.12": {
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "os": ["linux"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/linux-arm64@0.25.7": {
+ "integrity": "sha512-HfQZQqrNOfS1Okn7PcsGUqHymL1cWGBslf78dGvtrj8q7cN3FkapFgNA4l/a5lXDwr7BqP2BSO6mz9UremNPbg==",
+ "os": ["linux"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/linux-arm64@0.27.3": {
+ "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==",
+ "os": ["linux"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/linux-arm@0.25.12": {
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "os": ["linux"],
+ "cpu": ["arm"]
+ },
+ "@esbuild/linux-arm@0.25.7": {
+ "integrity": "sha512-JZMIci/1m5vfQuhKoFXogCKVYVfYQmoZJg8vSIMR4TUXbF+0aNlfXH3DGFEFMElT8hOTUF5hisdZhnrZO/bkDw==",
+ "os": ["linux"],
+ "cpu": ["arm"]
+ },
+ "@esbuild/linux-arm@0.27.3": {
+ "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==",
+ "os": ["linux"],
+ "cpu": ["arm"]
+ },
+ "@esbuild/linux-ia32@0.25.12": {
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "os": ["linux"],
+ "cpu": ["ia32"]
+ },
+ "@esbuild/linux-ia32@0.25.7": {
+ "integrity": "sha512-9Jex4uVpdeofiDxnwHRgen+j6398JlX4/6SCbbEFEXN7oMO2p0ueLN+e+9DdsdPLUdqns607HmzEFnxwr7+5wQ==",
+ "os": ["linux"],
+ "cpu": ["ia32"]
+ },
+ "@esbuild/linux-ia32@0.27.3": {
+ "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==",
+ "os": ["linux"],
+ "cpu": ["ia32"]
+ },
+ "@esbuild/linux-loong64@0.25.12": {
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "os": ["linux"],
+ "cpu": ["loong64"]
+ },
+ "@esbuild/linux-loong64@0.25.7": {
+ "integrity": "sha512-TG1KJqjBlN9IHQjKVUYDB0/mUGgokfhhatlay8aZ/MSORMubEvj/J1CL8YGY4EBcln4z7rKFbsH+HeAv0d471w==",
+ "os": ["linux"],
+ "cpu": ["loong64"]
+ },
+ "@esbuild/linux-loong64@0.27.3": {
+ "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==",
+ "os": ["linux"],
+ "cpu": ["loong64"]
+ },
+ "@esbuild/linux-mips64el@0.25.12": {
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "os": ["linux"],
+ "cpu": ["mips64el"]
+ },
+ "@esbuild/linux-mips64el@0.25.7": {
+ "integrity": "sha512-Ty9Hj/lx7ikTnhOfaP7ipEm/ICcBv94i/6/WDg0OZ3BPBHhChsUbQancoWYSO0WNkEiSW5Do4febTTy4x1qYQQ==",
+ "os": ["linux"],
+ "cpu": ["mips64el"]
+ },
+ "@esbuild/linux-mips64el@0.27.3": {
+ "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==",
+ "os": ["linux"],
+ "cpu": ["mips64el"]
+ },
+ "@esbuild/linux-ppc64@0.25.12": {
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "os": ["linux"],
+ "cpu": ["ppc64"]
+ },
+ "@esbuild/linux-ppc64@0.25.7": {
+ "integrity": "sha512-MrOjirGQWGReJl3BNQ58BLhUBPpWABnKrnq8Q/vZWWwAB1wuLXOIxS2JQ1LT3+5T+3jfPh0tyf5CpbyQHqnWIQ==",
+ "os": ["linux"],
+ "cpu": ["ppc64"]
+ },
+ "@esbuild/linux-ppc64@0.27.3": {
+ "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==",
+ "os": ["linux"],
+ "cpu": ["ppc64"]
+ },
+ "@esbuild/linux-riscv64@0.25.12": {
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "os": ["linux"],
+ "cpu": ["riscv64"]
+ },
+ "@esbuild/linux-riscv64@0.25.7": {
+ "integrity": "sha512-9pr23/pqzyqIZEZmQXnFyqp3vpa+KBk5TotfkzGMqpw089PGm0AIowkUppHB9derQzqniGn3wVXgck19+oqiOw==",
+ "os": ["linux"],
+ "cpu": ["riscv64"]
+ },
+ "@esbuild/linux-riscv64@0.27.3": {
+ "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==",
+ "os": ["linux"],
+ "cpu": ["riscv64"]
+ },
+ "@esbuild/linux-s390x@0.25.12": {
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "os": ["linux"],
+ "cpu": ["s390x"]
+ },
+ "@esbuild/linux-s390x@0.25.7": {
+ "integrity": "sha512-4dP11UVGh9O6Y47m8YvW8eoA3r8qL2toVZUbBKyGta8j6zdw1cn9F/Rt59/Mhv0OgY68pHIMjGXWOUaykCnx+w==",
+ "os": ["linux"],
+ "cpu": ["s390x"]
+ },
+ "@esbuild/linux-s390x@0.27.3": {
+ "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==",
+ "os": ["linux"],
+ "cpu": ["s390x"]
+ },
+ "@esbuild/linux-x64@0.25.12": {
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "os": ["linux"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/linux-x64@0.25.7": {
+ "integrity": "sha512-ghJMAJTdw/0uhz7e7YnpdX1xVn7VqA0GrWrAO2qKMuqbvgHT2VZiBv1BQ//VcHsPir4wsL3P2oPggfKPzTKoCA==",
+ "os": ["linux"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/linux-x64@0.27.3": {
+ "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==",
+ "os": ["linux"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/netbsd-arm64@0.25.12": {
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "os": ["netbsd"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/netbsd-arm64@0.25.7": {
+ "integrity": "sha512-bwXGEU4ua45+u5Ci/a55B85KWaDSRS8NPOHtxy2e3etDjbz23wlry37Ffzapz69JAGGc4089TBo+dGzydQmydg==",
+ "os": ["netbsd"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/netbsd-arm64@0.27.3": {
+ "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==",
+ "os": ["netbsd"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/netbsd-x64@0.25.12": {
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "os": ["netbsd"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/netbsd-x64@0.25.7": {
+ "integrity": "sha512-tUZRvLtgLE5OyN46sPSYlgmHoBS5bx2URSrgZdW1L1teWPYVmXh+QN/sKDqkzBo/IHGcKcHLKDhBeVVkO7teEA==",
+ "os": ["netbsd"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/netbsd-x64@0.27.3": {
+ "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==",
+ "os": ["netbsd"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/openbsd-arm64@0.25.12": {
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "os": ["openbsd"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/openbsd-arm64@0.25.7": {
+ "integrity": "sha512-bTJ50aoC+WDlDGBReWYiObpYvQfMjBNlKztqoNUL0iUkYtwLkBQQeEsTq/I1KyjsKA5tyov6VZaPb8UdD6ci6Q==",
+ "os": ["openbsd"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/openbsd-arm64@0.27.3": {
+ "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==",
+ "os": ["openbsd"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/openbsd-x64@0.25.12": {
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "os": ["openbsd"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/openbsd-x64@0.25.7": {
+ "integrity": "sha512-TA9XfJrgzAipFUU895jd9j2SyDh9bbNkK2I0gHcvqb/o84UeQkBpi/XmYX3cO1q/9hZokdcDqQxIi6uLVrikxg==",
+ "os": ["openbsd"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/openbsd-x64@0.27.3": {
+ "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==",
+ "os": ["openbsd"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/openharmony-arm64@0.25.12": {
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "os": ["openharmony"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/openharmony-arm64@0.25.7": {
+ "integrity": "sha512-5VTtExUrWwHHEUZ/N+rPlHDwVFQ5aME7vRJES8+iQ0xC/bMYckfJ0l2n3yGIfRoXcK/wq4oXSItZAz5wslTKGw==",
+ "os": ["openharmony"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/openharmony-arm64@0.27.3": {
+ "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==",
+ "os": ["openharmony"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/sunos-x64@0.25.12": {
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "os": ["sunos"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/sunos-x64@0.25.7": {
+ "integrity": "sha512-umkbn7KTxsexhv2vuuJmj9kggd4AEtL32KodkJgfhNOHMPtQ55RexsaSrMb+0+jp9XL4I4o2y91PZauVN4cH3A==",
+ "os": ["sunos"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/sunos-x64@0.27.3": {
+ "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==",
+ "os": ["sunos"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/win32-arm64@0.25.12": {
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "os": ["win32"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/win32-arm64@0.25.7": {
+ "integrity": "sha512-j20JQGP/gz8QDgzl5No5Gr4F6hurAZvtkFxAKhiv2X49yi/ih8ECK4Y35YnjlMogSKJk931iNMcd35BtZ4ghfw==",
+ "os": ["win32"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/win32-arm64@0.27.3": {
+ "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==",
+ "os": ["win32"],
+ "cpu": ["arm64"]
+ },
+ "@esbuild/win32-ia32@0.25.12": {
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "os": ["win32"],
+ "cpu": ["ia32"]
+ },
+ "@esbuild/win32-ia32@0.25.7": {
+ "integrity": "sha512-4qZ6NUfoiiKZfLAXRsvFkA0hoWVM+1y2bSHXHkpdLAs/+r0LgwqYohmfZCi985c6JWHhiXP30mgZawn/XrqAkQ==",
+ "os": ["win32"],
+ "cpu": ["ia32"]
+ },
+ "@esbuild/win32-ia32@0.27.3": {
+ "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==",
+ "os": ["win32"],
+ "cpu": ["ia32"]
+ },
+ "@esbuild/win32-x64@0.25.12": {
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "os": ["win32"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/win32-x64@0.25.7": {
+ "integrity": "sha512-FaPsAHTwm+1Gfvn37Eg3E5HIpfR3i6x1AIcla/MkqAIupD4BW3MrSeUqfoTzwwJhk3WE2/KqUn4/eenEJC76VA==",
+ "os": ["win32"],
+ "cpu": ["x64"]
+ },
+ "@esbuild/win32-x64@0.27.3": {
+ "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==",
+ "os": ["win32"],
+ "cpu": ["x64"]
+ },
+ "@jridgewell/gen-mapping@0.3.13": {
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dependencies": [
+ "@jridgewell/sourcemap-codec",
+ "@jridgewell/trace-mapping"
+ ]
+ },
+ "@jridgewell/remapping@2.3.5": {
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dependencies": [
+ "@jridgewell/gen-mapping",
+ "@jridgewell/trace-mapping"
+ ]
+ },
+ "@jridgewell/resolve-uri@3.1.2": {
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="
+ },
+ "@jridgewell/sourcemap-codec@1.5.5": {
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="
+ },
+ "@jridgewell/trace-mapping@0.3.31": {
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dependencies": [
+ "@jridgewell/resolve-uri",
+ "@jridgewell/sourcemap-codec"
+ ]
+ },
+ "@mjackson/node-fetch-server@0.7.0": {
+ "integrity": "sha512-un8diyEBKU3BTVj3GzlTPA1kIjCkGdD+AMYQy31Gf9JCkfoZzwgJ79GUtHrF2BN3XPNMLpubbzPcxys+a3uZEw=="
+ },
+ "@opentelemetry/api@1.9.0": {
+ "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="
+ },
+ "@preact/signals-core@1.13.0": {
+ "integrity": "sha512-slT6XeTCAbdql61GVLlGU4x7XHI7kCZV5Um5uhE4zLX4ApgiiXc0UYFvVOKq06xcovzp7p+61l68oPi563ARKg=="
+ },
+ "@preact/signals@2.8.1_preact@10.28.4": {
+ "integrity": "sha512-wX6U0SpcCukZTJBs5ChljvBZb3XmYzA5gd4vKHgX8wZZKaQCo2WHtmThdLx+mcVvlBa5u3XShC7ffbETJD4BiQ==",
+ "dependencies": [
+ "@preact/signals-core",
+ "preact"
+ ]
+ },
+ "@prefresh/babel-plugin@0.5.3": {
+ "integrity": "sha512-57LX2SHs4BX2s1IwCjNzTE2OJeEepRCNf1VTEpbNcUyHfMO68eeOWGDIt4ob9aYlW6PEWZ1SuwNikuoIXANDtQ=="
+ },
+ "@prefresh/core@1.5.9_preact@10.28.4": {
+ "integrity": "sha512-IKBKCPaz34OFVC+adiQ2qaTF5qdztO2/4ZPf4KsRTgjKosWqxVXmEbxCiUydYZRY8GVie+DQlKzQr9gt6HQ+EQ==",
+ "dependencies": [
+ "preact"
+ ]
+ },
+ "@prefresh/utils@1.2.1": {
+ "integrity": "sha512-vq/sIuN5nYfYzvyayXI4C2QkprfNaHUQ9ZX+3xLD8nL3rWyzpxOm1+K7RtMbhd+66QcaISViK7amjnheQ/4WZw=="
+ },
+ "@prefresh/vite@2.4.12_preact@10.28.4_vite@7.3.1__@types+node@24.2.0__picomatch@4.0.3_@types+node@24.2.0": {
+ "integrity": "sha512-FY1fzXpUjiuosznMV0YM7XAOPZjB5FIdWS0W24+XnlxYkt9hNAwwsiKYn+cuTEoMtD/ZVazS5QVssBr9YhpCQA==",
+ "dependencies": [
+ "@babel/core",
+ "@prefresh/babel-plugin",
+ "@prefresh/core",
+ "@prefresh/utils",
+ "@rollup/pluginutils",
+ "preact",
+ "vite"
+ ]
+ },
+ "@rollup/pluginutils@4.2.1": {
+ "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",
+ "dependencies": [
+ "estree-walker",
+ "picomatch@2.3.1"
+ ]
+ },
+ "@rollup/rollup-android-arm-eabi@4.59.0": {
+ "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
+ "os": ["android"],
+ "cpu": ["arm"]
+ },
+ "@rollup/rollup-android-arm64@4.59.0": {
+ "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
+ "os": ["android"],
+ "cpu": ["arm64"]
+ },
+ "@rollup/rollup-darwin-arm64@4.59.0": {
+ "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
+ "os": ["darwin"],
+ "cpu": ["arm64"]
+ },
+ "@rollup/rollup-darwin-x64@4.59.0": {
+ "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
+ "os": ["darwin"],
+ "cpu": ["x64"]
+ },
+ "@rollup/rollup-freebsd-arm64@4.59.0": {
+ "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
+ "os": ["freebsd"],
+ "cpu": ["arm64"]
+ },
+ "@rollup/rollup-freebsd-x64@4.59.0": {
+ "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
+ "os": ["freebsd"],
+ "cpu": ["x64"]
+ },
+ "@rollup/rollup-linux-arm-gnueabihf@4.59.0": {
+ "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
+ "os": ["linux"],
+ "cpu": ["arm"]
+ },
+ "@rollup/rollup-linux-arm-musleabihf@4.59.0": {
+ "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
+ "os": ["linux"],
+ "cpu": ["arm"]
+ },
+ "@rollup/rollup-linux-arm64-gnu@4.59.0": {
+ "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
+ "os": ["linux"],
+ "cpu": ["arm64"]
+ },
+ "@rollup/rollup-linux-arm64-musl@4.59.0": {
+ "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
+ "os": ["linux"],
+ "cpu": ["arm64"]
+ },
+ "@rollup/rollup-linux-loong64-gnu@4.59.0": {
+ "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
+ "os": ["linux"],
+ "cpu": ["loong64"]
+ },
+ "@rollup/rollup-linux-loong64-musl@4.59.0": {
+ "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
+ "os": ["linux"],
+ "cpu": ["loong64"]
+ },
+ "@rollup/rollup-linux-ppc64-gnu@4.59.0": {
+ "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
+ "os": ["linux"],
+ "cpu": ["ppc64"]
+ },
+ "@rollup/rollup-linux-ppc64-musl@4.59.0": {
+ "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
+ "os": ["linux"],
+ "cpu": ["ppc64"]
+ },
+ "@rollup/rollup-linux-riscv64-gnu@4.59.0": {
+ "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
+ "os": ["linux"],
+ "cpu": ["riscv64"]
+ },
+ "@rollup/rollup-linux-riscv64-musl@4.59.0": {
+ "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
+ "os": ["linux"],
+ "cpu": ["riscv64"]
+ },
+ "@rollup/rollup-linux-s390x-gnu@4.59.0": {
+ "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
+ "os": ["linux"],
+ "cpu": ["s390x"]
+ },
+ "@rollup/rollup-linux-x64-gnu@4.59.0": {
+ "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
+ "os": ["linux"],
+ "cpu": ["x64"]
+ },
+ "@rollup/rollup-linux-x64-musl@4.59.0": {
+ "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
+ "os": ["linux"],
+ "cpu": ["x64"]
+ },
+ "@rollup/rollup-openbsd-x64@4.59.0": {
+ "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
+ "os": ["openbsd"],
+ "cpu": ["x64"]
+ },
+ "@rollup/rollup-openharmony-arm64@4.59.0": {
+ "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
+ "os": ["openharmony"],
+ "cpu": ["arm64"]
+ },
+ "@rollup/rollup-win32-arm64-msvc@4.59.0": {
+ "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
+ "os": ["win32"],
+ "cpu": ["arm64"]
+ },
+ "@rollup/rollup-win32-ia32-msvc@4.59.0": {
+ "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
+ "os": ["win32"],
+ "cpu": ["ia32"]
+ },
+ "@rollup/rollup-win32-x64-gnu@4.59.0": {
+ "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
+ "os": ["win32"],
+ "cpu": ["x64"]
+ },
+ "@rollup/rollup-win32-x64-msvc@4.59.0": {
+ "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
+ "os": ["win32"],
+ "cpu": ["x64"]
+ },
+ "@tailwindcss/node@4.2.1": {
+ "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==",
+ "dependencies": [
+ "@jridgewell/remapping",
+ "enhanced-resolve",
+ "jiti",
+ "lightningcss",
+ "magic-string",
+ "source-map-js",
+ "tailwindcss"
+ ]
+ },
+ "@tailwindcss/oxide-android-arm64@4.2.1": {
+ "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==",
+ "os": ["android"],
+ "cpu": ["arm64"]
+ },
+ "@tailwindcss/oxide-darwin-arm64@4.2.1": {
+ "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==",
+ "os": ["darwin"],
+ "cpu": ["arm64"]
+ },
+ "@tailwindcss/oxide-darwin-x64@4.2.1": {
+ "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==",
+ "os": ["darwin"],
+ "cpu": ["x64"]
+ },
+ "@tailwindcss/oxide-freebsd-x64@4.2.1": {
+ "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==",
+ "os": ["freebsd"],
+ "cpu": ["x64"]
+ },
+ "@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1": {
+ "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==",
+ "os": ["linux"],
+ "cpu": ["arm"]
+ },
+ "@tailwindcss/oxide-linux-arm64-gnu@4.2.1": {
+ "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==",
+ "os": ["linux"],
+ "cpu": ["arm64"]
+ },
+ "@tailwindcss/oxide-linux-arm64-musl@4.2.1": {
+ "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==",
+ "os": ["linux"],
+ "cpu": ["arm64"]
+ },
+ "@tailwindcss/oxide-linux-x64-gnu@4.2.1": {
+ "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==",
+ "os": ["linux"],
+ "cpu": ["x64"]
+ },
+ "@tailwindcss/oxide-linux-x64-musl@4.2.1": {
+ "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==",
+ "os": ["linux"],
+ "cpu": ["x64"]
+ },
+ "@tailwindcss/oxide-wasm32-wasi@4.2.1": {
+ "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==",
+ "cpu": ["wasm32"]
+ },
+ "@tailwindcss/oxide-win32-arm64-msvc@4.2.1": {
+ "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==",
+ "os": ["win32"],
+ "cpu": ["arm64"]
+ },
+ "@tailwindcss/oxide-win32-x64-msvc@4.2.1": {
+ "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==",
+ "os": ["win32"],
+ "cpu": ["x64"]
+ },
+ "@tailwindcss/oxide@4.2.1": {
+ "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==",
+ "optionalDependencies": [
+ "@tailwindcss/oxide-android-arm64",
+ "@tailwindcss/oxide-darwin-arm64",
+ "@tailwindcss/oxide-darwin-x64",
+ "@tailwindcss/oxide-freebsd-x64",
+ "@tailwindcss/oxide-linux-arm-gnueabihf",
+ "@tailwindcss/oxide-linux-arm64-gnu",
+ "@tailwindcss/oxide-linux-arm64-musl",
+ "@tailwindcss/oxide-linux-x64-gnu",
+ "@tailwindcss/oxide-linux-x64-musl",
+ "@tailwindcss/oxide-wasm32-wasi",
+ "@tailwindcss/oxide-win32-arm64-msvc",
+ "@tailwindcss/oxide-win32-x64-msvc"
+ ]
+ },
+ "@tailwindcss/typography@0.5.19_tailwindcss@4.2.1": {
+ "integrity": "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==",
+ "dependencies": [
+ "postcss-selector-parser",
+ "tailwindcss"
+ ]
+ },
+ "@tailwindcss/vite@4.2.1_vite@7.3.1__@types+node@24.2.0__picomatch@4.0.3_@types+node@24.2.0": {
+ "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==",
+ "dependencies": [
+ "@tailwindcss/node",
+ "@tailwindcss/oxide",
+ "tailwindcss",
+ "vite"
+ ]
+ },
+ "@types/estree@1.0.8": {
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="
+ },
+ "@types/node@24.2.0": {
+ "integrity": "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==",
+ "dependencies": [
+ "undici-types"
+ ]
+ },
+ "baseline-browser-mapping@2.10.0": {
+ "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==",
+ "bin": true
+ },
+ "browserslist@4.28.1": {
+ "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
+ "dependencies": [
+ "baseline-browser-mapping",
+ "caniuse-lite",
+ "electron-to-chromium",
+ "node-releases",
+ "update-browserslist-db"
+ ],
+ "bin": true
+ },
+ "caniuse-lite@1.0.30001774": {
+ "integrity": "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA=="
+ },
+ "convert-source-map@2.0.0": {
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
+ },
+ "cssesc@3.0.0": {
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "bin": true
+ },
+ "debug@4.4.3": {
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dependencies": [
+ "ms"
+ ]
+ },
+ "detect-libc@2.1.2": {
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="
+ },
+ "electron-to-chromium@1.5.302": {
+ "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg=="
+ },
+ "enhanced-resolve@5.19.0": {
+ "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==",
+ "dependencies": [
+ "graceful-fs",
+ "tapable"
+ ]
+ },
+ "esbuild-wasm@0.25.12": {
+ "integrity": "sha512-rZqkjL3Y6FwLpSHzLnaEy8Ps6veCNo1kZa9EOfJvmWtBq5dJH4iVjfmOO6Mlkv9B0tt9WFPFmb/VxlgJOnueNg==",
+ "bin": true
+ },
+ "esbuild@0.25.12": {
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "optionalDependencies": [
+ "@esbuild/aix-ppc64@0.25.12",
+ "@esbuild/android-arm@0.25.12",
+ "@esbuild/android-arm64@0.25.12",
+ "@esbuild/android-x64@0.25.12",
+ "@esbuild/darwin-arm64@0.25.12",
+ "@esbuild/darwin-x64@0.25.12",
+ "@esbuild/freebsd-arm64@0.25.12",
+ "@esbuild/freebsd-x64@0.25.12",
+ "@esbuild/linux-arm@0.25.12",
+ "@esbuild/linux-arm64@0.25.12",
+ "@esbuild/linux-ia32@0.25.12",
+ "@esbuild/linux-loong64@0.25.12",
+ "@esbuild/linux-mips64el@0.25.12",
+ "@esbuild/linux-ppc64@0.25.12",
+ "@esbuild/linux-riscv64@0.25.12",
+ "@esbuild/linux-s390x@0.25.12",
+ "@esbuild/linux-x64@0.25.12",
+ "@esbuild/netbsd-arm64@0.25.12",
+ "@esbuild/netbsd-x64@0.25.12",
+ "@esbuild/openbsd-arm64@0.25.12",
+ "@esbuild/openbsd-x64@0.25.12",
+ "@esbuild/openharmony-arm64@0.25.12",
+ "@esbuild/sunos-x64@0.25.12",
+ "@esbuild/win32-arm64@0.25.12",
+ "@esbuild/win32-ia32@0.25.12",
+ "@esbuild/win32-x64@0.25.12"
+ ],
+ "scripts": true,
+ "bin": true
+ },
+ "esbuild@0.25.7": {
+ "integrity": "sha512-daJB0q2dmTzo90L9NjRaohhRWrCzYxWNFTjEi72/h+p5DcY3yn4MacWfDakHmaBaDzDiuLJsCh0+6LK/iX+c+Q==",
+ "optionalDependencies": [
+ "@esbuild/aix-ppc64@0.25.7",
+ "@esbuild/android-arm@0.25.7",
+ "@esbuild/android-arm64@0.25.7",
+ "@esbuild/android-x64@0.25.7",
+ "@esbuild/darwin-arm64@0.25.7",
+ "@esbuild/darwin-x64@0.25.7",
+ "@esbuild/freebsd-arm64@0.25.7",
+ "@esbuild/freebsd-x64@0.25.7",
+ "@esbuild/linux-arm@0.25.7",
+ "@esbuild/linux-arm64@0.25.7",
+ "@esbuild/linux-ia32@0.25.7",
+ "@esbuild/linux-loong64@0.25.7",
+ "@esbuild/linux-mips64el@0.25.7",
+ "@esbuild/linux-ppc64@0.25.7",
+ "@esbuild/linux-riscv64@0.25.7",
+ "@esbuild/linux-s390x@0.25.7",
+ "@esbuild/linux-x64@0.25.7",
+ "@esbuild/netbsd-arm64@0.25.7",
+ "@esbuild/netbsd-x64@0.25.7",
+ "@esbuild/openbsd-arm64@0.25.7",
+ "@esbuild/openbsd-x64@0.25.7",
+ "@esbuild/openharmony-arm64@0.25.7",
+ "@esbuild/sunos-x64@0.25.7",
+ "@esbuild/win32-arm64@0.25.7",
+ "@esbuild/win32-ia32@0.25.7",
+ "@esbuild/win32-x64@0.25.7"
+ ],
+ "scripts": true,
+ "bin": true
+ },
+ "esbuild@0.27.3": {
+ "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
+ "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"
+ ],
+ "scripts": true,
+ "bin": true
+ },
+ "escalade@3.2.0": {
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="
+ },
+ "estree-walker@2.0.2": {
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
+ },
+ "fdir@6.5.0_picomatch@4.0.3": {
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dependencies": [
+ "picomatch@4.0.3"
+ ],
+ "optionalPeers": [
+ "picomatch@4.0.3"
+ ]
+ },
+ "fsevents@2.3.3": {
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "os": ["darwin"],
+ "scripts": true
+ },
+ "gensync@1.0.0-beta.2": {
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
+ },
+ "graceful-fs@4.2.11": {
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
+ },
+ "jiti@2.6.1": {
+ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
+ "bin": true
+ },
+ "js-tokens@4.0.0": {
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "jsesc@3.1.0": {
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "bin": true
+ },
+ "json5@2.2.3": {
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "bin": true
+ },
+ "lightningcss-android-arm64@1.31.1": {
+ "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==",
+ "os": ["android"],
+ "cpu": ["arm64"]
+ },
+ "lightningcss-darwin-arm64@1.31.1": {
+ "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==",
+ "os": ["darwin"],
+ "cpu": ["arm64"]
+ },
+ "lightningcss-darwin-x64@1.31.1": {
+ "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==",
+ "os": ["darwin"],
+ "cpu": ["x64"]
+ },
+ "lightningcss-freebsd-x64@1.31.1": {
+ "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==",
+ "os": ["freebsd"],
+ "cpu": ["x64"]
+ },
+ "lightningcss-linux-arm-gnueabihf@1.31.1": {
+ "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==",
+ "os": ["linux"],
+ "cpu": ["arm"]
+ },
+ "lightningcss-linux-arm64-gnu@1.31.1": {
+ "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==",
+ "os": ["linux"],
+ "cpu": ["arm64"]
+ },
+ "lightningcss-linux-arm64-musl@1.31.1": {
+ "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==",
+ "os": ["linux"],
+ "cpu": ["arm64"]
+ },
+ "lightningcss-linux-x64-gnu@1.31.1": {
+ "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==",
+ "os": ["linux"],
+ "cpu": ["x64"]
+ },
+ "lightningcss-linux-x64-musl@1.31.1": {
+ "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==",
+ "os": ["linux"],
+ "cpu": ["x64"]
+ },
+ "lightningcss-win32-arm64-msvc@1.31.1": {
+ "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==",
+ "os": ["win32"],
+ "cpu": ["arm64"]
+ },
+ "lightningcss-win32-x64-msvc@1.31.1": {
+ "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==",
+ "os": ["win32"],
+ "cpu": ["x64"]
+ },
+ "lightningcss@1.31.1": {
+ "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==",
+ "dependencies": [
+ "detect-libc"
+ ],
+ "optionalDependencies": [
+ "lightningcss-android-arm64",
+ "lightningcss-darwin-arm64",
+ "lightningcss-darwin-x64",
+ "lightningcss-freebsd-x64",
+ "lightningcss-linux-arm-gnueabihf",
+ "lightningcss-linux-arm64-gnu",
+ "lightningcss-linux-arm64-musl",
+ "lightningcss-linux-x64-gnu",
+ "lightningcss-linux-x64-musl",
+ "lightningcss-win32-arm64-msvc",
+ "lightningcss-win32-x64-msvc"
+ ]
+ },
+ "lru-cache@5.1.1": {
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dependencies": [
+ "yallist"
+ ]
+ },
+ "magic-string@0.30.21": {
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dependencies": [
+ "@jridgewell/sourcemap-codec"
+ ]
+ },
+ "marked@17.0.3": {
+ "integrity": "sha512-jt1v2ObpyOKR8p4XaUJVk3YWRJ5n+i4+rjQopxvV32rSndTJXvIzuUdWWIy/1pFQMkQmvTXawzDNqOH/CUmx6A==",
+ "bin": true
+ },
+ "ms@2.1.3": {
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "nanoid@3.3.11": {
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "bin": true
+ },
+ "node-releases@2.0.27": {
+ "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="
+ },
+ "picocolors@1.1.1": {
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
+ },
+ "picomatch@2.3.1": {
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
+ },
+ "picomatch@4.0.3": {
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="
+ },
+ "postcss-selector-parser@6.0.10": {
+ "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
+ "dependencies": [
+ "cssesc",
+ "util-deprecate"
+ ]
+ },
+ "postcss@8.5.6": {
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "dependencies": [
+ "nanoid",
+ "picocolors",
+ "source-map-js"
+ ]
+ },
+ "preact-render-to-string@6.6.6_preact@10.28.4": {
+ "integrity": "sha512-EfqZJytnjJldV+YaaqhthU2oXsEf5e+6rDv957p+zxAvNfFLQOPfvBOTncscQ+akzu6Wrl7s3Pa0LjUQmWJsGQ==",
+ "dependencies": [
+ "preact"
+ ]
+ },
+ "preact@10.28.4": {
+ "integrity": "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ=="
+ },
+ "rollup@4.59.0": {
+ "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
+ "dependencies": [
+ "@types/estree"
+ ],
+ "optionalDependencies": [
+ "@rollup/rollup-android-arm-eabi",
+ "@rollup/rollup-android-arm64",
+ "@rollup/rollup-darwin-arm64",
+ "@rollup/rollup-darwin-x64",
+ "@rollup/rollup-freebsd-arm64",
+ "@rollup/rollup-freebsd-x64",
+ "@rollup/rollup-linux-arm-gnueabihf",
+ "@rollup/rollup-linux-arm-musleabihf",
+ "@rollup/rollup-linux-arm64-gnu",
+ "@rollup/rollup-linux-arm64-musl",
+ "@rollup/rollup-linux-loong64-gnu",
+ "@rollup/rollup-linux-loong64-musl",
+ "@rollup/rollup-linux-ppc64-gnu",
+ "@rollup/rollup-linux-ppc64-musl",
+ "@rollup/rollup-linux-riscv64-gnu",
+ "@rollup/rollup-linux-riscv64-musl",
+ "@rollup/rollup-linux-s390x-gnu",
+ "@rollup/rollup-linux-x64-gnu",
+ "@rollup/rollup-linux-x64-musl",
+ "@rollup/rollup-openbsd-x64",
+ "@rollup/rollup-openharmony-arm64",
+ "@rollup/rollup-win32-arm64-msvc",
+ "@rollup/rollup-win32-ia32-msvc",
+ "@rollup/rollup-win32-x64-gnu",
+ "@rollup/rollup-win32-x64-msvc",
+ "fsevents"
+ ],
+ "bin": true
+ },
+ "semver@6.3.1": {
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "bin": true
+ },
+ "source-map-js@1.2.1": {
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="
+ },
+ "tailwindcss@4.2.1": {
+ "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="
+ },
+ "tapable@2.3.0": {
+ "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="
+ },
+ "tinyglobby@0.2.15_picomatch@4.0.3": {
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "dependencies": [
+ "fdir",
+ "picomatch@4.0.3"
+ ]
+ },
+ "undici-types@7.10.0": {
+ "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="
+ },
+ "update-browserslist-db@1.2.3_browserslist@4.28.1": {
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dependencies": [
+ "browserslist",
+ "escalade",
+ "picocolors"
+ ],
+ "bin": true
+ },
+ "util-deprecate@1.0.2": {
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ },
+ "vite@7.3.1_@types+node@24.2.0_picomatch@4.0.3": {
+ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
+ "dependencies": [
+ "@types/node",
+ "esbuild@0.27.3",
+ "fdir",
+ "picomatch@4.0.3",
+ "postcss",
+ "rollup",
+ "tinyglobby"
+ ],
+ "optionalDependencies": [
+ "fsevents"
+ ],
+ "optionalPeers": [
+ "@types/node"
+ ],
+ "bin": true
+ },
+ "yallist@3.1.1": {
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
+ }
+ },
+ "redirects": {
+ "https://esm.sh/@types/babel__helper-validator-identifier@~7.15.2/index.d.ts": "https://esm.sh/@types/babel__helper-validator-identifier@7.15.2/index.d.ts"
+ },
+ "remote": {
+ "https://deno.land/std@0.208.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee",
+ "https://deno.land/std@0.208.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56",
+ "https://deno.land/std@0.208.0/fs/_util.ts": "fbf57dcdc9f7bc8128d60301eece608246971a7836a3bb1e78da75314f08b978",
+ "https://deno.land/std@0.208.0/fs/ensure_dir.ts": "dc64c4c75c64721d4e3fb681f1382f803ff3d2868f08563ff923fdd20d071c40",
+ "https://deno.land/std@0.208.0/fs/expand_glob.ts": "4f98c508fc9e40d6311d2f7fd88aaad05235cc506388c22dda315e095305811d",
+ "https://deno.land/std@0.208.0/fs/walk.ts": "c1e6b43f72a46e89b630140308bd51a4795d416a416b4cfb7cd4bd1e25946723",
+ "https://deno.land/std@0.208.0/path/_common/assert_path.ts": "061e4d093d4ba5aebceb2c4da3318bfe3289e868570e9d3a8e327d91c2958946",
+ "https://deno.land/std@0.208.0/path/_common/basename.ts": "0d978ff818f339cd3b1d09dc914881f4d15617432ae519c1b8fdc09ff8d3789a",
+ "https://deno.land/std@0.208.0/path/_common/common.ts": "9e4233b2eeb50f8b2ae10ecc2108f58583aea6fd3e8907827020282dc2b76143",
+ "https://deno.land/std@0.208.0/path/_common/constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0",
+ "https://deno.land/std@0.208.0/path/_common/dirname.ts": "2ba7fb4cc9fafb0f38028f434179579ce61d4d9e51296fad22b701c3d3cd7397",
+ "https://deno.land/std@0.208.0/path/_common/format.ts": "11aa62e316dfbf22c126917f5e03ea5fe2ee707386555a8f513d27ad5756cf96",
+ "https://deno.land/std@0.208.0/path/_common/from_file_url.ts": "ef1bf3197d2efbf0297a2bdbf3a61d804b18f2bcce45548ae112313ec5be3c22",
+ "https://deno.land/std@0.208.0/path/_common/glob_to_reg_exp.ts": "5c3c2b79fc2294ec803d102bd9855c451c150021f452046312819fbb6d4dc156",
+ "https://deno.land/std@0.208.0/path/_common/normalize.ts": "2ba7fb4cc9fafb0f38028f434179579ce61d4d9e51296fad22b701c3d3cd7397",
+ "https://deno.land/std@0.208.0/path/_common/normalize_string.ts": "88c472f28ae49525f9fe82de8c8816d93442d46a30d6bb5063b07ff8a89ff589",
+ "https://deno.land/std@0.208.0/path/_common/relative.ts": "1af19d787a2a84b8c534cc487424fe101f614982ae4851382c978ab2216186b4",
+ "https://deno.land/std@0.208.0/path/_common/strip_trailing_separators.ts": "7ffc7c287e97bdeeee31b155828686967f222cd73f9e5780bfe7dfb1b58c6c65",
+ "https://deno.land/std@0.208.0/path/_common/to_file_url.ts": "a8cdd1633bc9175b7eebd3613266d7c0b6ae0fb0cff24120b6092ac31662f9ae",
+ "https://deno.land/std@0.208.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b",
+ "https://deno.land/std@0.208.0/path/_os.ts": "30b0c2875f360c9296dbe6b7f2d528f0f9c741cecad2e97f803f5219e91b40a2",
+ "https://deno.land/std@0.208.0/path/basename.ts": "04bb5ef3e86bba8a35603b8f3b69537112cdd19ce64b77f2522006da2977a5f3",
+ "https://deno.land/std@0.208.0/path/common.ts": "f4d061c7d0b95a65c2a1a52439edec393e906b40f1caf4604c389fae7caa80f5",
+ "https://deno.land/std@0.208.0/path/dirname.ts": "88a0a71c21debafc4da7a4cd44fd32e899462df458fbca152390887d41c40361",
+ "https://deno.land/std@0.208.0/path/extname.ts": "2da4e2490f3b48b7121d19fb4c91681a5e11bd6bd99df4f6f47d7a71bb6ecdf2",
+ "https://deno.land/std@0.208.0/path/format.ts": "3457530cc85d1b4bab175f9ae73998b34fd456c830d01883169af0681b8894fb",
+ "https://deno.land/std@0.208.0/path/from_file_url.ts": "e7fa233ea1dff9641e8d566153a24d95010110185a6f418dd2e32320926043f8",
+ "https://deno.land/std@0.208.0/path/glob.ts": "a00a81a55c02bbe074ab21a50b6495c6f7795f54cd718c824adaa92c6c9b7419",
+ "https://deno.land/std@0.208.0/path/glob_to_regexp.ts": "74d7448c471e293d03f05ccb968df4365fed6aaa508506b6325a8efdc01d8271",
+ "https://deno.land/std@0.208.0/path/is_absolute.ts": "67232b41b860571c5b7537f4954c88d86ae2ba45e883ee37d3dec27b74909d13",
+ "https://deno.land/std@0.208.0/path/is_glob.ts": "567dce5c6656bdedfc6b3ee6c0833e1e4db2b8dff6e62148e94a917f289c06ad",
+ "https://deno.land/std@0.208.0/path/join.ts": "98d3d76c819af4a11a81d5ba2dbb319f1ce9d63fc2b615597d4bcfddd4a89a09",
+ "https://deno.land/std@0.208.0/path/join_globs.ts": "9b84d5103b63d3dbed4b2cf8b12477b2ad415c7d343f1488505162dc0e5f4db8",
+ "https://deno.land/std@0.208.0/path/mod.ts": "3defabebc98279e62b392fee7a6937adc932a8f4dcd2471441e36c15b97b00e0",
+ "https://deno.land/std@0.208.0/path/normalize.ts": "aa95be9a92c7bd4f9dc0ba51e942a1973e2b93d266cd74f5ca751c136d520b66",
+ "https://deno.land/std@0.208.0/path/normalize_glob.ts": "674baa82e1c00b6cb153bbca36e06f8e0337cb8062db6d905ab5de16076ca46b",
+ "https://deno.land/std@0.208.0/path/parse.ts": "d87ff0deef3fb495bc0d862278ff96da5a06acf0625ca27769fc52ac0d3d6ece",
+ "https://deno.land/std@0.208.0/path/posix/_util.ts": "ecf49560fedd7dd376c6156cc5565cad97c1abe9824f4417adebc7acc36c93e5",
+ "https://deno.land/std@0.208.0/path/posix/basename.ts": "a630aeb8fd8e27356b1823b9dedd505e30085015407caa3396332752f6b8406a",
+ "https://deno.land/std@0.208.0/path/posix/common.ts": "e781d395dc76f6282e3f7dd8de13194abb8b04a82d109593141abc6e95755c8b",
+ "https://deno.land/std@0.208.0/path/posix/dirname.ts": "f48c9c42cc670803b505478b7ef162c7cfa9d8e751b59d278b2ec59470531472",
+ "https://deno.land/std@0.208.0/path/posix/extname.ts": "ee7f6571a9c0a37f9218fbf510c440d1685a7c13082c348d701396cc795e0be0",
+ "https://deno.land/std@0.208.0/path/posix/format.ts": "b94876f77e61bfe1f147d5ccb46a920636cd3cef8be43df330f0052b03875968",
+ "https://deno.land/std@0.208.0/path/posix/from_file_url.ts": "b97287a83e6407ac27bdf3ab621db3fccbf1c27df0a1b1f20e1e1b5acf38a379",
+ "https://deno.land/std@0.208.0/path/posix/glob_to_regexp.ts": "6ed00c71fbfe0ccc35977c35444f94e82200b721905a60bd1278b1b768d68b1a",
+ "https://deno.land/std@0.208.0/path/posix/is_absolute.ts": "159900a3422d11069d48395568217eb7fc105ceda2683d03d9b7c0f0769e01b8",
+ "https://deno.land/std@0.208.0/path/posix/is_glob.ts": "ec4fbc604b9db8487f7b56ab0e759b24a971ab6a45f7b0b698bc39b8b9f9680f",
+ "https://deno.land/std@0.208.0/path/posix/join.ts": "0c0d84bdc344876930126640011ec1b888e6facf74153ffad9ef26813aa2a076",
+ "https://deno.land/std@0.208.0/path/posix/join_globs.ts": "f4838d54b1f60a34a40625a3293f6e583135348be1b2974341ac04743cb26121",
+ "https://deno.land/std@0.208.0/path/posix/mod.ts": "f1b08a7f64294b7de87fc37190d63b6ce5b02889af9290c9703afe01951360ae",
+ "https://deno.land/std@0.208.0/path/posix/normalize.ts": "11de90a94ab7148cc46e5a288f7d732aade1d616bc8c862f5560fa18ff987b4b",
+ "https://deno.land/std@0.208.0/path/posix/normalize_glob.ts": "10a1840c628ebbab679254d5fa1c20e59106102354fb648a1765aed72eb9f3f9",
+ "https://deno.land/std@0.208.0/path/posix/parse.ts": "199208f373dd93a792e9c585352bfc73a6293411bed6da6d3bc4f4ef90b04c8e",
+ "https://deno.land/std@0.208.0/path/posix/relative.ts": "e2f230608b0f083e6deaa06e063943e5accb3320c28aef8d87528fbb7fe6504c",
+ "https://deno.land/std@0.208.0/path/posix/resolve.ts": "51579d83159d5c719518c9ae50812a63959bbcb7561d79acbdb2c3682236e285",
+ "https://deno.land/std@0.208.0/path/posix/separator.ts": "0b6573b5f3269a3164d8edc9cefc33a02dd51003731c561008c8bb60220ebac1",
+ "https://deno.land/std@0.208.0/path/posix/to_file_url.ts": "08d43ea839ee75e9b8b1538376cfe95911070a655cd312bc9a00f88ef14967b6",
+ "https://deno.land/std@0.208.0/path/posix/to_namespaced_path.ts": "c9228a0e74fd37e76622cd7b142b8416663a9b87db643302fa0926b5a5c83bdc",
+ "https://deno.land/std@0.208.0/path/relative.ts": "23d45ede8b7ac464a8299663a43488aad6b561414e7cbbe4790775590db6349c",
+ "https://deno.land/std@0.208.0/path/resolve.ts": "5b184efc87155a0af9fa305ff68a109e28de9aee81fc3e77cd01380f19daf867",
+ "https://deno.land/std@0.208.0/path/separator.ts": "40a3e9a4ad10bef23bc2cd6c610291b6c502a06237c2c4cd034a15ca78dedc1f",
+ "https://deno.land/std@0.208.0/path/to_file_url.ts": "edaafa089e0bce386e1b2d47afe7c72e379ff93b28a5829a5885e4b6c626d864",
+ "https://deno.land/std@0.208.0/path/to_namespaced_path.ts": "cf8734848aac3c7527d1689d2adf82132b1618eff3cc523a775068847416b22a",
+ "https://deno.land/std@0.208.0/path/windows/_util.ts": "f32b9444554c8863b9b4814025c700492a2b57ff2369d015360970a1b1099d54",
+ "https://deno.land/std@0.208.0/path/windows/basename.ts": "8a9dbf7353d50afbc5b221af36c02a72c2d1b2b5b9f7c65bf6a5a2a0baf88ad3",
+ "https://deno.land/std@0.208.0/path/windows/common.ts": "e781d395dc76f6282e3f7dd8de13194abb8b04a82d109593141abc6e95755c8b",
+ "https://deno.land/std@0.208.0/path/windows/dirname.ts": "5c2aa541384bf0bd9aca821275d2a8690e8238fa846198ef5c7515ce31a01a94",
+ "https://deno.land/std@0.208.0/path/windows/extname.ts": "07f4fa1b40d06a827446b3e3bcc8d619c5546b079b8ed0c77040bbef716c7614",
+ "https://deno.land/std@0.208.0/path/windows/format.ts": "343019130d78f172a5c49fdc7e64686a7faf41553268961e7b6c92a6d6548edf",
+ "https://deno.land/std@0.208.0/path/windows/from_file_url.ts": "d53335c12b0725893d768be3ac6bf0112cc5b639d2deb0171b35988493b46199",
+ "https://deno.land/std@0.208.0/path/windows/glob_to_regexp.ts": "290755e18ec6c1a4f4d711c3390537358e8e3179581e66261a0cf348b1a13395",
+ "https://deno.land/std@0.208.0/path/windows/is_absolute.ts": "245b56b5f355ede8664bd7f080c910a97e2169972d23075554ae14d73722c53c",
+ "https://deno.land/std@0.208.0/path/windows/is_glob.ts": "ec4fbc604b9db8487f7b56ab0e759b24a971ab6a45f7b0b698bc39b8b9f9680f",
+ "https://deno.land/std@0.208.0/path/windows/join.ts": "e6600bf88edeeef4e2276e155b8de1d5dec0435fd526ba2dc4d37986b2882f16",
+ "https://deno.land/std@0.208.0/path/windows/join_globs.ts": "f4838d54b1f60a34a40625a3293f6e583135348be1b2974341ac04743cb26121",
+ "https://deno.land/std@0.208.0/path/windows/mod.ts": "d7040f461465c2c21c1c68fc988ef0bdddd499912138cde3abf6ad60c7fb3814",
+ "https://deno.land/std@0.208.0/path/windows/normalize.ts": "9deebbf40c81ef540b7b945d4ccd7a6a2c5a5992f791e6d3377043031e164e69",
+ "https://deno.land/std@0.208.0/path/windows/normalize_glob.ts": "344ff5ed45430495b9a3d695567291e50e00b1b3b04ea56712a2acf07ab5c128",
+ "https://deno.land/std@0.208.0/path/windows/parse.ts": "120faf778fe1f22056f33ded069b68e12447668fcfa19540c0129561428d3ae5",
+ "https://deno.land/std@0.208.0/path/windows/relative.ts": "026855cd2c36c8f28f1df3c6fbd8f2449a2aa21f48797a74700c5d872b86d649",
+ "https://deno.land/std@0.208.0/path/windows/resolve.ts": "5ff441ab18a2346abadf778121128ee71bda4d0898513d4639a6ca04edca366b",
+ "https://deno.land/std@0.208.0/path/windows/separator.ts": "ae21f27015f10510ed1ac4a0ba9c4c9c967cbdd9d9e776a3e4967553c397bd5d",
+ "https://deno.land/std@0.208.0/path/windows/to_file_url.ts": "8e9ea9e1ff364aa06fa72999204229952d0a279dbb876b7b838b2b2fea55cce3",
+ "https://deno.land/std@0.208.0/path/windows/to_namespaced_path.ts": "e0f4d4a5e77f28a5708c1a33ff24360f35637ba6d8f103d19661255ef7bfd50d",
+ "https://deno.land/std@0.216.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975",
+ "https://deno.land/std@0.216.0/assert/_diff.ts": "dcc63d94ca289aec80644030cf88ccbf7acaa6fbd7b0f22add93616b36593840",
+ "https://deno.land/std@0.216.0/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4",
+ "https://deno.land/std@0.216.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5",
+ "https://deno.land/std@0.216.0/assert/assert_almost_equals.ts": "8b96b7385cc117668b0720115eb6ee73d04c9bcb2f5d2344d674918c9113688f",
+ "https://deno.land/std@0.216.0/assert/assert_array_includes.ts": "1688d76317fd45b7e93ef9e2765f112fdf2b7c9821016cdfb380b9445374aed1",
+ "https://deno.land/std@0.216.0/assert/assert_equals.ts": "4497c56fe7d2993b0d447926702802fc0becb44e319079e8eca39b482ee01b4e",
+ "https://deno.land/std@0.216.0/assert/assert_exists.ts": "24a7bf965e634f909242cd09fbaf38bde6b791128ece08e33ab08586a7cc55c9",
+ "https://deno.land/std@0.216.0/assert/assert_false.ts": "6f382568e5128c0f855e5f7dbda8624c1ed9af4fcc33ef4a9afeeedcdce99769",
+ "https://deno.land/std@0.216.0/assert/assert_greater.ts": "4945cf5729f1a38874d7e589e0fe5cc5cd5abe5573ca2ddca9d3791aa891856c",
+ "https://deno.land/std@0.216.0/assert/assert_greater_or_equal.ts": "573ed8823283b8d94b7443eb69a849a3c369a8eb9666b2d1db50c33763a5d219",
+ "https://deno.land/std@0.216.0/assert/assert_instance_of.ts": "72dc1faff1e248692d873c89382fa1579dd7b53b56d52f37f9874a75b11ba444",
+ "https://deno.land/std@0.216.0/assert/assert_is_error.ts": "6596f2b5ba89ba2fe9b074f75e9318cda97a2381e59d476812e30077fbdb6ed2",
+ "https://deno.land/std@0.216.0/assert/assert_less.ts": "2b4b3fe7910f65f7be52212f19c3977ecb8ba5b2d6d0a296c83cde42920bb005",
+ "https://deno.land/std@0.216.0/assert/assert_less_or_equal.ts": "b93d212fe669fbde959e35b3437ac9a4468f2e6b77377e7b6ea2cfdd825d38a0",
+ "https://deno.land/std@0.216.0/assert/assert_match.ts": "ec2d9680ed3e7b9746ec57ec923a17eef6d476202f339ad91d22277d7f1d16e1",
+ "https://deno.land/std@0.216.0/assert/assert_not_equals.ts": "ac86413ab70ffb14fdfc41740ba579a983fe355ba0ce4a9ab685e6b8e7f6a250",
+ "https://deno.land/std@0.216.0/assert/assert_not_instance_of.ts": "8f720d92d83775c40b2542a8d76c60c2d4aeddaf8713c8d11df8984af2604931",
+ "https://deno.land/std@0.216.0/assert/assert_not_match.ts": "b4b7c77f146963e2b673c1ce4846473703409eb93f5ab0eb60f6e6f8aeffe39f",
+ "https://deno.land/std@0.216.0/assert/assert_not_strict_equals.ts": "da0b8ab60a45d5a9371088378e5313f624799470c3b54c76e8b8abeec40a77be",
+ "https://deno.land/std@0.216.0/assert/assert_object_match.ts": "e85e5eef62a56ce364c3afdd27978ccab979288a3e772e6855c270a7b118fa49",
+ "https://deno.land/std@0.216.0/assert/assert_rejects.ts": "e9e0c8d9c3e164c7ac962c37b3be50577c5a2010db107ed272c4c1afb1269f54",
+ "https://deno.land/std@0.216.0/assert/assert_strict_equals.ts": "0425a98f70badccb151644c902384c12771a93e65f8ff610244b8147b03a2366",
+ "https://deno.land/std@0.216.0/assert/assert_string_includes.ts": "dfb072a890167146f8e5bdd6fde887ce4657098e9f71f12716ef37f35fb6f4a7",
+ "https://deno.land/std@0.216.0/assert/assert_throws.ts": "edddd86b39606c342164b49ad88dd39a26e72a26655e07545d172f164b617fa7",
+ "https://deno.land/std@0.216.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8",
+ "https://deno.land/std@0.216.0/assert/equal.ts": "fae5e8a52a11d3ac694bbe1a53e13a7969e3f60791262312e91a3e741ae519e2",
+ "https://deno.land/std@0.216.0/assert/fail.ts": "f310e51992bac8e54f5fd8e44d098638434b2edb802383690e0d7a9be1979f1c",
+ "https://deno.land/std@0.216.0/assert/mod.ts": "325df8c0683ad83a873b9691aa66b812d6275fc9fec0b2d180ac68a2c5efed3b",
+ "https://deno.land/std@0.216.0/assert/unimplemented.ts": "47ca67d1c6dc53abd0bd729b71a31e0825fc452dbcd4fde4ca06789d5644e7fd",
+ "https://deno.land/std@0.216.0/assert/unreachable.ts": "38cfecb95d8b06906022d2f9474794fca4161a994f83354fd079cac9032b5145",
+ "https://deno.land/std@0.216.0/async/delay.ts": "8e1d18fe8b28ff95885e2bc54eccec1713f57f756053576d8228e6ca110793ad",
+ "https://deno.land/std@0.216.0/datetime/constants.ts": "5c198b3b47fbcc4d913e61dcae1c37e053937affc2c9a6a5ad7e5473bab3e4a6",
+ "https://deno.land/std@0.216.0/encoding/_util.ts": "beacef316c1255da9bc8e95afb1fa56ed69baef919c88dc06ae6cb7a6103d376",
+ "https://deno.land/std@0.216.0/encoding/hex.ts": "4d47d3b25103cf81a2ed38f54b394d39a77b63338e1eaa04b70c614cb45ec2e6",
+ "https://deno.land/std@0.216.0/flags/mod.ts": "9f13f3a49c54618277ac49195af934f1c7d235731bcf80fd33b8b234e6839ce9",
+ "https://deno.land/std@0.216.0/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a",
+ "https://deno.land/std@0.216.0/fs/_create_walk_entry.ts": "5d9d2aaec05bcf09a06748b1684224d33eba7a4de24cf4cf5599991ca6b5b412",
+ "https://deno.land/std@0.216.0/fs/_get_file_info_type.ts": "da7bec18a7661dba360a1db475b826b18977582ce6fc9b25f3d4ee0403fe8cbd",
+ "https://deno.land/std@0.216.0/fs/_is_same_path.ts": "709c95868345fea051c58b9e96af95cff94e6ae98dfcff2b66dee0c212c4221f",
+ "https://deno.land/std@0.216.0/fs/_is_subdir.ts": "c68b309d46cc8568ed83c000f608a61bbdba0943b7524e7a30f9e450cf67eecd",
+ "https://deno.land/std@0.216.0/fs/_to_path_string.ts": "29bfc9c6c112254961d75cbf6ba814d6de5349767818eb93090cecfa9665591e",
+ "https://deno.land/std@0.216.0/fs/copy.ts": "dc0f68c4b6c3b090bfdb909387e309f6169b746bd713927c9507c9ef545d71f6",
+ "https://deno.land/std@0.216.0/fs/empty_dir.ts": "4f01e6d56e2aa8d90ad60f20bc25601f516b00f6c3044cdf6863a058791d91aa",
+ "https://deno.land/std@0.216.0/fs/ensure_dir.ts": "dffff68de0d10799b5aa9e39dec4e327e12bbd29e762292193684542648c4aeb",
+ "https://deno.land/std@0.216.0/fs/ensure_file.ts": "ac5cfde94786b0284d2c8e9f7f9425269bea1b2140612b4aea1f20b508870f59",
+ "https://deno.land/std@0.216.0/fs/ensure_link.ts": "d42af2edefeaa9817873ec6e46dc5d209ac4d744f8c69c5ecc2dffade78465b6",
+ "https://deno.land/std@0.216.0/fs/ensure_symlink.ts": "aee3f1655700f60090b4a3037f5b6c07ab37c36807cccad746ce89987719e6d2",
+ "https://deno.land/std@0.216.0/fs/eol.ts": "c9807291f78361d49fd986a9be04654610c615c5e2ec63d748976197d30ff206",
+ "https://deno.land/std@0.216.0/fs/exists.ts": "d2757ef764eaf5c6c5af7228e8447db2de42ab084a2dae540097f905723d83f5",
+ "https://deno.land/std@0.216.0/fs/expand_glob.ts": "a1ce02b05ed7b96985b0665067c9f1018f3f2ade7ee0fb0d629231050260b158",
+ "https://deno.land/std@0.216.0/fs/mod.ts": "107f5afa4424c2d3ce2f7e9266173198da30302c69af662c720115fe504dc5ee",
+ "https://deno.land/std@0.216.0/fs/move.ts": "39e0d7ccb88a566d20b949712020e766b15ef1ec19159573d11f949bd677909c",
+ "https://deno.land/std@0.216.0/fs/walk.ts": "78e1d01a9f75715614bf8d6e58bd77d9fafb1222c41194e607cd3849d7a0e771",
+ "https://deno.land/std@0.216.0/http/server.ts": "6dce295abc169d0956ae00432441331b3425afad4d79e8b3475739be2f04d614",
+ "https://deno.land/std@0.216.0/http/status.ts": "ed61b4882af2514a81aefd3245e8df4c47b9a8e54929a903577643d2d1ebf514",
+ "https://deno.land/std@0.216.0/json/common.ts": "33f1a4f39a45e2f9f357823fd0b5cf88b63fb4784b8c9a28f8120f70a20b23e9",
+ "https://deno.land/std@0.216.0/jsonc/mod.ts": "82722888823e1af5a8f7918bf810ea581f68081064d529218533acad6cb7c2bc",
+ "https://deno.land/std@0.216.0/jsonc/parse.ts": "747a0753289fdbfcb9cb86b709b56348c98abc107fbb0a7f350b87af4425a76a",
+ "https://deno.land/std@0.216.0/media_types/_db.ts": "1d695d9fe1c785e523d6de7191b33f33ecc7866db77358a4f966221cca56e2f9",
+ "https://deno.land/std@0.216.0/media_types/_util.ts": "afd54920a8a81add64248897898d3f30ca414a8803fe0c4e6d2893a3f6bd32b0",
+ "https://deno.land/std@0.216.0/media_types/content_type.ts": "ed3f2e1f243b418ad3f441edc95fd92efbadb0f9bde36219c7564c67f9639513",
+ "https://deno.land/std@0.216.0/media_types/format_media_type.ts": "ffef4718afa2489530cb94021bb865a466eb02037609f7e82899c017959d288a",
+ "https://deno.land/std@0.216.0/media_types/get_charset.ts": "bce5c0343c14590516cbfa1a3e80891d9a7a53bc9b4a9010061cc4f879e18f6c",
+ "https://deno.land/std@0.216.0/media_types/parse_media_type.ts": "487f000a38c230ccbac25420a50f600862e06796d0eee19d19631b9e84ee9654",
+ "https://deno.land/std@0.216.0/media_types/type_by_extension.ts": "bf4e3f5d6b58b624d5daa01cbb8b1e86d9939940a77e7c26e796a075b60ec73b",
+ "https://deno.land/std@0.216.0/media_types/vendor/mime-db.v1.52.0.ts": "0218d2c7d900e8cd6fa4a866e0c387712af4af9a1bae55d6b2546c73d273a1e6",
+ "https://deno.land/std@0.216.0/path/_common/assert_path.ts": "2ca275f36ac1788b2acb60fb2b79cb06027198bc2ba6fb7e163efaedde98c297",
+ "https://deno.land/std@0.216.0/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2",
+ "https://deno.land/std@0.216.0/path/_common/common.ts": "6157c7ec1f4db2b4a9a187efd6ce76dcaf1e61cfd49f87e40d4ea102818df031",
+ "https://deno.land/std@0.216.0/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c",
+ "https://deno.land/std@0.216.0/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8",
+ "https://deno.land/std@0.216.0/path/_common/format.ts": "92500e91ea5de21c97f5fe91e178bae62af524b72d5fcd246d6d60ae4bcada8b",
+ "https://deno.land/std@0.216.0/path/_common/from_file_url.ts": "d672bdeebc11bf80e99bf266f886c70963107bdd31134c4e249eef51133ceccf",
+ "https://deno.land/std@0.216.0/path/_common/glob_to_reg_exp.ts": "2007aa87bed6eb2c8ae8381adcc3125027543d9ec347713c1ad2c68427330770",
+ "https://deno.land/std@0.216.0/path/_common/normalize.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8",
+ "https://deno.land/std@0.216.0/path/_common/normalize_string.ts": "dfdf657a1b1a7db7999f7c575ee7e6b0551d9c20f19486c6c3f5ff428384c965",
+ "https://deno.land/std@0.216.0/path/_common/relative.ts": "faa2753d9b32320ed4ada0733261e3357c186e5705678d9dd08b97527deae607",
+ "https://deno.land/std@0.216.0/path/_common/strip_trailing_separators.ts": "7024a93447efcdcfeaa9339a98fa63ef9d53de363f1fbe9858970f1bba02655a",
+ "https://deno.land/std@0.216.0/path/_common/to_file_url.ts": "7f76adbc83ece1bba173e6e98a27c647712cab773d3f8cbe0398b74afc817883",
+ "https://deno.land/std@0.216.0/path/_interface.ts": "a1419fcf45c0ceb8acdccc94394e3e94f99e18cfd32d509aab514c8841799600",
+ "https://deno.land/std@0.216.0/path/_os.ts": "8fb9b90fb6b753bd8c77cfd8a33c2ff6c5f5bc185f50de8ca4ac6a05710b2c15",
+ "https://deno.land/std@0.216.0/path/basename.ts": "5d341aadb7ada266e2280561692c165771d071c98746fcb66da928870cd47668",
+ "https://deno.land/std@0.216.0/path/common.ts": "03e52e22882402c986fe97ca3b5bb4263c2aa811c515ce84584b23bac4cc2643",
+ "https://deno.land/std@0.216.0/path/constants.ts": "0c206169ca104938ede9da48ac952de288f23343304a1c3cb6ec7625e7325f36",
+ "https://deno.land/std@0.216.0/path/dirname.ts": "85bd955bf31d62c9aafdd7ff561c4b5fb587d11a9a5a45e2b01aedffa4238a7c",
+ "https://deno.land/std@0.216.0/path/extname.ts": "593303db8ae8c865cbd9ceec6e55d4b9ac5410c1e276bfd3131916591b954441",
+ "https://deno.land/std@0.216.0/path/format.ts": "98fad25f1af7b96a48efb5b67378fcc8ed77be895df8b9c733b86411632162af",
+ "https://deno.land/std@0.216.0/path/from_file_url.ts": "911833ae4fd10a1c84f6271f36151ab785955849117dc48c6e43b929504ee069",
+ "https://deno.land/std@0.216.0/path/glob_to_regexp.ts": "5e51f78a0248c75464bf1d49173de3ec2c032880a530578e56b3fed2a57e69d3",
+ "https://deno.land/std@0.216.0/path/is_absolute.ts": "4791afc8bfd0c87f0526eaa616b0d16e7b3ab6a65b62942e50eac68de4ef67d7",
+ "https://deno.land/std@0.216.0/path/is_glob.ts": "a65f6195d3058c3050ab905705891b412ff942a292bcbaa1a807a74439a14141",
+ "https://deno.land/std@0.216.0/path/join.ts": "ae2ec5ca44c7e84a235fd532e4a0116bfb1f2368b394db1c4fb75e3c0f26a33a",
+ "https://deno.land/std@0.216.0/path/join_globs.ts": "5b3bf248b93247194f94fa6947b612ab9d3abd571ca8386cf7789038545e54a0",
+ "https://deno.land/std@0.216.0/path/mod.ts": "6f856db94f6a72fc2cf69e0a85eb523aee6a3cd274470717e96f4bee0c9fe329",
+ "https://deno.land/std@0.216.0/path/normalize.ts": "4155743ccceeed319b350c1e62e931600272fad8ad00c417b91df093867a8352",
+ "https://deno.land/std@0.216.0/path/normalize_glob.ts": "cc89a77a7d3b1d01053b9dcd59462b75482b11e9068ae6c754b5cf5d794b374f",
+ "https://deno.land/std@0.216.0/path/parse.ts": "65e8e285f1a63b714e19ef24b68f56e76934c3df0b6e65fd440d3991f4f8aefb",
+ "https://deno.land/std@0.216.0/path/posix/_util.ts": "1e3937da30f080bfc99fe45d7ed23c47dd8585c5e473b2d771380d3a6937cf9d",
+ "https://deno.land/std@0.216.0/path/posix/basename.ts": "39ee27a29f1f35935d3603ccf01d53f3d6e0c5d4d0f84421e65bd1afeff42843",
+ "https://deno.land/std@0.216.0/path/posix/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4",
+ "https://deno.land/std@0.216.0/path/posix/constants.ts": "93481efb98cdffa4c719c22a0182b994e5a6aed3047e1962f6c2c75b7592bef1",
+ "https://deno.land/std@0.216.0/path/posix/dirname.ts": "6535d2bdd566118963537b9dda8867ba9e2a361015540dc91f5afbb65c0cce8b",
+ "https://deno.land/std@0.216.0/path/posix/extname.ts": "8d36ae0082063c5e1191639699e6f77d3acf501600a3d87b74943f0ae5327427",
+ "https://deno.land/std@0.216.0/path/posix/format.ts": "185e9ee2091a42dd39e2a3b8e4925370ee8407572cee1ae52838aed96310c5c1",
+ "https://deno.land/std@0.216.0/path/posix/from_file_url.ts": "951aee3a2c46fd0ed488899d024c6352b59154c70552e90885ed0c2ab699bc40",
+ "https://deno.land/std@0.216.0/path/posix/glob_to_regexp.ts": "54d3ff40f309e3732ab6e5b19d7111d2d415248bcd35b67a99defcbc1972e697",
+ "https://deno.land/std@0.216.0/path/posix/is_absolute.ts": "cebe561ad0ae294f0ce0365a1879dcfca8abd872821519b4fcc8d8967f888ede",
+ "https://deno.land/std@0.216.0/path/posix/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9",
+ "https://deno.land/std@0.216.0/path/posix/join.ts": "aef88d5fa3650f7516730865dbb951594d1a955b785e2450dbee93b8e32694f3",
+ "https://deno.land/std@0.216.0/path/posix/join_globs.ts": "f6e2619c196b82d8fd67ba2cf680e5b44461f38bdfeec26d7b3f55bd92a85988",
+ "https://deno.land/std@0.216.0/path/posix/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604",
+ "https://deno.land/std@0.216.0/path/posix/normalize.ts": "baeb49816a8299f90a0237d214cef46f00ba3e95c0d2ceb74205a6a584b58a91",
+ "https://deno.land/std@0.216.0/path/posix/normalize_glob.ts": "41b477068deb832df7f51d6e2b3c0bc274d20919e20c5240d785ba535572d3d0",
+ "https://deno.land/std@0.216.0/path/posix/parse.ts": "d5bac4eb21262ab168eead7e2196cb862940c84cee572eafedd12a0d34adc8fb",
+ "https://deno.land/std@0.216.0/path/posix/relative.ts": "3907d6eda41f0ff723d336125a1ad4349112cd4d48f693859980314d5b9da31c",
+ "https://deno.land/std@0.216.0/path/posix/resolve.ts": "bac20d9921beebbbb2b73706683b518b1d0c1b1da514140cee409e90d6b2913a",
+ "https://deno.land/std@0.216.0/path/posix/to_file_url.ts": "7aa752ba66a35049e0e4a4be5a0a31ac6b645257d2e031142abb1854de250aaf",
+ "https://deno.land/std@0.216.0/path/posix/to_namespaced_path.ts": "28b216b3c76f892a4dca9734ff1cc0045d135532bfd9c435ae4858bfa5a2ebf0",
+ "https://deno.land/std@0.216.0/path/relative.ts": "ab739d727180ed8727e34ed71d976912461d98e2b76de3d3de834c1066667add",
+ "https://deno.land/std@0.216.0/path/resolve.ts": "a6f977bdb4272e79d8d0ed4333e3d71367cc3926acf15ac271f1d059c8494d8d",
+ "https://deno.land/std@0.216.0/path/to_file_url.ts": "88f049b769bce411e2d2db5bd9e6fd9a185a5fbd6b9f5ad8f52bef517c4ece1b",
+ "https://deno.land/std@0.216.0/path/to_namespaced_path.ts": "b706a4103b104cfadc09600a5f838c2ba94dbcdb642344557122dda444526e40",
+ "https://deno.land/std@0.216.0/path/windows/_util.ts": "d5f47363e5293fced22c984550d5e70e98e266cc3f31769e1710511803d04808",
+ "https://deno.land/std@0.216.0/path/windows/basename.ts": "e2dbf31d1d6385bfab1ce38c333aa290b6d7ae9e0ecb8234a654e583cf22f8fe",
+ "https://deno.land/std@0.216.0/path/windows/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4",
+ "https://deno.land/std@0.216.0/path/windows/constants.ts": "5afaac0a1f67b68b0a380a4ef391bf59feb55856aa8c60dfc01bd3b6abb813f5",
+ "https://deno.land/std@0.216.0/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9",
+ "https://deno.land/std@0.216.0/path/windows/extname.ts": "165a61b00d781257fda1e9606a48c78b06815385e7d703232548dbfc95346bef",
+ "https://deno.land/std@0.216.0/path/windows/format.ts": "bbb5ecf379305b472b1082cd2fdc010e44a0020030414974d6029be9ad52aeb6",
+ "https://deno.land/std@0.216.0/path/windows/from_file_url.ts": "ced2d587b6dff18f963f269d745c4a599cf82b0c4007356bd957cb4cb52efc01",
+ "https://deno.land/std@0.216.0/path/windows/glob_to_regexp.ts": "6dcd1242bd8907aa9660cbdd7c93446e6927b201112b0cba37ca5d80f81be51b",
+ "https://deno.land/std@0.216.0/path/windows/is_absolute.ts": "4a8f6853f8598cf91a835f41abed42112cebab09478b072e4beb00ec81f8ca8a",
+ "https://deno.land/std@0.216.0/path/windows/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9",
+ "https://deno.land/std@0.216.0/path/windows/join.ts": "e0b3356615c1a75c56ebb6a7311157911659e11fd533d80d724800126b761ac3",
+ "https://deno.land/std@0.216.0/path/windows/join_globs.ts": "f6e2619c196b82d8fd67ba2cf680e5b44461f38bdfeec26d7b3f55bd92a85988",
+ "https://deno.land/std@0.216.0/path/windows/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604",
+ "https://deno.land/std@0.216.0/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780",
+ "https://deno.land/std@0.216.0/path/windows/normalize_glob.ts": "c57c186b0785ba5320a85e573c264f42c46eb1d0a4a78611f4791a7083baaa17",
+ "https://deno.land/std@0.216.0/path/windows/parse.ts": "b9239edd892a06a06625c1b58425e199f018ce5649ace024d144495c984da734",
+ "https://deno.land/std@0.216.0/path/windows/relative.ts": "3e1abc7977ee6cc0db2730d1f9cb38be87b0ce4806759d271a70e4997fc638d7",
+ "https://deno.land/std@0.216.0/path/windows/resolve.ts": "75b2e3e1238d840782cee3d8864d82bfaa593c7af8b22f19c6422cf82f330ab3",
+ "https://deno.land/std@0.216.0/path/windows/to_file_url.ts": "1cd63fd35ec8d1370feaa4752eccc4cc05ea5362a878be8dc7db733650995484",
+ "https://deno.land/std@0.216.0/path/windows/to_namespaced_path.ts": "4ffa4fb6fae321448d5fe810b3ca741d84df4d7897e61ee29be961a6aac89a4c",
+ "https://deno.land/std@0.216.0/regexp/escape.ts": "57303d6c9c6aa058d9a79a3c70113c545391639a87e9a18428220c1bad407549",
+ "https://deno.land/std@0.216.0/semver/_comparator_format.ts": "b5a56b999670c0b3a3e8ad437ca0fafbfce0e973bba6769979d7665e318e8b6c",
+ "https://deno.land/std@0.216.0/semver/_comparator_intersects.ts": "65b744d76b3be4ed91afd149754f530681032890d32fd65d02faf8ef96491cb7",
+ "https://deno.land/std@0.216.0/semver/_comparator_max.ts": "c3a97d5b43b9104afa3687780500ef79b69ae5107cee2359004f80ea48969c7d",
+ "https://deno.land/std@0.216.0/semver/_comparator_min.ts": "080a9939b177d64904e1772da02dc4673f9cd1b3c9ae1a5c534cfdf4bb3ee9af",
+ "https://deno.land/std@0.216.0/semver/_constants.ts": "90879e4ea94a34c49c8ecea3d9c06e13e61ecb7caca80c8f289139440ca9835a",
+ "https://deno.land/std@0.216.0/semver/_is_comparator.ts": "d032762a6993b7cd3e4243cbeded0eeab70773dff960d4e92af8770550eea7b6",
+ "https://deno.land/std@0.216.0/semver/_parse_comparator.ts": "2dfa7f08da84038f8e2c50d629a329b2870a096791fd1f299a00de3bb547c34a",
+ "https://deno.land/std@0.216.0/semver/_shared.ts": "8d44684775cde4a64bd6bdb99b51f3bc59ed65f10af78ca136cc2eab3f6716f1",
+ "https://deno.land/std@0.216.0/semver/can_parse.ts": "d4a26f74be078f3ab10293b07bf022021a2f362b3e21b58422c214e7268110b2",
+ "https://deno.land/std@0.216.0/semver/compare.ts": "e8871844a35cc8fe16e883c16e5237e06a93aa4830ae10d06501abe63586fc57",
+ "https://deno.land/std@0.216.0/semver/constants.ts": "04c8625428552e967c85c59e80766441418839f7a94c50c652c6a9d83b0f3ef1",
+ "https://deno.land/std@0.216.0/semver/difference.ts": "be4f01b7745406408a16b708185a48c1c652cc87e0244b12a5ca75c5585db668",
+ "https://deno.land/std@0.216.0/semver/equals.ts": "8b9b18260c9a55feee9d3f9250fba345be922380f2e8f8009e455c394ce5e81d",
+ "https://deno.land/std@0.216.0/semver/format.ts": "26d3a357ac5abd73dee0fe7dbbac6107fbdce0a844370c7b1bcb673c92e46bf6",
+ "https://deno.land/std@0.216.0/semver/format_range.ts": "ee96cc1f3002cfb62b821477f1a90374e6c021ec13045c34a0620021b1d862af",
+ "https://deno.land/std@0.216.0/semver/greater_or_equal.ts": "89c26f68070896944676eb9704cbb617febc6ed693720282741d6859c3d1fe80",
+ "https://deno.land/std@0.216.0/semver/greater_than.ts": "d8c4a227cd28ea80a1de9c80215d7f3f95786fe1b196f0cb5ec91d6567adad27",
+ "https://deno.land/std@0.216.0/semver/gtr.ts": "1101ecf6f427de9ba6348860f312c15b55f9301f97d2e34bd9e57957184574e9",
+ "https://deno.land/std@0.216.0/semver/increment.ts": "427a043be71d6481e45c1a3939b955e800924d70779cb297b872d9cbf9f0e46d",
+ "https://deno.land/std@0.216.0/semver/is_range.ts": "4cea4096436ea02555d38cc758effd978ca77d8ae63d8db15f2910b1ff04aec2",
+ "https://deno.land/std@0.216.0/semver/is_semver.ts": "57914027d6141e593eb04418aaabbfd6f4562a1c53c6c33a1743fa50ada8d849",
+ "https://deno.land/std@0.216.0/semver/less_or_equal.ts": "7dbf8190f37f3281048c30cf11e072a7af18685534ae88d295baa170b485bd90",
+ "https://deno.land/std@0.216.0/semver/less_than.ts": "b0c7902c54cecadcc7c1c80afc2f6a0f1bf0b3f53c8d2bfd11f01a3a414cccfe",
+ "https://deno.land/std@0.216.0/semver/ltr.ts": "4c147830444c9020eccc17cd8d4d9aced5b0f6cfb3c8b99fb9cdcca8fe90356f",
+ "https://deno.land/std@0.216.0/semver/max_satisfying.ts": "03e5182a7424c308ddbb410e4b927da0dabc4e07d4b5a72f7e9b26fb18a02152",
+ "https://deno.land/std@0.216.0/semver/min_satisfying.ts": "b6fadc9af17278289481c416e1eb135614f88063f4fc2b7b72b43eb3baa2f08f",
+ "https://deno.land/std@0.216.0/semver/mod.ts": "6fcb9531909763993c70e1278b898cc9dd1373d6f4cbcdc41be4fc629e9e2052",
+ "https://deno.land/std@0.216.0/semver/not_equals.ts": "17147a6f68b9d14f4643c1e2150378ccf6954710309f9618f75b411752a8e13d",
+ "https://deno.land/std@0.216.0/semver/parse.ts": "2ba215c9aa3c71be753570724cfad75cc81972f0026dc81836ea3d1986112066",
+ "https://deno.land/std@0.216.0/semver/parse_range.ts": "7ce841031e14af27c9abcc10878efe60135de59c935e311d671a91ffc48bbc46",
+ "https://deno.land/std@0.216.0/semver/range_intersects.ts": "28de545143652cffa447e859ad087d75e74c009762df0ebc2f03cca2eed9831d",
+ "https://deno.land/std@0.216.0/semver/range_max.ts": "b994695e885045518e1655a2c519d726003c7381b3e64be2090663378a6bfe20",
+ "https://deno.land/std@0.216.0/semver/range_min.ts": "269ace0521e055fe10ef8c3d342ddf2cf3eb9c53a8efb2eecac198085cc789c3",
+ "https://deno.land/std@0.216.0/semver/reverse_sort.ts": "98316b5c960cb0608df949d563328c7696d6b4f76ccea22a08974d27c1969893",
+ "https://deno.land/std@0.216.0/semver/test_range.ts": "6262307357a8b413dc34546c8401392ed2bc7a5e4ddd999195a56a0fe4fc1d4a",
+ "https://deno.land/std@0.216.0/semver/try_parse.ts": "a2639ec588c374331d5f655bfbdf8d5a2f2cc704c8b56ac94cd077944de150c7",
+ "https://deno.land/std@0.216.0/semver/try_parse_range.ts": "239e0d711c5745da8c4dcda3c0797b4b5a83bfe494a51d3a0f005472cdc7b016",
+ "https://deno.land/std@0.216.0/semver/types.ts": "8ed52c8cfc59e249a0dbab597d8c31bcf10405dcbe9714585055ea02252ae0d0",
+ "https://deno.land/std@0.216.0/testing/snapshot.ts": "35ca1c8e8bfb98d7b7e794f1b7be8d992483fcff572540e41396f22a5bddb944",
+ "https://deno.land/std@0.224.0/dotenv/load.ts": "587b342f0f6a3df071331fe6ba1c823729ab68f7d53805809475e486dd4161d7",
+ "https://deno.land/std@0.224.0/dotenv/mod.ts": "0180eaeedaaf88647318811cdaa418cc64dc51fb08354f91f5f480d0a1309f7d",
+ "https://deno.land/std@0.224.0/dotenv/parse.ts": "09977ff88dfd1f24f9973a338f0f91bbdb9307eb5ff6085446e7c423e4c7ba0c",
+ "https://deno.land/std@0.224.0/dotenv/stringify.ts": "275da322c409170160440836342eaa7cf012a1d11a7e700d8ca4e7f2f8aa4615",
+ "https://deno.land/x/code_block_writer@12.0.0/mod.ts": "2c3448060e47c9d08604c8f40dee34343f553f33edcdfebbf648442be33205e5",
+ "https://deno.land/x/code_block_writer@12.0.0/utils/string_utils.ts": "60cb4ec8bd335bf241ef785ccec51e809d576ff8e8d29da43d2273b69ce2a6ff",
+ "https://deno.land/x/denoflate@1.2.1/mod.ts": "f5628e44b80b3d80ed525afa2ba0f12408e3849db817d47a883b801f9ce69dd6",
+ "https://deno.land/x/denoflate@1.2.1/pkg/denoflate.js": "b9f9ad9457d3f12f28b1fb35c555f57443427f74decb403113d67364e4f2caf4",
+ "https://deno.land/x/denoflate@1.2.1/pkg/denoflate_bg.wasm.js": "d581956245407a2115a3d7e8d85a9641c032940a8e810acbd59ca86afd34d44d",
+ "https://deno.land/x/esbuild@v0.20.2/mod.js": "67c608ee283233f5d0faa322b887356857c547a8e6a00981f798b2cd38e02436",
+ "https://deno.land/x/esbuild@v0.20.2/wasm.js": "5a887c1e38ad1056af11c58d45b6084d33bd33a62afa480d805801739370eed0",
+ "https://deno.land/x/fresh@1.6.8/dev.ts": "720dd3a64b62b852db7b6ae471c246c5c605cf4a3091c4cbc802790f36d43e4c",
+ "https://deno.land/x/fresh@1.6.8/server.ts": "d5817615a3ac822d422627f2cd6f850a31e11f7e73b328a79807f722e6519bac",
+ "https://deno.land/x/fresh@1.6.8/src/build/aot_snapshot.ts": "4ac6330e5325dd9411fa2a46e97bb289f910fde4be82dc349d3e2b4bb1a7c07d",
+ "https://deno.land/x/fresh@1.6.8/src/build/deps.ts": "5a0d934a2e66d61e675d3c48e7db83b3d9d01cd4e13eca05ca8145acf26ea991",
+ "https://deno.land/x/fresh@1.6.8/src/build/esbuild.ts": "fdad9cc58f0ead0f954faad4a3c6b07da312acbe3306da742ba083ddb666d4b3",
+ "https://deno.land/x/fresh@1.6.8/src/build/mod.ts": "b9d1695a86746ac3a1c52f0e07e723faa2310d1dfd109b9a2eebab6727c4702b",
+ "https://deno.land/x/fresh@1.6.8/src/constants.ts": "4795d194b6c6b95f0e876c0a997fbaf57f94cfe253442c5819f95410870b79b3",
+ "https://deno.land/x/fresh@1.6.8/src/dev/build.ts": "9aaf84a781ee4d11d73ec549425f273fe8339812fdd8f726e1ec1ba61bdf0e9d",
+ "https://deno.land/x/fresh@1.6.8/src/dev/deps.ts": "93af624becfb2d8497e3d7ef0cf5ef48df61495dc5951b5f922c6a129a9fb75c",
+ "https://deno.land/x/fresh@1.6.8/src/dev/dev_command.ts": "3e3dcc80180faf8868d44d892ddfa8c5ad06033e4d94c0934302e157db1de63d",
+ "https://deno.land/x/fresh@1.6.8/src/dev/error.ts": "21a38d240c00279662e6adde41367f1da0ae7e2836d993f818ea94aabab53e7b",
+ "https://deno.land/x/fresh@1.6.8/src/dev/manifest.ts": "156fb0ce3f77b9fdac18f8798eee36283c2fb440795c6024b6b6ab938e91f9cb",
+ "https://deno.land/x/fresh@1.6.8/src/dev/mod.ts": "d44f3063d157bce53ba534d37b7ff8f262c379ab75229bc63d06c47c67b6b7e6",
+ "https://deno.land/x/fresh@1.6.8/src/dev/update_check.ts": "0b8e4659b49e3a951c684b7faf66be7428948c3e7d492d37397f9a485874515a",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/Partial.tsx": "92e16fa7edf37dc8e254024a5410ea2c8986804a6ddf911af4d30209dff80a22",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/active_url.ts": "c718797b11189c7e2c86569355d55056148907121e958e00f71c56593aecc329",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/build_id.ts": "8376e70e42ce456dfa6932c638409d2ef1bca4833b4ceba0bf74510080a7f976",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/csp.ts": "9ee900e9b0b786057b1009da5976298c202d1b86d1f1e4d2510bde5f06530ac9",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/deserializer.ts": "1b83e75fa61c48b074ea121f33647d1ed15c68fa2f2a11b0a7f7a12cd38af627",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/entrypoints/client.ts": "a9224606e41bc58d81f37b7125650432920a7d136bdf416051e925ac9bbd1f05",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/entrypoints/deserializer.ts": "e836f44c454e1f67c86eab30f108eb9be05a38489604a24e418b564b77058b96",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/entrypoints/main.ts": "de3aa5cbd9b3abfa825939b58bc8df088ab183e042c0447b37180f4ea31c613c",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/entrypoints/main_dev.ts": "d2960e339119e45017954c7cf6798b9e0a3110d173cc378e1e3e7bc84bd68c34",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/entrypoints/signals.ts": "782c81f97d125ad4f92aa0160dad3a2e8b6ea7a61cec7fdab87bbbbd8c0d215c",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/head.ts": "0f9932874497ab6e57ed1ba01d549e843523df4a5d36ef97460e7a43e3132fdc",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/polyfills.ts": "c3de932b2f23df9a4ade1ab4f8890730c0db0a71bf85faa41742a1763631e917",
+ "https://deno.land/x/fresh@1.6.8/src/runtime/utils.ts": "4f40630c308e8ea7d53860687905caf1a2f2a46ad8692f24e905a8e996b584c3",
+ "https://deno.land/x/fresh@1.6.8/src/server/boot.ts": "969da650e882adba6559af3784b90473d357201345d4e5b24a0cf5e582882d6b",
+ "https://deno.land/x/fresh@1.6.8/src/server/build_id.ts": "82d9cb985de6b1e38c3108e5a00667b16e80eedc145d73835d6b44349ebe6389",
+ "https://deno.land/x/fresh@1.6.8/src/server/code_frame.ts": "fac505f138fbd1bb260030122b87aeb2f5b5e54018e3066e105c669c686cc373",
+ "https://deno.land/x/fresh@1.6.8/src/server/compose.ts": "490aa1a7d540cc02bd4a184bea03eb2370aa34d93fe5a6ae1f31e2086eef4e76",
+ "https://deno.land/x/fresh@1.6.8/src/server/config.ts": "a5d0545d18c68d01770a4eb321d2fc85081ad7992ae63b1497f0b92ee122410a",
+ "https://deno.land/x/fresh@1.6.8/src/server/constants.ts": "e75a7f7b14185b6f85747613591348313200fe8e218cb473b1da9db941ee68d1",
+ "https://deno.land/x/fresh@1.6.8/src/server/context.ts": "fbfcb0e0c6377ea0a6b11063705c07daedb75bcf2845b31c3794345c40aeb1b4",
+ "https://deno.land/x/fresh@1.6.8/src/server/default_error_page.tsx": "094ad8d52d31f99172a606d0a0d8236604a1f9bb6d1f928d0d466d55b36dae70",
+ "https://deno.land/x/fresh@1.6.8/src/server/defines.ts": "f518ff10e499d4543bb9231f55026f26be2507eaccb072aafab93c8cc0bc3adc",
+ "https://deno.land/x/fresh@1.6.8/src/server/deps.ts": "efa2ddf6a21457839e42b6a69eca0c12a22a0bf3a6dd140b58abfe54e66328e8",
+ "https://deno.land/x/fresh@1.6.8/src/server/error_overlay.tsx": "e6ab4cef0ea812a1e1f32ee9116c61f64db8466d46e228acbb953215f4517d9c",
+ "https://deno.land/x/fresh@1.6.8/src/server/fs_extract.ts": "4dda675f03f0397310e4e6d4a57f3bf907db8a61a1a65423e67855daf5b9b36e",
+ "https://deno.land/x/fresh@1.6.8/src/server/htmlescape.ts": "834ac7d0caa9fc38dffd9b8613fb47aeecd4f22d5d70c51d4b20a310c085835c",
+ "https://deno.land/x/fresh@1.6.8/src/server/init_safe_deps.ts": "8c74d8708986d156126355b0935a1915069bfdc389ccabd3d2d72d1c9e04025c",
+ "https://deno.land/x/fresh@1.6.8/src/server/mod.ts": "6cee56e234f6bc19f62f3b6c0d287dc7b9632fcbfb8f56dde1d81423532d65c4",
+ "https://deno.land/x/fresh@1.6.8/src/server/render.ts": "b89387eb20c91969ace2de27b6c462f4e42c040d37b68440fe374e5cea9ea794",
+ "https://deno.land/x/fresh@1.6.8/src/server/rendering/fresh_tags.tsx": "5f1238e465d9ad94aebdf5e3701f2b9da3c944d8c5cc4dc8005ff1418b164989",
+ "https://deno.land/x/fresh@1.6.8/src/server/rendering/preact_hooks.ts": "db1a1ad7e4fbdac19b0758789ba7700531c214d531e1d03264b81a73beab05b5",
+ "https://deno.land/x/fresh@1.6.8/src/server/rendering/state.ts": "5e0c3a60964596cc28c1804545eae323cbc92eec9ce8cb0932d5168a6d1f33e9",
+ "https://deno.land/x/fresh@1.6.8/src/server/rendering/template.tsx": "bd1bc8edb054caac22043117f254927e8413e04cd1897009a2214ab374a1be19",
+ "https://deno.land/x/fresh@1.6.8/src/server/router.ts": "257a293776ee682937b8abb6d803971a6863a2f161b1e079b57c013589d0ed0b",
+ "https://deno.land/x/fresh@1.6.8/src/server/serializer.ts": "f0cffb863bbdbac6ed53fefe181e415d6aefc2101f2dc92a562b364088809e44",
+ "https://deno.land/x/fresh@1.6.8/src/server/tailwind_aot_error_page.tsx": "7265b66dc76a2e54b40774bbeb3cc7d4deb2eac537e08712e90e9c7b9399e53a",
+ "https://deno.land/x/fresh@1.6.8/src/server/types.ts": "f5911c9eef864df8ef58fe5bd353ebd22267b35ef2ef8b21def825fd274d05a6",
+ "https://deno.land/x/fresh@1.6.8/src/types.ts": "05169e3389979d8283de0ec1db3a765324ffd730b6af29ffe02752f341ae7d35",
+ "https://deno.land/x/fresh@1.6.8/versions.json": "c6cc2d0d2bff47425e59f953b8a237a6523dcf8e10f02e7ad92d50f2c5f2552c",
+ "https://deno.land/x/ts_morph@21.0.1/common/DenoRuntime.ts": "a505f1feae9a77c8f6ab1c18c55d694719e96573f68e9c36463b243e1bef4c3e",
+ "https://deno.land/x/ts_morph@21.0.1/common/mod.ts": "01985d2ee7da8d1caee318a9d07664774fbee4e31602bc2bb6bb62c3489555ed",
+ "https://deno.land/x/ts_morph@21.0.1/common/ts_morph_common.js": "236475fb18476307e07b3a97dc92fe8fb69e4a9df4ca59aa098dd6430bae7237",
+ "https://deno.land/x/ts_morph@21.0.1/common/typescript.js": "d72ba73c3eb625ff755075dbde78df2a844d22190ef1ad74d0c5dcd7005ba85e",
+ "https://deno.land/x/ts_morph@21.0.1/mod.ts": "adba9b82f24865d15d2c78ef6074b9a7457011719056c9928c800f130a617c93",
+ "https://deno.land/x/ts_morph@21.0.1/ts_morph.js": "fddb96abdf0cb0ac427d52757c4ffa6ff7fe9a772846d9bf6167518b7b276cad",
+ "https://esm.sh/*@preact/signals-core@1.5.1": "375c3958358064bf74df7e273d76755be9330994cddc687413aacc4e7f9177b3",
+ "https://esm.sh/*@preact/signals-core@1.5.1/denonext/signals-core.mjs": "aef7e41046f10bfd789833d60bb18b07a75530d3f1f9e56de63e87fd4e88f07b",
+ "https://esm.sh/*@preact/signals@1.2.2": "325a059801c4a39c5bb1ff7441f81a7f894f5d1e63e03fa7da6f5125a8507098",
+ "https://esm.sh/*@preact/signals@1.2.2/denonext/signals.mjs": "577dda8004eaf5d783e9cd90d40694f733964630873bb00370b600b4247d0dd3",
+ "https://esm.sh/*preact-render-to-string@6.3.1": "37f046906d7cc1ce35828a029a05a4eed6c8eefc4b646a301939757dfbf8ab18",
+ "https://esm.sh/*preact-render-to-string@6.3.1/denonext/preact-render-to-string.mjs": "859e9f3dc137a53c17542bbed4cf8accdca81a2895d7a52d1fca38e6c5c00c90",
+ "https://esm.sh/@babel/helper-validator-identifier@7.22.20": "3b0b7d94b8ac689175ecb7e72183b07c6a771cc7680a7c9916091add73bd7f88",
+ "https://esm.sh/@babel/helper-validator-identifier@7.22.20/denonext/helper-validator-identifier.mjs": "f765fd69eb4fd81b839b76bf60f227caac4fe4d41b4c646cc08aa7b8d948fe17",
+ "https://esm.sh/preact@10.22.0": "0fb9b89617c3a27b6be4eee74bd07b845e92900e6b7fdb757bc3a498a6ec9065",
+ "https://esm.sh/preact@10.22.0/debug": "fb8d7b9ea5c7bbfb6cb9d9f9abfa31e8038b08ec623ec029f8feafbe6c5891e4",
+ "https://esm.sh/preact@10.22.0/denonext/debug.mjs": "64ce18634f47de8a2053cc9c9874eeffd7a956532f8e322b138e27a5b7163847",
+ "https://esm.sh/preact@10.22.0/denonext/devtools.mjs": "6c08d70ecd3e6b67e003f742cfd7931ce294c1a354d5d5768f3713593d59b025",
+ "https://esm.sh/preact@10.22.0/denonext/hooks.mjs": "f0fe69655ba3c4c88747b228acd6115c315bce6afeb8160d80afdb6712d949ff",
+ "https://esm.sh/preact@10.22.0/denonext/jsx-runtime.mjs": "135034958157406811f9d44d7f07595da1da9f8ec9dc6adf316e3f3815661e7e",
+ "https://esm.sh/preact@10.22.0/denonext/preact.mjs": "8d07e2251111a69a3d7caf057173bbb806ac7d79954397ce5377309067f50097",
+ "https://esm.sh/preact@10.22.0/hooks": "8a1ea3148ef7373b9c3dc027a147ff6728a4e53e10e3506c1191b087f0e564e1",
+ "https://esm.sh/preact@10.22.0/jsx-runtime": "6c6117abd414386ed23785f7c198e03bee696c1fa0fee01b72a64abe5e7ae7fb"
+ },
+ "workspace": {
+ "dependencies": [
+ "jsr:@fresh/core@^2.2.0",
+ "jsr:@fresh/plugin-vite@^1.0.8",
+ "npm:@preact/signals@^2.8.1",
+ "npm:@tailwindcss/typography@~0.5.19",
+ "npm:@tailwindcss/vite@^4.2.1",
+ "npm:marked@^17.0.3",
+ "npm:preact@^10.28.4",
+ "npm:tailwindcss@^4.2.1",
+ "npm:vite@^7.3.1"
+ ]
+ }
+}
diff --git a/web/islands/Chat.tsx b/web/islands/Chat.tsx
new file mode 100644
index 0000000..a2d6982
--- /dev/null
+++ b/web/islands/Chat.tsx
@@ -0,0 +1,265 @@
+import { useSignal } from "@preact/signals";
+import { useEffect, useRef } from "preact/hooks";
+
+import { Answer } from "../components/Answer.tsx";
+import { LoadingIndicator } from "../components/LoadingIndicator.tsx";
+import { Query } from "../components/Query.tsx";
+import { ControlsPanel } from "../islands/ControlsPanel.tsx";
+import {
+ allowBookmarkFilterEnabled,
+ allowedBookmarkGroups,
+ backendPort,
+ baselineThinkingEffort,
+ bookmarkGroups,
+ dynamicThinkingEffort,
+ messageHistory,
+ referencesRequired,
+ sessionId,
+} from "../utils/appState.ts";
+
+export default function Chat() {
+ const abortControllerRef = useRef(null);
+ const currentQuery = useSignal(null);
+ const currentNode = useSignal(null);
+ const historyIndex = useSignal(-1);
+ const inputRef = useRef(null);
+ const isLoading = useSignal(false);
+ const query = useSignal("");
+ const savedInput = useSignal("");
+
+ useEffect(() => {
+ fetch("/api/config")
+ .then((res) => res.ok ? res.json() : null)
+ .then((config) => {
+ if (config?.ports?.backend) {
+ backendPort.value = config.ports.backend;
+ }
+ })
+ .catch(() => {});
+ }, []);
+
+ const getAllowedBookmarks = () => {
+ if (!allowBookmarkFilterEnabled.value) {
+ return [];
+ }
+ return bookmarkGroups.value
+ .filter((g) => allowedBookmarkGroups.value.has(g.id))
+ .flatMap((g) => g.bookmarks.map((s) => s.url));
+ };
+
+ // Auto-focus input and scroll into view when loading completes
+ useEffect(() => {
+ if (!isLoading.value) {
+ requestAnimationFrame(() => {
+ inputRef.current?.focus();
+ inputRef.current?.scrollIntoView({
+ behavior: "smooth",
+ block: "center",
+ });
+ });
+ }
+ }, [isLoading.value]);
+
+ const handleStop = () => {
+ if (abortControllerRef.current) {
+ abortControllerRef.current.abort();
+ abortControllerRef.current = null;
+ }
+ // Immediately update UI
+ isLoading.value = false;
+ currentNode.value = null;
+ currentQuery.value = null;
+ inputRef.current?.focus();
+ };
+
+ const handleSubmit = async (e: Event) => {
+ e.preventDefault();
+ const userQuery = query.value.trim();
+ if (!userQuery || isLoading.value) return;
+
+ abortControllerRef.current = new AbortController();
+ currentNode.value = "RouterNode";
+ currentQuery.value = userQuery;
+ isLoading.value = true;
+ query.value = "";
+
+ try {
+ const response = await fetch(
+ `http://localhost:${backendPort.value}/api/query`,
+ {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ query: userQuery,
+ session_id: sessionId.value,
+ references_required: referencesRequired.value,
+ allowed_sites: getAllowedBookmarks(),
+ baseline_thinking_effort: baselineThinkingEffort.value,
+ dynamic_thinking_effort: dynamicThinkingEffort.value,
+ }),
+ signal: abortControllerRef.current.signal,
+ },
+ );
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+ }
+
+ const reader = response.body?.getReader();
+ if (!reader) {
+ throw new Error("No response body");
+ }
+
+ const decoder = new TextDecoder();
+ let buffer = "";
+ let eventType = "";
+
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+
+ const chunk = decoder.decode(value, { stream: true });
+ buffer += chunk;
+ const lines = buffer.split("\n");
+ buffer = lines.pop() || "";
+
+ for (const line of lines) {
+ if (line.startsWith("event:")) {
+ eventType = line.slice(6).trim();
+ } else if (line.startsWith("data:")) {
+ try {
+ const data = JSON.parse(line.slice(5).trim());
+ if (eventType === "node") {
+ currentNode.value = data.node_type;
+ } else if (eventType === "answer") {
+ messageHistory.value = [
+ ...messageHistory.value,
+ {
+ query: userQuery,
+ answer: String(data.answer),
+ references: data.references || [],
+ },
+ ];
+ currentNode.value = null;
+ currentQuery.value = null;
+ } else if (eventType === "error") {
+ messageHistory.value = [
+ ...messageHistory.value,
+ {
+ query: userQuery,
+ answer: `Error: ${data.message}`,
+ references: [],
+ },
+ ];
+ currentNode.value = null;
+ currentQuery.value = null;
+ }
+ } catch {
+ // Skip malformed SSE data and continue processing
+ }
+ }
+ }
+ }
+ } catch (err) {
+ if (err instanceof Error && err.name !== "AbortError") {
+ messageHistory.value = [
+ ...messageHistory.value,
+ {
+ query: userQuery,
+ answer: `Error: ${err.message}`,
+ references: [],
+ },
+ ];
+ }
+ currentNode.value = null;
+ currentQuery.value = null;
+ } finally {
+ isLoading.value = false;
+ abortControllerRef.current = null;
+ inputRef.current?.focus();
+ }
+ };
+
+ return (
+
+
+
+
+ {messageHistory.value.map((result, idx) => (
+
+ ))}
+
+ {isLoading.value && (
+
+
+
+
+ )}
+
+ {!isLoading.value && (
+
+
+
+
+ )}
+
+
+
+ );
+}
diff --git a/web/islands/ControlsPanel.tsx b/web/islands/ControlsPanel.tsx
new file mode 100644
index 0000000..316a8eb
--- /dev/null
+++ b/web/islands/ControlsPanel.tsx
@@ -0,0 +1,149 @@
+import { signal } from "@preact/signals";
+import {
+ ControlAddButton,
+ ControlNumberInput,
+ ControlNumberSlider,
+ ControlRow,
+ ControlSection,
+ ControlToggle,
+} from "../components/Controls.tsx";
+import { addBookmarkGroup } from "../utils/bookmarks.ts";
+import {
+ aiSectionOpen,
+ allowBookmarkFilterEnabled,
+ baselineThinkingEffort,
+ bookmarkGroups,
+ clearMemory,
+ dynamicThinkingEffort,
+ referencesRequired,
+ searchSectionOpen,
+} from "../utils/appState.ts";
+import { BookmarkGroupRow } from "../components/BookmarkGroupRow.tsx";
+import { HealthStatus } from "../components/HealthStatus.tsx";
+
+const collapsed = signal(false);
+
+const collapsedPanelArrow = (
+
+);
+
+export function ControlsPanel() {
+ if (collapsed.value) {
+ return (
+ (collapsed.value = false)}
+ title="Expand controls"
+ >
+ {collapsedPanelArrow}
+
+ );
+ }
+
+ return (
+
+
+
+ {/* Header */}
+
Controls
+
+ {/* AI */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Search */}
+
+
+
+
+
+
+
+
+
+ {bookmarkGroups.value.map((group) => (
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/web/main.ts b/web/main.ts
index cb0ff5c..f5bf0c5 100644
--- a/web/main.ts
+++ b/web/main.ts
@@ -1 +1,8 @@
-export {};
+import { App, staticFiles } from "fresh";
+import { type State } from "./utils.ts";
+
+export const app = new App();
+
+app.use(staticFiles());
+
+app.fsRoutes();
diff --git a/web/routes/_app.tsx b/web/routes/_app.tsx
new file mode 100644
index 0000000..3a3030c
--- /dev/null
+++ b/web/routes/_app.tsx
@@ -0,0 +1,15 @@
+import { define } from "../utils.ts";
+
+export default define.page(function App({ Component }) {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+});
diff --git a/web/routes/api/config.ts b/web/routes/api/config.ts
new file mode 100644
index 0000000..71ad1a1
--- /dev/null
+++ b/web/routes/api/config.ts
@@ -0,0 +1,20 @@
+import { define } from "../../utils.ts";
+
+const CONFIG_PATH =
+ new URL("../../../librarian.config.json", import.meta.url).pathname;
+
+export const handler = define.handlers({
+ async GET() {
+ try {
+ const text = await Deno.readTextFile(CONFIG_PATH);
+ return new Response(text, {
+ headers: { "Content-Type": "application/json" },
+ });
+ } catch {
+ return new Response(JSON.stringify({ error: "Config not found" }), {
+ status: 404,
+ headers: { "Content-Type": "application/json" },
+ });
+ }
+ },
+});
diff --git a/web/routes/api/health.ts b/web/routes/api/health.ts
new file mode 100644
index 0000000..4c3f35f
--- /dev/null
+++ b/web/routes/api/health.ts
@@ -0,0 +1,48 @@
+import { define } from "../../utils.ts";
+
+const ENV_SCHEMA_PATH =
+ new URL("../../../env.schema.json", import.meta.url).pathname;
+
+interface EnvVarDef {
+ description: string;
+ required: boolean;
+ default?: string;
+ link?: string;
+}
+
+export const handler = define.handlers({
+ async GET() {
+ let schema: Record = {};
+ try {
+ const text = await Deno.readTextFile(ENV_SCHEMA_PATH);
+ schema = JSON.parse(text).env;
+ } catch {
+ return new Response(
+ JSON.stringify({ error: "Could not load env schema" }),
+ {
+ status: 500,
+ headers: { "Content-Type": "application/json" },
+ },
+ );
+ }
+
+ const env: Record<
+ string,
+ { set: boolean; required: boolean; description: string; link?: string }
+ > = {};
+ for (const [name, config] of Object.entries(schema)) {
+ env[name] = {
+ set: Deno.env.get(name) !== undefined,
+ required: config.required,
+ description: config.description,
+ ...(config.link ? { link: config.link } : {}),
+ };
+ }
+
+ const model = Deno.env.get("VLLM_MODEL_NAME") ?? null;
+
+ return new Response(JSON.stringify({ env, model }), {
+ headers: { "Content-Type": "application/json" },
+ });
+ },
+});
diff --git a/web/routes/index.tsx b/web/routes/index.tsx
new file mode 100644
index 0000000..eec2984
--- /dev/null
+++ b/web/routes/index.tsx
@@ -0,0 +1,29 @@
+import { Head } from "fresh/runtime";
+import { define } from "../utils.ts";
+import Chat from "../islands/Chat.tsx";
+
+export default define.page(function Home() {
+ return (
+
+
+
Librarian
+
+
+
+
+ );
+});
diff --git a/web/static/favicon.ico b/web/static/favicon.ico
new file mode 100644
index 0000000..1f02b9e
Binary files /dev/null and b/web/static/favicon.ico differ
diff --git a/web/static/fireside-angel.svg b/web/static/fireside-angel.svg
new file mode 100644
index 0000000..6c80573
--- /dev/null
+++ b/web/static/fireside-angel.svg
@@ -0,0 +1,43 @@
+
diff --git a/web/utils.ts b/web/utils.ts
new file mode 100644
index 0000000..4635511
--- /dev/null
+++ b/web/utils.ts
@@ -0,0 +1,6 @@
+import { createDefine } from "fresh";
+
+// deno-lint-ignore no-empty-interface
+export interface State {}
+
+export const define = createDefine();
diff --git a/web/utils/appState.ts b/web/utils/appState.ts
new file mode 100644
index 0000000..9e77c8a
--- /dev/null
+++ b/web/utils/appState.ts
@@ -0,0 +1,116 @@
+import { effect, signal } from "@preact/signals";
+import { IS_BROWSER } from "fresh/runtime";
+import { BookmarkGroup } from "../utils/bookmarks.ts";
+
+// Helper for persisted signals at module level (not a hook)
+function createPersistedSignal(
+ key: string,
+ initial: T,
+ serialize: (v: T) => S = (v) => v as unknown as S,
+ deserialize: (v: S) => T = (v) => v as unknown as T,
+) {
+ let valueToUse = initial;
+
+ if (IS_BROWSER) {
+ const stored = localStorage.getItem(key);
+ if (stored) {
+ try {
+ valueToUse = deserialize(JSON.parse(stored));
+ } catch {
+ localStorage.removeItem(key);
+ }
+ }
+ }
+
+ const sig = signal(valueToUse);
+
+ if (IS_BROWSER) {
+ effect(() => {
+ localStorage.setItem(key, JSON.stringify(serialize(sig.value)));
+ });
+ }
+
+ return sig;
+}
+
+// Signals
+
+export const backendPort = signal(8001);
+
+export const allowBookmarkFilterEnabled = createPersistedSignal(
+ "allow-filter-enabled",
+ false,
+);
+
+export const allowedBookmarkGroups = createPersistedSignal<
+ Set,
+ string[]
+>(
+ "allowed-bookmark-groups",
+ new Set(),
+ (s) => [...s],
+ (a) => new Set(a),
+);
+
+export const bookmarkGroups = createPersistedSignal(
+ "bookmark-groups",
+ [],
+);
+
+interface QueryResult {
+ query: string;
+ answer: string;
+ references: string[];
+}
+
+export const messageHistory = createPersistedSignal(
+ "message-history",
+ [],
+);
+
+export const sessionId = createPersistedSignal(
+ "fireside-session-key",
+ IS_BROWSER ? crypto.randomUUID() : "",
+);
+
+export const referencesRequired = createPersistedSignal(
+ "references-required",
+ 1,
+);
+
+export const baselineThinkingEffort = createPersistedSignal(
+ "baseline-thinking-effort",
+ 5,
+);
+
+export const dynamicThinkingEffort = createPersistedSignal(
+ "dynamic-thinking-effort",
+ true,
+);
+
+export const aiSectionOpen = createPersistedSignal(
+ "controls-ai-section-open",
+ true,
+);
+
+export const searchSectionOpen = createPersistedSignal(
+ "controls-search-section-open",
+ true,
+);
+
+export function clearMemory() {
+ if (!IS_BROWSER) return;
+
+ // Clear backend session
+ if (sessionId.value) {
+ fetch(
+ `http://localhost:${backendPort.value}/api/session/${sessionId.value}`,
+ {
+ method: "DELETE",
+ },
+ ).catch(() => {});
+ }
+
+ // Clear frontend message history
+ messageHistory.value = [];
+}
diff --git a/web/utils/bookmarks.ts b/web/utils/bookmarks.ts
new file mode 100644
index 0000000..ee5484c
--- /dev/null
+++ b/web/utils/bookmarks.ts
@@ -0,0 +1,70 @@
+import { allowedBookmarkGroups, bookmarkGroups } from "../utils/appState.ts";
+
+export interface Bookmark {
+ id: string;
+ url: string;
+}
+
+export interface BookmarkGroup {
+ id: string;
+ name: string;
+ bookmarks: Bookmark[];
+}
+
+export function createBookmark(url: string): Bookmark {
+ return { id: crypto.randomUUID(), url };
+}
+
+function createBookmarkGroup(name: string): BookmarkGroup {
+ return { id: crypto.randomUUID(), name, bookmarks: [] };
+}
+
+export function addBookmarkToGroup(bookmark: Bookmark, group: BookmarkGroup) {
+ bookmarkGroups.value = bookmarkGroups.value.map((g) =>
+ g.id === group.id
+ ? {
+ ...g,
+ bookmarks: [...g.bookmarks, bookmark],
+ }
+ : g
+ );
+}
+
+export function addBookmarkGroup(name: string) {
+ const newGroup = createBookmarkGroup(name);
+ bookmarkGroups.value = [...bookmarkGroups.value, newGroup];
+ allowedBookmarkGroups.value = new Set([
+ ...allowedBookmarkGroups.value,
+ newGroup.id,
+ ]);
+}
+
+export function deleteBookmarkGroup(group: BookmarkGroup) {
+ if (group && group.bookmarks.length > 0) {
+ if (
+ !confirm(
+ `Delete "${group.name}" and its ${group.bookmarks.length} bookmarks?`,
+ )
+ ) {
+ return;
+ }
+ }
+ bookmarkGroups.value = bookmarkGroups.value.filter((g) => g.id !== group.id);
+ allowedBookmarkGroups.value = new Set(
+ [...allowedBookmarkGroups.value].filter((id) => id !== group.id),
+ );
+}
+
+export function removeBookmarkFromGroup(
+ bookmark: Bookmark,
+ group: BookmarkGroup,
+) {
+ bookmarkGroups.value = bookmarkGroups.value.map((g) =>
+ g.id === group.id
+ ? {
+ ...g,
+ bookmarks: g.bookmarks.filter((b) => b.id !== bookmark.id),
+ }
+ : g
+ );
+}
diff --git a/web/vite.config.ts b/web/vite.config.ts
new file mode 100644
index 0000000..67a37d0
--- /dev/null
+++ b/web/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from "vite";
+import { fresh } from "@fresh/plugin-vite";
+import tailwindcss from "@tailwindcss/vite";
+
+export default defineConfig({
+ plugins: [fresh(), tailwindcss()],
+});