diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 000000000..9e429e498 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,26 @@ +# deps +/node_modules + +# generated content +.source + +# test & build +/coverage +/.next/ +/out/ +/build +*.tsbuildinfo + +# misc +.DS_Store +*.pem +/.pnp +.pnp.js +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# others +.env*.local +.vercel +next-env.d.ts \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..9b7bba9e0 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,45 @@ +# docs + +This is a Next.js application generated with +[Create Fumadocs](https://github.com/fuma-nama/fumadocs). + +Run development server: + +```bash +npm run dev +# or +pnpm dev +# or +yarn dev +``` + +Open http://localhost:3000 with your browser to see the result. + +## Explore + +In the project, you can see: + +- `lib/source.ts`: Code for content source adapter, [`loader()`](https://fumadocs.dev/docs/headless/source-api) provides the interface to access your content. +- `lib/layout.shared.tsx`: Shared options for layouts, optional but preferred to keep. + +| Route | Description | +| ------------------------- | ------------------------------------------------------ | +| `app/(home)` | The route group for your landing page and other pages. | +| `app/docs` | The documentation layout and pages. | +| `app/api/search/route.ts` | The Route Handler for search. | + +### Fumadocs MDX + +A `source.config.ts` config file has been included, you can customise different options like frontmatter schema. + +Read the [Introduction](https://fumadocs.dev/docs/mdx) for further details. + +## Learn More + +To learn more about Next.js and Fumadocs, take a look at the following +resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js + features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +- [Fumadocs](https://fumadocs.dev) - learn about Fumadocs diff --git a/docs/app/(home)/layout.tsx b/docs/app/(home)/layout.tsx new file mode 100644 index 000000000..77379fac3 --- /dev/null +++ b/docs/app/(home)/layout.tsx @@ -0,0 +1,6 @@ +import { HomeLayout } from 'fumadocs-ui/layouts/home'; +import { baseOptions } from '@/lib/layout.shared'; + +export default function Layout({ children }: LayoutProps<'/'>) { + return {children}; +} diff --git a/docs/app/(home)/page.tsx b/docs/app/(home)/page.tsx new file mode 100644 index 000000000..8168b82a6 --- /dev/null +++ b/docs/app/(home)/page.tsx @@ -0,0 +1,5 @@ +import { redirect } from 'next/navigation'; + +export default function HomePage() { + redirect('/docs'); +} diff --git a/docs/app/api/search/route.ts b/docs/app/api/search/route.ts new file mode 100644 index 000000000..7ba7e8231 --- /dev/null +++ b/docs/app/api/search/route.ts @@ -0,0 +1,7 @@ +import { source } from '@/lib/source'; +import { createFromSource } from 'fumadocs-core/search/server'; + +export const { GET } = createFromSource(source, { + // https://docs.orama.com/docs/orama-js/supported-languages + language: 'english', +}); diff --git a/docs/app/docs/[[...slug]]/page.tsx b/docs/app/docs/[[...slug]]/page.tsx new file mode 100644 index 000000000..53ce219c5 --- /dev/null +++ b/docs/app/docs/[[...slug]]/page.tsx @@ -0,0 +1,63 @@ +import { getPageImage, getPageMarkdownUrl, source } from '@/lib/source'; +import { + DocsBody, + DocsDescription, + DocsPage, + DocsTitle, + MarkdownCopyButton, + ViewOptionsPopover, +} from 'fumadocs-ui/layouts/docs/page'; +import { notFound } from 'next/navigation'; +import { getMDXComponents } from '@/components/mdx'; +import type { Metadata } from 'next'; +import { createRelativeLink } from 'fumadocs-ui/mdx'; +import { gitConfig } from '@/lib/shared'; + +export default async function Page(props: PageProps<'/docs/[[...slug]]'>) { + const params = await props.params; + const page = source.getPage(params.slug); + if (!page) notFound(); + + const MDX = page.data.body; + const markdownUrl = getPageMarkdownUrl(page).url; + + return ( + + {page.data.title} + {page.data.description} +
+ + +
+ + + +
+ ); +} + +export async function generateStaticParams() { + return source.generateParams(); +} + +export async function generateMetadata(props: PageProps<'/docs/[[...slug]]'>): Promise { + const params = await props.params; + const page = source.getPage(params.slug); + if (!page) notFound(); + + return { + title: page.data.title, + description: page.data.description, + openGraph: { + images: getPageImage(page).url, + }, + }; +} diff --git a/docs/app/docs/layout.tsx b/docs/app/docs/layout.tsx new file mode 100644 index 000000000..a373143bf --- /dev/null +++ b/docs/app/docs/layout.tsx @@ -0,0 +1,11 @@ +import { source } from '@/lib/source'; +import { DocsLayout } from 'fumadocs-ui/layouts/docs'; +import { baseOptions } from '@/lib/layout.shared'; + +export default function Layout({ children }: LayoutProps<'/docs'>) { + return ( + + {children} + + ); +} diff --git a/docs/app/global.css b/docs/app/global.css new file mode 100644 index 000000000..b8ef04e50 --- /dev/null +++ b/docs/app/global.css @@ -0,0 +1,53 @@ +@import 'tailwindcss'; +@import 'fumadocs-ui/css/neutral.css'; +@import 'fumadocs-ui/css/preset.css'; +@import 'fumadocs-twoslash/twoslash.css'; + +@theme { + --color-fd-background: hsl(0, 0%, 98%); + --color-fd-foreground: hsl(0, 0%, 3.9%); + --color-fd-muted: hsl(0, 0%, 96.1%); + --color-fd-muted-foreground: hsl(0, 0%, 45.1%); + --color-fd-popover: hsl(0, 0%, 100%); + --color-fd-popover-foreground: hsl(0, 0%, 15.1%); + --color-fd-card: hsl(0, 0%, 99.7%); + --color-fd-card-foreground: hsl(0, 0%, 3.9%); + --color-fd-border: hsla(0, 0%, 60%, 0.2); + --color-fd-primary: hsl(0, 0%, 9%); + --color-fd-primary-foreground: hsl(0, 0%, 98%); + --color-fd-secondary: hsl(0, 0%, 96.1%); + --color-fd-secondary-foreground: hsl(0, 0%, 9%); + --color-fd-accent: hsl(0, 0%, 94.1%); + --color-fd-accent-foreground: hsl(0, 0%, 9%); + --color-fd-ring: hsl(0, 0%, 63.9%); + --color-purple: hsl(262, 52%, 56%); +} + +.dark { + --color-fd-background: hsl(0, 0%, 2%); + --color-fd-foreground: hsl(0, 0%, 98%); + --color-fd-muted: hsl(0, 0%, 8%); + --color-fd-muted-foreground: hsl(0, 0%, 60%); + --color-fd-popover: hsl(0, 0%, 4%); + --color-fd-popover-foreground: hsl(0, 0%, 98%); + --color-fd-card: hsl(0, 0%, 4%); + --color-fd-card-foreground: hsl(0, 0%, 98%); + --color-fd-border: hsl(0, 0%, 50%, 0.2); + --color-fd-primary: hsl(0, 0%, 98%); + --color-fd-primary-foreground: hsl(0, 0%, 9%); + --color-fd-secondary: hsl(0, 0%, 12.9%); + --color-fd-secondary-foreground: hsl(0, 0%, 98%); + --color-fd-accent: hsl(0, 0%, 15%); + --color-fd-accent-foreground: hsl(0, 0%, 100%); + --color-fd-ring: hsl(0, 0%, 34.9%); + --color-purple: hsl(262, 60%, 65%); +} + +html { + scrollbar-gutter: stable; +} + +html > body[data-scroll-locked] { + margin-right: 0px !important; + --removed-body-scroll-bar-size: 0px !important; +} diff --git a/docs/app/layout.tsx b/docs/app/layout.tsx new file mode 100644 index 000000000..1e5e74d69 --- /dev/null +++ b/docs/app/layout.tsx @@ -0,0 +1,28 @@ +import { RootProvider } from 'fumadocs-ui/provider/next'; +import './global.css'; +import { Inter } from 'next/font/google'; +import type { Metadata } from 'next'; + +const inter = Inter({ + subsets: ['latin'], +}); + +export const metadata: Metadata = { + title: { + default: 'Headroom', + template: '%s | Headroom', + }, + description: + 'Compress everything your AI agent reads. Same answers, fraction of the tokens.', + metadataBase: new URL('https://chopratejas.github.io/headroom/'), +}; + +export default function Layout({ children }: LayoutProps<'/'>) { + return ( + + + {children} + + + ); +} diff --git a/docs/app/llms-full.txt/route.ts b/docs/app/llms-full.txt/route.ts new file mode 100644 index 000000000..d494d2cbb --- /dev/null +++ b/docs/app/llms-full.txt/route.ts @@ -0,0 +1,10 @@ +import { getLLMText, source } from '@/lib/source'; + +export const revalidate = false; + +export async function GET() { + const scan = source.getPages().map(getLLMText); + const scanned = await Promise.all(scan); + + return new Response(scanned.join('\n\n')); +} diff --git a/docs/app/llms.mdx/docs/[[...slug]]/route.ts b/docs/app/llms.mdx/docs/[[...slug]]/route.ts new file mode 100644 index 000000000..250181a70 --- /dev/null +++ b/docs/app/llms.mdx/docs/[[...slug]]/route.ts @@ -0,0 +1,23 @@ +import { getLLMText, getPageMarkdownUrl, source } from '@/lib/source'; +import { notFound } from 'next/navigation'; + +export const revalidate = false; + +export async function GET(_req: Request, { params }: RouteContext<'/llms.mdx/docs/[[...slug]]'>) { + const { slug } = await params; + const page = source.getPage(slug?.slice(0, -1)); + if (!page) notFound(); + + return new Response(await getLLMText(page), { + headers: { + 'Content-Type': 'text/markdown', + }, + }); +} + +export function generateStaticParams() { + return source.getPages().map((page) => ({ + lang: page.locale, + slug: getPageMarkdownUrl(page).segments, + })); +} diff --git a/docs/app/llms.txt/route.ts b/docs/app/llms.txt/route.ts new file mode 100644 index 000000000..fc80cb652 --- /dev/null +++ b/docs/app/llms.txt/route.ts @@ -0,0 +1,8 @@ +import { source } from '@/lib/source'; +import { llms } from 'fumadocs-core/source'; + +export const revalidate = false; + +export function GET() { + return new Response(llms(source).index()); +} diff --git a/docs/app/og/docs/[...slug]/route.tsx b/docs/app/og/docs/[...slug]/route.tsx new file mode 100644 index 000000000..2d741be3c --- /dev/null +++ b/docs/app/og/docs/[...slug]/route.tsx @@ -0,0 +1,27 @@ +import { getPageImage, source } from '@/lib/source'; +import { notFound } from 'next/navigation'; +import { ImageResponse } from 'next/og'; +import { generate as DefaultImage } from 'fumadocs-ui/og'; + +export const revalidate = false; + +export async function GET(_req: Request, { params }: RouteContext<'/og/docs/[...slug]'>) { + const { slug } = await params; + const page = source.getPage(slug.slice(0, -1)); + if (!page) notFound(); + + return new ImageResponse( + , + { + width: 1200, + height: 630, + }, + ); +} + +export function generateStaticParams() { + return source.getPages().map((page) => ({ + lang: page.locale, + slug: getPageImage(page).segments, + })); +} diff --git a/docs/bun.lock b/docs/bun.lock new file mode 100644 index 000000000..a04d1db86 --- /dev/null +++ b/docs/bun.lock @@ -0,0 +1,1176 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "docs", + "dependencies": { + "dotted-map": "^3.1.0", + "fumadocs-core": "16.7.10", + "fumadocs-mdx": "14.2.11", + "fumadocs-twoslash": "^3.1.3", + "fumadocs-typescript": "^4.0.3", + "fumadocs-ui": "16.7.10", + "headroom-ai": "file:../sdk/typescript", + "lucide-react": "^1.7.0", + "next": "16.2.2", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "tailwind-merge": "^3.5.0", + }, + "devDependencies": { + "@ai-sdk/openai": "^3.0.51", + "@anthropic-ai/sdk": "^0.82.0", + "@tailwindcss/postcss": "^4.2.2", + "@types/mdx": "^2.0.13", + "@types/node": "^25.5.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "ai": "^6.0.149", + "openai": "^6.33.0", + "postcss": "^8.5.8", + "tailwindcss": "^4.2.2", + "typescript": "^5.9.3", + }, + }, + }, + "packages": { + "@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.67", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-FFX4P5Fd6lcQJc2OLngZQkbbJHa0IDDZi087Edb8qRZx6h90krtM61ArbMUL8us/7ZUwojCXnyJ/wQ2Eflx2jQ=="], + + "@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.91", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-J39Dh6Gyg6HjG3A7OFKnJMp3QyZ3Eex+XDiX8aFBdRwwZm3jGWaMhkCxQPH7yiQ9kRiErZwHXX/Oexx4SyGGGA=="], + + "@ai-sdk/openai": ["@ai-sdk/openai@3.0.51", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-qBgDOC+vlXwLFbZ3UoKx3T8VFyul3K39JNyW6E4XnOnzLT4Mlhb0GeDC06RvYqwGWOQFBQNLe/vegOMVtNpl5g=="], + + "@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="], + + "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.23", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-z8GlDaCmRSDlqkMF2f4/RFgWxdarvIbyuk+m6WXT1LYgsnGiXRJGTD2Z1+SDl3LqtFuRtGX1aghYvQLoHL/9pg=="], + + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + + "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.82.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-xdHTjL1GlUlDugHq/I47qdOKp/ROPvuHl7ROJCgUQigbvPu7asf9KcAcU1EqdrP2LuVhEKaTs7Z+ShpZDRzHdQ=="], + + "@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.9.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], + + "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="], + + "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="], + + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.8", "", { "dependencies": { "@floating-ui/dom": "^1.7.6" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A=="], + + "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], + + "@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.1.1", "", {}, "sha512-CbNbf+tlJn1baRnPkNePnBqTLxGliG6DDgNa/UtV66abwIjwsliPMOt0172tzxABYzSuxZBZfcp//qI8AvBWPg=="], + + "@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.8.2", "", { "dependencies": { "@formatjs/fast-memoize": "3.1.1" } }, "sha512-q05KMYGJLyqFNFtIb8NhWLF5X3aK/k0wYt7dnRFuy6aLQL+vUwQ1cg5cO4qawEiINybeCPXAWlprY2mSBjSXAQ=="], + + "@fumadocs/tailwind": ["@fumadocs/tailwind@0.0.3", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "tailwindcss": "^4.0.0" }, "optionalPeers": ["tailwindcss"] }, "sha512-/FWcggMz9BhoX+13xBoZLX+XX9mYvJ50dkTqy3IfocJqua65ExcsKfxwKH8hgTO3vA5KnWv4+4jU7LaW2AjAmQ=="], + + "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], + + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], + + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], + + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], + + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], + + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], + + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], + + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="], + + "@next/env": ["@next/env@16.2.2", "", {}, "sha512-LqSGz5+xGk9EL/iBDr2yo/CgNQV6cFsNhRR2xhSXYh7B/hb4nePCxlmDvGEKG30NMHDFf0raqSyOZiQrO7BkHQ=="], + + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.2.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B92G3ulrwmkDSEJEp9+XzGLex5wC1knrmCSIylyVeiAtCIfvEJYiN3v5kXPlYt5R4RFlsfO/v++aKV63Acrugg=="], + + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.2.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-7ZwSgNKJNQiwW0CKhNm9B1WS2L1Olc4B2XY0hPYCAL3epFnugMhuw5TMWzMilQ3QCZcCHoYm9NGWTHbr5REFxw=="], + + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-c3m8kBHMziMgo2fICOP/cd/5YlrxDU5YYjAJeQLyFsCqVF8xjOTH/QYG4a2u48CvvZZSj1eHQfBCbyh7kBr30Q=="], + + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-VKLuscm0P/mIfzt+SDdn2+8TNNJ7f0qfEkA+az7OqQbjzKdBxAHs0UvuiVoCtbwX+dqMEL9U54b5wQ/aN3dHeg=="], + + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-kU3OPHJq6sBUjOk7wc5zJ7/lipn8yGldMoAv4z67j6ov6Xo/JvzA7L7LCsyzzsXmgLEhk3Qkpwqaq/1+XpNR3g=="], + + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-CKXRILyErMtUftp+coGcZ38ZwE/Aqq45VMCcRLr2I4OXKrgxIBDXHnBgeX/UMil0S09i2JXaDL3Q+TN8D/cKmg=="], + + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.2.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-sS/jSk5VUoShUqINJFvNjVT7JfR5ORYj/+/ZpOYbbIohv/lQfduWnGAycq2wlknbOql2xOR0DoV0s6Xfcy49+g=="], + + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.2.2", "", { "os": "win32", "cpu": "x64" }, "sha512-aHaKceJgdySReT7qeck5oShucxWRiiEuwCGK8HHALe6yZga8uyFpLkPgaRw3kkF04U7ROogL/suYCNt/+CuXGA=="], + + "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], + + "@orama/orama": ["@orama/orama@3.1.18", "", {}, "sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA=="], + + "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="], + + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], + + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="], + + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], + + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="], + + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="], + + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], + + "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], + + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], + + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], + + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], + + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="], + + "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], + + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], + + "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="], + + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], + + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], + + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], + + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], + + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], + + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="], + + "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="], + + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="], + + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], + + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], + + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], + + "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="], + + "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], + + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], + + "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="], + + "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="], + + "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], + + "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="], + + "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.1", "", { "os": "android", "cpu": "arm" }, "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.60.1", "", { "os": "android", "cpu": "arm64" }, "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.60.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.60.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.60.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.60.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.60.1", "", { "os": "linux", "cpu": "arm" }, "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.60.1", "", { "os": "linux", "cpu": "arm" }, "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.60.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.60.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.60.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.60.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.60.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.60.1", "", { "os": "linux", "cpu": "x64" }, "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.60.1", "", { "os": "linux", "cpu": "x64" }, "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.60.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.60.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.60.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.60.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.60.1", "", { "os": "win32", "cpu": "x64" }, "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.60.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ=="], + + "@shikijs/core": ["@shikijs/core@4.0.2", "", { "dependencies": { "@shikijs/primitive": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw=="], + + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag=="], + + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg=="], + + "@shikijs/langs": ["@shikijs/langs@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg=="], + + "@shikijs/primitive": ["@shikijs/primitive@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw=="], + + "@shikijs/rehype": ["@shikijs/rehype@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@types/hast": "^3.0.4", "hast-util-to-string": "^3.0.1", "shiki": "4.0.2", "unified": "^11.0.5", "unist-util-visit": "^5.1.0" } }, "sha512-cmPlKLD8JeojasNFoY64162ScpEdEdQUMuVodPCrv1nx1z3bjmGwoKWDruQWa/ejSznImlaeB0Ty6Q3zPaVQAA=="], + + "@shikijs/themes": ["@shikijs/themes@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA=="], + + "@shikijs/transformers": ["@shikijs/transformers@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/types": "4.0.2" } }, "sha512-1+L0gf9v+SdDXs08vjaLb3mBFa8U7u37cwcBQIv/HCocLwX69Tt6LpUCjtB+UUTvQxI7BnjZKhN/wMjhHBcJGg=="], + + "@shikijs/twoslash": ["@shikijs/twoslash@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/types": "4.0.2", "twoslash": "^0.3.6" }, "peerDependencies": { "typescript": ">=5.5.0" } }, "sha512-yHRudhirlMxOwDO6Q4OFU9hJMvUqNkY8hwtUfbaSEoG7A2cYicdO4c8fdDaDtyJ50HK7I8vTokrkIHTK3DCkLQ=="], + + "@shikijs/types": ["@shikijs/types@4.0.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg=="], + + "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + + "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], + + "@tailwindcss/node": ["@tailwindcss/node@4.2.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.2" } }, "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA=="], + + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.2", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.2", "@tailwindcss/oxide-darwin-arm64": "4.2.2", "@tailwindcss/oxide-darwin-x64": "4.2.2", "@tailwindcss/oxide-freebsd-x64": "4.2.2", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", "@tailwindcss/oxide-linux-x64-musl": "4.2.2", "@tailwindcss/oxide-wasm32-wasi": "4.2.2", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" } }, "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg=="], + + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.2", "", { "os": "android", "cpu": "arm64" }, "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg=="], + + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg=="], + + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw=="], + + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ=="], + + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2", "", { "os": "linux", "cpu": "arm" }, "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ=="], + + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw=="], + + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag=="], + + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg=="], + + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ=="], + + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.2", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q=="], + + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ=="], + + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.2", "", { "os": "win32", "cpu": "x64" }, "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA=="], + + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.2.2", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.2.2", "@tailwindcss/oxide": "4.2.2", "postcss": "^8.5.6", "tailwindcss": "4.2.2" } }, "sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ=="], + + "@ts-morph/common": ["@ts-morph/common@0.28.1", "", { "dependencies": { "minimatch": "^10.0.1", "path-browserify": "^1.0.1", "tinyglobby": "^0.2.14" } }, "sha512-W74iWf7ILp1ZKNYXY5qbddNaml7e9Sedv5lvU1V8lftlitkc9Pq1A+jlH23ltDgWYeZFFEqGCD1Ies9hqu3O+g=="], + + "@turf/boolean-point-in-polygon": ["@turf/boolean-point-in-polygon@7.3.4", "", { "dependencies": { "@turf/helpers": "7.3.4", "@turf/invariant": "7.3.4", "@types/geojson": "^7946.0.10", "point-in-polygon-hao": "^1.1.0", "tslib": "^2.8.1" } }, "sha512-v/4hfyY90Vz9cDgs2GwjQf+Lft8o7mNCLJOTz/iv8SHAIgMMX0czEoIaNVOJr7tBqPqwin1CGwsncrkf5C9n8Q=="], + + "@turf/helpers": ["@turf/helpers@7.3.4", "", { "dependencies": { "@types/geojson": "^7946.0.10", "tslib": "^2.8.1" } }, "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g=="], + + "@turf/invariant": ["@turf/invariant@7.3.4", "", { "dependencies": { "@turf/helpers": "7.3.4", "@types/geojson": "^7946.0.10", "tslib": "^2.8.1" } }, "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ=="], + + "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], + + "@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="], + + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + + "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], + + "@types/mdx": ["@types/mdx@2.0.13", "", {}, "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw=="], + + "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], + + "@types/node": ["@types/node@25.5.2", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg=="], + + "@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="], + + "@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], + + "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], + + "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], + + "@typescript/vfs": ["@typescript/vfs@1.6.4", "", { "dependencies": { "debug": "^4.4.3" }, "peerDependencies": { "typescript": "*" } }, "sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ=="], + + "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + + "@vercel/oidc": ["@vercel/oidc@3.1.0", "", {}, "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w=="], + + "@vitest/expect": ["@vitest/expect@2.1.9", "", { "dependencies": { "@vitest/spy": "2.1.9", "@vitest/utils": "2.1.9", "chai": "^5.1.2", "tinyrainbow": "^1.2.0" } }, "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw=="], + + "@vitest/mocker": ["@vitest/mocker@2.1.9", "", { "dependencies": { "@vitest/spy": "2.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.12" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg=="], + + "@vitest/pretty-format": ["@vitest/pretty-format@2.1.9", "", { "dependencies": { "tinyrainbow": "^1.2.0" } }, "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ=="], + + "@vitest/runner": ["@vitest/runner@2.1.9", "", { "dependencies": { "@vitest/utils": "2.1.9", "pathe": "^1.1.2" } }, "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g=="], + + "@vitest/snapshot": ["@vitest/snapshot@2.1.9", "", { "dependencies": { "@vitest/pretty-format": "2.1.9", "magic-string": "^0.30.12", "pathe": "^1.1.2" } }, "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ=="], + + "@vitest/spy": ["@vitest/spy@2.1.9", "", { "dependencies": { "tinyspy": "^3.0.2" } }, "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ=="], + + "@vitest/utils": ["@vitest/utils@2.1.9", "", { "dependencies": { "@vitest/pretty-format": "2.1.9", "loupe": "^3.1.2", "tinyrainbow": "^1.2.0" } }, "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ=="], + + "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], + + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], + + "ai": ["ai@6.0.149", "", { "dependencies": { "@ai-sdk/gateway": "3.0.91", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-3asRb/m3ZGH7H4+VTuTgj8eQYJZ9IJUmV0ljLslY92mQp6Zj+NVn4SmFj0TBr2Y/wFBWC3xgn++47tSGOXxdbw=="], + + "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], + + "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], + + "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], + + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + + "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], + + "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.16", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-Lyf3aK28zpsD1yQMiiHD4RvVb6UdMoo8xzG2XzFIfR9luPzOpcBlAsT/qfB1XWS1bxWT+UtE4WmQgsp297FYOA=="], + + "brace-expansion": ["brace-expansion@5.0.5", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="], + + "bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="], + + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001786", "", {}, "sha512-4oxTZEvqmLLrERwxO76yfKM7acZo310U+v4kqexI2TL1DkkUEMT8UijrxxcnVdxR3qkVf5awGRX+4Z6aPHVKrA=="], + + "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], + + "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], + + "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], + + "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="], + + "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], + + "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="], + + "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], + + "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + + "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], + + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "code-block-writer": ["code-block-writer@13.0.3", "", {}, "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg=="], + + "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], + + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + + "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + + "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + + "compute-scroll-into-view": ["compute-scroll-into-view@3.1.1", "", {}, "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw=="], + + "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + + "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], + + "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], + + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], + + "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], + + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], + + "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], + + "dotenv": ["dotenv@17.4.1", "", {}, "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw=="], + + "dotted-map": ["dotted-map@3.1.0", "", { "dependencies": { "@turf/boolean-point-in-polygon": "^7.3.4", "proj4": "^2.20.2" } }, "sha512-E0z9o5IaTf44FnWHvbyg4QQcBwXgzZJr82HJASWb1dKUCULHfnlWKRpfe5EFHTk/yaoS1sQSLMyMrL6o74/sIw=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], + + "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + + "esast-util-from-estree": ["esast-util-from-estree@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "unist-util-position-from-estree": "^2.0.0" } }, "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ=="], + + "esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="], + + "esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], + + "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + + "estree-util-attach-comments": ["estree-util-attach-comments@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw=="], + + "estree-util-build-jsx": ["estree-util-build-jsx@3.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-walker": "^3.0.0" } }, "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ=="], + + "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="], + + "estree-util-scope": ["estree-util-scope@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0" } }, "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ=="], + + "estree-util-to-js": ["estree-util-to-js@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "astring": "^1.8.0", "source-map": "^0.7.0" } }, "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg=="], + + "estree-util-value-to-estree": ["estree-util-value-to-estree@3.5.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ=="], + + "estree-util-visit": ["estree-util-visit@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/unist": "^3.0.0" } }, "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww=="], + + "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + + "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], + + "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], + + "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], + + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fix-dts-default-cjs-exports": ["fix-dts-default-cjs-exports@1.0.1", "", { "dependencies": { "magic-string": "^0.30.17", "mlly": "^1.7.4", "rollup": "^4.34.8" } }, "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg=="], + + "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + + "form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="], + + "formdata-node": ["formdata-node@4.4.1", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" } }, "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ=="], + + "framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "fumadocs-core": ["fumadocs-core@16.7.10", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.8.2", "@orama/orama": "^3.1.18", "@shikijs/rehype": "^4.0.2", "@shikijs/transformers": "^4.0.2", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "image-size": "^2.0.2", "mdast-util-mdx": "^3.0.0", "mdast-util-to-markdown": "^2.1.2", "negotiator": "^1.0.0", "npm-to-yarn": "^3.0.1", "path-to-regexp": "^8.4.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^4.0.2", "tinyglobby": "^0.2.15", "unified": "^11.0.5", "unist-util-visit": "^5.1.0", "vfile": "^6.0.3" }, "peerDependencies": { "@mdx-js/mdx": "*", "@mixedbread/sdk": "^0.46.0", "@orama/core": "1.x.x", "@oramacloud/client": "2.x.x", "@tanstack/react-router": "1.x.x", "@types/estree-jsx": "*", "@types/hast": "*", "@types/mdast": "*", "@types/react": "*", "algoliasearch": "5.x.x", "flexsearch": "*", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "^0.26.0 || ^0.27.0 || ^1.0.0", "zod": "4.x.x" }, "optionalPeers": ["@mdx-js/mdx", "@mixedbread/sdk", "@orama/core", "@oramacloud/client", "@tanstack/react-router", "@types/estree-jsx", "@types/hast", "@types/mdast", "@types/react", "algoliasearch", "flexsearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-ltAQO+CgCkGUUef33vGXZBj1SNzIRq9SpmZzOIEnXL1+nBZGHiRlSuRK0xqcAtvFwvCOVQN5GNhWmahNoqXo4g=="], + + "fumadocs-mdx": ["fumadocs-mdx@14.2.11", "", { "dependencies": { "@mdx-js/mdx": "^3.1.1", "@standard-schema/spec": "^1.1.0", "chokidar": "^5.0.0", "esbuild": "^0.27.3", "estree-util-value-to-estree": "^3.5.0", "js-yaml": "^4.1.1", "mdast-util-mdx": "^3.0.0", "mdast-util-to-markdown": "^2.1.2", "picocolors": "^1.1.1", "picomatch": "^4.0.3", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.1.0", "vfile": "^6.0.3", "zod": "^4.3.6" }, "peerDependencies": { "@fumadocs/mdx-remote": "^1.4.0", "@types/mdast": "*", "@types/mdx": "*", "@types/react": "*", "fumadocs-core": "^15.0.0 || ^16.0.0", "mdast-util-directive": "*", "next": "^15.3.0 || ^16.0.0", "react": "*", "vite": "6.x.x || 7.x.x || 8.x.x" }, "optionalPeers": ["@fumadocs/mdx-remote", "@types/mdast", "@types/mdx", "@types/react", "mdast-util-directive", "next", "react", "vite"], "bin": { "fumadocs-mdx": "dist/bin.js" } }, "sha512-j0gHKs45c62ARteE8/yBM2Nu2I8AE2Cs37ktPEdc/8EX7TL66XP74un5OpHp6itLyWTu8Jur0imOiiIDq8+rDg=="], + + "fumadocs-twoslash": ["fumadocs-twoslash@3.1.15", "", { "dependencies": { "@radix-ui/react-popover": "^1.1.15", "@shikijs/twoslash": "^4.0.2", "mdast-util-from-markdown": "^2.0.3", "mdast-util-gfm": "^3.1.0", "mdast-util-to-hast": "^13.2.1", "shiki": "^4.0.2", "tailwind-merge": "^3.5.0", "twoslash": "^0.3.6" }, "peerDependencies": { "@types/react": "*", "fumadocs-ui": "^15.0.0 || ^16.0.0", "react": "18.x.x || 19.x.x" }, "optionalPeers": ["@types/react"] }, "sha512-MygtupZnfH0fKjDpI5Nb68cVMEnCpYrvWLcfWP6hJeZvyBWjCDTjN5x1PffUtsP6rHWdgpZuw8T51OnNC7f88w=="], + + "fumadocs-typescript": ["fumadocs-typescript@4.0.14", "", { "dependencies": { "estree-util-value-to-estree": "^3.5.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "remark": "^15.0.1", "remark-rehype": "^11.1.2", "tinyglobby": "^0.2.15", "ts-morph": "^27.0.2", "unist-util-visit": "^5.0.0" }, "peerDependencies": { "@types/react": "*", "fumadocs-core": "^15.7.0 || ^16.0.0", "fumadocs-ui": "^15.7.0 || ^16.0.0", "typescript": "*" }, "optionalPeers": ["@types/react", "fumadocs-ui"] }, "sha512-Jx2ldrFP2jEKUeczHuj1OCaCXNxJbVX/bseYaGA3+DY5BK0otaozfs2bJK75TfbGPF3grAZdSe+0KGP1DOTYqQ=="], + + "fumadocs-ui": ["fumadocs-ui@16.7.10", "", { "dependencies": { "@fumadocs/tailwind": "0.0.3", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-direction": "^1.1.1", "@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-presence": "^1.1.5", "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", "class-variance-authority": "^0.7.1", "lucide-react": "^1.7.0", "motion": "^12.38.0", "next-themes": "^0.4.6", "react-medium-image-zoom": "^5.4.1", "react-remove-scroll": "^2.7.2", "rehype-raw": "^7.0.0", "scroll-into-view-if-needed": "^3.1.0", "tailwind-merge": "^3.5.0", "unist-util-visit": "^5.1.0" }, "peerDependencies": { "@takumi-rs/image-response": "*", "@types/mdx": "*", "@types/react": "*", "fumadocs-core": "16.7.10", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "shiki": "*" }, "optionalPeers": ["@takumi-rs/image-response", "@types/mdx", "@types/react", "next", "shiki"] }, "sha512-QJD007wuavYgjh057Q6KgTS8tNPV060QpaitEJxxaUAzJRHEDRnRal1eHpCF5hEYgaM1Ah8DuLlYIDE9HwTt6A=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="], + + "hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="], + + "hast-util-raw": ["hast-util-raw@9.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "hast-util-from-parse5": "^8.0.0", "hast-util-to-parse5": "^8.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "parse5": "^7.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw=="], + + "hast-util-to-estree": ["hast-util-to-estree@3.1.3", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-attach-comments": "^3.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w=="], + + "hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="], + + "hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="], + + "hast-util-to-parse5": ["hast-util-to-parse5@8.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA=="], + + "hast-util-to-string": ["hast-util-to-string@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A=="], + + "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], + + "hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="], + + "headroom-ai": ["headroom-ai@file:../sdk/typescript", { "devDependencies": { "@ai-sdk/anthropic": "^3.0.64", "@ai-sdk/openai": "^3.0.48", "@ai-sdk/provider": "^1.0.0", "@anthropic-ai/sdk": "^0.39.0", "ai": "^6.0.0", "dotenv": "^17.3.1", "openai": "^4.80.0", "tsup": "^8.0.0", "typescript": "^5.5.0", "vitest": "^2.0.0" }, "peerDependencies": { "@ai-sdk/provider": ">=1.0.0", "@anthropic-ai/sdk": ">=0.30.0", "ai": ">=6.0.0", "openai": ">=4.0.0" }, "optionalPeers": ["@ai-sdk/provider", "@anthropic-ai/sdk", "ai", "openai"] }], + + "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], + + "humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], + + "image-size": ["image-size@2.0.2", "", { "bin": { "image-size": "bin/image-size.js" } }, "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w=="], + + "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], + + "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], + + "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], + + "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], + + "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], + + "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], + + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + + "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], + + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + + "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], + + "json-schema-to-ts": ["json-schema-to-ts@3.1.1", "", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="], + + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + + "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], + + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], + + "load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="], + + "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], + + "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], + + "lucide-react": ["lucide-react@1.7.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-yI7BeItCLZJTXikmK4KNUGCKoGzSvbKlfCvw44bU4fXAL6v3gYS4uHD1jzsLkfwODYwI6Drw5Tu9Z5ulDe0TSg=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="], + + "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="], + + "mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.3", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q=="], + + "mdast-util-gfm": ["mdast-util-gfm@3.1.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", "mdast-util-gfm-footnote": "^2.0.0", "mdast-util-gfm-strikethrough": "^2.0.0", "mdast-util-gfm-table": "^2.0.0", "mdast-util-gfm-task-list-item": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ=="], + + "mdast-util-gfm-autolink-literal": ["mdast-util-gfm-autolink-literal@2.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-find-and-replace": "^3.0.0", "micromark-util-character": "^2.0.0" } }, "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ=="], + + "mdast-util-gfm-footnote": ["mdast-util-gfm-footnote@2.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0" } }, "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ=="], + + "mdast-util-gfm-strikethrough": ["mdast-util-gfm-strikethrough@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg=="], + + "mdast-util-gfm-table": ["mdast-util-gfm-table@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg=="], + + "mdast-util-gfm-task-list-item": ["mdast-util-gfm-task-list-item@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ=="], + + "mdast-util-mdx": ["mdast-util-mdx@3.0.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w=="], + + "mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="], + + "mdast-util-mdx-jsx": ["mdast-util-mdx-jsx@3.2.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q=="], + + "mdast-util-mdxjs-esm": ["mdast-util-mdxjs-esm@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg=="], + + "mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="], + + "mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="], + + "mdast-util-to-markdown": ["mdast-util-to-markdown@2.1.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA=="], + + "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], + + "mgrs": ["mgrs@1.0.0", "", {}, "sha512-awNbTOqCxK1DBGjalK3xqWIstBZgN6fxsMSiXLs9/spqWkF2pAhb2rrYCFSsr1/tT7PhcDGjZndG8SWYn0byYA=="], + + "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], + + "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], + + "micromark-extension-gfm": ["micromark-extension-gfm@3.0.0", "", { "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", "micromark-extension-gfm-strikethrough": "^2.0.0", "micromark-extension-gfm-table": "^2.0.0", "micromark-extension-gfm-tagfilter": "^2.0.0", "micromark-extension-gfm-task-list-item": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w=="], + + "micromark-extension-gfm-autolink-literal": ["micromark-extension-gfm-autolink-literal@2.1.0", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw=="], + + "micromark-extension-gfm-footnote": ["micromark-extension-gfm-footnote@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw=="], + + "micromark-extension-gfm-strikethrough": ["micromark-extension-gfm-strikethrough@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw=="], + + "micromark-extension-gfm-table": ["micromark-extension-gfm-table@2.1.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg=="], + + "micromark-extension-gfm-tagfilter": ["micromark-extension-gfm-tagfilter@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg=="], + + "micromark-extension-gfm-task-list-item": ["micromark-extension-gfm-task-list-item@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw=="], + + "micromark-extension-mdx-expression": ["micromark-extension-mdx-expression@3.0.1", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q=="], + + "micromark-extension-mdx-jsx": ["micromark-extension-mdx-jsx@3.0.2", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ=="], + + "micromark-extension-mdx-md": ["micromark-extension-mdx-md@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ=="], + + "micromark-extension-mdxjs": ["micromark-extension-mdxjs@3.0.0", "", { "dependencies": { "acorn": "^8.0.0", "acorn-jsx": "^5.0.0", "micromark-extension-mdx-expression": "^3.0.0", "micromark-extension-mdx-jsx": "^3.0.0", "micromark-extension-mdx-md": "^2.0.0", "micromark-extension-mdxjs-esm": "^3.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ=="], + + "micromark-extension-mdxjs-esm": ["micromark-extension-mdxjs-esm@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-position-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A=="], + + "micromark-factory-destination": ["micromark-factory-destination@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA=="], + + "micromark-factory-label": ["micromark-factory-label@2.0.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg=="], + + "micromark-factory-mdx-expression": ["micromark-factory-mdx-expression@2.0.3", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-position-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ=="], + + "micromark-factory-space": ["micromark-factory-space@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg=="], + + "micromark-factory-title": ["micromark-factory-title@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw=="], + + "micromark-factory-whitespace": ["micromark-factory-whitespace@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ=="], + + "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], + + "micromark-util-chunked": ["micromark-util-chunked@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA=="], + + "micromark-util-classify-character": ["micromark-util-classify-character@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q=="], + + "micromark-util-combine-extensions": ["micromark-util-combine-extensions@2.0.1", "", { "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg=="], + + "micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@2.0.2", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw=="], + + "micromark-util-decode-string": ["micromark-util-decode-string@2.0.1", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ=="], + + "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="], + + "micromark-util-events-to-acorn": ["micromark-util-events-to-acorn@2.0.3", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg=="], + + "micromark-util-html-tag-name": ["micromark-util-html-tag-name@2.0.1", "", {}, "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA=="], + + "micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q=="], + + "micromark-util-resolve-all": ["micromark-util-resolve-all@2.0.1", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg=="], + + "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="], + + "micromark-util-subtokenize": ["micromark-util-subtokenize@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA=="], + + "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="], + + "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], + + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="], + + "motion": ["motion@12.38.0", "", { "dependencies": { "framer-motion": "^12.38.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w=="], + + "motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="], + + "motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "next": ["next@16.2.2", "", { "dependencies": { "@next/env": "16.2.2", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.2.2", "@next/swc-darwin-x64": "16.2.2", "@next/swc-linux-arm64-gnu": "16.2.2", "@next/swc-linux-arm64-musl": "16.2.2", "@next/swc-linux-x64-gnu": "16.2.2", "@next/swc-linux-x64-musl": "16.2.2", "@next/swc-win32-arm64-msvc": "16.2.2", "@next/swc-win32-x64-msvc": "16.2.2", "sharp": "^0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-i6AJdyVa4oQjyvX/6GeER8dpY/xlIV+4NMv/svykcLtURJSy/WzDnnUk/TM4d0uewFHK7xSQz4TbIwPgjky+3A=="], + + "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], + + "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], + + "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + + "npm-to-yarn": ["npm-to-yarn@3.0.1", "", {}, "sha512-tt6PvKu4WyzPwWUzy/hvPFqn+uwXO0K1ZHka8az3NnrhWJDmSqI8ncWq0fkL0k/lmmi5tAC11FXwXuh0rFbt1A=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "oniguruma-parser": ["oniguruma-parser@0.12.1", "", {}, "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w=="], + + "oniguruma-to-es": ["oniguruma-to-es@4.3.5", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, "sha512-Zjygswjpsewa0NLTsiizVuMQZbp0MDyM6lIt66OxsF21npUDlzpHi1Mgb/qhQdkb+dWFTzJmFbEWdvZgRho8eQ=="], + + "openai": ["openai@6.33.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-xAYN1W3YsDXJWA5F277135YfkEk6H7D3D6vWwRhJ3OEkzRgcyK8z/P5P9Gyi/wB4N8kK9kM5ZjprfvyHagKmpw=="], + + "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], + + "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + + "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], + + "path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], + + "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], + + "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + + "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + + "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + + "point-in-polygon-hao": ["point-in-polygon-hao@1.2.4", "", { "dependencies": { "robust-predicates": "^3.0.2" } }, "sha512-x2pcvXeqhRHlNRdhLs/tgFapAbSSe86wa/eqmj1G6pWftbEs5aVRJhRGM6FYSUERKu0PjekJzMq0gsI2XyiclQ=="], + + "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], + + "postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="], + + "postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="], + + "proj4": ["proj4@2.20.8", "", { "dependencies": { "mgrs": "1.0.0", "wkt-parser": "^1.5.5" } }, "sha512-1C8sfT4xY4PAPwk0MroFBTGF4R4bzDXdmPQTGYVLsoNssrZ9odzObxS2dTeGBty8jW8KO7h16C1Hs2JP+ctfFw=="], + + "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], + + "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], + + "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="], + + "react-medium-image-zoom": ["react-medium-image-zoom@5.4.3", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-cDIwdn35fRUPsGnnj/cG6Pacll+z+Mfv6EWU2wDO5ngbZjg5uLRb2ZhEnh92ufbXCJDFvXHekb8G3+oKqUcv5g=="], + + "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], + + "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], + + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], + + "readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], + + "recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-build-jsx": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="], + + "recma-jsx": ["recma-jsx@1.0.1", "", { "dependencies": { "acorn-jsx": "^5.0.0", "estree-util-to-js": "^2.0.0", "recma-parse": "^1.0.0", "recma-stringify": "^1.0.0", "unified": "^11.0.0" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w=="], + + "recma-parse": ["recma-parse@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "esast-util-from-js": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ=="], + + "recma-stringify": ["recma-stringify@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-to-js": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g=="], + + "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="], + + "regex-recursion": ["regex-recursion@6.0.2", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg=="], + + "regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="], + + "rehype-raw": ["rehype-raw@7.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", "vfile": "^6.0.0" } }, "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww=="], + + "rehype-recma": ["rehype-recma@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "hast-util-to-estree": "^3.0.0" } }, "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw=="], + + "remark": ["remark@15.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A=="], + + "remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="], + + "remark-mdx": ["remark-mdx@3.1.1", "", { "dependencies": { "mdast-util-mdx": "^3.0.0", "micromark-extension-mdxjs": "^3.0.0" } }, "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg=="], + + "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="], + + "remark-rehype": ["remark-rehype@11.1.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw=="], + + "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], + + "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + + "robust-predicates": ["robust-predicates@3.0.3", "", {}, "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA=="], + + "rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="], + + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], + + "scroll-into-view-if-needed": ["scroll-into-view-if-needed@3.1.0", "", { "dependencies": { "compute-scroll-into-view": "^3.0.2" } }, "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ=="], + + "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + + "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], + + "shiki": ["shiki@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/engine-javascript": "4.0.2", "@shikijs/engine-oniguruma": "4.0.2", "@shikijs/langs": "4.0.2", "@shikijs/themes": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ=="], + + "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], + + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + + "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], + + "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], + + "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], + + "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], + + "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], + + "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], + + "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="], + + "tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="], + + "tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="], + + "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="], + + "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], + + "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], + + "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], + + "tinyexec": ["tinyexec@1.0.4", "", {}, "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="], + + "tinyrainbow": ["tinyrainbow@1.2.0", "", {}, "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ=="], + + "tinyspy": ["tinyspy@3.0.2", "", {}, "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q=="], + + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], + + "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], + + "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], + + "ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="], + + "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], + + "ts-morph": ["ts-morph@27.0.2", "", { "dependencies": { "@ts-morph/common": "~0.28.1", "code-block-writer": "^13.0.3" } }, "sha512-fhUhgeljcrdZ+9DZND1De1029PrE+cMkIP7ooqkLRTrRLTqcki2AstsyJm0vRNbTbVCNJ0idGlbBrfqc7/nA8w=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "tsup": ["tsup@8.5.1", "", { "dependencies": { "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.27.0", "fix-dts-default-cjs-exports": "^1.0.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.34.8", "source-map": "^0.7.6", "sucrase": "^3.35.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing=="], + + "twoslash": ["twoslash@0.3.6", "", { "dependencies": { "@typescript/vfs": "^1.6.2", "twoslash-protocol": "0.3.6" }, "peerDependencies": { "typescript": "^5.5.0" } }, "sha512-VuI5OKl+MaUO9UIW3rXKoPgHI3X40ZgB/j12VY6h98Ae1mCBihjPvhOPeJWlxCYcmSbmeZt5ZKkK0dsVtp+6pA=="], + + "twoslash-protocol": ["twoslash-protocol@0.3.6", "", {}, "sha512-FHGsJ9Q+EsNr5bEbgG3hnbkvEBdW5STgPU824AHUjB4kw0Dn4p8tABT7Ncg1Ie6V0+mDg3Qpy41VafZXcQhWMA=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + + "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], + + "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], + + "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="], + + "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="], + + "unist-util-position-from-estree": ["unist-util-position-from-estree@2.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ=="], + + "unist-util-remove-position": ["unist-util-remove-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q=="], + + "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="], + + "unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="], + + "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], + + "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], + + "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], + + "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="], + + "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], + + "vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="], + + "vite-node": ["vite-node@2.1.9", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.3.7", "es-module-lexer": "^1.5.4", "pathe": "^1.1.2", "vite": "^5.0.0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA=="], + + "vitest": ["vitest@2.1.9", "", { "dependencies": { "@vitest/expect": "2.1.9", "@vitest/mocker": "2.1.9", "@vitest/pretty-format": "^2.1.9", "@vitest/runner": "2.1.9", "@vitest/snapshot": "2.1.9", "@vitest/spy": "2.1.9", "@vitest/utils": "2.1.9", "chai": "^5.1.2", "debug": "^4.3.7", "expect-type": "^1.1.0", "magic-string": "^0.30.12", "pathe": "^1.1.2", "std-env": "^3.8.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.1", "tinypool": "^1.0.1", "tinyrainbow": "^1.2.0", "vite": "^5.0.0", "vite-node": "2.1.9", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", "@vitest/browser": "2.1.9", "@vitest/ui": "2.1.9", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q=="], + + "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], + + "web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="], + + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + + "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + + "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], + + "wkt-parser": ["wkt-parser@1.5.5", "", {}, "sha512-/zMYi94/7D7fxcOSlVmWn6vnOMj3Gq5d1xvVjaYOS9n6h0qOJ4I7YYVxBWYcH1vq9+suhqzXkn05Yx47zQNUIA=="], + + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + + "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], + + "@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-popover/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.2", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw=="], + + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "headroom-ai/@ai-sdk/provider": ["@ai-sdk/provider@1.1.3", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg=="], + + "headroom-ai/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.39.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-eMyDIPRZbt1CCLErRCi3exlAvNkBtRe+kW5vvJyef93PmNr/clstYgHhtvmkxN82nlKgzyGPCyGxrm0JQ1ZIdg=="], + + "headroom-ai/openai": ["openai@4.104.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" }, "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA=="], + + "mlly/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], + + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + + "pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "tsup/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + + "tsup/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + + "vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], + + "vitest/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + + "headroom-ai/@anthropic-ai/sdk/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], + + "headroom-ai/openai/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], + + "tsup/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + + "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], + + "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], + + "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], + + "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], + + "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], + + "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], + + "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], + + "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], + + "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], + + "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], + + "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], + + "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], + + "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], + + "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], + + "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], + + "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], + + "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], + + "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], + + "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], + + "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], + + "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], + + "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], + + "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], + + "headroom-ai/@anthropic-ai/sdk/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], + + "headroom-ai/openai/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], + } +} diff --git a/docs/components/button.tsx b/docs/components/button.tsx new file mode 100644 index 000000000..c214fbca5 --- /dev/null +++ b/docs/components/button.tsx @@ -0,0 +1,59 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; +import { cn } from "@/lib/cn"; + +const buttonVariants = cva( + "cursor-pointer active:scale-99 duration-200 font-medium inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full text-sm font-medium focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: "bg-foreground text-background hover:brightness-95", + neutral: "bg-foreground text-background hover:brightness-95", + destructive: + "bg-destructive text-destructive-foreground shadow-md hover:bg-destructive/90", + outline: + "shadow-sm text-foreground shadow-black/6.5 border border-transparent bg-card ring-1 ring-foreground/15 duration-200 hover:bg-muted/50", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-foreground/5 text-foreground/75 hover:text-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-8 px-3 py-2", + sm: "h-7 px-2.5 text-sm", + lg: "h-11 px-6 font-medium text-base", + icon: "size-9", + "icon-sm": "size-7", + "icon-xs": "size-5", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +export interface ButtonProps + extends + React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + }, +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/docs/components/code-block.tsx b/docs/components/code-block.tsx new file mode 100644 index 000000000..4f85304bd --- /dev/null +++ b/docs/components/code-block.tsx @@ -0,0 +1,12 @@ +interface CodeBlockProps { + code: string; + lang?: string; +} + +export function CodeBlock({ code }: CodeBlockProps) { + return ( +
+      {code}
+    
+ ); +} diff --git a/docs/components/community-charts.tsx b/docs/components/community-charts.tsx new file mode 100644 index 000000000..8887126c0 --- /dev/null +++ b/docs/components/community-charts.tsx @@ -0,0 +1,346 @@ +'use client' + +import { useState } from 'react' +import { + AreaChart, Area, BarChart, Bar, + XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid, +} from 'recharts' + +// --- Embedded telemetry data --- +const DATA = { + total_tokens_saved: 41750654085, + total_cost_saved: 176635.62, + total_requests: 1194154, + unique_instances: 889, + active_days: 14, + daily_stats: [ + { date: '2026-03-30', requests: 1050, instances: 17, cost_saved: 42.29, tokens_saved: 7560502 }, + { date: '2026-03-31', requests: 26526, instances: 149, cost_saved: 1904.15, tokens_saved: 1004245860 }, + { date: '2026-04-01', requests: 53480, instances: 117, cost_saved: 3353.50, tokens_saved: 860455498 }, + { date: '2026-04-02', requests: 64906, instances: 123, cost_saved: 18007.10, tokens_saved: 3431477414 }, + { date: '2026-04-03', requests: 99872, instances: 162, cost_saved: 29238.20, tokens_saved: 6159073542 }, + { date: '2026-04-04', requests: 90992, instances: 147, cost_saved: 12863.30, tokens_saved: 1864667449 }, + { date: '2026-04-05', requests: 162541, instances: 142, cost_saved: 49802.60, tokens_saved: 11990261722 }, + { date: '2026-04-06', requests: 127494, instances: 174, cost_saved: 11533.70, tokens_saved: 3850552409 }, + { date: '2026-04-07', requests: 158840, instances: 201, cost_saved: 14260.90, tokens_saved: 4113326538 }, + { date: '2026-04-08', requests: 84459, instances: 186, cost_saved: 8383.12, tokens_saved: 2317153362 }, + { date: '2026-04-09', requests: 137856, instances: 208, cost_saved: 10663.80, tokens_saved: 2058570508 }, + { date: '2026-04-10', requests: 111043, instances: 192, cost_saved: 9893.92, tokens_saved: 1979992305 }, + { date: '2026-04-11', requests: 65851, instances: 147, cost_saved: 5853.92, tokens_saved: 1521911387 }, + { date: '2026-04-12', requests: 9244, instances: 27, cost_saved: 835.12, tokens_saved: 591405589 }, + ], + hourly_stats: [ + { hour: '2026-04-10 06:00', requests: 8548, instances: 9, cost_saved: 577.12, tokens_saved: 198669219 }, + { hour: '2026-04-10 07:00', requests: 8289, instances: 18, cost_saved: 456.34, tokens_saved: 172834374 }, + { hour: '2026-04-10 08:00', requests: 8066, instances: 23, cost_saved: 559.56, tokens_saved: 196181344 }, + { hour: '2026-04-10 09:00', requests: 4890, instances: 16, cost_saved: 206.95, tokens_saved: 124914685 }, + { hour: '2026-04-10 10:00', requests: 9531, instances: 21, cost_saved: 421.51, tokens_saved: 236470420 }, + { hour: '2026-04-10 11:00', requests: 5170, instances: 13, cost_saved: 174.45, tokens_saved: 114113494 }, + { hour: '2026-04-10 12:00', requests: 10982, instances: 20, cost_saved: 388.05, tokens_saved: 166308102 }, + { hour: '2026-04-10 13:00', requests: 8001, instances: 16, cost_saved: 228.53, tokens_saved: 134921875 }, + { hour: '2026-04-10 14:00', requests: 4950, instances: 15, cost_saved: 208.56, tokens_saved: 119763470 }, + { hour: '2026-04-10 15:00', requests: 9000, instances: 17, cost_saved: 1739.51, tokens_saved: 166911747 }, + { hour: '2026-04-10 16:00', requests: 12569, instances: 17, cost_saved: 1130.82, tokens_saved: 312958735 }, + { hour: '2026-04-10 17:00', requests: 12057, instances: 17, cost_saved: 443.07, tokens_saved: 203763560 }, + { hour: '2026-04-10 18:00', requests: 14011, instances: 18, cost_saved: 1018.06, tokens_saved: 294928335 }, + { hour: '2026-04-10 19:00', requests: 12599, instances: 17, cost_saved: 915.21, tokens_saved: 327535343 }, + { hour: '2026-04-10 20:00', requests: 10522, instances: 16, cost_saved: 2484.87, tokens_saved: 206735552 }, + { hour: '2026-04-10 21:00', requests: 7125, instances: 16, cost_saved: 928.27, tokens_saved: 289265979 }, + { hour: '2026-04-10 22:00', requests: 4481, instances: 9, cost_saved: 190.60, tokens_saved: 137301814 }, + { hour: '2026-04-10 23:00', requests: 4033, instances: 5, cost_saved: 154.82, tokens_saved: 126989500 }, + { hour: '2026-04-11 00:00', requests: 8998, instances: 12, cost_saved: 770.90, tokens_saved: 254824094 }, + { hour: '2026-04-11 01:00', requests: 13729, instances: 12, cost_saved: 668.12, tokens_saved: 330717273 }, + { hour: '2026-04-11 02:00', requests: 3738, instances: 2, cost_saved: 152.18, tokens_saved: 126547280 }, + { hour: '2026-04-11 03:00', requests: 4449, instances: 4, cost_saved: 185.03, tokens_saved: 134597314 }, + { hour: '2026-04-11 04:00', requests: 5961, instances: 9, cost_saved: 303.65, tokens_saved: 157734893 }, + { hour: '2026-04-11 05:00', requests: 6550, instances: 8, cost_saved: 248.84, tokens_saved: 158834743 }, + { hour: '2026-04-11 06:00', requests: 5429, instances: 8, cost_saved: 268.11, tokens_saved: 155129772 }, + { hour: '2026-04-11 07:00', requests: 5671, instances: 11, cost_saved: 225.25, tokens_saved: 143244185 }, + { hour: '2026-04-11 08:00', requests: 7258, instances: 12, cost_saved: 264.80, tokens_saved: 158618368 }, + { hour: '2026-04-11 09:00', requests: 8732, instances: 7, cost_saved: 301.46, tokens_saved: 157720064 }, + { hour: '2026-04-11 10:00', requests: 6058, instances: 6, cost_saved: 230.22, tokens_saved: 155936384 }, + { hour: '2026-04-11 11:00', requests: 7615, instances: 13, cost_saved: 444.21, tokens_saved: 288328690 }, + { hour: '2026-04-11 12:00', requests: 6749, instances: 10, cost_saved: 716.35, tokens_saved: 542054609 }, + { hour: '2026-04-11 13:00', requests: 6276, instances: 10, cost_saved: 2259.74, tokens_saved: 572384133 }, + { hour: '2026-04-11 14:00', requests: 8858, instances: 16, cost_saved: 846.04, tokens_saved: 602153567 }, + { hour: '2026-04-11 15:00', requests: 9284, instances: 12, cost_saved: 811.16, tokens_saved: 581585147 }, + { hour: '2026-04-11 16:00', requests: 7390, instances: 16, cost_saved: 749.69, tokens_saved: 566925112 }, + { hour: '2026-04-11 17:00', requests: 11558, instances: 13, cost_saved: 1023.99, tokens_saved: 623709492 }, + { hour: '2026-04-11 18:00', requests: 6154, instances: 10, cost_saved: 709.22, tokens_saved: 546162461 }, + { hour: '2026-04-11 19:00', requests: 5711, instances: 11, cost_saved: 660.33, tokens_saved: 548094492 }, + { hour: '2026-04-11 20:00', requests: 9287, instances: 13, cost_saved: 800.20, tokens_saved: 575078608 }, + { hour: '2026-04-11 21:00', requests: 5858, instances: 9, cost_saved: 675.77, tokens_saved: 547657183 }, + { hour: '2026-04-11 22:00', requests: 5523, instances: 13, cost_saved: 1133.82, tokens_saved: 638333840 }, + { hour: '2026-04-11 23:00', requests: 7668, instances: 8, cost_saved: 903.46, tokens_saved: 592286174 }, + { hour: '2026-04-12 00:00', requests: 5723, instances: 9, cost_saved: 655.44, tokens_saved: 543699655 }, + { hour: '2026-04-12 01:00', requests: 5291, instances: 8, cost_saved: 673.29, tokens_saved: 552129148 }, + { hour: '2026-04-12 02:00', requests: 6689, instances: 9, cost_saved: 698.83, tokens_saved: 551696076 }, + { hour: '2026-04-12 03:00', requests: 6532, instances: 8, cost_saved: 749.06, tokens_saved: 569436595 }, + { hour: '2026-04-12 04:00', requests: 4805, instances: 3, cost_saved: 644.29, tokens_saved: 540846848 }, + { hour: '2026-04-12 05:00', requests: 5181, instances: 6, cost_saved: 642.90, tokens_saved: 539173642 }, + { hour: '2026-04-12 06:00', requests: 4739, instances: 1, cost_saved: 637.17, tokens_saved: 537999942 }, + ], + top_instances: [ + { os: 'Windows', version: '0.5.18', cost_saved: 36325.40, instance_id: '1d5d8ed0', tokens_saved: 8852060567 }, + { os: 'Linux', version: '0.5.19', cost_saved: 2188.80, instance_id: '96d9632f', tokens_saved: 2395311403 }, + { os: 'Windows', version: '0.5.17', cost_saved: 11878.30, instance_id: '1e850cb3', tokens_saved: 2375786993 }, + { os: 'Windows', version: '0.5.17', cost_saved: 9080.36, instance_id: '0cdfb8e9', tokens_saved: 1816351278 }, + { os: 'Linux', version: '0.5.18', cost_saved: 7580.30, instance_id: '7456b0f9', tokens_saved: 1635744469 }, + { os: 'Darwin', version: '0.5.16', cost_saved: 1772.99, instance_id: '1661b732', tokens_saved: 1488844495 }, + { os: 'Darwin', version: '0.5.17', cost_saved: 4667.23, instance_id: '08bf5ae1', tokens_saved: 933450700 }, + { os: 'Darwin', version: '0.5.18', cost_saved: 0, instance_id: 'e20f01b6', tokens_saved: 565038755 }, + { os: 'Linux', version: '0.5.18', cost_saved: 538.37, instance_id: '5b0795b2', tokens_saved: 557489086 }, + { os: 'Windows', version: '0.5.18', cost_saved: 1773.69, instance_id: 'eff9e644', tokens_saved: 503362483 }, + { os: 'Windows', version: '0.5.18', cost_saved: 1812.66, instance_id: '388102c7', tokens_saved: 485305324 }, + { os: 'Linux', version: '0.5.17', cost_saved: 2297.45, instance_id: '3ee70444', tokens_saved: 468622655 }, + { os: 'Darwin', version: '0.5.16', cost_saved: 319.65, instance_id: '6e758d1e', tokens_saved: 437502391 }, + { os: 'Linux', version: '0.5.18', cost_saved: 1461.02, instance_id: 'b2e71a28', tokens_saved: 415224504 }, + { os: 'Darwin', version: '0.5.21', cost_saved: 509.44, instance_id: '8b3795aa', tokens_saved: 353583838 }, + { os: 'Linux', version: '0.5.17', cost_saved: 1663.48, instance_id: 'b6a1a735', tokens_saved: 334438796 }, + { os: 'Linux', version: '0.5.21', cost_saved: 1603.77, instance_id: 'd0c16fa0', tokens_saved: 322890921 }, + { os: 'Linux', version: '0.5.18', cost_saved: 1580.12, instance_id: '4140eb00', tokens_saved: 316804284 }, + { os: 'Darwin', version: '0.5.21', cost_saved: 1052.77, instance_id: '2b11b55c', tokens_saved: 308601543 }, + { os: 'Darwin', version: '0.5.17', cost_saved: 1473.78, instance_id: '1ede777b', tokens_saved: 296950447 }, + ], +} + +// --- Formatters --- + +function fmt(n: number): string { + if (n >= 1e9) return `${(n / 1e9).toFixed(1)}B` + if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M` + if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K` + return n.toFixed(0) +} + +function fmtUsd(n: number): string { + if (n >= 1e3) return `$${(n / 1e3).toFixed(1)}K` + return `$${n.toFixed(0)}` +} + +const MONTHS = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] + +function fmtDateDaily(d: string): string { + const [, m, day] = d.split('-') + return `${MONTHS[parseInt(m, 10) - 1]} ${parseInt(day, 10)}` +} + +function fmtDateHourly(d: string): string { + // "2026-04-10 06:00" → "Apr 10 6am" + const [date, time] = d.split(' ') + const [, m, day] = date.split('-') + const hour = parseInt(time.split(':')[0], 10) + const ampm = hour >= 12 ? 'pm' : 'am' + const h12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour + return `${MONTHS[parseInt(m, 10) - 1]} ${parseInt(day, 10)} ${h12}${ampm}` +} + +// --- Components --- + +const PURPLE = 'hsl(262, 52%, 56%)' +const PURPLE_LIGHT = 'hsl(262, 60%, 65%)' + +type Metric = 'cost_saved' | 'requests' | 'tokens_saved' +type TimeRange = 'daily' | 'hourly' + +function ToggleButton({ active, onClick, children }: { active: boolean; onClick: () => void; children: React.ReactNode }) { + return ( + + ) +} + +function CustomTooltip({ active, payload, label }: any) { + if (!active || !payload?.length) return null + return ( +
+

{label}

+ {payload.map((p: any) => ( +

+ {p.dataKey === 'cost_saved' ? fmtUsd(p.value) : fmt(p.value)} +

+ ))} +
+ ) +} + +function StatsCards() { + return ( +
+ {[ + { label: 'Cost Saved', value: fmtUsd(DATA.total_cost_saved) }, + { label: 'Requests Optimized', value: fmt(DATA.total_requests) }, + { label: 'Active Instances', value: fmt(DATA.unique_instances) }, + { label: 'Active Days', value: String(DATA.active_days) }, + ].map(s => ( +
+ {s.value} + {s.label} +
+ ))} +
+ ) +} + +function AreaChartSection() { + const [metric, setMetric] = useState('tokens_saved') + const [timeRange, setTimeRange] = useState('hourly') + + const isHourly = timeRange === 'hourly' + const chartData: { label: string; requests: number; instances: number; cost_saved: number; tokens_saved: number }[] = !isHourly + ? DATA.daily_stats.map(d => ({ label: fmtDateDaily(d.date), requests: d.requests, instances: d.instances, cost_saved: d.cost_saved, tokens_saved: d.tokens_saved })) + : DATA.hourly_stats.map(d => ({ label: fmtDateHourly(d.hour), requests: d.requests, instances: d.instances, cost_saved: d.cost_saved, tokens_saved: d.tokens_saved })) + + const metricLabels: Record = { + cost_saved: 'Cost Saved', + requests: 'Requests', + tokens_saved: 'Tokens Saved', + } + + const tickFormatter = (v: number) => + metric === 'cost_saved' ? fmtUsd(v) : fmt(v) + + return ( +
+
+
+ {(['cost_saved', 'requests', 'tokens_saved'] as Metric[]).map(m => ( + setMetric(m)}> + {metricLabels[m]} + + ))} +
+
+ {(['hourly', 'daily'] as TimeRange[]).map(t => ( + setTimeRange(t)}> + {t === 'hourly' ? 'Last 48h' : 'Daily'} + + ))} +
+
+
+ + + + + + + + + + + + } /> + + + +
+
+ ) +} + +function BarChartSection() { + const barData = DATA.top_instances.slice(0, 10).map(i => ({ + name: `${i.instance_id} (${i.os})`, + tokens_saved: i.tokens_saved, + cost_saved: i.cost_saved, + })) + + return ( +
+
+ + + + + + { + if (!active || !payload?.length) return null + const d = payload[0].payload + return ( +
+

{d.name}

+

{fmt(d.tokens_saved)} tokens

+

{fmtUsd(d.cost_saved)} saved

+
+ ) + }} /> + +
+
+
+
+ ) +} + +function DataTable() { + return ( +
+
+ + + + + + + + + + + + {DATA.top_instances.map((inst, i) => ( + + + + + + + + ))} + +
InstanceOSVersionTokens SavedCost Saved
{inst.instance_id}{inst.os}{inst.version}{fmt(inst.tokens_saved)}{fmtUsd(inst.cost_saved)}
+
+
+ ) +} + +export function CommunityCharts({ section }: { section?: 'stats' | 'area' | 'bar' | 'table' }) { + if (section === 'stats') return + if (section === 'area') return + if (section === 'bar') return + if (section === 'table') return + + // Render all if no section specified + return ( +
+ + + + +
+ ) +} diff --git a/docs/components/map.tsx b/docs/components/map.tsx new file mode 100644 index 000000000..71be66f04 --- /dev/null +++ b/docs/components/map.tsx @@ -0,0 +1,95 @@ +'use client' +import DottedMap from 'dotted-map' +import { useEffect, useState } from 'react' + +const pins = [ + { lat: 40.73061, lng: -73.935242 }, + { lat: 48.8534, lng: 2.3488 }, + { lat: 51.5074, lng: -0.1278 }, + { lat: 35.6895, lng: 139.6917 }, + { lat: 34.0522, lng: -118.2437 }, + { lat: 55.7558, lng: 37.6173 }, + { lat: 39.9042, lng: 116.4074 }, + { lat: 19.4326, lng: -99.1332 }, + { lat: 37.7749, lng: -122.4194 }, + { lat: -33.8688, lng: 151.2093 }, + { lat: 28.6139, lng: 77.209 }, + { lat: 52.52, lng: 13.405 }, + { lat: 41.9028, lng: 12.4964 }, + { lat: 43.65107, lng: -79.347015 }, + { lat: -23.55052, lng: -46.633308 }, + { lat: 31.2304, lng: 121.4737 }, + { lat: 55.9533, lng: -3.1883 }, + { lat: 35.6762, lng: 139.6503 }, + { lat: 1.3521, lng: 103.8198 }, + { lat: 37.5665, lng: 126.978 }, + { lat: 53.3498, lng: -6.2603 }, + { lat: 30.0444, lng: 31.2357 }, + { lat: 50.4501, lng: 30.5234 }, + { lat: -34.6037, lng: -58.3816 }, + { lat: 59.9343, lng: 30.3351 }, + { lat: 25.276987, lng: 55.296249 }, + { lat: 45.4642, lng: 9.19 }, + { lat: -22.9068, lng: -43.1729 }, + { lat: 40.4168, lng: -3.7038 }, + { lat: 41.3851, lng: 2.1734 }, + { lat: 13.7563, lng: 100.5018 }, + { lat: 52.3676, lng: 4.9041 }, + { lat: -37.8136, lng: 144.9631 }, + { lat: 60.1695, lng: 24.9354 }, + { lat: 47.4979, lng: 19.0402 }, + { lat: 59.3293, lng: 18.0686 }, + { lat: 35.9078, lng: 127.7669 }, + { lat: 46.2044, lng: 6.1432 }, + { lat: 29.7604, lng: -95.3698 }, + { lat: 39.7392, lng: -104.9903 }, + { lat: -11.6647, lng: 27.4794 }, + { lat: -10.7026, lng: 25.5122 }, + { lat: -4.4419, lng: 15.2663 }, +] + +function buildSvg(isDark: boolean) { + const map = new DottedMap({ height: 55, grid: 'diagonal' }) + + pins.forEach((pin) => { + map.addPin({ + ...pin, + svgOptions: { + color: isDark + ? '#a78bfa' // bright purple on #050505 + : '#7c3aed', // vivid purple on #FAFAFA + radius: 0.4, + }, + }) + }) + + return map.getSVG({ + radius: 0.22, + color: isDark + ? '#555555' // medium gray on #050505 + : '#a0a0a0', // medium gray on #FAFAFA + shape: 'circle', + backgroundColor: 'transparent', + }) +} + +export const Map = () => { + const [isDark, setIsDark] = useState(false) + + useEffect(() => { + const check = () => setIsDark(document.documentElement.classList.contains('dark')) + check() + const observer = new MutationObserver(check) + observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }) + return () => observer.disconnect() + }, []) + + const svgMap = buildSvg(isDark) + + return ( + map illustration + ) +} diff --git a/docs/components/marketing.tsx b/docs/components/marketing.tsx new file mode 100644 index 000000000..8b3c8f669 --- /dev/null +++ b/docs/components/marketing.tsx @@ -0,0 +1,224 @@ +import Link from 'next/link'; +import { Button } from './button'; +import { CodeBlock } from './code-block'; + +// --- Live Stats Grid --- + +const liveStats = [ + { value: '$176.6K', label: 'Cost Saved' }, + { value: '1.19M', label: 'Requests Optimized' }, + { value: '889', label: 'Active Instances' }, + { value: '14', label: 'Active Days' }, +]; + +export function LiveStats() { + return ( +
+
+ {liveStats.map((s) => ( +
+ + {s.value} + + + {s.label} + +
+ ))} +
+ + View detailed charts and breakdowns → + +
+ ); +} + +// --- Key Features Grid --- + +const features: { + title: string; + description: string; + href: string; + code?: string; + lang?: string; +}[] = [ + { + title: 'Lossless Compression (CCR)', + description: + 'Compresses aggressively, stores originals, gives the LLM a tool to retrieve full details. Nothing is thrown away.', + href: '/docs/ccr', + }, + { + title: 'Smart Content Detection', + description: + 'Auto-detects JSON, code, logs, text, diffs, HTML. Routes each to the best compressor. Zero configuration needed.', + href: '/docs/how-compression-works', + }, + { + title: 'Cache Optimization', + description: + "Stabilizes prefixes so provider KV caches hit. Tracks frozen messages to preserve the 90% read discount.", + href: '/docs/cache-optimization', + }, + { + title: 'Image Compression', + description: + '40-90% token reduction via trained ML router. Automatically selects resize/quality tradeoff per image.', + href: '/docs/image-compression', + }, + { + title: 'Persistent Memory', + description: + 'Hierarchical memory (user/session/agent/turn) with SQLite + HNSW backends. Survives across conversations.', + href: '/docs/memory', + }, + { + title: 'Failure Learning', + description: + 'Reads past sessions, finds failed tool calls, correlates with what succeeded, writes learnings to CLAUDE.md.', + href: '/docs/failure-learning', + }, + { + title: 'Multi-Agent Context', + description: 'Compress what moves between agents. Any framework.', + href: '/docs/shared-context', + code: 'ctx = SharedContext()\nctx.put("research", big_output)\nsummary = ctx.get("research")', + lang: 'python', + }, + { + title: 'Metrics & Observability', + description: + 'Prometheus endpoint, per-request logging, cost tracking, budget limits, pipeline timing breakdowns.', + href: '/docs/metrics', + }, +]; + +export async function KeyFeatures() { + return ( +
+ {await Promise.all( + features.map(async (f) => ( +
+

+ {f.title} +

+

+ {f.description} +

+ {f.code && } + + Learn more → + +
+ )), + )} +
+ ); +} + +// --- Framework Integrations Bento --- + +const integrations: { + title: string; + description: string; + code: string; + lang: string; + href: string; +}[] = [ + { + title: 'LangChain', + description: + 'Wrap any chat model. Supports memory, retrievers, tools, streaming, async.', + code: 'from headroom.integrations.langchain import HeadroomChatModel\nllm = HeadroomChatModel(ChatOpenAI())', + lang: 'python', + href: '/docs/langchain', + }, + { + title: 'Agno', + description: + 'Full agent framework integration with observability hooks.', + code: 'from headroom.integrations.agno import HeadroomAgnoModel\nmodel = HeadroomAgnoModel(Claude())\nagent = Agent(model=model)', + lang: 'python', + href: '/docs/agno', + }, + { + title: 'Strands', + description: + 'Model wrapping + tool output hook provider for Strands Agents.', + code: 'from headroom.integrations.strands import HeadroomStrandsModel\nmodel = HeadroomStrandsModel(...)\nagent = Agent(model=model)', + lang: 'python', + href: '/docs/strands', + }, + { + title: 'MCP Tools', + description: + 'Three tools for Claude Code, Cursor, or any MCP client: headroom_compress, headroom_retrieve, headroom_stats.', + code: 'headroom mcp install && claude', + lang: 'bash', + href: '/docs/mcp', + }, + { + title: 'TypeScript SDK', + description: + 'compress(), Vercel AI SDK middleware, OpenAI and Anthropic client wrappers.', + code: 'npm install headroom-ai', + lang: 'bash', + href: '/docs/vercel-ai-sdk', + }, + { + title: 'Vercel AI SDK', + description: + 'One-liner withHeadroom() or headroomMiddleware() for any Vercel AI SDK model.', + code: "import { withHeadroom } from 'headroom-ai/vercel-ai'\nconst model = withHeadroom(openai('gpt-4o'))", + lang: 'typescript', + href: '/docs/vercel-ai-sdk', + }, +]; + +export async function FrameworkIntegrations() { + return ( +
+
+ {await Promise.all( + integrations.map(async (i) => ( +
+

+ {i.title} +

+

+ {i.description} +

+ + + {i.title} Guide → + +
+ )), + )} +
+ +
+ ); +} diff --git a/docs/components/mdx.tsx b/docs/components/mdx.tsx new file mode 100644 index 000000000..8538c0904 --- /dev/null +++ b/docs/components/mdx.tsx @@ -0,0 +1,41 @@ +import defaultMdxComponents from 'fumadocs-ui/mdx'; +import type { MDXComponents } from 'mdx/types'; +import * as Twoslash from 'fumadocs-twoslash/ui'; +import { AutoTypeTable, type AutoTypeTableProps } from 'fumadocs-typescript/ui'; +import { createGenerator } from 'fumadocs-typescript'; +import { TypeTable } from 'fumadocs-ui/components/type-table'; +import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; +import { + LiveStats, + KeyFeatures, + FrameworkIntegrations, +} from './marketing'; +import { StatsSection } from './stats'; +import { CommunityCharts } from './community-charts'; + +const generator = createGenerator(); + +export function getMDXComponents(components?: MDXComponents) { + return { + ...defaultMdxComponents, + ...Twoslash, + AutoTypeTable: (props: Partial) => ( + + ), + TypeTable, + Tab, + Tabs, + StatsSection, + CommunityCharts, + LiveStats, + KeyFeatures, + FrameworkIntegrations, + ...components, + } satisfies MDXComponents; +} + +export const useMDXComponents = getMDXComponents; + +declare global { + type MDXProvidedComponents = ReturnType; +} diff --git a/docs/components/stats.tsx b/docs/components/stats.tsx new file mode 100644 index 000000000..2f53fbef0 --- /dev/null +++ b/docs/components/stats.tsx @@ -0,0 +1,71 @@ +import { Map } from '@/components/map' + +export function StatsSection() { + return ( +
+
+
+ +
+
+
+
+
+

+ The Context Optimization Layer for{' '} + + LLM Applications + +

+

+ Compress everything your AI agent reads.{' '} + + Same answers, fraction of the tokens. + +

+
+
+
+ + 87 % + +

+ + Token Reduction + +

+
+
+ + 100 % + +

+ + Accuracy + +

+
+
+ 6 +

+ + Algorithms + +

+
+
+ + 100 + + +

+ + Providers + +

+
+
+
+
+
+ ) +} diff --git a/docs/content/docs/agno.mdx b/docs/content/docs/agno.mdx new file mode 100644 index 000000000..292c30c69 --- /dev/null +++ b/docs/content/docs/agno.mdx @@ -0,0 +1,154 @@ +--- +title: Agno +description: Automatic context compression for Agno AI agents with model wrapping and observability hooks. +--- + +Headroom integrates with [Agno](https://github.com/agno-agi/agno) (formerly Phidata) to compress context for AI agents. Wrap any Agno model for automatic optimization, and use hooks for observability. + +## Installation + +```bash +pip install "headroom-ai[agno]" agno +``` + +## Quick start + +```python +from agno.agent import Agent +from agno.models.openai import OpenAIChat +from headroom.integrations.agno import HeadroomAgnoModel + +model = HeadroomAgnoModel(OpenAIChat(id="gpt-4o")) +agent = Agent(model=model) + +response = agent.run("What's the capital of France?") + +print(f"Tokens saved: {model.total_tokens_saved}") +print(model.get_savings_summary()) +# {'total_requests': 1, 'total_tokens_saved': 245, 'average_savings_percent': 12.3} +``` + +Works with any Agno provider: + +```python +from agno.models.anthropic import Claude +from agno.models.google import Gemini + +claude_model = HeadroomAgnoModel(Claude(id="claude-sonnet-4-20250514")) +gemini_model = HeadroomAgnoModel(Gemini(id="gemini-2.0-flash")) +``` + +## Observability hooks + +Use hooks for detailed tracking without modifying your model: + +```python +from headroom.integrations.agno import ( + HeadroomAgnoModel, + HeadroomPreHook, + HeadroomPostHook, +) + +model = HeadroomAgnoModel(OpenAIChat(id="gpt-4o")) + +pre_hook = HeadroomPreHook() +post_hook = HeadroomPostHook(token_alert_threshold=10000) + +agent = Agent( + model=model, + pre_hooks=[pre_hook], + post_hooks=[post_hook], +) + +response = agent.run("Analyze this large dataset...") + +# Check for alerts +if post_hook.alerts: + print(f"{len(post_hook.alerts)} requests exceeded threshold") +``` + +Or use the convenience factory: + +```python +from headroom.integrations.agno import create_headroom_hooks + +pre_hook, post_hook = create_headroom_hooks( + token_alert_threshold=5000, + log_level="DEBUG", +) +``` + +## Tool-heavy agents + +Tool outputs (JSON, logs, search results) see the biggest compression gains at 70-90% reduction: + +```python +from agno.tools.duckduckgo import DuckDuckGoTools + +model = HeadroomAgnoModel(OpenAIChat(id="gpt-4o")) + +agent = Agent( + model=model, + tools=[DuckDuckGoTools()], + show_tool_calls=True, +) + +response = agent.run("Research the latest AI developments") +print(f"Tokens saved: {model.total_tokens_saved}") +``` + +## Async support + +```python +import asyncio + +async def process(): + model = HeadroomAgnoModel(OpenAIChat(id="gpt-4o")) + + response = await model.aresponse(messages) + + async for chunk in model.aresponse_stream(messages): + print(chunk, end="", flush=True) + +asyncio.run(process()) +``` + +## Standalone message optimization + +Optimize messages without wrapping a model: + +```python +from headroom.integrations.agno import optimize_messages + +optimized, metrics = optimize_messages(messages, model="gpt-4o") +print(f"Tokens saved: {metrics['tokens_saved']}") +``` + +## Session management + +Reset metrics between sessions: + +```python +model = HeadroomAgnoModel(OpenAIChat(id="gpt-4o")) + +# Session 1 +agent.run("First conversation...") +print(model.get_savings_summary()) + +# Reset for new session +model.reset() + +# Session 2 starts fresh +agent.run("Second conversation...") +``` + +## Supported providers + +| Provider | Agno Model | Auto-Detected | +|----------|-----------|---------------| +| OpenAI | `OpenAIChat`, `OpenAILike` | Yes | +| Anthropic | `Claude`, `AwsBedrock` | Yes | +| Google | `Gemini`, `VertexAI` | Yes | +| Groq | `Groq` | Yes | +| Mistral | `Mistral` | Yes | +| Ollama | `Ollama` | Yes | diff --git a/docs/content/docs/anthropic-sdk.mdx b/docs/content/docs/anthropic-sdk.mdx new file mode 100644 index 000000000..150c0021c --- /dev/null +++ b/docs/content/docs/anthropic-sdk.mdx @@ -0,0 +1,127 @@ +--- +title: Anthropic SDK +description: Auto-compress messages in the Anthropic TypeScript SDK with a single withHeadroom() wrapper. +--- + +Headroom wraps the Anthropic TypeScript SDK to automatically compress messages before every `messages.create()` call. All other methods pass through unchanged. + +## Installation + +```bash +npm install headroom-ai @anthropic-ai/sdk +``` + + +The TypeScript SDK sends messages to a local Headroom proxy for compression. Start the proxy before using the SDK: + +```bash +pip install "headroom-ai[proxy]" +headroom proxy +``` + + +## Quick start + +```ts twoslash +import { withHeadroom } from 'headroom-ai/anthropic'; +import Anthropic from '@anthropic-ai/sdk'; + +const client = withHeadroom(new Anthropic()); + +const response = await client.messages.create({ + model: 'claude-sonnet-4-5-20250929', + messages: longConversation, + max_tokens: 1024, +}); +``` + +Every call to `client.messages.create()` compresses messages first. The response format is identical to the unwrapped client. + +## How it works + +`withHeadroom()` returns a proxy around your Anthropic client that intercepts `messages.create()`: + +1. Converts Anthropic-format messages to OpenAI format (the compression engine's native format) +2. Sends them to the Headroom proxy's `/v1/compress` endpoint +3. Converts the compressed messages back to Anthropic format +4. Forwards the request to Anthropic as normal + +### Message format conversion + +The adapter handles the full Anthropic message format including content blocks: + +| Anthropic format | OpenAI format | +|-----------------|---------------| +| `{ type: "text", text: "..." }` | `{ role: "user", content: "..." }` | +| `{ type: "tool_use", id, name, input }` | `{ tool_calls: [{ id, function: { name, arguments } }] }` | +| `{ type: "tool_result", tool_use_id, content }` | `{ role: "tool", tool_call_id, content }` | + +This conversion is lossless. Your request and response behave identically to an unwrapped client. + +## Options + +Pass compression options as the second argument: + +```ts twoslash +import { withHeadroom } from 'headroom-ai/anthropic'; +import Anthropic from '@anthropic-ai/sdk'; + +const client = withHeadroom(new Anthropic(), { + model: 'claude-sonnet-4-5-20250929', + baseUrl: 'http://localhost:8787', +}); +``` + +## Streaming + +Streaming works normally. Compression happens before the request: + +```ts twoslash +import { withHeadroom } from 'headroom-ai/anthropic'; +import Anthropic from '@anthropic-ai/sdk'; + +const client = withHeadroom(new Anthropic()); + +const stream = await client.messages.create({ + model: 'claude-sonnet-4-5-20250929', + messages: longConversation, + max_tokens: 1024, + stream: true, +}); +``` + +## Tool use + +Tool results are where compression has the biggest impact. Large JSON payloads from tool calls are compressed automatically: + +```ts twoslash +import { withHeadroom } from 'headroom-ai/anthropic'; +import Anthropic from '@anthropic-ai/sdk'; + +const client = withHeadroom(new Anthropic()); + +const response = await client.messages.create({ + model: 'claude-sonnet-4-5-20250929', + max_tokens: 1024, + messages: [ + { role: 'user', content: 'What went wrong?' }, + { + role: 'assistant', + content: [ + { type: 'tool_use', id: 'toolu_1', name: 'get_logs', input: { service: 'api' } }, + ], + }, + { + role: 'user', + content: [ + { + type: 'tool_result', + tool_use_id: 'toolu_1', + content: hugeLogOutput, // Compressed automatically + }, + ], + }, + ], + tools: [{ name: 'get_logs', description: 'Get logs', input_schema: { type: 'object', properties: {} } }], +}); +``` diff --git a/docs/content/docs/api-reference.mdx b/docs/content/docs/api-reference.mdx new file mode 100644 index 000000000..342460064 --- /dev/null +++ b/docs/content/docs/api-reference.mdx @@ -0,0 +1,785 @@ +--- +title: API Reference +description: Complete API reference for the Headroom Python and TypeScript SDKs. Core client, configuration types, result types, errors, and utilities. +--- + +Complete API reference for the Headroom Python and TypeScript SDKs. + +## Core + +### HeadroomClient + +The main entry point for the Headroom SDK. + + + + + + +```ts twoslash +import { HeadroomClient } from 'headroom-ai'; + +const client = new HeadroomClient({ + baseUrl: 'http://localhost:8787', + apiKey: 'your-api-key', + timeout: 30_000, + fallback: true, + retries: 2, +}); +``` + + + + +**Constructor Parameters** + + + +```python +from headroom import HeadroomClient, OpenAIProvider +from openai import OpenAI + +client = HeadroomClient( + original_client=OpenAI(), + provider=OpenAIProvider(), + default_mode="optimize", +) +``` + + + + +### chat.completions.create() + +Create a chat completion with optional optimization. + + + + +The TypeScript SDK uses `compress()` to optimize messages before sending them to your LLM client: + +```ts twoslash +import { compress } from 'headroom-ai'; + +const result = await compress(messages, { + model: 'gpt-4o', + tokenBudget: 100_000, +}); + +// Then pass result.messages to your LLM client +``` + + + + +Accepts all standard OpenAI/Anthropic parameters plus Headroom-specific overrides: + + + +```python +response = client.chat.completions.create( + model="gpt-4o", + messages=[...], + headroom_mode="optimize", + headroom_keep_turns=5, + headroom_tool_profiles={ + "important_tool": {"skip_compression": True}, + }, +) +``` + + + + +### chat.completions.simulate() + +Preview optimization without making an API call. + +```python +plan = client.chat.completions.simulate( + model="gpt-4o", + messages=[...], +) + +print(f"Tokens: {plan.tokens_before} -> {plan.tokens_after}") +print(f"Savings: {plan.savings_percent:.1f}%") +print(f"Transforms: {plan.transforms_applied}") +``` + +**Returns:** `SimulationResult` + +### compress() (TypeScript) + +Top-level function to compress messages via the Headroom proxy. + + + +```ts twoslash +import { compress } from 'headroom-ai'; + +const result = await compress(messages, { + model: 'gpt-4o', + baseUrl: 'http://localhost:8787', + timeout: 15_000, + fallback: true, + retries: 2, + tokenBudget: 100_000, +}); +``` + +### get_stats() + +Quick stats for the current session (no database query). + +```python +stats = client.get_stats() +# Returns dict with "session", "config", and "transforms" keys +``` + +### get_metrics() + +Query stored metrics from the database. + +```python +from datetime import datetime, timedelta + +metrics = client.get_metrics( + start_time=datetime.utcnow() - timedelta(hours=1), + limit=100, +) +``` + +### get_summary() + +Aggregate statistics across all stored metrics. + +```python +summary = client.get_summary() +# Returns dict with total_requests, total_tokens_saved, +# avg_compression_ratio, total_cost_saved_usd +``` + +### validate_setup() + +Validate that the client is configured correctly. + +```python +result = client.validate_setup() +if not result["valid"]: + for issue in result["issues"]: + print(f" - {issue}") +``` + +--- + +## Configuration + +### SmartCrusherConfig + + + + + + + + + + + +```python +from headroom import SmartCrusherConfig + +config = SmartCrusherConfig( + min_tokens_to_crush=200, + max_items_after_crush=50, + keep_first=3, + keep_last=2, + relevance_threshold=0.3, + anomaly_std_threshold=2.0, + preserve_errors=True, +) +``` + + + + +### CacheAlignerConfig + + + + + + + + + + + +```python +from headroom import CacheAlignerConfig + +config = CacheAlignerConfig( + enabled=True, + extract_dates=True, + normalize_whitespace=True, + stable_prefix_min_tokens=100, +) +``` + + + + +### RollingWindowConfig + + + + + + + + + + + +```python +from headroom import RollingWindowConfig + +config = RollingWindowConfig( + max_tokens=100000, + preserve_system=True, + preserve_recent_turns=5, + drop_oldest_first=True, +) +``` + + + + +### IntelligentContextConfig + + + + + + + + + + + +```python +from headroom.config import IntelligentContextConfig, ScoringWeights + +config = IntelligentContextConfig( + enabled=True, + keep_system=True, + keep_last_turns=2, + output_buffer_tokens=4000, + use_importance_scoring=True, + scoring_weights=ScoringWeights(), + toin_integration=True, +) +``` + + + + +### ScoringWeights + + + + + + + + + + + +Weights are automatically normalized to sum to 1.0. + + + + +### HeadroomConfig + + + + +', description: 'Override context limits per model' }, + toolCrusher: { type: 'ToolCrusherConfig', description: 'Tool crusher configuration' }, + smartCrusher: { type: 'SmartCrusherConfig', description: 'Smart crusher configuration' }, + cacheAligner: { type: 'CacheAlignerConfig', description: 'Cache aligner configuration' }, + rollingWindow: { type: 'RollingWindowConfig', description: 'Rolling window configuration' }, + cacheOptimizer: { type: 'CacheOptimizerConfig', description: 'Cache optimizer configuration' }, + ccr: { type: 'CCRConfig', description: 'CCR (Cross-Conversation Retrieval) configuration' }, + prefixFreeze: { type: 'PrefixFreezeConfig', description: 'Prefix freeze configuration' }, + contentRouterEnabled: { type: 'boolean', description: 'Enable content-type routing' }, + intelligentContext: { type: 'IntelligentContextConfig', description: 'Intelligent context management configuration' }, + generateDiffArtifact: { type: 'boolean', description: 'Generate diff artifacts for debugging' }, +}} /> + + + + +The top-level config object that contains all sub-configurations: + +```python +from headroom import HeadroomConfig + +config = HeadroomConfig() +config.smart_crusher.min_tokens_to_crush = 100 +config.cache_aligner.enabled = True +config.rolling_window.preserve_recent_turns = 3 +``` + + + + +### RelevanceScorerConfig + + + + + + + + + + + + + + +--- + +## Results + +### CompressResult (TypeScript) + + + +### SimulationResult (Python) + + + +### WasteSignals (Python) + + + +### RequestMetrics (Python) + + + +--- + +## Providers + +### OpenAIProvider + +```python +from headroom import OpenAIProvider + +provider = OpenAIProvider( + enable_prefix_caching=True, +) + +counter = provider.get_token_counter("gpt-4o") +tokens = counter.count_text("Hello, world!") +limit = provider.get_context_limit("gpt-4o") # 128000 +cost = provider.estimate_cost(input_tokens=1000, output_tokens=500, model="gpt-4o") +``` + +### AnthropicProvider + +```python +from headroom import AnthropicProvider +from anthropic import Anthropic + +provider = AnthropicProvider( + client=Anthropic(), + enable_cache_control=True, +) + +counter = provider.get_token_counter("claude-3-5-sonnet-latest") +tokens = counter.count_messages(messages) # Accurate count via API +``` + +### GoogleProvider + +```python +from headroom import GoogleProvider + +provider = GoogleProvider( + enable_context_caching=True, +) +``` + +--- + +## Relevance Scoring + +### create_scorer() + +Factory function to create scorers: + +```python +from headroom import create_scorer + +# Auto-select best available scorer +scorer = create_scorer() + +# Explicitly choose type +scorer = create_scorer(scorer_type="hybrid", alpha=0.7) +``` + +### BM25Scorer + +Fast keyword-based scoring (zero dependencies): + +```python +from headroom import BM25Scorer + +scorer = BM25Scorer() +scores = scorer.score_items(items=["item 1", "item 2"], query="search query") +``` + +### EmbeddingScorer + +Semantic similarity scoring (requires `headroom-ai[relevance]`): + +```python +from headroom import EmbeddingScorer, embedding_available + +if embedding_available(): + scorer = EmbeddingScorer(model="all-MiniLM-L6-v2") + scores = scorer.score_items(items, query) +``` + +### HybridScorer + +Combines BM25 and embeddings: + +```python +from headroom import HybridScorer + +scorer = HybridScorer(alpha=0.5) # 50% BM25, 50% embedding +scores = scorer.score_items(items, query) +``` + +--- + +## Transforms (Direct Use) + +### SmartCrusher + +```python +from headroom import SmartCrusher + +crusher = SmartCrusher() +result = crusher.crush(data={"results": [...]}, query="user query") +``` + +### CacheAligner + +```python +from headroom import CacheAligner + +aligner = CacheAligner() +result = aligner.align(messages) +``` + +### RollingWindow + +```python +from headroom import RollingWindow + +window = RollingWindow(config) +result = window.apply(messages, max_tokens=100000) +``` + +### IntelligentContextManager + +```python +from headroom.transforms import IntelligentContextManager +from headroom.config import IntelligentContextConfig + +config = IntelligentContextConfig( + keep_system=True, + keep_last_turns=2, + use_importance_scoring=True, +) + +manager = IntelligentContextManager(config, toin=toin) +result = manager.apply(messages, tokenizer, model_limit=128000) +``` + +### TransformPipeline + +```python +from headroom import TransformPipeline + +pipeline = TransformPipeline([ + SmartCrusher(), + CacheAligner(), + RollingWindow(), +]) + +result = pipeline.transform(messages) +``` + +--- + +## Errors + + + + +| Exception | Meaning | +|-----------|---------| +| `HeadroomError` | Base class for all errors | +| `HeadroomConnectionError` | Cannot reach proxy | +| `HeadroomAuthError` | 401 from proxy | +| `HeadroomCompressError` | Compression failed (includes `statusCode`, `errorType`) | +| `ConfigurationError` | Invalid configuration | +| `ProviderError` | Provider issues | +| `StorageError` | Storage failures | +| `TokenizationError` | Token counting failed | +| `CacheError` | Cache operations failed | +| `ValidationError` | Validation failures | +| `TransformError` | Transform execution failed | + +Use `mapProxyError(status, type, message)` to convert proxy error responses to the correct class. + + + + +| Exception | Meaning | +|-----------|---------| +| `HeadroomError` | Base class for all Headroom errors | +| `ConfigurationError` | Invalid config values | +| `ProviderError` | Provider issue (unknown model, etc.) | +| `StorageError` | Database issue | +| `CompressionError` | Compression failed (rare) | +| `ValidationError` | Setup validation failed | + +All exceptions include a `details` dict with additional context. + + + + +--- + +## Utilities + +### Tokenizer + +```python +from headroom import Tokenizer, count_tokens_text, count_tokens_messages + +# Quick counting +tokens = count_tokens_text("Hello, world!", model="gpt-4o") + +# With tokenizer instance +tokenizer = Tokenizer(model="gpt-4o") +tokens = tokenizer.count_text("Hello") +tokens = tokenizer.count_messages(messages) +``` + +### generate_report() + +Generate HTML/Markdown reports from stored metrics: + +```python +from headroom import generate_report + +report = generate_report( + store_url="sqlite:///headroom.db", + format="html", + period="day", +) +``` + +--- + +## TypeScript Message Types + + + +The TypeScript SDK uses the standard OpenAI message format with `SystemMessage`, `UserMessage`, `AssistantMessage`, and `ToolMessage` variants. diff --git a/docs/content/docs/architecture.mdx b/docs/content/docs/architecture.mdx new file mode 100644 index 000000000..1c86bfaed --- /dev/null +++ b/docs/content/docs/architecture.mdx @@ -0,0 +1,131 @@ +--- +title: Architecture +description: How Headroom's three-stage compression pipeline works, from message parsing through transform execution to provider cache optimization. +--- + +Headroom sits between your application and the LLM provider. It intercepts messages, compresses them intelligently, and forwards the optimized request. The response comes back unchanged. + +## High-Level Flow + +``` ++---------------------------------------------------------------+ +| YOUR APPLICATION | ++---------------------------------------------------------------+ + | + v ++---------------------------------------------------------------+ +| HEADROOM CLIENT | +| +-----------+ +------------+ +---------+ | +| | ANALYZE | > | TRANSFORM | > | CALL | | +| | (Parser) | | (Pipeline)| | (API) | | +| +-----------+ +------------+ +---------+ | +| | | | | +| v v v | +| Count tokens Apply compressions Send to LLM provider | +| Detect waste Preserve meaning Log metrics | ++---------------------------------------------------------------+ + | + v ++---------------------------------------------------------------+ +| OPENAI / ANTHROPIC / GOOGLE | ++---------------------------------------------------------------+ +``` + +## Entry Points + +Headroom can be used in three ways, all feeding into the same pipeline: + +| Entry Point | How It Works | Code Changes | +|-------------|-------------|--------------| +| **SDK Mode** | Wrap your LLM client with `HeadroomClient` | Minimal -- swap client constructor | +| **Proxy Mode** | Run `headroom proxy` and point your client at it | Zero -- just change the base URL | +| **Integrations** | LangChain, Vercel AI SDK, Agno adapters | Framework-specific setup | + +## The Transform Pipeline + +Messages flow through a sequence of transforms. Each transform is independent, safe to skip, and fails gracefully (returns original content unchanged). + +### Stage 1: Cache Aligner + +Extracts dynamic content (dates, UUIDs, session tokens) from your system prompt and moves it to the end. This stabilizes the prefix so provider caches (Anthropic `cache_control`, OpenAI prefix caching) can hit on repeated calls. + +``` +Before: "You are helpful. Current Date: 2024-12-15" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Changes daily = cache miss every day + +After: "You are helpful." [stable prefix] + "[Context: Current Date: 2024-12-15]" [dynamic tail] +``` + +Overhead: sub-millisecond. + +### Stage 2: Smart Crusher + +Analyzes tool output content and compresses it using statistical methods. This is where the bulk of token savings come from. + +**What it does:** + +1. Parses JSON arrays in tool outputs +2. Runs field-level statistical analysis (variance, uniqueness, change points) +3. Selects a representative subset using the Kneedle algorithm on bigram coverage +4. Preserves errors, anomalies, and distribution boundaries unconditionally +5. Factors out constant fields shared by all items + +**Strategies by content type:** + +| Content | Strategy | Typical Savings | +|---------|----------|-----------------| +| JSON arrays of dicts | Statistical sampling + anomaly preservation | 83--95% | +| JSON arrays of strings | Dedup + adaptive sampling | 60--90% | +| JSON arrays of numbers | Statistical summary + outlier preservation | 70--85% | +| Build/test logs | Pattern clustering | 85--94% | +| HTML | Article extraction (trafilatura-based) | ~95% | + +**Item retention split:** 30% from array start (schema), 15% from end (recency), 55% by importance score. Error items are always kept regardless of budget. + +Overhead: 1--50ms for typical payloads. Scales linearly with input size. + +### Stage 3: Context Manager + +Ensures the final message array fits within the model's context window. + +**Rolling Window** (default): Drops oldest messages first, preserving system prompt and recent turns. Tool calls and their responses are dropped as atomic units. + +**Intelligent Context** (advanced): Scores every message on six dimensions (recency, semantic similarity, TOIN importance, error indicators, forward references, token density) and drops the lowest-scored messages first. Dropped messages are stored in CCR for potential retrieval. + +Overhead: sub-millisecond for Rolling Window; depends on scoring config for Intelligent Context. + +## Provider Cache Optimization + +After the pipeline, Headroom applies provider-specific cache hints: + +| Provider | Mechanism | Savings | +|----------|-----------|---------| +| Anthropic | `cache_control` blocks on stable prefix | Up to 90% on cached tokens | +| OpenAI | Prefix alignment for automatic caching | Up to 50% on cached tokens | +| Google | `CachedContent` API | Up to 75% on cached tokens | + +## CCR: Compress-Cache-Retrieve + +When SmartCrusher compresses a tool output or Intelligent Context drops messages, the original content is stored in a local compression cache. If the LLM needs the full data, it can request retrieval via a `ccr_retrieve` tool call. This makes compression reversible. + +``` +Compress: 1000 items -> 15 items (stored original in CCR) +Cache: Hash-indexed local store (SQLite) +Retrieve: LLM calls ccr_retrieve("abc123") -> original 1000 items +``` + +## TOIN: Tool Output Intelligence Network + +TOIN learns compression patterns across sessions and users. When a tool is used repeatedly, TOIN builds up statistics about which fields matter, which items get retrieved, and what compression strategies work best. These learned patterns feed back into SmartCrusher and Intelligent Context scoring. + +Cold start: For new tool types, TOIN falls back to statistical heuristics. Patterns build up over time as tools are used. + +## What Headroom Does NOT Touch + +- **User messages**: Never compressed (the user's intent must be preserved exactly) +- **System prompts**: Content preserved; only dynamic parts are relocated for caching +- **Code**: Passes through unchanged unless tree-sitter AST compression is explicitly enabled +- **Model responses**: Returned unchanged from the provider +- **Short content**: Tool outputs under 200 tokens pass through (overhead exceeds savings) diff --git a/docs/content/docs/benchmarks.mdx b/docs/content/docs/benchmarks.mdx new file mode 100644 index 000000000..53856f160 --- /dev/null +++ b/docs/content/docs/benchmarks.mdx @@ -0,0 +1,150 @@ +--- +title: Benchmarks +description: Compression performance, accuracy preservation, latency overhead, and real-world production telemetry from 250+ Headroom proxy instances. +--- + +Headroom's core promise: compress context without losing accuracy. This page covers compression benchmarks, accuracy evaluations, latency overhead, and production telemetry. + +## Compression Performance + +Tested on Apple M-series (CPU), Headroom v0.5.18. Each test runs `compress()` on realistic tool outputs. + +| Content Type | Original | Compressed | Saved | Ratio | Latency | +|---|---|---|---|---|---| +| JSON array (100 items) | 3,163 | 297 | 2,866 | **90.6%** | 1ms | +| JSON array (500 items) | 9,526 | 1,614 | 7,912 | **83.1%** | 2ms | +| Shell output (200 lines) | 3,238 | 469 | 2,769 | **85.5%** | 1ms | +| Build log (200 lines) | 2,412 | 148 | 2,264 | **93.9%** | 1ms | +| grep results (150 hits) | 2,624 | 2,624 | 0 | 0.0% | <1ms | +| Python source (~480 lines) | 2,958 | 2,958 | 0 | 0.0% | <1ms | +| **Total** | **23,921** | **8,110** | **15,811** | **66.1%** | **5ms** | + + +grep results and Python source show 0% compression. These are already compact structured formats. SmartCrusher only compresses JSON arrays; code passes through to preserve correctness. + + +## Accuracy Benchmarks + +### HTML Extraction + +**Dataset**: Scrapinghub Article Extraction Benchmark (181 HTML pages with ground truth) + +| Metric | Value | +|---|---| +| **F1 Score** | 0.919 | +| **Precision** | 0.879 | +| **Recall** | 0.982 | +| **Compression** | 94.9% | + +For LLM applications, recall is critical -- 98.2% means nearly all article content is preserved. The slight precision drop (some extra content) does not hurt LLM accuracy. + +### JSON Compression (SmartCrusher) + +**Test**: 100 production log entries with critical error at position 67. Task: find the error, error code, resolution, and affected count. + +| Metric | Baseline | Headroom | +|---|---|---| +| Input tokens | 10,144 | 1,260 | +| Correct answers | 4/4 | **4/4** | +| Compression | -- | **87.6%** | + +SmartCrusher preserves first N items (schema), last N items (recency), all anomalies (errors, warnings), and statistical distribution. + +### QA Accuracy Preservation + +| Metric | Original HTML | Extracted | Delta | +|---|---|---|---| +| F1 Score | 0.85 | 0.87 | +0.02 | +| Exact Match | 60% | 62% | +2% | + + +Removing HTML noise sometimes helps LLMs focus on relevant content, leading to slightly higher scores on extraction benchmarks. + + +## Latency Overhead + +### SDK Compression Latency + +Measured per-scenario on Apple M-series (CPU): + +| Scenario | Tokens In | Tokens Out | Saved | p50 (ms) | p95 (ms) | +|----------|-----------|------------|-------|----------|----------| +| JSON: Search Results (100 items) | 10.2K | 1.5K | 8.7K | 189 | 231 | +| JSON: Search Results (500 items) | 50.2K | 1.5K | 48.7K | 943 | 955 | +| JSON: Search Results (1K items) | 100.5K | 1.5K | 99.0K | 2,012 | 2,198 | +| JSON: API Responses (500 items) | 38.9K | 1.1K | 37.8K | 743 | 776 | +| JSON: Database Rows (1K rows) | 43.7K | 605 | 43.1K | 961 | 1,104 | +| JSON: String Array (100 strings) | 1.1K | 231 | 820 | 15 | 15 | +| JSON: String Array (500 strings) | 4.9K | 233 | 4.6K | 72 | 80 | +| JSON: Number Array (200 numbers) | 1.2K | 192 | 1.1K | 31 | 62 | +| JSON: Mixed Array (250 items) | 2.3K | 368 | 1.9K | 38 | 40 | + +### Cost-Benefit Analysis + +Net latency benefit = LLM time saved from fewer tokens minus compression overhead (at Claude Sonnet pricing, $3.0/MTok): + +| Scenario | Compress (ms) | LLM Saved (ms) | Net Benefit | Savings per 1K Requests | +|----------|---------------|-----------------|-------------|------------------------| +| JSON: Search Results (100 items) | 189 | 261 | **+72ms** | $26 | +| JSON: Search Results (500 items) | 943 | 1,461 | **+518ms** | $146 | +| JSON: Search Results (1K items) | 2,012 | 2,969 | **+957ms** | $297 | +| JSON: API Responses (500 items) | 743 | 1,134 | **+391ms** | $113 | +| JSON: Database Rows (1K rows) | 961 | 1,292 | **+331ms** | $129 | + +Compression pays for itself in latency for 11 of 12 tested scenarios against Claude Sonnet. Slower and more expensive models (Opus) benefit even more. + +### Pipeline Step Timing + +| Step | Median | P90 | Description | +|------|--------|-----|-------------| +| `pipeline_total` | 16.9ms | 289ms | Full compression pipeline | +| `content_router` | 11.7ms | 259ms | Content detection + routing | +| `smart_crusher` | 50.1ms | 50ms | JSON array compression | +| `text_compressor` | 32.0ms | 576ms | Text compression (Kompress ONNX) | +| `initial_token_count` | 2.9ms | 16ms | Token counting (tiktoken) | + +ContentRouter accounts for 91--98% of pipeline cost on average. CacheAligner and RollingWindow are sub-millisecond. + +## Production Telemetry + +Real-world data from **50,000+ proxy sessions** across 250+ unique instances (March--April 2026). Collected via anonymous telemetry (opt-out: `HEADROOM_TELEMETRY=off`). + +### Proxy Overhead + +| Percentile | Latency | +|---|---| +| **Median (P50)** | **52ms** | +| P90 | 309ms | +| P99 | 4,172ms | +| Mean | 161ms | + +The median 52ms overhead is negligible compared to LLM inference time (typically 2--10 seconds). + +### Compression Rate + +| Percentile | Compression | +|---|---| +| P25 | 4.8% | +| **Median** | **4.8%** | +| P75 | 6.9% | +| Mean | 11.3% | + +Median compression is modest because many requests are short conversational turns. Heavy tool-use sessions (file reads, shell output) see 40--80% compression. + +### Fleet Summary + +| Metric | Value | +|---|---| +| Clean instances | 249 | +| Total tokens saved | 1.4 billion | +| Total savings | ~$4,000 | +| OS distribution | Linux 57%, macOS 38%, Windows 5% | + +## Reproducing Results + +```bash +git clone https://github.com/chopratejas/headroom.git +cd headroom +pip install -e ".[evals,html]" +pytest tests/test_evals/ -v -s +``` diff --git a/docs/content/docs/cache-optimization.mdx b/docs/content/docs/cache-optimization.mdx new file mode 100644 index 000000000..33c41e586 --- /dev/null +++ b/docs/content/docs/cache-optimization.mdx @@ -0,0 +1,163 @@ +--- +title: Cache Optimization +description: Stabilize message prefixes for provider KV cache hits and configure provider-specific caching strategies. +--- + +LLM providers cache prompt prefixes to avoid reprocessing identical input on repeated calls. Headroom's **CacheAligner** stabilizes your message prefixes so these caches actually hit, and then applies provider-specific strategies to maximize savings. + +## How CacheAligner works + +System prompts often contain dynamic content -- today's date, session IDs, timestamps -- that changes between requests. Even a single character difference at the start of a prompt invalidates the entire provider cache. + +CacheAligner solves this by extracting dynamic content and moving it to the end of the message, keeping the prefix stable: + +``` +Before: + "You are helpful. Current Date: 2025-04-06" <- changes daily, no cache hit + +After: + "You are helpful." <- stable prefix, cache hit + "[Context: Current Date: 2025-04-06]" <- dynamic part moved to tail +``` + +The prefix stays byte-identical across requests, so the provider's KV cache can reuse previously computed attention states. + +## Provider-specific strategies + +Each LLM provider implements caching differently. Headroom applies the optimal strategy for each. + +### Anthropic + +Anthropic supports explicit `cache_control` blocks that mark content as cacheable. Cached input tokens cost **90% less** than regular input tokens. + +Headroom automatically inserts `cache_control` breakpoints at the right positions in your messages so that stable prefixes (system prompts, early conversation turns) are cached across requests. + +| Metric | Value | +|---|---| +| Cache read discount | 90% off input price | +| Cache write cost | 25% premium on first write | +| Cache TTL | 5 minutes (extended on hit) | + +### OpenAI + +OpenAI uses automatic **prefix caching** -- if consecutive requests share the same message prefix, the provider reuses cached KV states. No explicit API markers are needed, but the prefix must be byte-identical. + +CacheAligner ensures your prefixes remain stable by extracting dynamic content, which is the key requirement for OpenAI prefix caching to work. + +| Metric | Value | +|---|---| +| Cache read discount | 50% off input price | +| Activation | Automatic (prefix match) | +| Min prefix length | 1024 tokens | + +### Google + +Google provides the **CachedContent API**, which lets you explicitly cache large context (system instructions, documents, tools) and reference it across requests. Cached tokens cost **75% less**. + +Headroom can manage CachedContent lifecycle automatically, creating and refreshing cached content objects as needed. + +| Metric | Value | +|---|---| +| Cache read discount | 75% off input price | +| Mechanism | Explicit CachedContent API objects | +| Min cache size | 32,768 tokens | + +## Configuration + + + +```ts twoslash +import { compress } from "headroom-ai"; +import type { + CacheAlignerConfig, + CacheOptimizerConfig, + HeadroomConfig, +} from "headroom-ai"; + +// CacheAligner: stabilize prefixes for cache hits +const cacheAligner: CacheAlignerConfig = { + enabled: true, + datePatterns: [ + "Today is \\w+ \\d+, \\d{4}", + "Current time: .*", + ], + normalizeWhitespace: true, + collapseBlankLines: true, +}; + +// CacheOptimizer: provider-level caching +const cacheOptimizer: CacheOptimizerConfig = { + enabled: true, + autoDetectProvider: true, // Detect Anthropic/OpenAI/Google automatically + minCacheableTokens: 1024, +}; + +// Full configuration +const config: HeadroomConfig = { + cacheAligner, + cacheOptimizer, +}; + +// Compress with cache optimization +const result = await compress(messages, { + model: "claude-sonnet-4-20250514", + config, +}); +``` + + +```python +from headroom import HeadroomClient, OpenAIProvider, AnthropicProvider, GoogleProvider +from headroom.transforms import CacheAlignerConfig +from openai import OpenAI + +# CacheAligner configuration +aligner_config = CacheAlignerConfig( + enabled=True, + dynamic_patterns=[ + r"Today is \w+ \d+, \d{4}", + r"Current time: .*", + r"Session ID: [a-f0-9-]+", + ], +) + +# Provider-specific cache settings +# OpenAI: prefix caching (automatic, just keep prefixes stable) +client = HeadroomClient( + original_client=OpenAI(), + provider=OpenAIProvider(enable_prefix_caching=True), + enable_cache_optimizer=True, +) + +# Anthropic: cache_control blocks (90% read discount) +from anthropic import Anthropic + +client = HeadroomClient( + original_client=Anthropic(), + provider=AnthropicProvider(enable_cache_control=True), + enable_cache_optimizer=True, +) + +# Google: CachedContent API (75% read discount) +client = HeadroomClient( + original_client=google_client, + provider=GoogleProvider(enable_context_caching=True), + enable_cache_optimizer=True, +) +``` + + + +## How savings compound + +CacheAligner and provider caching work together with Headroom's compression transforms: + +1. **SmartCrusher** reduces token count by 70-90% +2. **CacheAligner** stabilizes prefixes so provider caches hit +3. **Provider caching** discounts the remaining input tokens by 50-90% + +For example, with Anthropic: +- 100K input tokens compressed to 20K (80% savings from SmartCrusher) +- 18K of those 20K hit the cache (90% cache read discount) +- Effective cost: 2K full-price tokens + 18K at 10% = 3.8K equivalent tokens +- **Total savings: 96.2%** compared to the original 100K tokens diff --git a/docs/content/docs/ccr.mdx b/docs/content/docs/ccr.mdx new file mode 100644 index 000000000..57e3cb1a5 --- /dev/null +++ b/docs/content/docs/ccr.mdx @@ -0,0 +1,205 @@ +--- +title: Reversible Compression (CCR) +description: Compress-Cache-Retrieve architecture that makes compression lossless — the LLM can always get the original data back. +--- + +Headroom's CCR (Compress-Cache-Retrieve) architecture makes compression **reversible**. When content is compressed, the original data is cached locally. If the LLM needs the full data, it retrieves it instantly. + + + Unlike traditional lossy compression, CCR guarantees that every piece of original data remains accessible. You get 70-90% token savings with zero risk of permanent data loss. + + +## The problem with traditional compression + +Traditional compression forces a difficult tradeoff: + +- **Aggressive compression** risks losing data the LLM needs +- **Conservative compression** misses out on token savings + +CCR eliminates this tradeoff entirely. Compress aggressively, retrieve on demand. + +## Architecture + +CCR flows through four phases: + +``` +TOOL OUTPUT (1000 items) + -> SmartCrusher compresses to 20 items + -> Original cached with hash=abc123 + -> Retrieval tool injected into context + +LLM PROCESSING + Option A: LLM solves task with 20 items -> Done (90% savings) + Option B: LLM calls headroom_retrieve(hash=abc123) + -> Response Handler returns full data automatically +``` + +## Phase 1: Compression Store + +When SmartCrusher compresses tool output: + +1. The original content is stored in an LRU cache +2. A hash key is generated for retrieval +3. A marker is added to the compressed output: + +``` +[1000 items compressed to 20. Retrieve more: hash=abc123] +``` + +## Phase 2: Tool Injection + +Headroom injects a `headroom_retrieve` tool into the LLM's available tools: + +```json +{ + "name": "headroom_retrieve", + "description": "Retrieve original uncompressed data from Headroom cache", + "parameters": { + "hash": "The hash key from the compression marker", + "query": "Optional: search within the cached data" + } +} +``` + +The LLM sees this tool alongside your application's tools and can call it whenever the compressed data is insufficient. + +## Phase 3: Response Handler + +When the LLM calls `headroom_retrieve`: + +1. The Response Handler intercepts the tool call +2. Data is retrieved from the local cache (around 1ms) +3. The result is added to the conversation +4. The API call continues automatically + +The client never sees CCR tool calls -- they are handled transparently by Headroom. + +## Phase 4: Context Tracker + +Across multiple turns, the Context Tracker maintains awareness of all compressed content: + +1. Remembers what was compressed in earlier turns +2. Analyzes new queries for relevance to compressed content +3. Proactively expands relevant data before the LLM asks + +``` +Turn 1: User searches for files + -> 500 files compressed to 15, cached (hash=abc123) + -> LLM answers with 15 files + +Turn 5: User asks "What about the auth middleware?" + -> Context Tracker detects "auth" may match cached content + -> Proactively expands compressed data + -> LLM finds auth_middleware.py in the full list +``` + +## BM25 search within compressed data + +The LLM does not have to retrieve everything. It can search within compressed data using the optional `query` parameter: + +```json +{ + "name": "headroom_retrieve", + "parameters": { + "hash": "abc123", + "query": "authentication errors" + } +} +``` + +This runs a BM25 search over the cached items, returning only the relevant subset instead of the full original payload. + +## Retrieving originals + +CCR works automatically through the proxy, but you can also retrieve cached data programmatically: + + + +```ts twoslash +import { compress } from "headroom-ai"; +import type { CCRConfig } from "headroom-ai"; + +// CCR is enabled by default when compressing through the proxy. +const result = await compress(messages, { + model: "gpt-4o", +}); + +// Access compressed messages — CCR markers are embedded automatically +console.log(result.messages); + +// CCR configuration options +const ccrConfig: CCRConfig = { + enabled: true, + injectTool: true, // Inject headroom_retrieve tool + injectRetrievalMarker: true, // Add retrieval markers to compressed output + feedbackEnabled: true, // Learn from retrieval patterns + storeMaxEntries: 1000, // Max cached items + storeTtlSeconds: 3600, // Cache TTL +}; +``` + + +```python +from headroom import HeadroomClient, OpenAIProvider +from openai import OpenAI + +client = HeadroomClient( + original_client=OpenAI(), + provider=OpenAIProvider(), + default_mode="optimize", +) + +# CCR happens automatically during chat completions. +# The LLM calls headroom_retrieve when it needs more data. +response = client.chat.completions.create( + model="gpt-4o", + messages=messages, +) + +# CCR is enabled by default. To disable: +# headroom proxy --no-ccr-responses + +# To disable proactive expansion: +# headroom proxy --no-ccr-expansion +``` + + + +## Message-level CCR + +CCR is not limited to tool outputs. When IntelligentContext drops low-importance messages to fit the context budget, those messages are also stored in CCR: + +``` +100-message conversation (50K tokens) + -> IntelligentContext scores messages by importance + -> Drops 60 low-scoring messages + -> Dropped messages cached with hash=def456 + -> Marker inserted: "60 messages dropped, retrieve: def456" +``` + +The marker includes the CCR reference so the LLM can recover earlier context: + +``` +[Earlier context compressed: 60 message(s) dropped by importance scoring. +Full content available via ccr_retrieve tool with reference 'def456'.] +``` + +When users retrieve dropped messages via CCR, TOIN learns those message patterns are important and scores them higher in future sessions -- improving drop decisions across all users. + +## CCR-enabled components + +| Component | What it compresses | CCR integration | +|---|---|---| +| **SmartCrusher** | JSON arrays (tool outputs) | Stores original array, marker includes hash | +| **ContentRouter** | Code, logs, search results, text | Stores original content by strategy | +| **IntelligentContext** | Messages (conversation turns) | Stores dropped messages, marker includes hash | + +## Why CCR matters + +| Approach | Risk | Savings | +|---|---|---| +| No compression | None | 0% | +| Traditional compression | Data loss | 70-90% | +| CCR compression | None (reversible) | 70-90% | + +CCR gives you the savings of aggressive compression with zero risk. The LLM can always retrieve the original data if needed. diff --git a/docs/content/docs/code-compression.mdx b/docs/content/docs/code-compression.mdx new file mode 100644 index 000000000..472cdbd52 --- /dev/null +++ b/docs/content/docs/code-compression.mdx @@ -0,0 +1,173 @@ +--- +title: Code Compression +description: AST-aware compression that preserves imports, signatures, and types while compressing function bodies. Powered by tree-sitter. +--- + +Headroom's CodeAwareCompressor uses tree-sitter to parse source code into an AST, then selectively compresses function bodies while preserving the structural elements that LLMs need -- imports, signatures, type annotations, and error handlers. + +## Why AST-Aware Compression? + +Naive truncation breaks code. Cutting a function in half leaves invalid syntax that confuses the LLM. CodeAwareCompressor guarantees: + +- **Syntax validity** -- output always parses correctly +- **Structural preservation** -- imports, signatures, types, decorators are kept intact +- **Lightweight** -- ~50MB (tree-sitter) vs ~1GB for LLMLingua + +## Supported Languages + +| Tier | Languages | Support Level | +|---|---|---| +| Tier 1 | Python, JavaScript, TypeScript | Full AST analysis | +| Tier 2 | Go, Rust, Java, C, C++ | Function body compression | + +## What Gets Preserved vs Compressed + +**Always preserved:** +- Import statements +- Function and method signatures +- Class definitions +- Type annotations +- Decorators +- Error handlers (`try`/`except`, `try`/`catch`) + +**Compressed:** +- Function bodies (implementations) +- Comments (unless configured to preserve) +- Verbose docstrings (configurable: full, first line, or removed) + +## Example + +```python +from headroom.transforms import CodeAwareCompressor + +compressor = CodeAwareCompressor() + +code = ''' +import os +from typing import List + +def process_items(items: List[str]) -> List[str]: + """Process a list of items.""" + results = [] + for item in items: + if not item: + continue + processed = item.strip().lower() + results.append(processed) + return results +''' + +result = compressor.compress(code, language="python") +print(result.compressed) +# import os +# from typing import List +# +# def process_items(items: List[str]) -> List[str]: +# """Process a list of items.""" +# results = [] +# for item in items: +# # ... (5 lines compressed) +# pass + +print(f"Compression: {result.compression_ratio:.0%}") # ~55% +print(f"Syntax valid: {result.syntax_valid}") # True +``` + +## Configuration + +```python +from headroom.transforms import CodeAwareCompressor, CodeCompressorConfig, DocstringMode + +config = CodeCompressorConfig( + preserve_imports=True, # Always keep imports + preserve_signatures=True, # Always keep function signatures + preserve_type_annotations=True, # Keep type hints + preserve_error_handlers=True, # Keep try/except blocks + preserve_decorators=True, # Keep decorators + docstring_mode=DocstringMode.FIRST_LINE, # FULL, FIRST_LINE, REMOVE + target_compression_rate=0.2, # Keep 20% of tokens + max_body_lines=5, # Lines to keep per function body + min_tokens_for_compression=100, # Skip small content + language_hint=None, # Auto-detect if None + fallback_to_llmlingua=True, # Use LLMLingua for unknown langs +) + +compressor = CodeAwareCompressor(config) +result = compressor.compress(code) +``` + +### Configuration Options + +| Option | Default | Description | +|---|---|---| +| `preserve_imports` | `True` | Keep all import statements | +| `preserve_signatures` | `True` | Keep function/method signatures | +| `preserve_type_annotations` | `True` | Keep type hints | +| `preserve_error_handlers` | `True` | Keep try/except blocks | +| `preserve_decorators` | `True` | Keep decorators | +| `docstring_mode` | `FIRST_LINE` | How to handle docstrings: `FULL`, `FIRST_LINE`, `REMOVE` | +| `target_compression_rate` | `0.2` | Fraction of tokens to keep (0.2 = keep 20%) | +| `max_body_lines` | `5` | Max lines to keep per function body | +| `min_tokens_for_compression` | `100` | Skip files smaller than this | +| `language_hint` | `None` | Override language detection | +| `fallback_to_llmlingua` | `True` | Use LLMLingua for unsupported languages | + +## Before and After + +```python +# Before (full source file) +def process_data(items: List[str]) -> Dict[str, int]: + """Process items and count occurrences.""" + result = {} + for item in items: + item = item.strip().lower() + if item in result: + result[item] += 1 + else: + result[item] = 1 + return result + +# After (signature preserved, body compressed) +def process_data(items: List[str]) -> Dict[str, int]: + """Process items and count occurrences.""" + result = {} + for item in items: + # ... (5 lines compressed) + pass +``` + +The LLM sees the function's purpose, its input/output types, and the general approach -- enough to reason about the code without needing every implementation line. + +## Installation + +```bash +# Install tree-sitter language pack +pip install "headroom-ai[code]" +``` + +## Memory Management + +Tree-sitter parsers are lazy-loaded and cached. You can free memory when done: + +```python +from headroom.transforms import is_tree_sitter_available, unload_tree_sitter + +# Check if tree-sitter is installed +print(is_tree_sitter_available()) # True + +# Free memory when done +unload_tree_sitter() +``` + +## Performance + +| Metric | Value | +|---|---| +| Compression | 40-70% token reduction | +| Speed | ~10-50ms per file | +| Memory | ~50MB (tree-sitter parsers) | +| Syntax validity | Guaranteed | + + + When you use the Headroom proxy or call `compress()`, source code is automatically detected and routed to CodeAwareCompressor. Direct usage gives you control over compression settings per language. + diff --git a/docs/content/docs/community-savings.mdx b/docs/content/docs/community-savings.mdx new file mode 100644 index 000000000..4bdb88b34 --- /dev/null +++ b/docs/content/docs/community-savings.mdx @@ -0,0 +1,22 @@ +--- +title: Community Savings +description: Aggregate savings from Headroom instances across the community. Anonymous telemetry data — no prompts, no content, no PII. +--- + +Real-time aggregate metrics from Headroom proxy instances worldwide. All data is anonymous — only token counts, compression ratios, and cost estimates are collected. [Opt out anytime](https://github.com/chopratejas/headroom/blob/main/headroom/telemetry/beacon.py) with `HEADROOM_TELEMETRY=off`. + +## Overview + + + +## Savings Over Time + + + +## Top Savings by Instance + + + +## Instance Details + + diff --git a/docs/content/docs/configuration.mdx b/docs/content/docs/configuration.mdx new file mode 100644 index 000000000..aa080cb4a --- /dev/null +++ b/docs/content/docs/configuration.mdx @@ -0,0 +1,371 @@ +--- +title: Configuration +description: All configuration options for the Headroom Python and TypeScript SDKs, proxy server, and per-request overrides. +--- + +Headroom can be configured via the SDK constructor, proxy command line, environment variables, or per-request overrides. + +## Modes + +| Mode | Behavior | Use Case | +|------|----------|----------| +| `audit` | Observes and logs, no modifications | Production monitoring, baseline measurement | +| `optimize` | Applies safe, deterministic transforms | Production optimization | +| `simulate` | Returns plan without API call | Testing, cost estimation | + +## SDK Configuration + + + +```ts twoslash +import { HeadroomClient } from 'headroom-ai'; + +// Reads from HEADROOM_BASE_URL and HEADROOM_API_KEY automatically +const client = new HeadroomClient(); + +// Or configure explicitly +const explicit = new HeadroomClient({ + baseUrl: 'http://localhost:8787', + apiKey: 'your-api-key', + timeout: 30_000, + fallback: true, + retries: 2, +}); +``` + + +```python +from headroom import HeadroomClient, OpenAIProvider +from openai import OpenAI + +client = HeadroomClient( + original_client=OpenAI(), + provider=OpenAIProvider(), + + # Mode: "audit" (observe only) or "optimize" (apply transforms) + default_mode="optimize", + + # Enable provider-specific cache optimization + enable_cache_optimizer=True, + + # Enable query-level semantic caching + enable_semantic_cache=False, + + # Override default context limits per model + model_context_limits={ + "gpt-4o": 128000, + "gpt-4o-mini": 128000, + }, + + # Database location (defaults to temp directory) + # store_url="sqlite:////absolute/path/to/headroom.db", +) +``` + + + +## Per-Request Overrides + +Override configuration for individual requests: + + + +```ts twoslash +import { compress } from 'headroom-ai'; + +const result = await compress(messages, { + model: 'gpt-4o', + tokenBudget: 100_000, + timeout: 15_000, +}); +``` + + +```python +response = client.chat.completions.create( + model="gpt-4o", + messages=[...], + + # Override mode for this request + headroom_mode="audit", + + # Reserve more tokens for output + headroom_output_buffer_tokens=8000, + + # Keep last N turns (don't compress) + headroom_keep_turns=5, + + # Skip compression for specific tools + headroom_tool_profiles={ + "important_tool": {"skip_compression": True} + }, +) +``` + + + +## SmartCrusher Configuration + +Fine-tune JSON compression behavior: + +```python +from headroom.transforms import SmartCrusherConfig + +config = SmartCrusherConfig( + # Maximum items to keep after compression + max_items_after_crush=15, + + # Minimum tokens before applying compression + min_tokens_to_crush=200, + + # Relevance scoring tier: "bm25" (fast) or "embedding" (accurate) + relevance_tier="bm25", + + # Always keep items with these field values + preserve_fields=["error", "warning", "failure"], +) +``` + +## CacheAligner Configuration + +Control prefix stabilization for provider cache hit rates: + +```python +from headroom.transforms import CacheAlignerConfig + +config = CacheAlignerConfig( + # Enable/disable cache alignment + enabled=True, + + # Patterns to extract from system prompt + dynamic_patterns=[ + r"Today is \w+ \d+, \d{4}", + r"Current time: .*", + ], +) +``` + +## RollingWindow Configuration + +Control context window management when messages exceed model limits: + +```python +from headroom.transforms import RollingWindowConfig + +config = RollingWindowConfig( + # Minimum turns to always keep + min_keep_turns=3, + + # Reserve tokens for output + output_buffer_tokens=4000, + + # Drop oldest tool outputs first + prefer_drop_tool_outputs=True, +) +``` + +## IntelligentContext Configuration + +Semantic-aware context management with importance scoring: + +```python +from headroom.config import IntelligentContextConfig, ScoringWeights + +# Customize scoring weights (must sum to 1.0, or will be normalized) +weights = ScoringWeights( + recency=0.20, # Newer messages score higher + semantic_similarity=0.20, # Similarity to recent context + toin_importance=0.25, # TOIN-learned retrieval patterns + error_indicator=0.15, # TOIN-learned error field types + forward_reference=0.15, # Messages referenced by later messages + token_density=0.05, # Information density +) + +config = IntelligentContextConfig( + enabled=True, + keep_system=True, # Never drop system messages + keep_last_turns=2, # Protect last N user turns + output_buffer_tokens=4000, # Reserve for model output + use_importance_scoring=True, + scoring_weights=weights, + toin_integration=True, # Use TOIN patterns if available + recency_decay_rate=0.1, # Exponential decay lambda + compress_threshold=0.1, # Try compression first if <10% over budget +) +``` + +### Scoring Weights + + + +Weights are automatically normalized to sum to 1.0: + +```python +weights = ScoringWeights(recency=1.0, toin_importance=1.0) +normalized = weights.normalized() +# recency=0.5, toin_importance=0.5, others=0.0 +``` + +## Proxy Configuration + +### Command Line Options + +```bash +headroom proxy \ + --port 8787 \ # Port to listen on + --host 0.0.0.0 \ # Host to bind to + --budget 10.00 \ # Daily budget limit in USD + --log-file headroom.jsonl # Log file path +``` + +### Feature Flags + +```bash +# Disable optimization (passthrough mode) +headroom proxy --no-optimize + +# Disable semantic caching +headroom proxy --no-cache + +# Enable LLMLingua ML compression +headroom proxy --llmlingua +headroom proxy --llmlingua --llmlingua-device cuda --llmlingua-rate 0.4 +``` + +## Environment Variables + +| Variable | Description | Default | +|----------|-------------|---------| +| `HEADROOM_LOG_LEVEL` | Logging level | `INFO` | +| `HEADROOM_STORE_URL` | Database URL | temp directory | +| `HEADROOM_DEFAULT_MODE` | Default mode | `optimize` | +| `HEADROOM_MODEL_LIMITS` | Custom model config (JSON string or file path) | -- | +| `HEADROOM_BASE_URL` | Base URL of the Headroom proxy (TypeScript SDK) | `http://localhost:8787` | +| `HEADROOM_API_KEY` | API key for Headroom Cloud authentication | -- | +| `HEADROOM_SAVINGS_PATH` | Override persistent savings file location | `~/.headroom/proxy_savings.json` | +| `HEADROOM_TELEMETRY` | Set to `off` to disable anonymous telemetry | `on` | + +## Custom Model Configuration + +Configure context limits and pricing for new or custom models: + +```json +{ + "anthropic": { + "context_limits": { + "claude-4-opus-20250301": 200000, + "claude-custom-finetune": 128000 + }, + "pricing": { + "claude-4-opus-20250301": { + "input": 15.00, + "output": 75.00, + "cached_input": 1.50 + } + } + }, + "openai": { + "context_limits": { + "gpt-5": 256000, + "ft:gpt-4o:my-org": 128000 + } + } +} +``` + +Save as `~/.headroom/models.json`, or set `HEADROOM_MODEL_LIMITS` to a JSON string or file path. + +Settings are resolved in this order (later overrides earlier): + +1. Built-in defaults +2. `~/.headroom/models.json` config file +3. `HEADROOM_MODEL_LIMITS` environment variable +4. SDK constructor arguments + +### Pattern-Based Inference + +Unknown models are automatically inferred from naming patterns: + +| Pattern | Inferred Settings | +|---------|-------------------| +| `*opus*` | 200K context, Opus-tier pricing | +| `*sonnet*` | 200K context, Sonnet-tier pricing | +| `*haiku*` | 200K context, Haiku-tier pricing | +| `gpt-4o*` | 128K context, GPT-4o pricing | +| `o1*`, `o3*` | 200K context, reasoning model pricing | + +## Provider-Specific Settings + + + +```python +from headroom import OpenAIProvider + +provider = OpenAIProvider( + enable_prefix_caching=True, +) +``` + + +```python +from headroom import AnthropicProvider + +provider = AnthropicProvider( + enable_cache_control=True, +) +``` + + +```python +from headroom import GoogleProvider + +provider = GoogleProvider( + enable_context_caching=True, +) +``` + + + +## Tool Profiles + +Skip or customize compression for specific tools: + +```python +response = client.chat.completions.create( + model="gpt-4o", + messages=messages, + headroom_tool_profiles={ + "important_tool": {"skip_compression": True}, + "search_tool": {"max_items_after_crush": 25}, + }, +) +``` + +## Configuration Precedence + +Settings are applied in this order (later overrides earlier): + +1. Default values +2. Environment variables +3. SDK constructor arguments +4. Per-request overrides + +## Validation + +Validate your configuration at startup: + +```python +result = client.validate_setup() + +if not result["valid"]: + print("Configuration issues:") + for issue in result["issues"]: + print(f" - {issue}") +``` diff --git a/docs/content/docs/context-management.mdx b/docs/content/docs/context-management.mdx new file mode 100644 index 000000000..cd71ba0ec --- /dev/null +++ b/docs/content/docs/context-management.mdx @@ -0,0 +1,188 @@ +--- +title: Context Management +description: Intelligent importance-based context management that scores messages by learned patterns, with rolling window fallback and output buffer reservation. +--- + +When conversations grow beyond a model's context window, Headroom decides which messages to keep and which to drop. Instead of naively removing the oldest messages, **IntelligentContext** scores every message by learned importance and drops the least valuable ones first. + +## IntelligentContext + +IntelligentContext is a message-level compressor. It analyzes your conversation, assigns an importance score to each message, and removes low-scoring messages until the conversation fits within the token budget. + +Dropped messages are not lost -- they are stored in [CCR](/docs/ccr) for on-demand retrieval by the LLM. + +``` +100-message conversation (50K tokens) with a 32K budget + -> Score each message by importance + -> Drop 60 lowest-scoring messages + -> Cache dropped messages in CCR (hash=def456) + -> Insert marker: "60 messages dropped, retrieve: def456" + -> Final context: 40 messages within budget +``` + +## Scoring weights + +Each message receives a weighted score from six factors: + +| Weight | Default | Description | +|---|---|---| +| `recency` | 0.20 | Exponential decay from the end of the conversation. Recent messages score higher. | +| `semantic_similarity` | 0.20 | Embedding cosine similarity to recent context. Messages related to the current topic score higher. | +| `toin_importance` | 0.25 | TOIN retrieval rate -- messages matching patterns that users frequently retrieve via CCR are scored higher. Learned across all users. | +| `error_indicator` | 0.15 | TOIN field semantics error detection. Messages containing error patterns (learned, not hardcoded) are preserved. | +| `forward_reference` | 0.15 | Count of later messages that reference this one. Messages that other messages depend on are kept. | +| `token_density` | 0.05 | Unique tokens divided by total tokens. Dense, information-rich messages score higher than repetitive ones. | + + + Error detection does not rely on keyword matching like "error" or "fail". Instead, it uses TOIN's learned `field_semantics.inferred_type` to identify error-bearing messages -- this adapts to your specific data patterns across sessions and users. + + +Weights are automatically normalized to sum to 1.0, so you can set relative values without worrying about exact proportions. + +## Rolling window fallback + +If IntelligentContext is disabled or scoring data is unavailable, Headroom falls back to a **rolling window** strategy: + +- Drop the oldest messages first +- Always keep the system prompt +- Always keep the last N user/assistant turns +- Drop tool calls and their responses as atomic pairs (no orphaned tool data) + +This provides a safe baseline that works without any learned data. + +## Protection rules + +Headroom enforces several protections to ensure model output quality: + +### Output buffer reservation + +A configurable number of tokens is reserved for the model's response. The context budget is calculated as: + +``` +context_budget = model_context_limit - output_buffer_tokens +``` + +This prevents the input from consuming the entire context window and leaving no room for the model to respond. + +### System message protection + +System messages are never dropped. They contain critical instructions, persona definitions, and tool descriptions that the model needs throughout the conversation. + +### Turn protection + +The last N user/assistant turns are always preserved, ensuring the model has immediate conversational context. By default, the last 2 turns are protected. + +## Configuration + + + +```ts twoslash +import { compress } from "headroom-ai"; +import type { + IntelligentContextConfig, + ScoringWeights, + RollingWindowConfig, + HeadroomConfig, +} from "headroom-ai"; + +// Scoring weights (normalized automatically) +const scoringWeights: ScoringWeights = { + recency: 0.20, + semanticSimilarity: 0.20, + toinImportance: 0.25, + errorIndicator: 0.15, + forwardReference: 0.15, + tokenDensity: 0.05, +}; + +// IntelligentContext configuration +const intelligentContext: IntelligentContextConfig = { + enabled: true, + keepSystem: true, + keepLastTurns: 2, + outputBufferTokens: 4000, + useImportanceScoring: true, + scoringWeights, + toinIntegration: true, + recencyDecayRate: 0.1, + compressThreshold: 0.1, +}; + +// Rolling window fallback +const rollingWindow: RollingWindowConfig = { + enabled: true, + keepSystem: true, + keepLastTurns: 3, + outputBufferTokens: 4000, +}; + +// Full configuration +const config: HeadroomConfig = { + intelligentContext, + rollingWindow, +}; + +const result = await compress(messages, { + model: "gpt-4o", + config, +}); + +console.log(`Compressed: ${result.tokensBefore} -> ${result.tokensAfter}`); +``` + + +```python +from headroom import HeadroomClient, OpenAIProvider +from headroom.config import IntelligentContextConfig, ScoringWeights +from openai import OpenAI + +# Customize scoring weights +weights = ScoringWeights( + recency=0.20, + semantic_similarity=0.20, + toin_importance=0.25, + error_indicator=0.15, + forward_reference=0.15, + token_density=0.05, +) + +context_config = IntelligentContextConfig( + enabled=True, + keep_system=True, # Never drop system messages + keep_last_turns=2, # Protect last 2 user turns + output_buffer_tokens=4000, # Reserve for model output + use_importance_scoring=True, + scoring_weights=weights, + toin_integration=True, # Use TOIN patterns + recency_decay_rate=0.1, # Exponential decay lambda + compress_threshold=0.1, # Try compression first if <10% over budget +) + +client = HeadroomClient( + original_client=OpenAI(), + provider=OpenAIProvider(), + default_mode="optimize", +) + +# Per-request overrides +response = client.chat.completions.create( + model="gpt-4o", + messages=messages, + headroom_output_buffer_tokens=8000, # More room for long responses + headroom_keep_turns=5, # Protect last 5 turns +) +``` + + + +## How scoring improves over time + +IntelligentContext integrates with TOIN (Tool-Output Intelligence Network) to learn from real usage: + +1. Messages are dropped based on current scores +2. Dropped messages are stored in CCR +3. If the LLM retrieves a dropped message, TOIN records that pattern +4. Future conversations score similar message patterns higher +5. Drop accuracy improves across all users, not just within one session + +This feedback loop means the system gets smarter the more it is used. Error messages that users frequently need are automatically preserved, while verbose success messages that nobody retrieves are dropped more aggressively. diff --git a/docs/content/docs/errors.mdx b/docs/content/docs/errors.mdx new file mode 100644 index 000000000..d4fd65c60 --- /dev/null +++ b/docs/content/docs/errors.mdx @@ -0,0 +1,276 @@ +--- +title: Error Handling +description: How to catch and handle Headroom errors in Python and TypeScript. Error hierarchy, proxy error mapping, and safety guarantees. +--- + +Headroom provides explicit exceptions for debugging, with a core safety guarantee: **compression failures never break your LLM calls**. If compression fails, the original content passes through unchanged. + +## Error Hierarchy + + + + +``` +HeadroomError (base class) + +-- HeadroomConnectionError # Cannot reach proxy + +-- HeadroomAuthError # 401 from proxy + +-- HeadroomCompressError # Compression failed (with statusCode) + +-- ConfigurationError # Invalid configuration + +-- ProviderError # Provider issues + +-- StorageError # Storage failures + +-- TokenizationError # Token counting failed + +-- CacheError # Cache operations failed + +-- ValidationError # Validation failures + +-- TransformError # Transform execution failed +``` + +```ts twoslash +import { + HeadroomError, + HeadroomConnectionError, + HeadroomAuthError, + HeadroomCompressError, + ConfigurationError, + ProviderError, + mapProxyError, +} from 'headroom-ai'; +``` + + + + +``` +HeadroomError (base class) + +-- ConfigurationError # Invalid configuration + +-- ProviderError # Provider issues (unknown model, etc.) + +-- StorageError # Database/storage failures + +-- CompressionError # Compression failures (rare) + +-- ValidationError # Setup validation failures +``` + +```python +from headroom import ( + HeadroomError, + ConfigurationError, + ProviderError, + StorageError, + CompressionError, + ValidationError, +) +``` + + + + +## Catching Errors + + + + +```ts twoslash +import { compress, HeadroomConnectionError, HeadroomAuthError, HeadroomCompressError, HeadroomError } from 'headroom-ai'; + +try { + const result = await compress(messages, { model: 'gpt-4o' }); +} catch (e) { + if (e instanceof HeadroomConnectionError) { + console.error('Cannot reach proxy:', e.message); + } else if (e instanceof HeadroomAuthError) { + console.error('Auth failed:', e.message); + } else if (e instanceof HeadroomCompressError) { + console.error(`Compress failed (${e.statusCode}):`, e.message); + } else if (e instanceof HeadroomError) { + console.error('Headroom error:', e.message, e.details); + } +} +``` + + + + +```python +from headroom import ( + HeadroomClient, + HeadroomError, + ConfigurationError, + StorageError, +) + +try: + client = HeadroomClient(...) + response = client.chat.completions.create(...) + +except ConfigurationError as e: + print(f"Config issue: {e}") + print(f"Details: {e.details}") + +except StorageError as e: + print(f"Storage issue: {e}") + # Headroom continues to work, just without metrics persistence + +except HeadroomError as e: + print(f"Headroom error: {e}") +``` + + + + +## Error Types in Detail + +### ConfigurationError + +Raised when configuration is invalid. + + + +```ts twoslash +import { ConfigurationError } from 'headroom-ai'; + +// ConfigurationError is thrown when the proxy returns +// a configuration_error type in its error response +``` + + +```python +try: + client = HeadroomClient( + original_client=OpenAI(), + provider=OpenAIProvider(), + default_mode="invalid_mode", # Will raise ConfigurationError + ) +except ConfigurationError as e: + print(f"Config error: {e}") + print(f"Field: {e.details.get('field')}") +``` + + + +### ProviderError + +Raised for provider-specific issues (unknown model, API error, token counting failure). + +```python +try: + response = client.chat.completions.create( + model="unknown-model-xyz", + messages=[...], + ) +except ProviderError as e: + print(f"Provider error: {e}") + print(f"Provider: {e.details.get('provider')}") +``` + +### StorageError + +Raised when database operations fail. Storage errors do not affect core functionality -- the application can continue without historical metrics. + +```python +try: + metrics = client.get_metrics() +except StorageError as e: + metrics = [] # Continue without historical metrics +``` + +### CompressionError + +Raised when compression fails (rare). In practice, compression errors are caught internally and the original content passes through unchanged. This exception is only raised in strict mode. + +### HeadroomConnectionError (TypeScript) + +Raised when the TypeScript SDK cannot connect to the Headroom proxy. + +```ts twoslash +import { compress, HeadroomConnectionError } from 'headroom-ai'; + +try { + await compress(messages, { model: 'gpt-4o' }); +} catch (e) { + if (e instanceof HeadroomConnectionError) { + console.error('Is the proxy running? Start with: headroom proxy'); + } +} +``` + +## Proxy Error Mapping + +The TypeScript SDK automatically maps proxy error responses to the correct error class: + +| HTTP Status | Proxy Error Type | TypeScript Class | +|-------------|-----------------|-----------------| +| 401 | -- | `HeadroomAuthError` | +| 4xx/5xx | `configuration_error` | `ConfigurationError` | +| 4xx/5xx | `provider_error` | `ProviderError` | +| 4xx/5xx | `storage_error` | `StorageError` | +| 4xx/5xx | `tokenization_error` | `TokenizationError` | +| 4xx/5xx | `validation_error` | `ValidationError` | +| 4xx/5xx | `transform_error` | `TransformError` | +| 4xx/5xx | (other) | `HeadroomCompressError` | + +The `mapProxyError()` function handles this mapping: + +```ts twoslash +import { mapProxyError } from 'headroom-ai'; + +const error = mapProxyError(400, 'configuration_error', 'Invalid mode'); +// Returns a ConfigurationError instance +``` + +## Error Details + +All Headroom exceptions include a `details` dict/object with additional context: + + + +```ts twoslash +import { HeadroomError } from 'headroom-ai'; + +// HeadroomError.details is Record | undefined +// HeadroomCompressError also has .statusCode and .errorType +``` + + +```python +try: + client = HeadroomClient(...) +except HeadroomError as e: + print(f"Error: {e}") + print(f"Type: {type(e).__name__}") + print(f"Details: {e.details}") + # Details might include: + # - field: which config field caused the error + # - provider: which provider was involved + # - model: which model was requested + # - original_error: underlying exception +``` + + + +## Safety Guarantee + +If compression fails, the original content passes through unchanged. Your LLM calls never fail due to Headroom: + +```python +messages = [ + {"role": "tool", "content": "malformed json {{{"} +] + +# This will NOT raise an exception +# The malformed content passes through unchanged +response = client.chat.completions.create( + model="gpt-4o", + messages=messages, +) +``` + +## Best Practices + +1. **Catch specific exceptions** rather than broad `Exception` to avoid hiding real bugs +2. **Let StorageError pass** -- storage errors do not affect core compression functionality +3. **Validate on startup** with `client.validate_setup()` to catch configuration issues early +4. **Enable logging** at WARNING level to see when compression is skipped + +```python +import logging +logging.basicConfig(level=logging.WARNING) +# WARNING:headroom.transforms.smart_crusher:Skipping compression: invalid JSON +``` diff --git a/docs/content/docs/failure-learning.mdx b/docs/content/docs/failure-learning.mdx new file mode 100644 index 000000000..7b0777083 --- /dev/null +++ b/docs/content/docs/failure-learning.mdx @@ -0,0 +1,138 @@ +--- +title: Failure Learning +description: Offline failure analysis for coding agents. Analyzes past sessions, finds what went wrong, correlates with what fixed it, and writes project-level learnings. +--- + +`headroom learn` analyzes past coding agent sessions, finds what went wrong, correlates each failure with what eventually worked, and writes specific project-level learnings that prevent the same mistakes next session. + +## Quick Start + +```bash +# See recommendations for current project (dry-run, no changes) +headroom learn + +# Write recommendations to CLAUDE.md and MEMORY.md +headroom learn --apply + +# Analyze a specific project +headroom learn --project ~/my-project --apply + +# Analyze all projects +headroom learn --all --apply +``` + +## Success Correlation + +The core innovation. Instead of cataloging failures ("Read failed 5 times"), Headroom finds what the model did to **fix** each failure: + +- **Failed**: `Read axion-formats/src/main/java/.../FirstClassEntity.java` +- **Then succeeded**: `Read axion-scala-common/src/main/scala/.../FirstClassEntity.scala` +- **Learning**: "`FirstClassEntity` is at `axion-scala-common/`, not `axion-formats/`" + +This produces specific, actionable corrections -- not generic advice. + +## What It Learns + +### Environment Facts + +Which runtime commands work vs fail. + +```markdown +### Environment +- **Python**: use `uv run python` (not `python3` -- modules not available outside venv) +``` + +### File Path Corrections + +Wrong paths the model keeps guessing, with the correct locations. + +```markdown +### File Path Corrections +- `axion-common/src/.../AxionSparkConstants.scala` + -> actually at `axion-spark-common/src/.../AxionSparkConstants.scala` +``` + +### Search Scope + +Which directories to search in (narrow paths fail, broader ones work). + +```markdown +### Search Scope +- Don't search `axion-model/` -> use `axion/` (the repo root) +``` + +### Command Patterns + +How commands should (and should not) be run. + +```markdown +### Command Patterns +- **user_prefers_manual**: User rejected gradle 18 times -- show the command, don't execute +- **python_runtime**: Use `uv run python` not `python3` (ModuleNotFoundError) +``` + +### Known Large Files + +Files that need `offset`/`limit` with Read. + +```markdown +### Known Large Files +- `proxy/server.py` (~8000 lines) -- always use offset/limit +``` + +## Where Learnings Go + +| Pattern | Destination | Why | +|---------|-------------|-----| +| Environment, paths, search scope, commands, large files | **CLAUDE.md** | Stable project facts, version-controllable | +| Missing paths, retry patterns, permissions | **MEMORY.md** | May change, agent-specific | + +CLAUDE.md lives in your project directory. MEMORY.md lives in `~/.claude/projects/*/memory/`. + +## Marker-Based Updates + +Headroom manages a clearly-delimited section in each file: + +```markdown + +## Headroom Learned Patterns +*Auto-generated by `headroom learn` -- do not edit manually* +... + +``` + +On re-run, only the content between markers is replaced. Your existing file content is preserved. + +## Architecture + +The system is built with an adapter pattern so it can support multiple agent systems: + +- **Scanners** read tool-specific log formats (e.g., `~/.claude/projects/*.jsonl`) and produce normalized `ToolCall` sequences +- **Analyzers** work on `ToolCall` data -- same analysis logic for any agent system +- **Writers** output to tool-specific context injection mechanisms (e.g., CLAUDE.md) + +To add support for a new agent (e.g., Cursor), you write a Scanner that reads its log format and a Writer that outputs to `.cursorrules`. The analyzers stay the same. + +## CLI Reference + +```bash +headroom learn [OPTIONS] + +Options: + --project PATH Project directory to analyze (default: current directory) + --all Analyze all discovered projects + --apply Write recommendations (default: dry-run) + --claude-dir PATH Path to .claude directory (default: ~/.claude) +``` + +## Real-World Results + +Tested on 67,583 tool calls across 23 projects: + +| Metric | Value | +|--------|-------| +| Failure rate | 7.5% (5,066 failures) | +| Corrections extracted | 164 per project (avg) | +| Path corrections | 22 (axion project) | +| Search scope corrections | 24 (axion project) | +| Command patterns learned | 5 (axion project) | diff --git a/docs/content/docs/how-compression-works.mdx b/docs/content/docs/how-compression-works.mdx new file mode 100644 index 000000000..e36143ee1 --- /dev/null +++ b/docs/content/docs/how-compression-works.mdx @@ -0,0 +1,160 @@ +--- +title: How Compression Works +description: Understand Headroom's three-stage compression pipeline, automatic content routing, and how different content types are compressed. +--- + +Headroom automatically detects what kind of content you're sending and routes it to the right compressor. You don't need to configure anything -- just call `compress()` and the pipeline handles the rest. + +## The Three-Stage Pipeline + +Every request flows through three stages: + +``` +┌──────────────┐ ┌────────────────┐ ┌─────────────────────┐ +│ CacheAligner │────>│ ContentRouter │────>│ IntelligentContext │ +│ │ │ │ │ │ +│ Stabilize │ │ Detect type & │ │ Score messages & │ +│ prefix for │ │ route to best │ │ fit within token │ +│ cache hits │ │ compressor │ │ budget │ +└──────────────┘ └────────────────┘ └─────────────────────┘ +``` + +1. **CacheAligner** extracts dynamic content (dates, user context) from your system prompt so the static prefix stays cacheable across requests. +2. **ContentRouter** inspects each tool output and routes it to the optimal compressor -- SmartCrusher for JSON arrays, CodeAwareCompressor for source code, LogCompressor for build output, and so on. +3. **IntelligentContext** scores every message by importance (recency, semantic relevance, error indicators) and drops the lowest-value messages to fit within the model's context window. + +## Content Type Detection + +The router auto-detects content type by analyzing structure and patterns. No manual hints required. + +| Content Type | Detection Signal | Compressor | Typical Savings | +|---|---|---|---| +| JSON arrays | Valid JSON with array elements | SmartCrusher | 70-90% | +| Source code | Syntax patterns, indentation, keywords | CodeAwareCompressor | 40-70% | +| Search results | `file:line:content` format | SearchCompressor | 80-95% | +| Build/test logs | Timestamps, log levels, pytest/npm markers | LogCompressor | 85-95% | +| Diffs | Unified diff format | DiffCompressor | 60-80% | +| HTML | Tag structure | HTMLCompressor | 50-70% | +| Plain text | Fallback | TextCompressor | 60-80% | + +## Quick Start + + + +```ts twoslash +import { compress } from "headroom-ai"; + +const messages = [ + { role: "system" as const, content: "You are a helpful assistant." }, + { role: "user" as const, content: "Summarize this data" }, + { role: "tool" as const, content: '{"results": [...]}', tool_call_id: "call_1" }, +]; + +const result = await compress(messages); +console.log(`Tokens saved: ${result.tokensSaved}`); +console.log(`Compression ratio: ${result.compressionRatio}`); +``` + + +```python +from headroom.compression import compress + +result = compress(content) +print(result.compressed) +print(f"Saved {result.savings_percentage:.0f}% tokens") +``` + + + +## Configuring the Compressor + + + +```ts twoslash +import { compress } from "headroom-ai"; + +const result = await compress(messages, { + model: "gpt-4o", + tokenBudget: 50000, +}); + +console.log(`Before: ${result.tokensBefore} tokens`); +console.log(`After: ${result.tokensAfter} tokens`); +console.log(`Transforms: ${result.transformsApplied.join(", ")}`); +``` + + +```python +from headroom.compression import UniversalCompressor, UniversalCompressorConfig + +config = UniversalCompressorConfig( + compression_ratio_target=0.5, # Keep 50% of content + use_entropy_preservation=True, # Preserve UUIDs, hashes + use_magika=True, # ML-based content detection + ccr_enabled=True, # Store originals for retrieval +) + +compressor = UniversalCompressor(config=config) +result = compressor.compress(content) + +print(f"Type: {result.content_type}") +print(f"Handler: {result.handler_used}") +print(f"Saved: {result.savings_percentage:.0f}%") +``` + + + +## Structure Preservation + +Headroom doesn't blindly truncate. It identifies what matters in each content type and preserves it: + +| Content Type | What's Preserved | What's Compressed | +|---|---|---| +| **JSON** | Keys, brackets, booleans, nulls, short values, UUIDs | Long string values, whitespace | +| **Code** | Imports, function signatures, class definitions, types | Function bodies, comments | +| **Logs** | Timestamps, log levels, error messages, stack traces | Repeated patterns, verbose details | +| **Text** | High-entropy tokens (IDs, hashes), headers | Low-information content | + +## Real Compression Ratios + +| Content Type | Compression | Speed | What's Preserved | +|---|---|---|---| +| JSON (large arrays) | 70-90% | ~1ms | All keys, structure | +| Source code (Python) | 50-70% | ~10ms | Signatures, imports | +| Search results | 80-95% | ~2ms | Relevant matches | +| Build logs | 85-95% | ~3ms | Errors, stack traces | +| Plain text | 60-80% | ~5ms | High-entropy tokens | + +## Batch Compression + +For multiple contents, batch compression is more efficient: + +```python +from headroom.compression import UniversalCompressor + +compressor = UniversalCompressor() + +contents = [ + '{"users": [...]}', + 'def hello(): pass', + 'Plain text content', +] + +results = compressor.compress_batch(contents) + +for result in results: + print(f"{result.content_type}: {result.savings_percentage:.0f}% saved") +``` + +## What Happens Under the Hood + +When you call `compress()`, here is the full sequence: + +1. **Content detection** -- Magika (ML-based) or pattern matching identifies the content type +2. **Structure extraction** -- A handler extracts a structure mask marking what to preserve +3. **Compression** -- Non-structural content is compressed (SmartCrusher, LLMLingua, or text utilities) +4. **CCR storage** -- If enabled, the original is stored for retrieval when the LLM needs full context + + + The pipeline works out of the box with no configuration. All detection, routing, and compression happens automatically. Configuration is available when you need fine-grained control. + diff --git a/docs/content/docs/image-compression.mdx b/docs/content/docs/image-compression.mdx new file mode 100644 index 000000000..61d8ad067 --- /dev/null +++ b/docs/content/docs/image-compression.mdx @@ -0,0 +1,153 @@ +--- +title: Image Compression +description: ML-powered image compression that reduces vision model token usage by 40-90% while maintaining answer accuracy. +--- + +Vision models charge by the token, and images are expensive. A single 1024x1024 image costs ~765 tokens on OpenAI. Headroom's image compression uses a trained ML router to analyze your query and automatically select the optimal compression technique, saving 40-90% of image tokens. + +## How It Works + +``` +User uploads image + asks question + | + [Query Analysis] + TrainedRouter (MiniLM from HuggingFace) + Classifies: "What animal is this?" -> full_low + | + [Image Analysis] + SigLIP analyzes image properties + (has text? complex? fine details?) + | + [Apply Compression] + OpenAI: detail="low" + Anthropic: Resize to 512px + Google: Resize to 768px + | + Compressed request to LLM +``` + +The router is a fine-tuned MiniLM classifier (`chopratejas/technique-router` on HuggingFace) with 93.7% accuracy across 1,157 training examples. + +## Compression Techniques + +| Technique | Savings | When Used | Example Query | +|---|---|---|---| +| `full_low` | ~87% | General understanding | "What is this?", "Describe the scene" | +| `preserve` | 0% | Fine details needed | "Count the whiskers", "Read the serial number" | +| `crop` | 50-90% | Region-specific queries | "What's in the corner?", "Focus on the background" | +| `transcode` | ~99% | Text extraction | "Read the sign", "Transcribe the document" | + +## Quick Start + +### With Headroom Proxy (Zero Code Changes) + +```bash +# Start the proxy +headroom proxy --port 8787 + +# Connect your client -- images are compressed automatically +ANTHROPIC_BASE_URL=http://localhost:8787 claude +``` + +### With HeadroomClient + +```python +from headroom import HeadroomClient + +client = HeadroomClient(provider="openai") + +response = client.chat.completions.create( + model="gpt-4o", + messages=[{ + "role": "user", + "content": [ + {"type": "text", "text": "What animal is this?"}, + {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,..."}} + ] + }] +) +# Image automatically compressed with detail="low" (87% savings) +``` + +### Direct API + +```python +from headroom.image import ImageCompressor + +compressor = ImageCompressor() + +# Compress images in messages +compressed_messages = compressor.compress(messages, provider="openai") + +# Check savings +print(f"Saved {compressor.last_savings:.0f}% tokens") +print(f"Technique: {compressor.last_result.technique.value}") +``` + +## Provider Support + +The compressor adapts its strategy per provider: + +| Provider | Compression Method | Details | +|---|---|---| +| **OpenAI** | Sets `detail="low"` | Native detail parameter | +| **Anthropic** | Resizes to 512px | PIL-based resize | +| **Google Gemini** | Resizes to 768px | Optimized for Gemini's 768x768 tile system | + +### Token Savings by Provider + +**OpenAI** (1024x1024 image): + +| Technique | Before | After | Savings | +|---|---|---|---| +| `full_low` | 765 tokens | 85 tokens | 89% | +| `preserve` | 765 tokens | 765 tokens | 0% | + +**Anthropic** (1024x1024 image): + +| Before | After | Savings | +|---|---|---| +| ~1,398 tokens | ~349 tokens | 75% | + +**Google Gemini** (1536x1536 image): + +| Before | After | Savings | +|---|---|---| +| 1,032 tokens (4 tiles) | 258 tokens (1 tile) | 75% | + +## Configuration + +```python +from headroom.image import ImageCompressor + +compressor = ImageCompressor( + model_id="chopratejas/technique-router", # HuggingFace model + use_siglip=True, # Enable image analysis + device="cuda", # Use GPU if available (auto, cuda, cpu, mps) +) +``` + +### Proxy Configuration + +```bash +# Enable image compression (default) +headroom proxy --image-optimize + +# Disable image compression +headroom proxy --no-image-optimize +``` + +## Performance + +| Metric | Value | +|---|---| +| Router inference | ~10ms (CPU), ~2ms (GPU) | +| Image resize | ~5-20ms | +| First request | +2-3s (model download, cached after) | +| Router accuracy | 93.7% | +| Model size | ~128MB | +| GPU memory (SigLIP) | ~400MB | + + + When using the Headroom proxy, image compression happens automatically on every request that contains images. No code changes needed. + diff --git a/docs/content/docs/index.mdx b/docs/content/docs/index.mdx new file mode 100644 index 000000000..cb8633ba2 --- /dev/null +++ b/docs/content/docs/index.mdx @@ -0,0 +1,109 @@ +--- +title: Introduction +description: Headroom is the context optimization layer for LLM applications. Compress tool outputs, DB results, file reads, and RAG results before they reach the model. Same answers, fraction of the tokens. +--- + + + +Headroom compresses everything your AI agent reads -- tool outputs, database results, file reads, RAG retrievals, API responses -- before it reaches the LLM. The model sees less noise, responds faster, and costs less. + +## Quick preview + + + +```ts twoslash +import { compress } from 'headroom-ai'; + +const messages = [ + { role: 'user' as const, content: 'Analyze these results' }, +]; + +const result = await compress(messages, { model: 'gpt-4o' }); +console.log(`Saved ${result.tokensSaved} tokens (${(result.compressionRatio * 100).toFixed(0)}%)`); +``` + + +```python +from headroom import compress + +result = compress(messages, model="gpt-4o") +response = client.messages.create( + model="gpt-4o", + messages=result.messages, +) +print(f"Saved {result.tokens_saved} tokens ({result.compression_ratio:.0%})") +``` + + + +## Community stats + + + +## What gets compressed + +| Content type | What happens | Typical savings | +|---|---|---| +| JSON arrays (tool outputs) | Statistical analysis keeps errors, anomalies, boundaries | 70--90% | +| Source code | AST-aware compression preserves signatures, collapses bodies | 40--70% | +| Build/test logs | Keeps failures and errors, drops passing noise | 80--95% | +| Search results | Ranks by relevance, keeps top matches | 60--80% | +| Plain text | ModernBERT token classification removes redundancy | 30--50% | +| Git diffs | Preserves change hunks, drops unchanged context | 40--60% | +| Images | ML router selects optimal resize/quality tradeoff | 40--90% | + +## Where Headroom fits + +``` +Your Agent / App + | + | tool outputs, logs, DB reads, RAG results, file reads, API responses + v + Headroom <-- proxy, Python library, TS SDK, or framework integration + | + v + LLM Provider (OpenAI, Anthropic, Google, Bedrock, 100+ via LiteLLM) +``` + +Headroom works as a **transparent proxy** (zero code changes), a **Python function** (`compress()`), a **TypeScript function** (`compress()`), or a **framework integration** (LangChain, Agno, Strands, LiteLLM, Vercel AI SDK, MCP). + +## Real-world results + +**100 production log entries. One critical error buried at position 67.** + +| Metric | Baseline | Headroom | +|---|---|---| +| Input tokens | 10,144 | 1,260 | +| Correct answers | **4/4** | **4/4** | + +87.6% fewer tokens. Same answer. The FATAL error was automatically preserved -- not by keyword matching, but by statistical analysis of field variance. + +| Scenario | Before | After | Savings | +|---|---|---|---| +| Code search (100 results) | 17,765 | 1,408 | **92%** | +| SRE incident debugging | 65,694 | 5,118 | **92%** | +| Codebase exploration | 78,502 | 41,254 | **47%** | +| GitHub issue triage | 54,174 | 14,761 | **73%** | + +## Key Features + + + +## Framework Integrations + + + +## Nothing is lost + +Compressed content goes into the CCR store (Compress-Cache-Retrieve). The LLM gets a `headroom_retrieve` tool and can fetch full originals when it needs more detail. Compression is aggressive but reversible. + +## Next steps + + + + + + + + + diff --git a/docs/content/docs/installation.mdx b/docs/content/docs/installation.mdx new file mode 100644 index 000000000..211bd781e --- /dev/null +++ b/docs/content/docs/installation.mdx @@ -0,0 +1,164 @@ +--- +title: Installation +description: Install Headroom via pip, npm, or Docker. Includes all Python extras, TypeScript setup, Docker image tags, and environment variables. +--- + +## Python + +Headroom requires **Python 3.10+** and is published as `headroom-ai` on PyPI. + +### Core package + +```bash +pip install headroom-ai +``` + +The core package includes the `compress()` function, SmartCrusher, CacheAligner, and IntelligentContext. No heavy dependencies. + +### Extras + +Install only what you need, or grab everything with `[all]`: + +```bash +pip install "headroom-ai[all]" +``` + +| Extra | What it adds | Install command | +|---|---|---| +| `proxy` | Proxy server, MCP tools, HTTP API | `pip install "headroom-ai[proxy]"` | +| `ml` | Kompress (ModernBERT text compression, requires PyTorch) | `pip install "headroom-ai[ml]"` | +| `code` | CodeCompressor (tree-sitter AST parsing) | `pip install "headroom-ai[code]"` | +| `mcp` | MCP server tools (`headroom_compress`, `headroom_retrieve`, `headroom_stats`) | `pip install "headroom-ai[mcp]"` | +| `langchain` | LangChain `HeadroomChatModel` wrapper | `pip install "headroom-ai[langchain]"` | +| `agno` | Agno `HeadroomAgnoModel` wrapper | `pip install "headroom-ai[agno]"` | +| `evals` | Evaluation framework (GSM8K, SQuAD, BFCL benchmarks) | `pip install "headroom-ai[evals]"` | +| `all` | Everything above | `pip install "headroom-ai[all]"` | + +You can combine extras: + +```bash +pip install "headroom-ai[proxy,langchain,ml]" +``` + +### Verify the install + +```bash +python -c "import headroom; print(headroom.__version__)" +``` + +## TypeScript / Node.js + +The TypeScript SDK is published as `headroom-ai` on npm. It requires **Node.js 18+**. + +```bash +npm install headroom-ai +``` + +Or with other package managers: + +```bash +pnpm add headroom-ai +yarn add headroom-ai +``` + + +The TypeScript SDK sends messages to the Headroom proxy over HTTP for compression. The proxy runs the full compression pipeline (Python). Start it before using the SDK: + +```bash +pip install "headroom-ai[proxy]" +headroom proxy --port 8787 +``` + +Then point the SDK at it: + +```ts +import { compress } from 'headroom-ai'; + +const result = await compress(messages, { + baseUrl: 'http://localhost:8787', +}); +``` + + +### Verify the install + +```bash +node -e "const h = require('headroom-ai'); console.log('headroom-ai loaded')" +``` + +## Docker + +Pre-built images are published to GitHub Container Registry on every release. + +```bash +docker pull ghcr.io/chopratejas/headroom:latest +docker run -p 8787:8787 ghcr.io/chopratejas/headroom:latest +``` + +### Image tags + +| Tag | Extras | Base image | Description | +|---|---|---|---| +| `latest` | `proxy` | Debian slim | Default image, runs the proxy | +| `` | `proxy` | Debian slim | Pinned version | +| `nonroot` | `proxy` | Debian slim | Runs as non-root user | +| `code` | `proxy,code` | Debian slim | Includes tree-sitter for code compression | +| `code-nonroot` | `proxy,code` | Debian slim | Code compression, non-root | +| `slim` | `proxy` | Distroless | Minimal image, no shell | +| `slim-nonroot` | `proxy` | Distroless | Minimal, non-root | +| `code-slim` | `proxy,code` | Distroless | Code compression, minimal | +| `code-slim-nonroot` | `proxy,code` | Distroless | Code compression, minimal, non-root | + +### Build from source + +Use Docker Bake for multi-variant builds: + +```bash +# List all targets +docker buildx bake --list targets + +# Build the default runtime image +docker buildx bake runtime-default + +# Build a specific variant with custom registry +docker buildx bake runtime-code-slim-nonroot \ + --set '*.tags=my-registry/headroom:code-slim-nonroot' +``` + +## Environment variables + +These variables configure Headroom at runtime. Set them in your shell, `.env` file, or container environment. + +### LLM provider keys + +| Variable | Description | +|---|---| +| `OPENAI_API_KEY` | OpenAI API key (used when proxying to OpenAI) | +| `ANTHROPIC_API_KEY` | Anthropic API key (used when proxying to Anthropic) | +| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` | AWS credentials for Bedrock backend | +| `GOOGLE_APPLICATION_CREDENTIALS` | Google Cloud credentials for Vertex AI backend | + +### Proxy configuration + +| Variable | Default | Description | +|---|---|---| +| `HEADROOM_PORT` | `8787` | Port the proxy listens on | +| `HEADROOM_HOST` | `0.0.0.0` | Host the proxy binds to | +| `HEADROOM_MODE` | `optimize` | Default mode: `optimize`, `audit`, or `passthrough` | +| `HEADROOM_LOG_LEVEL` | `INFO` | Logging level | + +### TypeScript SDK + +| Variable | Default | Description | +|---|---|---| +| `HEADROOM_BASE_URL` | `http://localhost:8787` | Proxy URL for the TypeScript SDK | +| `HEADROOM_API_KEY` | _(none)_ | API key if the proxy requires auth | + +## Next steps + + + + + + + diff --git a/docs/content/docs/langchain.mdx b/docs/content/docs/langchain.mdx new file mode 100644 index 000000000..a94fa9231 --- /dev/null +++ b/docs/content/docs/langchain.mdx @@ -0,0 +1,188 @@ +--- +title: LangChain +description: Automatic context compression for LangChain chat models, memory, retrievers, and agents. +--- + +Headroom integrates with LangChain to compress context across all LangChain patterns: chat models, memory, retrievers, agents, and streaming. + +## Installation + +```bash +pip install "headroom-ai[langchain]" +``` + +## Quick start + +Wrap any chat model in one line: + +```python +from langchain_openai import ChatOpenAI +from headroom.integrations import HeadroomChatModel + +llm = HeadroomChatModel(ChatOpenAI(model="gpt-4o")) + +# Use exactly like before +response = llm.invoke("Hello!") + +# Check savings +print(llm.get_metrics()) +# {'tokens_saved': 12500, 'savings_percent': 45.2, 'requests': 50} +``` + +Works with any provider: + +```python +from langchain_anthropic import ChatAnthropic + +llm = HeadroomChatModel(ChatAnthropic(model="claude-sonnet-4-20250514")) +``` + +## Memory integration + +`HeadroomChatMessageHistory` wraps any chat history with automatic compression. Long conversations stay under your token budget: + +```python +from langchain.memory import ConversationBufferMemory +from langchain_community.chat_message_histories import ChatMessageHistory +from headroom.integrations import HeadroomChatMessageHistory + +base_history = ChatMessageHistory() +compressed_history = HeadroomChatMessageHistory( + base_history, + compress_threshold_tokens=4000, # Compress when over 4K tokens + keep_recent_turns=5, # Always keep last 5 turns +) + +memory = ConversationBufferMemory(chat_memory=compressed_history) +``` + +After usage: + +```python +print(compressed_history.get_compression_stats()) +# {'compression_count': 12, 'total_tokens_saved': 28000} +``` + +## Retriever integration + +`HeadroomDocumentCompressor` filters retrieved documents by relevance. Retrieve many for recall, keep the best for precision: + +```python +from langchain.retrievers import ContextualCompressionRetriever +from langchain_community.vectorstores import FAISS +from headroom.integrations import HeadroomDocumentCompressor + +base_retriever = vectorstore.as_retriever(search_kwargs={"k": 50}) + +compressor = HeadroomDocumentCompressor( + max_documents=10, + min_relevance=0.3, + prefer_diverse=True, # MMR-style diversity +) + +retriever = ContextualCompressionRetriever( + base_compressor=compressor, + base_retriever=base_retriever, +) + +# Retrieves 50 docs, returns best 10 +docs = retriever.invoke("What is Python?") +``` + +## Agent tool wrapping + +`wrap_tools_with_headroom` compresses tool outputs before they re-enter the agent's context: + +```python +from langchain_core.tools import tool +from headroom.integrations import wrap_tools_with_headroom + +@tool +def search_database(query: str) -> str: + """Search the database.""" + return json.dumps({"results": [...], "total": 1000}) + +wrapped_tools = wrap_tools_with_headroom( + [search_database], + min_chars_to_compress=1000, +) + +agent = create_openai_tools_agent(llm, wrapped_tools, prompt) +executor = AgentExecutor(agent=agent, tools=wrapped_tools) +``` + +Per-tool metrics: + +```python +from headroom.integrations import get_tool_metrics + +metrics = get_tool_metrics() +print(metrics.get_summary()) +# {'total_invocations': 25, 'total_compressions': 18, 'total_chars_saved': 450000} +``` + +## LangGraph ReAct agent + +```python +from langchain_openai import ChatOpenAI +from langgraph.prebuilt import create_react_agent +from headroom.integrations import HeadroomChatModel, wrap_tools_with_headroom + +llm = HeadroomChatModel(ChatOpenAI(model="gpt-4o")) +tools = wrap_tools_with_headroom([search_web, query_database]) + +agent = create_react_agent(llm, tools) +result = agent.invoke({ + "messages": [("user", "Find users who signed up last week")] +}) +``` + +## LangGraph custom graph + +Insert a compression node between tools and the agent in a custom `StateGraph`: + +```python +from langgraph.graph import StateGraph, MessagesState, START, END +from headroom.integrations.langchain import create_compress_tool_messages_node + +graph = StateGraph(MessagesState) +graph.add_node("agent", agent_node) +graph.add_node("tools", tools_node) +graph.add_node("compress", create_compress_tool_messages_node( + min_tokens_to_compress=100, +)) + +# Wire: tools -> compress -> agent +graph.add_edge(START, "agent") +graph.add_edge("tools", "compress") +graph.add_edge("compress", "agent") +``` + +## Streaming + +Full async support: + +```python +# Async invoke +response = await llm.ainvoke("Hello!") + +# Async streaming +async for chunk in llm.astream("Tell me a story"): + print(chunk.content, end="", flush=True) +``` + +## Custom configuration + +```python +from headroom import HeadroomConfig, HeadroomMode + +config = HeadroomConfig( + default_mode=HeadroomMode.OPTIMIZE, + smart_crusher_target_ratio=0.3, +) + +llm = HeadroomChatModel( + ChatOpenAI(model="gpt-4o"), + headroom_config=config, +) +``` diff --git a/docs/content/docs/limitations.mdx b/docs/content/docs/limitations.mdx new file mode 100644 index 000000000..d39b00b30 --- /dev/null +++ b/docs/content/docs/limitations.mdx @@ -0,0 +1,143 @@ +--- +title: Limitations +description: When Headroom helps, when it does not, and what to watch out for. Honest documentation of compression constraints and safety gates. +--- + +Headroom is designed to compress LLM context without losing accuracy. This page documents when it helps, when it does not, and the safety gates that prevent harmful compression. + +## When Headroom Helps vs. Does Not + +| Content Type | Compression | Latency Impact | Best For | +|---|---|---|---| +| **JSON: Arrays of dicts** (search results, API responses, DB rows) | 86--100% | Net latency win on Sonnet/Opus | Primary use case | +| **JSON: Arrays of strings** (file paths, log lines, tags) | 60--90% | Net latency win | String dedup + sampling | +| **JSON: Arrays of numbers** (metrics, time series) | 70--85% | Net latency win | Statistical summary | +| **JSON: Mixed-type arrays** | 50--70% | Net latency win | Group-by-type compression | +| **Structured logs** (as JSON) | 82--95% | Net latency win | Log entries in tool outputs | +| **Agentic conversations** (25--50 turns) | 56--81% | Break-even to net win | Multi-tool agent sessions | +| **Plain text** (documentation, articles) | 43--46% | Adds latency (cost savings only) | Cost optimization | +| **Code** | Passthrough | Minimal overhead | See below | +| **RAG document contexts** | Passthrough | Minimal overhead | Not compressed | + +### Where Headroom Adds the Most Value + +- Long agent sessions with accumulated tool outputs (40--80% compression) +- JSON-heavy workflows -- API responses, database queries (83--94% compression) +- Build and test output (85--94% compression) +- Multi-tool agents (60--76% compression across tool results) + +### Where Headroom Adds Little Value + +- Short conversational exchanges (median 4.8% compression) +- Code-only sessions (reading/writing files) -- code passes through +- Single-turn requests with no accumulated context + +## What Headroom Does NOT Compress + +- **Short messages** (< 300 tokens) -- overhead exceeds savings +- **Source code** -- passes through unchanged to preserve correctness +- **grep/search results** -- compact structured format, already minimal +- **Images** -- counted at fixed token cost (~1,600 tokens), not compressed +- **System prompts** -- preserved for prefix cache compatibility + +## Code Compression + +Headroom includes an AST-aware CodeCompressor (tree-sitter, 8 languages) but it is gated behind safety protections that prevent it from firing in most real-world scenarios. This is intentional. + +**Why code mostly passes through:** + +1. **Word count gate**: Content under 50 words is silently skipped +2. **Recent code protection** (`protect_recent_code=4`): Code in the last 4 messages is never compressed +3. **Analysis intent protection** (`protect_analysis_context=True`): If the most recent user message contains keywords like "analyze", "review", "explain", "fix", "debug" -- ALL code in the conversation is protected + +**Why this is the right default**: Code is almost always fetched because the user wants to work with it. Compressing function bodies would remove exactly what they need. + +**Where code savings come from**: The IntelligentContextManager drops old code messages that are no longer relevant (scoring-based), which is a better strategy than stripping function bodies. + +**Override**: Set `protect_analysis_context=False` in `ContentRouterConfig` for aggressive code compression. Requires `headroom-ai[code]` for tree-sitter. + +## JSON Compression Constraints + +### What Gets Compressed + +- Arrays of **dicts**: Full statistical analysis with adaptive K (Kneedle algorithm) +- Arrays of **strings**: Dedup + adaptive sampling + error preservation +- Arrays of **numbers**: Statistical summary + outlier/change-point preservation +- **Mixed-type** arrays: Grouped by type, each group compressed independently +- **Nested** objects: Recursed into, arrays within are compressed (up to depth 5) + +### What Passes Through + +- Arrays below 5 items (`min_items_to_analyze`) +- Content below 200 tokens (`min_tokens_to_crush`) +- Bool-only arrays +- JSON objects without array values +- Malformed JSON (silently passes through, no error) + +### Edge Cases + +- **NaN/Infinity** in numeric fields: Filtered out before statistics are computed +- **Nesting depth > 5**: Inner arrays not examined for compression +- **Mixed-type arrays with small groups**: Groups below `min_items_to_analyze` are kept as-is + +## Safety Gates + +All compressors follow the same principle: **fail gracefully, return original content unchanged**. + +- Invalid JSON passes through (no error raised) +- AST parse failure falls back to original or LLMLingua +- Compression that makes output larger returns the original +- Missing optional dependencies (tree-sitter, LLMLingua) cause a passthrough with warning log +- Errors are logged at WARNING level and never propagated to callers + + +LLMLingua out-of-memory during model loading raises a `RuntimeError`. All other failures are silently handled. + + +## Adaptive K: How Item Retention Works + +SmartCrusher does not use fixed K values. It uses information-theoretic sizing: + +1. **Kneedle algorithm** on bigram coverage curves finds the point where adding more items stops providing new information +2. **SimHash** fingerprinting detects near-duplicate items +3. **zlib validation** ensures the subset captures the full set's diversity + +The resulting K is split: 30% from array start, 15% from end, 55% for importance-scored items. + +**Safety guarantees (additive, never dropped):** + +- Error items (containing "error", "exception", "failed", "critical") -- across ALL array types +- Numeric anomalies (> 2 standard deviations from mean) +- String length anomalies (> 2 standard deviations from mean length) +- Change points (sudden shifts in running values) + +These are kept even if they exceed the K budget. + +## Configuration Tuning + +| Parameter | Default | Effect | +|---|---|---| +| `min_items_to_analyze` | 5 | Arrays below this pass through | +| `min_tokens_to_crush` | 200 | Content below this passes through | +| `max_items_after_crush` | 15 | Upper bound on retained items | +| `variance_threshold` | 2.0 | Std devs for anomaly detection (lower = more preserved) | +| `protect_analysis_context` | True | Protect code when user asks about it | +| `protect_recent_code` | 4 | Messages from end to protect code in | +| `skip_user_messages` | True | Never compress user messages | +| `toin_confidence_threshold` | 0.3 | Minimum TOIN confidence to apply hints | + +## Provider Interactions + +- CacheAligner maximizes Anthropic/OpenAI prefix cache hit rates +- Token counting uses model-specific tokenizers (tiktoken for OpenAI, calibrated estimation for Anthropic) +- Compression works with all providers -- no provider-specific limitations +- Compressed content is valid JSON -- downstream tools and parsers work unchanged + +## TOIN Cold Start + +The Tool Output Intelligence Network (TOIN) learns compression patterns from usage. For new tool types: + +- No learned patterns exist -- falls back to statistical heuristics +- Confidence below `toin_confidence_threshold` (default 0.3) -- TOIN hints ignored +- Patterns build up over time as tools are used repeatedly +- Cross-session learning requires persistence (`TelemetryConfig.storage_path`) diff --git a/docs/content/docs/litellm.mdx b/docs/content/docs/litellm.mdx new file mode 100644 index 000000000..4a5b4136d --- /dev/null +++ b/docs/content/docs/litellm.mdx @@ -0,0 +1,89 @@ +--- +title: LiteLLM +description: Add Headroom compression to LiteLLM with a single callback. Works with all 100+ supported providers. +--- + +Headroom integrates with [LiteLLM](https://github.com/BerriAI/litellm) as a callback that compresses messages before they reach any provider. One line to enable, works with all 100+ LiteLLM-supported providers. + +## Installation + +```bash +pip install headroom-ai litellm +``` + +## Quick start + +```python +import litellm +from headroom.integrations.litellm_callback import HeadroomCallback + +litellm.callbacks = [HeadroomCallback()] + +# All calls now compressed automatically +response = litellm.completion(model="gpt-4o", messages=[...]) +response = litellm.completion(model="bedrock/claude-sonnet", messages=[...]) +response = litellm.completion(model="azure/gpt-4o", messages=[...]) +``` + +The callback compresses messages in LiteLLM's `pre_call_hook` before they reach the provider. + +## How it works + +1. You call `litellm.completion()` with your messages +2. `HeadroomCallback.pre_call_hook` compresses the messages +3. LiteLLM sends the compressed messages to the provider +4. The response comes back unchanged + +This works with every provider LiteLLM supports: OpenAI, Anthropic, Bedrock, Azure, Vertex AI, Cohere, Groq, Mistral, Together, Ollama, and more. + +## With LiteLLM Proxy + +If you run LiteLLM as a proxy server, use the ASGI middleware: + +```python +from litellm.proxy.proxy_server import app +from headroom.integrations.asgi import CompressionMiddleware + +app.add_middleware(CompressionMiddleware) +``` + +Or configure via YAML: + +```yaml +# litellm_config.yaml +litellm_settings: + callbacks: ["headroom.integrations.litellm_callback.HeadroomCallback"] +``` + +## Direct compress() with LiteLLM + +You can also use `compress()` directly instead of the callback: + +```python +import litellm +from headroom import compress + +messages = [{"role": "user", "content": large_content}] +compressed = compress(messages, model="bedrock/claude-sonnet") + +response = litellm.completion( + model="bedrock/claude-sonnet", + messages=compressed.messages, +) + +print(f"Saved {compressed.tokens_saved} tokens") +``` + +## ASGI middleware + +Drop-in middleware for any ASGI application. Intercepts `/v1/messages`, `/v1/chat/completions`, `/v1/responses`, and `/chat/completions`: + +```python +from fastapi import FastAPI +from headroom.integrations.asgi import CompressionMiddleware + +app = FastAPI() +app.add_middleware(CompressionMiddleware) +``` + +Response headers include `x-headroom-compressed: true` and `x-headroom-tokens-saved: 1234`. diff --git a/docs/content/docs/mcp.mdx b/docs/content/docs/mcp.mdx new file mode 100644 index 000000000..018da9546 --- /dev/null +++ b/docs/content/docs/mcp.mdx @@ -0,0 +1,149 @@ +--- +title: MCP Tools +description: Compression, retrieval, and stats as MCP tools for Claude Code, Cursor, and any MCP-compatible host. +--- + +Headroom's MCP server exposes compression, retrieval, and observability as tools that any MCP-compatible AI coding tool can call -- Claude Code, Cursor, Codex, and more. No proxy required. + +## Installation + +```bash +# MCP tools only (lightweight) +pip install "headroom-ai[mcp]" + +# Or with the proxy +pip install "headroom-ai[proxy]" +``` + +## Setup for Claude Code + +```bash +# Register with Claude Code (one-time) +headroom mcp install + +# Start Claude Code — it now has headroom tools +claude +``` + +Claude Code can now compress content on demand, retrieve originals, and check session stats. + +For automatic compression of **all** traffic, also run the proxy: + +```bash +# Terminal 1 +headroom proxy + +# Terminal 2 +ANTHROPIC_BASE_URL=http://127.0.0.1:8787 claude +``` + +## Tools + +### headroom_compress + +Compress content on demand. The LLM calls this when it wants to shrink large content before reasoning over it. + +**Parameters:** +- `content` (required) -- text to compress (files, JSON, logs, search results) + +**Returns:** +- `compressed` -- compressed text +- `hash` -- key for retrieving the original later +- `original_tokens` / `compressed_tokens` / `savings_percent` +- `transforms` -- which compression algorithms were applied + +Example flow: + +``` +Claude: Let me compress this large output to save context space. + +-> headroom_compress(content="[5000 lines of grep results...]") + +<- { + "compressed": "[key matches with context...]", + "hash": "a1b2c3d4e5f6...", + "original_tokens": 12000, + "compressed_tokens": 3200, + "savings_percent": 73.3, + "transforms": ["router:search:0.27"] + } +``` + +The original is stored locally for 1 hour. If the LLM needs the full content later, it calls `headroom_retrieve`. + +### headroom_retrieve + +Retrieve original uncompressed content by hash. + +**Parameters:** +- `hash` (required) -- hash key from a previous compression +- `query` (optional) -- search within the original to return only matching items + +**Returns:** +- `original_content` (full retrieval) or `results` (filtered search) +- `source` -- `"local"` or `"proxy"` + +Retrieval checks the local store first, then falls back to the proxy's store. Hashes from either source work transparently. + +### headroom_stats + +Session compression statistics. + +**Returns:** +- `compressions`, `retrievals`, `tokens_saved`, `savings_percent` +- `estimated_cost_saved_usd` +- `recent_events` -- last 10 compression/retrieval events +- `sub_agents` -- stats from sub-agent MCP instances +- `combined` -- main + sub-agent totals +- `proxy` -- request count, cache hits, cost saved (if proxy is running) + +Sub-agent stats are aggregated via a shared stats file at `~/.headroom/session_stats.jsonl`. + +## CLI commands + +```bash +# Install (registers with Claude Code) +headroom mcp install +headroom mcp install --proxy-url http://host:9000 # Custom proxy URL +headroom mcp install --force # Overwrite existing + +# Check status +headroom mcp status + +# Uninstall +headroom mcp uninstall + +# Debug mode +headroom mcp serve --debug +``` + +## Cross-tool compatibility + +| Tool | MCP Support | Setup | +|------|-------------|-------| +| Claude Code | Native | `headroom mcp install` | +| Cursor | Supported | Add to Cursor MCP settings | +| Codex | If supported | Configure MCP server | +| Any MCP host | Yes | Point to `headroom mcp serve` | + +## Architecture + +### MCP only (no proxy) + +The LLM calls `headroom_compress` on demand. Compression happens locally in the MCP process. Originals are stored in a local `CompressionStore` with 1-hour TTL. + +### MCP + Proxy (full setup) + +The proxy compresses all traffic at the HTTP level (before the LLM sees content). MCP tools operate after the LLM receives content. They handle different data and do not double-compress. + +`headroom_retrieve` checks the local store first, then falls back to the proxy's store. + +## Troubleshooting + +**"MCP SDK not installed"** -- Run `pip install "headroom-ai[mcp]"`. + +**"Proxy not running"** -- Start the proxy with `headroom proxy` in another terminal. Only needed for proxy-backed retrieval. + +**"Entry not found or expired"** -- Local content expires after 1 hour, proxy content after 5 minutes. + +**Claude doesn't see headroom tools** -- Run `headroom mcp status`, restart Claude Code, and verify with `/mcp` inside Claude Code. diff --git a/docs/content/docs/memory.mdx b/docs/content/docs/memory.mdx new file mode 100644 index 000000000..352d59b5b --- /dev/null +++ b/docs/content/docs/memory.mdx @@ -0,0 +1,243 @@ +--- +title: Persistent Memory +description: Hierarchical, temporal memory for LLM applications. Enable your AI to remember across conversations with intelligent scoping and versioning. +--- + +LLMs have two fundamental limitations: context windows overflow with too much history, and every conversation starts from zero. Persistent Memory solves both by extracting key facts, persisting them, and injecting them when relevant. + +This is **temporal compression** -- instead of carrying 10,000 tokens of conversation history, carry 100 tokens of extracted memories. + +## Quick Start + +```python +from openai import OpenAI +from headroom import with_memory + +# One line -- that's it +client = with_memory(OpenAI(), user_id="alice") + +# Use exactly like normal +response = client.chat.completions.create( + model="gpt-4o", + messages=[{"role": "user", "content": "I prefer Python for backend work"}] +) +# Memory extracted INLINE -- zero extra latency + +# Later, in a new conversation... +response = client.chat.completions.create( + model="gpt-4o", + messages=[{"role": "user", "content": "What language should I use?"}] +) +# Response uses the Python preference from memory +``` + +## How It Works + +The `with_memory()` wrapper intercepts every chat completion call: + +1. **Inject** -- Semantic search finds relevant memories and prepends them to the user message +2. **Instruct** -- Adds a memory extraction instruction to the system prompt +3. **Call** -- Forwards the request to the LLM +4. **Parse** -- Extracts the `` block from the response +5. **Store** -- Saves with embeddings, vector index, and full-text search index +6. **Return** -- Cleans the response (strips the memory block before returning) + +Memory extraction happens **inline** as part of the LLM response. No extra API calls, no extra latency. + +## Hierarchical Scoping + +Memories exist at four scope levels, from broadest to narrowest: + +| Scope | Persists Across | Use Case | +|-------|-----------------|----------| +| **User** | All sessions, all time | Long-term preferences, identity | +| **Session** | Current session only | Current task context | +| **Agent** | Current agent in session | Agent-specific context | +| **Turn** | Single turn only | Ephemeral working memory | + +```python +from openai import OpenAI +from headroom import with_memory + +# Session 1: Morning +client1 = with_memory( + OpenAI(), + user_id="bob", + session_id="morning-session", +) +response = client1.chat.completions.create( + model="gpt-4o", + messages=[{"role": "user", "content": "I prefer Go for performance-critical code"}] +) +# Memory stored at USER level (persists across sessions) + +# Session 2: Afternoon (different session, same user) +client2 = with_memory( + OpenAI(), + user_id="bob", + session_id="afternoon-session", +) +response = client2.chat.completions.create( + model="gpt-4o", + messages=[{"role": "user", "content": "What language for my new microservice?"}] +) +# Recalls Go preference from morning session +``` + +## Memory Categories + +Memories are categorized for better organization and retrieval: + +| Category | Description | Examples | +|----------|-------------|----------| +| `PREFERENCE` | Likes, dislikes, preferred approaches | "Prefers Python", "Likes dark mode" | +| `FACT` | Identity, role, constraints | "Works at fintech startup", "Senior engineer" | +| `CONTEXT` | Current goals, ongoing tasks | "Migrating to microservices", "Working on auth" | +| `ENTITY` | Information about entities | "Project Apollo uses React", "Team lead is Sarah" | +| `DECISION` | Decisions made | "Chose PostgreSQL over MySQL" | +| `INSIGHT` | Derived insights | "User tends to prefer typed languages" | + +## Memory API + +The `with_memory()` wrapper exposes a `.memory` attribute for direct access: + +```python +client = with_memory(OpenAI(), user_id="alice") + +# Search memories (semantic) +results = client.memory.search("python preferences", top_k=5) +for memory in results: + print(f"{memory.content}") + +# Add a memory manually +client.memory.add( + "User is a senior engineer", + category="fact", + importance=0.9, +) + +# Get all memories for this user +all_memories = client.memory.get_all() + +# Clear all memories +client.memory.clear() + +# Get stats +stats = client.memory.stats() +print(f"Total memories: {stats['total']}") +print(f"By category: {stats['categories']}") +``` + +## Temporal Versioning + +When facts change, Headroom creates a **supersession chain** that preserves history: + +```python +from headroom.memory import HierarchicalMemory, MemoryCategory + +memory = await HierarchicalMemory.create() + +# Original fact +orig = await memory.add( + content="User works at Google", + user_id="alice", + category=MemoryCategory.FACT, +) + +# User changes jobs -- supersede the old memory +new = await memory.supersede( + old_memory_id=orig.id, + new_content="User now works at Anthropic", +) + +# Query current state (excludes superseded by default) +current = await memory.query(MemoryFilter( + user_id="alice", + include_superseded=False, +)) +# Returns only "User now works at Anthropic" + +# Get the full chain +chain = await memory.get_history(new.id) +# [ +# Memory(content="User works at Google", is_current=False), +# Memory(content="User now works at Anthropic", is_current=True), +# ] +``` + +This gives you an audit trail, the ability to debug why the LLM made certain decisions, and rollback if needed. + +## Backends + +### Embedder Backends + +```python +from headroom.memory import MemoryConfig, EmbedderBackend + +# Local embeddings (recommended -- fast, free, private) +config = MemoryConfig( + embedder_backend=EmbedderBackend.LOCAL, + embedder_model="all-MiniLM-L6-v2", +) + +# OpenAI embeddings (higher quality, costs money) +config = MemoryConfig( + embedder_backend=EmbedderBackend.OPENAI, + openai_api_key="sk-...", + embedder_model="text-embedding-3-small", +) + +# Ollama embeddings (local server, many models) +config = MemoryConfig( + embedder_backend=EmbedderBackend.OLLAMA, + ollama_base_url="http://localhost:11434", + embedder_model="nomic-embed-text", +) +``` + +### Storage + +Storage uses **SQLite** for CRUD and filtering, **HNSW** for vector similarity search, and **FTS5** for full-text keyword search. All embedded -- no external services required. + +```python +config = MemoryConfig( + db_path="memory.db", + vector_dimension=384, + hnsw_ef_construction=200, + hnsw_m=16, + hnsw_ef_search=50, + cache_enabled=True, + cache_max_size=1000, +) +``` + +## Provider Compatibility + +Memory works with any OpenAI-compatible client: + +```python +from openai import OpenAI +from headroom import with_memory + +# OpenAI +client = with_memory(OpenAI(), user_id="alice") + +# Azure OpenAI +client = with_memory( + OpenAI(base_url="https://your-resource.openai.azure.com/..."), + user_id="alice", +) + +# Groq +from groq import Groq +client = with_memory(Groq(), user_id="alice") +``` + +## Performance + +| Operation | Latency | Notes | +|-----------|---------|-------| +| Memory injection | <50ms | Local embeddings + HNSW search | +| Memory extraction | +50-100 tokens | Part of LLM response (inline) | +| Memory storage | <10ms | SQLite + HNSW + FTS5 indexing | +| Cache hit | <1ms | LRU cache lookup | diff --git a/docs/content/docs/meta.json b/docs/content/docs/meta.json new file mode 100644 index 000000000..d538b3fef --- /dev/null +++ b/docs/content/docs/meta.json @@ -0,0 +1,49 @@ +{ + "pages": [ + "---Getting Started---", + "index", + "quickstart", + "installation", + "community-savings", + "---Compression---", + "how-compression-works", + "smart-crusher", + "code-compression", + "image-compression", + "text-and-logs", + "---Reversible Compression---", + "ccr", + "---Cache & Context---", + "cache-optimization", + "context-management", + "---Memory---", + "memory", + "shared-context", + "failure-learning", + "---Proxy Server---", + "proxy", + "---Integrations---", + "vercel-ai-sdk", + "openai-sdk", + "anthropic-sdk", + "langchain", + "agno", + "strands", + "litellm", + "mcp", + "---Configuration---", + "configuration", + "---Observability---", + "metrics", + "simulation", + "---API Reference---", + "api-reference", + "---Architecture---", + "architecture", + "benchmarks", + "limitations", + "---Help---", + "errors", + "troubleshooting" + ] +} diff --git a/docs/content/docs/metrics.mdx b/docs/content/docs/metrics.mdx new file mode 100644 index 000000000..4f741ff23 --- /dev/null +++ b/docs/content/docs/metrics.mdx @@ -0,0 +1,272 @@ +--- +title: Metrics & Monitoring +description: Monitor compression performance, cost savings, and system health with Headroom's built-in metrics, Prometheus endpoint, and SDK APIs. +--- + +Headroom provides comprehensive metrics for monitoring compression performance, cost savings, and system health through both the proxy server and the SDK. + +## Proxy Endpoints + +### Stats Endpoint + +```bash +curl http://localhost:8787/stats +``` + +```json +{ + "persistent_savings": { + "lifetime": { + "tokens_saved": 12500, + "compression_savings_usd": 0.04 + } + }, + "requests": { + "total": 42, + "cached": 5, + "rate_limited": 0, + "failed": 0 + }, + "tokens": { + "input": 50000, + "output": 8000, + "saved": 12500, + "savings_percent": 25.0 + }, + "cost": { + "total_cost_usd": 0.15, + "total_savings_usd": 0.04 + }, + "cache": { + "entries": 10, + "total_hits": 5 + } +} +``` + +Persistent savings are stored at `~/.headroom/proxy_savings.json` and survive proxy restarts. Override the path with `HEADROOM_SAVINGS_PATH`. + +### Historical Savings + +```bash +curl http://localhost:8787/stats-history +``` + +Returns durable compression history with hourly, daily, weekly, and monthly rollups. Supports CSV export: + +```bash +curl "http://localhost:8787/stats-history?format=csv&series=daily" +curl "http://localhost:8787/stats-history?format=csv&series=monthly" +``` + +### Prometheus Metrics + +```bash +curl http://localhost:8787/metrics +``` + +``` +# HELP headroom_requests_total Total requests processed +headroom_requests_total{mode="optimize"} 1234 + +# HELP headroom_tokens_saved_total Total tokens saved +headroom_tokens_saved_total 5678900 + +# HELP headroom_compression_ratio Compression ratio histogram +headroom_compression_ratio_bucket{le="0.5"} 890 +headroom_compression_ratio_bucket{le="0.7"} 1100 +headroom_compression_ratio_bucket{le="0.9"} 1200 + +# HELP headroom_latency_seconds Request latency histogram +headroom_latency_seconds_bucket{le="0.01"} 800 +headroom_latency_seconds_bucket{le="0.1"} 1150 + +# HELP headroom_cache_hits_total Cache hit counter +headroom_cache_hits_total 456 +``` + +### Health Check + +```bash +curl http://localhost:8787/health +``` + +```json +{ + "status": "healthy", + "version": "0.1.0", + "uptime_seconds": 3600, + "llmlingua_enabled": false +} +``` + +## SDK Metrics + + + + +### Proxy Stats + +The TypeScript SDK queries the proxy for stats: + +```ts twoslash +import { HeadroomClient } from 'headroom-ai'; + +const client = new HeadroomClient(); + +// Get proxy stats +const stats = await client.proxyStats(); +console.log(`Tokens saved: ${stats.tokens.saved}`); +console.log(`Savings: ${stats.tokens.savings_percent}%`); +``` + +### Compression Result Metrics + +Every `compress()` call returns metrics: + +```ts twoslash +import { compress } from 'headroom-ai'; + +const result = await compress(messages, { model: 'gpt-4o' }); +console.log(`Tokens: ${result.tokensBefore} -> ${result.tokensAfter}`); +console.log(`Saved: ${result.tokensSaved} (${(result.compressionRatio * 100).toFixed(1)}%)`); +console.log(`Transforms: ${result.transformsApplied.join(', ')}`); +``` + + + + +### Session Stats + +Quick stats for the current session (no database query): + +```python +stats = client.get_stats() +print(f"Mode: {stats['config']['mode']}") +print(f"Tokens saved: {stats['session']['tokens_saved_total']}") +print(f"Avg compression: {stats['session']['compression_ratio_avg']:.1%}") +``` + +Returns: + +```python +{ + "session": { + "requests_total": 10, + "tokens_input_before": 50000, + "tokens_input_after": 35000, + "tokens_saved_total": 15000, + "tokens_output_total": 8000, + "cache_hits": 3, + "compression_ratio_avg": 0.70, + }, + "config": { + "mode": "optimize", + "provider": "openai", + "cache_optimizer_enabled": True, + "semantic_cache_enabled": False, + }, + "transforms": { + "smart_crusher_enabled": True, + "cache_aligner_enabled": True, + "rolling_window_enabled": True, + }, +} +``` + +### Historical Metrics + +Query stored metrics from the database: + +```python +from datetime import datetime, timedelta + +metrics = client.get_metrics( + start_time=datetime.utcnow() - timedelta(hours=1), + limit=100, +) + +for m in metrics: + print(f"{m.timestamp}: {m.tokens_input_before} -> {m.tokens_input_after}") +``` + +### Summary Statistics + +Aggregate statistics across all stored metrics: + +```python +summary = client.get_summary() +print(f"Total requests: {summary['total_requests']}") +print(f"Total tokens saved: {summary['total_tokens_saved']}") +print(f"Average compression: {summary['avg_compression_ratio']:.1%}") +print(f"Total cost savings: ${summary['total_cost_saved_usd']:.2f}") +``` + + + + +## Logging + + + +```python +import logging + +# INFO level shows compression summaries +logging.basicConfig(level=logging.INFO) + +# DEBUG level shows detailed transform decisions +logging.basicConfig(level=logging.DEBUG) +``` + +Example output: + +``` +INFO:headroom.transforms.pipeline:Pipeline complete: 45000 -> 4500 tokens (saved 40500, 90.0% reduction) +INFO:headroom.transforms.smart_crusher:SmartCrusher applied top_n strategy: kept 15 of 1000 items +DEBUG:headroom.transforms.smart_crusher:Kept items: [0,1,2,42,77,97,98,99] (errors at 42, warnings at 77) +``` + + +```bash +# Log to file +headroom proxy --log-file headroom.jsonl + +# Increase verbosity +headroom proxy --log-level debug +``` + + + +## Cost Tracking + +### Budget Alerts + +Set a budget limit in the proxy: + +```bash +headroom proxy --budget 10.00 +``` + +When the budget is exceeded, requests return a budget exceeded error, the `/stats` endpoint shows budget status, and logs indicate the budget state. + +## Key Metrics to Monitor + +| Metric | What It Tells You | Target | +|--------|-------------------|--------| +| `tokens_saved_total` | Total cost savings | Higher is better | +| `compression_ratio_avg` | Efficiency | 0.7--0.9 typical | +| `cache_hit_rate` | Cache effectiveness | >20% is good | +| `latency_p99` | Performance impact | <10ms | +| `failed_requests` | Reliability | 0 | + +## Grafana Dashboard + +Example Prometheus queries for a Grafana dashboard: + +| Panel | PromQL | +|-------|--------| +| Tokens Saved | `headroom_tokens_saved_total` | +| Compression Ratio (median) | `histogram_quantile(0.5, headroom_compression_ratio_bucket)` | +| Request Latency (p99) | `histogram_quantile(0.99, headroom_latency_seconds_bucket)` | +| Cache Hit Rate | `headroom_cache_hits_total / (headroom_cache_hits_total + headroom_cache_misses_total)` | diff --git a/docs/content/docs/openai-sdk.mdx b/docs/content/docs/openai-sdk.mdx new file mode 100644 index 000000000..399367dfd --- /dev/null +++ b/docs/content/docs/openai-sdk.mdx @@ -0,0 +1,126 @@ +--- +title: OpenAI SDK +description: Auto-compress messages in the OpenAI Node.js SDK with a single withHeadroom() wrapper. +--- + +Headroom wraps the OpenAI Node.js SDK to automatically compress messages before every `chat.completions.create()` call. All other methods (embeddings, images, audio) pass through unchanged. + +## Installation + +```bash +npm install headroom-ai openai +``` + + +The TypeScript SDK sends messages to a local Headroom proxy for compression. Start the proxy before using the SDK: + +```bash +pip install "headroom-ai[proxy]" +headroom proxy +``` + + +## Quick start + +```ts twoslash +import { withHeadroom } from 'headroom-ai/openai'; +import OpenAI from 'openai'; + +const client = withHeadroom(new OpenAI()); + +// Messages are compressed automatically before sending +const response = await client.chat.completions.create({ + model: 'gpt-4o', + messages: longConversation, +}); +``` + +That's it. Every call to `client.chat.completions.create()` compresses the messages first. The response format is identical to the unwrapped client. + +## How it works + +`withHeadroom()` returns a proxy around your OpenAI client that intercepts `chat.completions.create()`: + +1. Extracts `messages` from the request params +2. Sends them to the Headroom proxy's `/v1/compress` endpoint +3. Replaces the original messages with the compressed result +4. Forwards the request to OpenAI as normal + +All other client methods are untouched: + +```ts twoslash +import { withHeadroom } from 'headroom-ai/openai'; +import OpenAI from 'openai'; + +const client = withHeadroom(new OpenAI()); + +// These pass through unchanged +const embedding = await client.embeddings.create({ + model: 'text-embedding-3-small', + input: 'Hello world', +}); +``` + +## Options + +Pass compression options as the second argument: + +```ts twoslash +import { withHeadroom } from 'headroom-ai/openai'; +import OpenAI from 'openai'; + +const client = withHeadroom(new OpenAI(), { + model: 'gpt-4o', + baseUrl: 'http://localhost:8787', +}); +``` + +## Streaming + +Streaming works normally. Compression happens before the request is sent: + +```ts twoslash +import { withHeadroom } from 'headroom-ai/openai'; +import OpenAI from 'openai'; + +const client = withHeadroom(new OpenAI()); + +const stream = await client.chat.completions.create({ + model: 'gpt-4o', + messages: longConversation, + stream: true, +}); + +for await (const chunk of stream) { + process.stdout.write(chunk.choices[0]?.delta?.content ?? ''); +} +``` + +## Tool calling + +Tool call messages and tool results are compressed like any other message content. Large tool outputs (JSON arrays, logs) see the biggest savings: + +```ts twoslash +import { withHeadroom } from 'headroom-ai/openai'; +import OpenAI from 'openai'; + +const client = withHeadroom(new OpenAI()); + +const response = await client.chat.completions.create({ + model: 'gpt-4o', + messages: [ + { role: 'user', content: 'Search for recent errors' }, + { + role: 'assistant', + content: null, + tool_calls: [{ id: 'call_1', type: 'function', function: { name: 'search', arguments: '{"q":"errors"}' } }], + }, + { + role: 'tool', + tool_call_id: 'call_1', + content: hugeJsonResult, // Compressed automatically + }, + ], + tools: [{ type: 'function', function: { name: 'search', parameters: {} } }], +}); +``` diff --git a/docs/content/docs/proxy.mdx b/docs/content/docs/proxy.mdx new file mode 100644 index 000000000..d1313f784 --- /dev/null +++ b/docs/content/docs/proxy.mdx @@ -0,0 +1,246 @@ +--- +title: Proxy Server +description: Run the Headroom proxy to compress LLM traffic for any client — Claude Code, Cursor, OpenAI SDK, or custom apps. +--- + +The Headroom proxy is a standalone HTTP server that compresses all LLM traffic passing through it. Point any client at the proxy and get automatic context optimization. + +## Starting the proxy + +```bash +# Basic usage +headroom proxy + +# Custom host and port +headroom proxy --host 0.0.0.0 --port 8080 + +# With logging and budget +headroom proxy \ + --log-file /var/log/headroom.jsonl \ + --budget 100.0 +``` + +Telemetry is enabled by default. Opt out with `HEADROOM_TELEMETRY=off` or `--no-telemetry`. + +## CLI options + +### Core + +| Option | Default | Description | +|--------|---------|-------------| +| `--host` | `127.0.0.1` | Host to bind to | +| `--port` | `8787` | Port to bind to | +| `--no-optimize` | `false` | Disable optimization (passthrough mode) | +| `--no-cache` | `false` | Disable semantic caching | +| `--no-rate-limit` | `false` | Disable rate limiting | +| `--log-file` | None | Path to JSONL log file | +| `--budget` | None | Daily budget limit in USD | +| `--openai-api-url` | `https://api.openai.com` | Custom OpenAI API URL | + +### Context management + +| Option | Default | Description | +|--------|---------|-------------| +| `--no-intelligent-context` | `false` | Fall back to RollingWindow (oldest-first drops) | +| `--no-intelligent-scoring` | `false` | Disable multi-factor importance scoring | +| `--no-compress-first` | `false` | Disable trying deeper compression before dropping | + +By default, the proxy uses **IntelligentContextManager** which scores messages by recency, semantic similarity, TOIN-learned patterns, error indicators, and forward references. Dropped messages are stored in CCR for retrieval. + +```bash +# Use legacy RollingWindow +headroom proxy --no-intelligent-context + +# Faster but less intelligent scoring +headroom proxy --no-intelligent-scoring +``` + +### LLMLingua (ML compression) + +| Option | Default | Description | +|--------|---------|-------------| +| `--llmlingua` | `false` | Enable LLMLingua-2 ML-based compression | +| `--llmlingua-device` | `auto` | Device: `auto`, `cuda`, `cpu`, `mps` | +| `--llmlingua-rate` | `0.3` | Target compression rate (0.3 = keep 30%) | + +```bash +pip install "headroom-ai[llmlingua]" + +headroom proxy --llmlingua --llmlingua-device cuda +headroom proxy --llmlingua --llmlingua-rate 0.2 +``` + + +LLMLingua adds ~2 GB of dependencies (torch, transformers), 10-30s cold start, and ~1 GB RAM. Enable when maximum compression justifies the cost. + + +## API endpoints + +### `GET /health` + +```bash +curl http://localhost:8787/health +``` + +```json +{ + "status": "healthy", + "optimize": true, + "stats": { + "total_requests": 42, + "tokens_saved": 15000, + "savings_percent": 45.2 + } +} +``` + +### `GET /stats` + +Live session statistics plus durable `persistent_savings` totals. Stored at `~/.headroom/proxy_savings.json` (override with `HEADROOM_SAVINGS_PATH`). + +```bash +curl http://localhost:8787/stats +``` + +### `GET /stats-history` + +Durable history with hourly, daily, weekly, and monthly rollups. Powers the `/dashboard` view. + +```bash +curl http://localhost:8787/stats-history +curl "http://localhost:8787/stats-history?format=csv&series=weekly" +``` + +### `GET /metrics` + +Prometheus-format metrics for monitoring. + +```bash +curl http://localhost:8787/metrics +``` + +``` +headroom_requests_total{mode="optimize"} 1234 +headroom_tokens_saved_total 5678900 +headroom_compression_ratio_bucket{le="0.5"} 890 +headroom_latency_seconds_bucket{le="0.01"} 800 +headroom_cache_hits_total 456 +``` + +### `POST /v1/messages` + +Anthropic API format. The proxy compresses messages, forwards to Anthropic, and returns the response. + +### `POST /v1/chat/completions` + +OpenAI API format. The proxy compresses messages, forwards to OpenAI, and returns the response. + +### `POST /v1/compress` + +Compression-only endpoint. Compresses messages without calling any LLM. Used by the TypeScript SDK. + +**Request:** +```json +{ + "messages": [{ "role": "user", "content": "..." }], + "model": "gpt-4o" +} +``` + +**Response:** +```json +{ + "messages": [{ "role": "user", "content": "..." }], + "tokens_before": 15000, + "tokens_after": 3500, + "tokens_saved": 11500, + "compression_ratio": 0.23, + "transforms_applied": ["router:smart_crusher:0.35"], + "ccr_hashes": ["a1b2c3"] +} +``` + +Set `x-headroom-bypass: true` to skip compression. + +## Agent wrapping + +Use `headroom wrap` to transparently proxy any CLI tool: + +```bash +# Claude Code +headroom wrap claude + +# OpenAI Codex +headroom wrap codex + +# Aider +headroom wrap aider + +# Cursor +headroom wrap cursor +``` + +Or set the base URL manually: + +```bash +# Claude Code +ANTHROPIC_BASE_URL=http://localhost:8787 claude + +# Cursor / any OpenAI-compatible client +OPENAI_BASE_URL=http://localhost:8787/v1 cursor +``` + +## Cloud providers + +```bash +# AWS Bedrock +headroom proxy --backend bedrock --region us-east-1 + +# Google Vertex AI +headroom proxy --backend vertex_ai --region us-central1 + +# Azure OpenAI +headroom proxy --backend azure + +# OpenRouter (400+ models) +OPENROUTER_API_KEY=sk-or-... headroom proxy --backend openrouter +``` + +## Environment variables + +```bash +export HEADROOM_HOST=0.0.0.0 +export HEADROOM_PORT=8787 +export HEADROOM_BUDGET=100.0 +export OPENAI_TARGET_API_URL=https://custom.openai.endpoint.com +headroom proxy +``` + +## Production deployment + +### gunicorn + +```bash +pip install gunicorn + +gunicorn headroom.proxy.server:app \ + --workers 4 \ + --bind 0.0.0.0:8787 \ + --worker-class uvicorn.workers.UvicornWorker +``` + +### Docker + +```dockerfile +FROM python:3.11-slim +RUN apt-get update && apt-get install -y --no-install-recommends build-essential \ + && pip install "headroom-ai[proxy]" \ + && apt-get purge -y build-essential && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* +EXPOSE 8787 +CMD ["headroom", "proxy", "--host", "0.0.0.0"] +``` + + +`build-essential` is required at install time because `headroom-ai` includes `hnswlib`, a C++ extension compiled from source. It is removed after installation to keep the image slim. + diff --git a/docs/content/docs/quickstart.mdx b/docs/content/docs/quickstart.mdx new file mode 100644 index 000000000..22c45db6d --- /dev/null +++ b/docs/content/docs/quickstart.mdx @@ -0,0 +1,240 @@ +--- +title: Quickstart +description: Get Headroom running in 5 minutes. Install, compress, and send to your LLM with fewer tokens. +--- + +This guide gets you from zero to compressed LLM calls in under 5 minutes. + +## 1. Install + + + +```bash +npm install headroom-ai +``` + + +```bash +pip install "headroom-ai[all]" +``` + + + + +The TypeScript SDK sends messages to a local Headroom proxy for compression. Start the proxy before using the TS SDK: + +```bash +pip install "headroom-ai[proxy]" +headroom proxy --port 8787 +``` + +The proxy runs the compression pipeline (Python) and exposes an HTTP API that the TS SDK calls. + + +## 2. Compress messages + + + +```ts twoslash +import { compress } from 'headroom-ai'; + +const messages = [ + { role: 'system' as const, content: 'You analyze search results.' }, + { role: 'user' as const, content: 'Search for Python tutorials.' }, + { + role: 'assistant' as const, + content: null, + tool_calls: [{ + id: 'call_1', + type: 'function' as const, + function: { name: 'search', arguments: '{"q": "python"}' }, + }], + }, + { + role: 'tool' as const, + tool_call_id: 'call_1', + content: JSON.stringify({ + results: Array.from({ length: 500 }, (_, i) => ({ + title: `Result ${i}`, + snippet: `Description ${i}`, + score: 100 - i, + })), + }), + }, + { role: 'user' as const, content: 'What are the top 3 results?' }, +]; + +const result = await compress(messages, { + model: 'gpt-4o', + baseUrl: 'http://localhost:8787', +}); +``` + + +```python +from headroom import compress +import json + +messages = [ + {"role": "system", "content": "You analyze search results."}, + {"role": "user", "content": "Search for Python tutorials."}, + { + "role": "assistant", + "content": None, + "tool_calls": [{ + "id": "call_1", + "type": "function", + "function": {"name": "search", "arguments": '{"q": "python"}'}, + }], + }, + { + "role": "tool", + "tool_call_id": "call_1", + "content": json.dumps({ + "results": [ + {"title": f"Result {i}", "snippet": f"Description {i}", "score": 100 - i} + for i in range(500) + ] + }), + }, + {"role": "user", "content": "What are the top 3 results?"}, +] + +result = compress(messages, model="gpt-4o") +``` + + + +## 3. Send to your LLM + +Use the compressed messages exactly like the originals: + + + +```ts twoslash +import OpenAI from 'openai'; + +const client = new OpenAI(); + +// result.messages from the previous step +const messages: any[] = []; + +const response = await client.chat.completions.create({ + model: 'gpt-4o', + messages, +}); + +console.log(response.choices[0].message.content); +``` + + +```python +from openai import OpenAI + +client = OpenAI() +response = client.chat.completions.create( + model="gpt-4o", + messages=result.messages, +) + +print(response.choices[0].message.content) +``` + + + +## 4. Check your savings + + + +```ts twoslash +const result = { + tokensBefore: 45000, + tokensAfter: 4500, + tokensSaved: 40500, + compressionRatio: 0.9, + transformsApplied: ['smart_crusher', 'cache_aligner'], + messages: [], + ccrHashes: [], + compressed: true, +}; +// ---cut--- +console.log(`Tokens before: ${result.tokensBefore}`); +console.log(`Tokens after: ${result.tokensAfter}`); +console.log(`Tokens saved: ${result.tokensSaved}`); +console.log(`Compression: ${(result.compressionRatio * 100).toFixed(0)}%`); +console.log(`Transforms: ${result.transformsApplied.join(', ')}`); +``` + +Example output: + +``` +Tokens before: 45000 +Tokens after: 4500 +Tokens saved: 40500 +Compression: 90% +Transforms: smart_crusher, cache_aligner +``` + + +```python +print(f"Tokens before: {result.tokens_before}") +print(f"Tokens after: {result.tokens_after}") +print(f"Tokens saved: {result.tokens_saved}") +print(f"Compression: {result.compression_ratio:.0%}") +print(f"Transforms: {result.transforms_applied}") +``` + +Example output: + +``` +Tokens before: 45000 +Tokens after: 4500 +Tokens saved: 40500 +Compression: 90% +Transforms: ['smart_crusher', 'cache_aligner'] +``` + + + +## Alternative: proxy mode (zero code changes) + +If you do not want to change any code, run Headroom as a proxy and point your existing client at it: + +```bash +# Start the proxy +headroom proxy --port 8787 + +# Point Claude Code at it +ANTHROPIC_BASE_URL=http://localhost:8787 claude + +# Or any OpenAI-compatible client +OPENAI_BASE_URL=http://localhost:8787/v1 your-app +``` + +All requests flow through Headroom automatically. Check savings at any time: + +```bash +curl http://localhost:8787/stats +# {"requests_total": 42, "tokens_saved_total": 125000, ...} +``` + +## What gets compressed + +The biggest savings come from tool outputs -- search results, database rows, log files, API responses. Headroom auto-detects the content type and routes it to the best compressor. No configuration needed. + +| Content type | Compressor | Typical savings | +|---|---|---| +| JSON arrays | SmartCrusher | 70--90% | +| Source code | CodeCompressor | 40--70% | +| Build/test logs | LogCompressor | 80--95% | +| Search results | SearchCompressor | 60--80% | +| Plain text | Kompress | 30--50% | + +## Next steps + + + + + + + diff --git a/docs/content/docs/shared-context.mdx b/docs/content/docs/shared-context.mdx new file mode 100644 index 000000000..0891a88c3 --- /dev/null +++ b/docs/content/docs/shared-context.mdx @@ -0,0 +1,227 @@ +--- +title: SharedContext +description: Compressed inter-agent context sharing. Reduce token usage by ~80% when agents hand off to each other. +--- + +When agents hand off to each other, context gets replayed in full. SharedContext compresses what moves between agents using Headroom's compression pipeline, typically saving **~80% of tokens** on agent handoffs. + +## Quick Start + + + +```ts twoslash +import { SharedContext } from "headroom"; + +const ctx = new SharedContext(); + +// Agent A stores large output +const entry = await ctx.put("research", bigResearchOutput, { + agent: "researcher", +}); + +// Agent B gets compressed version (~80% smaller) +const summary = ctx.get("research"); + +// Agent B needs full details on demand +const full = ctx.get("research", { full: true }); +``` + + +```python +from headroom import SharedContext + +ctx = SharedContext() + +# Agent A stores large output +ctx.put("research", big_research_output, agent="researcher") + +# Agent B gets compressed version (~80% smaller) +summary = ctx.get("research") + +# Agent B needs full details on demand +full = ctx.get("research", full=True) +``` + + + +## API + +### `put(key, content, agent?)` + +Store content under a key. Compresses automatically using Headroom's full pipeline (SmartCrusher for JSON, CodeCompressor for code, Kompress for text). + + + +```ts twoslash +import { SharedContext } from "headroom"; +const ctx = new SharedContext(); +// ---cut--- +const entry = await ctx.put("findings", bigJsonOutput, { + agent: "researcher", +}); + +entry.originalTokens; // 20000 +entry.compressedTokens; // 4000 +entry.savingsPercent; // 80.0 +entry.transforms; // ["router:json:0.20"] +``` + + +```python +entry = ctx.put("findings", big_json_output, agent="researcher") + +entry.original_tokens # 20,000 +entry.compressed_tokens # 4,000 +entry.savings_percent # 80.0 +entry.transforms # ["router:json:0.20"] +``` + + + +### `get(key, full?)` + +Retrieve content. Returns the compressed version by default, or the original with `full=True`. + + + +```ts twoslash +import { SharedContext } from "headroom"; +const ctx = new SharedContext(); +// ---cut--- +const compressed = ctx.get("findings"); // 4K tokens +const original = ctx.get("findings", { full: true }); // 20K tokens +const missing = ctx.get("nonexistent"); // null +``` + + +```python +compressed = ctx.get("findings") # 4K tokens +original = ctx.get("findings", full=True) # 20K tokens +missing = ctx.get("nonexistent") # None +``` + + + +### `stats()` + +Aggregated statistics across all entries. + + + +```ts twoslash +import { SharedContext } from "headroom"; +const ctx = new SharedContext(); +// ---cut--- +const stats = ctx.stats(); +stats.entries; // 3 +stats.totalOriginalTokens; // 60000 +stats.totalCompressedTokens; // 12000 +stats.totalTokensSaved; // 48000 +stats.savingsPercent; // 80.0 +``` + + +```python +stats = ctx.stats() +stats.entries # 3 +stats.total_original_tokens # 60000 +stats.total_compressed_tokens # 12000 +stats.total_tokens_saved # 48000 +stats.savings_percent # 80.0 +``` + + + +### `keys()` and `clear()` + +`keys()` lists all non-expired keys. `clear()` removes all entries. + +## Configuration + + + +```ts twoslash +import { SharedContext } from "headroom"; +// ---cut--- +const ctx = new SharedContext({ + model: "claude-sonnet-4-5-20250929", // For token counting + ttl: 3600, // 1 hour (default) + maxEntries: 100, // Evicts oldest when full +}); +``` + + +```python +ctx = SharedContext( + model="claude-sonnet-4-5-20250929", # For token counting + ttl=3600, # 1 hour (default) + max_entries=100, # Evicts oldest when full +) +``` + + + +Entries expire after `ttl` seconds. When `maxEntries` is reached, the oldest entry is evicted. + +## Framework Examples + +SharedContext is framework-agnostic. It works anywhere context moves between agents. + +### CrewAI + +```python +from headroom import SharedContext + +ctx = SharedContext() + +# After researcher task completes +ctx.put("findings", researcher_task.output.raw) + +# Coder task gets compressed context +coder_context = ctx.get("findings") +``` + +### LangGraph + +```python +from headroom import SharedContext + +ctx = SharedContext() + +def researcher_node(state): + result = do_research() + ctx.put("research", result) + return {"research_summary": ctx.get("research")} + +def coder_node(state): + # Compressed summary in state, full details on demand + full = ctx.get("research", full=True) + return {"code": write_code(full)} +``` + +### OpenAI Agents SDK + +```python +from headroom import SharedContext + +ctx = SharedContext() + +def compress_handoff(messages): + for msg in messages: + if len(msg.content) > 1000: + ctx.put(msg.id, msg.content) + msg.content = ctx.get(msg.id) + return messages + +handoff(agent=coder, input_filter=compress_handoff) +``` + +## How It Works + +Under the hood, `put()` calls `headroom.compress()` -- the same pipeline used by the Headroom proxy -- and stores the original in memory. `get()` returns the compressed version. `get(full=True)` returns the original. + +The compression pipeline routes content to the best compressor: + +- **JSON arrays** -- SmartCrusher (70-95% compression) +- **Code** -- CodeCompressor (AST-aware) +- **Text** -- Kompress (ModernBERT-based) or passthrough diff --git a/docs/content/docs/simulation.mdx b/docs/content/docs/simulation.mdx new file mode 100644 index 000000000..6ca494778 --- /dev/null +++ b/docs/content/docs/simulation.mdx @@ -0,0 +1,149 @@ +--- +title: Simulation +description: Preview compression results without making an LLM call. Use simulation for cost estimation, debugging, and understanding waste signals. +--- + +Simulation mode lets you preview what Headroom would do to your messages without sending them to an LLM. This is useful for cost estimation, debugging compression behavior, and understanding where token waste comes from. + +## Basic Usage + + + +```ts twoslash +import { compress } from 'headroom-ai'; + +// compress() returns the same result structure — +// use it without sending to your LLM to simulate +const result = await compress(messages, { model: 'gpt-4o' }); +console.log(`Would save: ${result.tokensSaved} tokens`); +console.log(`Compression ratio: ${(result.compressionRatio * 100).toFixed(1)}%`); +console.log(`Transforms: ${result.transformsApplied.join(', ')}`); +``` + + +```python +plan = client.chat.completions.simulate( + model="gpt-4o", + messages=large_conversation, +) + +print(f"Tokens before: {plan.tokens_before}") +print(f"Tokens after: {plan.tokens_after}") +print(f"Would save: {plan.tokens_saved} tokens ({plan.savings_percent:.1f}%)") +print(f"Transforms: {plan.transforms_applied}") +``` + + + +## Waste Signals + +Simulation reports where token waste comes from in your messages: + +```python +plan = client.chat.completions.simulate( + model="gpt-4o", + messages=messages, +) + +waste = plan.waste_signals +print(f"JSON bloat: {waste.json_bloat_tokens} tokens") +print(f"HTML noise: {waste.html_noise_tokens} tokens") +print(f"Whitespace: {waste.whitespace_tokens} tokens") +print(f"Dynamic dates: {waste.dynamic_date_tokens} tokens") +print(f"Repetition: {waste.repetition_tokens} tokens") +``` + +Waste signals help you understand which parts of your input are contributing the most unnecessary tokens. + +## Block Breakdown + +The parser breaks your conversation into blocks so you can see where tokens are concentrated: + +```python +# Block types: system, user, assistant, tool_call, tool_result, rag +# The breakdown shows token counts per block type +``` + +| Block Kind | Description | +|-----------|-------------| +| `system` | System prompt instructions | +| `user` | User messages | +| `assistant` | Model responses | +| `tool_call` | Function call requests | +| `tool_result` | Tool output (largest source of waste) | +| `rag` | Retrieved document context | + +## Use Cases + +### Cost Estimation + +Run simulation on a representative sample of your workload to estimate savings before enabling `optimize` mode: + +```python +import json + +total_before = 0 +total_after = 0 + +for messages in sample_conversations: + plan = client.chat.completions.simulate( + model="gpt-4o", + messages=messages, + ) + total_before += plan.tokens_before + total_after += plan.tokens_after + +savings_pct = (1 - total_after / total_before) * 100 +print(f"Estimated savings: {savings_pct:.1f}%") +print(f"Tokens saved: {total_before - total_after:,}") +``` + +### Debugging Compression + +Use simulation to understand why a particular conversation is or is not being compressed: + +```python +plan = client.chat.completions.simulate( + model="gpt-4o", + messages=messages, +) + +if plan.tokens_saved == 0: + print("No compression applied. Possible reasons:") + print("- Messages are too short (< 200 tokens per tool output)") + print("- No tool outputs with compressible JSON arrays") + print("- Content is already compact (code, grep results)") +else: + print(f"Transforms applied: {plan.transforms_applied}") + # See the optimized messages + print(json.dumps(plan.messages_optimized, indent=2)) +``` + +### Comparing Configurations + +Test different configurations to find the best settings for your workload: + +```python +from headroom import HeadroomClient, OpenAIProvider +from headroom.transforms import SmartCrusherConfig + +configs = [ + SmartCrusherConfig(max_items_after_crush=10), + SmartCrusherConfig(max_items_after_crush=25), + SmartCrusherConfig(max_items_after_crush=50), +] + +for config in configs: + client = HeadroomClient( + original_client=OpenAI(), + provider=OpenAIProvider(), + smart_crusher_config=config, + ) + plan = client.chat.completions.simulate(model="gpt-4o", messages=messages) + print(f"max_items={config.max_items_after_crush}: " + f"{plan.tokens_saved} tokens saved ({plan.savings_percent:.1f}%)") +``` + + +Simulation never calls the LLM API. It runs the full transform pipeline locally and returns the results, so there is no cost and no latency from the provider. + diff --git a/docs/content/docs/smart-crusher.mdx b/docs/content/docs/smart-crusher.mdx new file mode 100644 index 000000000..b318fa826 --- /dev/null +++ b/docs/content/docs/smart-crusher.mdx @@ -0,0 +1,143 @@ +--- +title: SmartCrusher +description: Statistical JSON and array compression that keeps important items and drops the rest, achieving 70-90% token reduction. +--- + +SmartCrusher is Headroom's compressor for JSON tool outputs. It analyzes arrays statistically, keeps the important items (errors, anomalies, relevant matches), and drops the rest. This is the compressor that fires automatically when ContentRouter detects JSON arrays. + +## How It Works + +SmartCrusher doesn't blindly truncate arrays. It scores each item across five dimensions: + +1. **First/Last items** -- Context for pagination and recency +2. **Error items** -- 100% preservation of error states (never dropped) +3. **Anomalies** -- Statistical outliers (> 2 standard deviations from the mean) +4. **Relevant items** -- Matches to the user's query via BM25/embeddings +5. **Change points** -- Significant transitions in data + +The result: a 1,000-item array becomes ~50 items with all the information the LLM actually needs. + +## What Gets Preserved + +| Category | Preserved | Why | +|---|---|---| +| Errors | 100% | Critical for debugging | +| First N | 100% | Context and pagination | +| Last N | 100% | Recency | +| Anomalies | All | Unusual values matter | +| Relevant | Top K | Match user's query | +| Others | Sampled | Statistical representation | + +## Quick Start + + + +```ts twoslash +import { compress } from "headroom-ai"; + +// SmartCrusher fires automatically for JSON tool outputs +const messages = [ + { role: "system" as const, content: "You are a helpful assistant." }, + { role: "user" as const, content: "Find errors in the last 24 hours" }, + { + role: "tool" as const, + content: JSON.stringify({ results: new Array(1000).fill({ status: "ok" }) }), + tool_call_id: "call_1", + }, +]; + +const result = await compress(messages); +console.log(`Tokens saved: ${result.tokensSaved}`); +// SmartCrusher keeps errors, anomalies, and relevant items +``` + + +```python +from headroom import SmartCrusher + +crusher = SmartCrusher() + +# Before: 1000 search results (45,000 tokens) +tool_output = {"results": ["...1000 items..."]} + +# After: ~50 important items (4,500 tokens) -- 90% reduction +compressed = crusher.crush(tool_output, query="user's question") +``` + + + +## Configuration + + + +```ts twoslash +import { compress } from "headroom-ai"; + +// Configure via the Headroom proxy or HeadroomClient +const result = await compress(messages, { + model: "gpt-4o", + tokenBudget: 10000, // SmartCrusher will reduce JSON to fit +}); + +console.log(`Transforms: ${result.transformsApplied}`); +// ["smart_crusher", "cache_aligner"] +``` + + +```python +from headroom import SmartCrusher, SmartCrusherConfig + +config = SmartCrusherConfig( + min_tokens_to_crush=200, # Only compress if > 200 tokens + max_items_after_crush=50, # Keep at most 50 items + keep_first=3, # Always keep first 3 items + keep_last=2, # Always keep last 2 items + relevance_threshold=0.3, # Keep items with relevance > 0.3 + anomaly_std_threshold=2.0, # Keep items > 2 std dev from mean + preserve_errors=True, # Always keep error items +) + +crusher = SmartCrusher(config) +compressed = crusher.crush(tool_output, query="find payment failures") +``` + + + +## Configuration Options + +| Option | Default | Description | +|---|---|---| +| `min_tokens_to_crush` | `200` | Only compress arrays with more than this many tokens | +| `max_items_after_crush` | `50` | Maximum items to keep after compression | +| `keep_first` | `3` | Always keep the first N items | +| `keep_last` | `2` | Always keep the last N items | +| `relevance_threshold` | `0.3` | Minimum relevance score to keep an item | +| `anomaly_std_threshold` | `2.0` | Standard deviation threshold for anomaly detection | +| `preserve_errors` | `True` | Always keep items containing error states | + +## Example: Before and After + +Consider a tool that returns 1,000 search results: + +```python +# Before compression: 45,000 tokens +{ + "results": [ + {"id": 1, "status": "ok", "message": "Success", "timestamp": "..."}, + {"id": 2, "status": "ok", "message": "Success", "timestamp": "..."}, + # ... 995 more "ok" results ... + {"id": 998, "status": "error", "message": "Connection timeout", "timestamp": "..."}, + {"id": 999, "status": "ok", "message": "Success", "timestamp": "..."}, + {"id": 1000, "status": "ok", "message": "Success", "timestamp": "..."}, + ] +} + +# After SmartCrusher: 4,500 tokens (90% reduction) +# Kept: first 3, last 2, the error at id=998, statistical sample +``` + +The LLM sees the structure, the error, and a representative sample -- everything it needs to answer "find errors in the last 24 hours" without wading through 1,000 identical success responses. + + + You don't need to call SmartCrusher directly. The ContentRouter detects JSON arrays and routes them to SmartCrusher automatically. Direct usage is available when you want fine-grained control over the configuration. + diff --git a/docs/content/docs/strands.mdx b/docs/content/docs/strands.mdx new file mode 100644 index 000000000..d7a570ce2 --- /dev/null +++ b/docs/content/docs/strands.mdx @@ -0,0 +1,137 @@ +--- +title: Strands +description: Context compression for Strands Agents via model wrapping and hook-based tool output compression. +--- + +Headroom integrates with [Strands Agents](https://github.com/strands-agents/sdk-python) through two patterns: wrap the model for full conversation compression, or hook into tool calls for targeted tool output compression. + +## Installation + +```bash +pip install headroom-ai strands-agents +``` + +## Quick start + +```python +from strands import Agent +from strands.models.bedrock import BedrockModel +from headroom.integrations.strands import HeadroomStrandsModel + +model = BedrockModel(model_id="us.anthropic.claude-sonnet-4-20250514-v1:0") +optimized = HeadroomStrandsModel(wrapped_model=model) + +agent = Agent(model=optimized) +response = agent("Investigate the production incident") + +print(f"Tokens saved: {optimized.total_tokens_saved}") +``` + +## Model wrapping + +Wraps the Strands `Model` interface. Every call to `stream()` compresses messages before they reach the provider: + +```python +from headroom import HeadroomConfig +from headroom.integrations.strands import HeadroomStrandsModel + +optimized = HeadroomStrandsModel( + wrapped_model=model, + config=HeadroomConfig(), +) + +agent = Agent(model=optimized) +response = agent("Analyze these logs") +``` + +## Hook provider (tool output compression) + +Compresses tool call results via Strands' hook system. Uses SmartCrusher on JSON arrays returned by tools: + +```python +from strands import Agent +from strands.models.bedrock import BedrockModel +from headroom.integrations.strands import HeadroomHookProvider + +model = BedrockModel(model_id="us.anthropic.claude-sonnet-4-20250514-v1:0") +hooks = HeadroomHookProvider( + compress_tool_outputs=True, + min_tokens_to_compress=200, + preserve_errors=True, +) + +agent = Agent(model=model, hooks=[hooks]) +response = agent("Search the database for recent failures") + +print(f"Tokens saved by hooks: {hooks.total_tokens_saved}") +``` + +The hook preserves error items, anomalous values (statistical outliers), items matching the query context, and boundary items (first/last). + +## Both together + +Model wrapping compresses conversation history. Hooks compress individual tool results. Use both for maximum savings: + +```python +from headroom.integrations.strands import HeadroomStrandsModel, HeadroomHookProvider + +optimized = HeadroomStrandsModel(wrapped_model=model) +hooks = HeadroomHookProvider(compress_tool_outputs=True) + +agent = Agent(model=optimized, hooks=[hooks]) +``` + +## How it works + +``` +Agent decides to call tool + | + v +Tool executes, returns result + | + v +HeadroomHookProvider (optional) + compresses tool result JSON + | + v +Agent builds next API request + | + v +HeadroomStrandsModel.stream() + compresses full message list + | + v +Provider API (Bedrock, etc.) +``` + +The model wrapper uses the full Headroom pipeline (CacheAligner, ContentRouter, IntelligentContext). The hook provider uses SmartCrusher directly for fast JSON compression. + +## Structured output + +```python +from pydantic import BaseModel + +class Analysis(BaseModel): + severity: str + root_cause: str + recommendation: str + +result = optimized.structured_output(Analysis, messages) +``` + +## Metrics + +```python +for m in optimized.metrics_history: + print(f" {m.tokens_before} -> {m.tokens_after} ({m.tokens_saved} saved)") + +print(f"Total saved: {optimized.total_tokens_saved}") +``` + +## Supported providers + +| Strands Model | Provider Detected | +|--------------|-------------------| +| `BedrockModel` | Anthropic (via Bedrock) | +| `OllamaModel` | OpenAI-compatible | +| Custom `Model` | Falls back to estimation | diff --git a/docs/content/docs/text-and-logs.mdx b/docs/content/docs/text-and-logs.mdx new file mode 100644 index 000000000..b19536486 --- /dev/null +++ b/docs/content/docs/text-and-logs.mdx @@ -0,0 +1,213 @@ +--- +title: Text & Log Compression +description: Specialized compressors for search results, build logs, diffs, and general text. Each preserves what matters for its content type. +--- + +Headroom provides specialized compressors for text-based content that isn't JSON or source code. Each one understands the structure of its content type and preserves what the LLM needs while dropping the noise. + +| Compressor | Input Type | What It Preserves | Typical Savings | +|---|---|---|---| +| `SearchCompressor` | grep/ripgrep output | Relevant matches, file diversity | 80-95% | +| `LogCompressor` | Build/test logs | Errors, stack traces, summaries | 85-95% | +| `DiffCompressor` | Unified diffs | Changed lines, context | 60-80% | +| `TextCompressor` | General text | Relevant paragraphs, anchors | 60-80% | +| `LLMLinguaCompressor` | Any text (max compression) | Semantic meaning via ML | 80-95% | + +## SearchCompressor + +Compresses search results (grep, ripgrep, ag) while keeping the matches that matter. + +```python +from headroom.transforms import SearchCompressor + +search_results = """ +src/utils.py:42:def process_data(items): +src/utils.py:43: \"\"\"Process items.\"\"\" +src/models.py:15:class DataProcessor: +src/models.py:89: def process(self, items): +... hundreds more matches ... +""" + +compressor = SearchCompressor() +result = compressor.compress(search_results, context="find process") + +print(f"Compressed {result.original_match_count} matches to {result.compressed_match_count}") +print(result.compressed) +``` + +**What gets preserved:** +- Exact query matches (lines containing the search term) +- High-relevance matches (scored by BM25 similarity) +- File diversity (results from different files are kept) +- First/last matches (context from start and end) + +### Configuration + +```python +from headroom.transforms import SearchCompressor, SearchCompressorConfig + +config = SearchCompressorConfig( + max_results=50, # Keep up to 50 matches + preserve_file_diversity=True, # Ensure different files represented + relevance_threshold=0.3, # Minimum relevance score to keep +) + +compressor = SearchCompressor(config) +``` + +## LogCompressor + +Compresses build and test output while preserving errors, warnings, and summaries. + +```python +from headroom.transforms import LogCompressor + +build_output = """ +===== test session starts ===== +collected 500 items +tests/test_foo.py::test_1 PASSED +... hundreds of passed tests ... +tests/test_bar.py::test_fail FAILED +AssertionError: expected 5, got 3 +===== 1 failed, 499 passed ===== +""" + +compressor = LogCompressor() +result = compressor.compress(build_output) + +print(result.compressed) +print(f"Compression ratio: {result.compression_ratio:.1%}") +``` + +**What gets preserved:** +- Errors and failures (any line with ERROR, FAILED, Exception) +- Warnings +- Full stack traces for debugging +- Test/build summary lines +- Section headers (structural markers like `=====`) + +**What gets dropped:** +- Hundreds of `PASSED` lines +- Verbose success output +- Repeated patterns + +## DiffCompressor + +Compresses unified diffs while keeping the actual changes and enough context to understand them. + +```python +from headroom.transforms import DiffCompressor + +diff_output = """ +diff --git a/src/main.py b/src/main.py +--- a/src/main.py ++++ b/src/main.py +@@ -42,7 +42,7 @@ + def process(items): +- return [x for x in items] ++ return [x.strip() for x in items if x] +""" + +compressor = DiffCompressor() +result = compressor.compress(diff_output) +``` + +## TextCompressor + +General-purpose text compression with anchor preservation. Best for documentation, README files, and prose content. + +```python +from headroom.transforms import TextCompressor + +long_text = """ +... thousands of lines of documentation ... +""" + +compressor = TextCompressor() +result = compressor.compress(long_text, context="authentication") + +print(result.compressed) +``` + +**What gets preserved:** +- Paragraphs relevant to the context query +- Headers and section markers +- Document structure and organization + +## LLMLingua (Optional, Maximum Compression) + +For maximum compression on any text, Headroom integrates with Microsoft's LLMLingua-2, a BERT-based token classifier trained via GPT-4 distillation. It achieves up to 20x compression while preserving semantic meaning. + +```python +from headroom.transforms import LLMLinguaCompressor, LLMLinguaConfig + +config = LLMLinguaConfig( + device="auto", # auto, cuda, cpu, mps + code_compression_rate=0.4, # Conservative for code + json_compression_rate=0.35, # Moderate for JSON + text_compression_rate=0.25, # Aggressive for text +) + +compressor = LLMLinguaCompressor(config) +result = compressor.compress(long_output) + +print(f"Before: {result.original_tokens} tokens") +print(f"After: {result.compressed_tokens} tokens") +print(f"Saved: {result.savings_percentage:.1f}%") +``` + + + LLMLingua adds ~2GB of model weights and 50-200ms latency per request. Install it only when you need maximum compression: `pip install "headroom-ai[llmlingua]"` + + +### Memory Management + +```python +from headroom.transforms import unload_llmlingua_model, is_llmlingua_model_loaded + +# Check if model is loaded +print(is_llmlingua_model_loaded()) # True + +# Free ~1GB RAM when done +unload_llmlingua_model() +``` + +## Content Type Detection + +If you're building your own routing logic, you can use the content type detector directly: + +```python +from headroom.transforms import detect_content_type, ContentType + +content = "src/main.py:42:def process():" + +detection = detect_content_type(content) +if detection.content_type == ContentType.SEARCH_RESULTS: + result = SearchCompressor().compress(content, context="process") +elif detection.content_type == ContentType.BUILD_OUTPUT: + result = LogCompressor().compress(content) +elif detection.content_type == ContentType.PLAIN_TEXT: + result = TextCompressor().compress(content, context="process") +``` + +## When Each Compressor Is Used + +The ContentRouter selects the right compressor automatically. Here's when each fires: + +| Content Pattern | Compressor | Detection Signal | +|---|---|---| +| `file:line:content` lines | SearchCompressor | grep/ripgrep output format | +| pytest, npm, cargo markers | LogCompressor | Build tool output patterns | +| `---/+++` and `@@` markers | DiffCompressor | Unified diff format | +| Prose, documentation | TextCompressor | Fallback for non-structured text | +| Any (max compression mode) | LLMLinguaCompressor | Explicitly enabled | + +## Performance + +| Compressor | Typical Input | Output | Speed | +|---|---|---|---| +| SearchCompressor | 1,000 matches | 30-50 matches | ~2ms | +| LogCompressor | 5,000 lines | 100-200 lines | ~3ms | +| DiffCompressor | Large diff | Changed hunks only | ~2ms | +| TextCompressor | 10,000 chars | 2,000 chars | ~2ms | +| LLMLinguaCompressor | Any text | 5-20% of original | 50-200ms | diff --git a/docs/content/docs/troubleshooting.mdx b/docs/content/docs/troubleshooting.mdx new file mode 100644 index 000000000..38f24d717 --- /dev/null +++ b/docs/content/docs/troubleshooting.mdx @@ -0,0 +1,352 @@ +--- +title: Troubleshooting +description: Solutions for common Headroom issues including proxy startup, connection errors, no token savings, high latency, and installation problems. +--- + +Solutions for common Headroom issues. + +## Proxy Server Issues + +### Proxy will not start + +**Symptom**: `headroom proxy` fails or hangs. + +```bash +# Check if port is already in use +lsof -i :8787 + +# Try a different port +headroom proxy --port 8788 + +# Check for missing dependencies +pip install "headroom-ai[proxy]" + +# Run with debug logging +headroom proxy --log-level debug +``` + +### Connection refused when calling proxy + +**Symptom**: `curl: (7) Failed to connect to localhost port 8787` + +```bash +# Verify proxy is running +curl http://localhost:8787/health + +# Check if proxy started on a different port +ps aux | grep headroom +``` + +### Proxy returns errors for some requests + +**Symptom**: Some requests work, others fail with 502/503. + +```bash +# Check proxy logs for the actual error +headroom proxy --log-level debug + +# Verify API key is set +echo $OPENAI_API_KEY # or ANTHROPIC_API_KEY + +# Test the underlying API directly +curl https://api.openai.com/v1/models \ + -H "Authorization: Bearer $OPENAI_API_KEY" +``` + +## No Token Savings + +**Symptom**: `stats['session']['tokens_saved_total']` is 0. + +**Diagnosis**: + +```python +stats = client.get_stats() +print(f"Mode: {stats['config']['mode']}") # Should be "optimize" +print(f"SmartCrusher: {stats['transforms']['smart_crusher_enabled']}") +``` + +**Common causes**: + +- Mode is `audit` (observation only, no modifications) +- Messages do not contain tool outputs +- Tool outputs are below the 200-token threshold +- Data is not compressible (high uniqueness, code, grep results) + +**Solutions**: + + + +```ts twoslash +import { compress } from 'headroom-ai'; + +// Ensure the proxy is running in optimize mode +// (default, unless --no-optimize was passed) +const result = await compress(messages, { model: 'gpt-4o' }); +console.log(`Saved: ${result.tokensSaved} tokens`); +console.log(`Compressed: ${result.compressed}`); +``` + + +```python +# 1. Ensure mode is "optimize" +client = HeadroomClient( + original_client=OpenAI(), + provider=OpenAIProvider(), + default_mode="optimize", # NOT "audit" +) + +# 2. Or override per-request +response = client.chat.completions.create( + model="gpt-4o", + messages=messages, + headroom_mode="optimize", +) + +# 3. Lower the compression threshold +config = HeadroomConfig() +config.smart_crusher.min_tokens_to_crush = 100 # Default is 200 +``` + + + +## Compression Too Aggressive + +**Symptom**: LLM responses are missing information that was in tool outputs. + +```python +# 1. Keep more items +config = HeadroomConfig() +config.smart_crusher.max_items_after_crush = 50 # Default: 15 + +# 2. Skip compression for specific tools +response = client.chat.completions.create( + model="gpt-4o", + messages=messages, + headroom_tool_profiles={ + "important_tool": {"skip_compression": True}, + }, +) + +# 3. Disable SmartCrusher entirely +config.smart_crusher.enabled = False +``` + +## High Latency + +**Symptom**: Requests take longer than expected. + +**Diagnosis**: + +```python +import time +import logging + +logging.basicConfig(level=logging.DEBUG) + +start = time.time() +response = client.chat.completions.create(...) +print(f"Total time: {time.time() - start:.2f}s") +``` + +**Solutions**: + +```python +# 1. Use BM25 instead of embeddings (faster) +config = HeadroomConfig() +config.smart_crusher.relevance.tier = "bm25" + +# 2. Increase threshold to skip small payloads +config.smart_crusher.min_tokens_to_crush = 500 + +# 3. Disable transforms you don't need +config.cache_aligner.enabled = False +config.rolling_window.enabled = False +``` + +## Installation Issues + +### pip install fails with C++ compilation error + +**Symptom**: `RuntimeError: Unsupported compiler -- at least C++11 support is needed!` + +```bash +# Linux / Debian-based (including Docker) +apt-get install -y build-essential && pip install headroom-ai + +# macOS (Xcode command line tools) +xcode-select --install && pip install headroom-ai +``` + +For Docker, install and remove build tools in one layer: + +```dockerfile +FROM python:3.11-slim +RUN apt-get update && apt-get install -y --no-install-recommends build-essential \ + && pip install "headroom-ai[proxy]" \ + && apt-get purge -y build-essential && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* +``` + +### ModuleNotFoundError: No module named 'headroom' + +```bash +# Check it is installed in the right environment +pip show headroom-ai + +# If using virtual environment, ensure it is activated +source venv/bin/activate + +# Reinstall +pip install --upgrade headroom-ai +``` + +### Missing optional dependency + +```bash +# For proxy server +pip install "headroom-ai[proxy]" + +# For embedding-based relevance scoring +pip install "headroom-ai[relevance]" + +# For code compression (tree-sitter) +pip install "headroom-ai[code]" + +# For everything +pip install "headroom-ai[all]" +``` + +## Provider-Specific Issues + +### OpenAI: Invalid API key + +```python +import os +from openai import OpenAI + +api_key = os.environ.get("OPENAI_API_KEY") +if not api_key: + raise ValueError("OPENAI_API_KEY not set") + +client = HeadroomClient( + original_client=OpenAI(api_key=api_key), + provider=OpenAIProvider(), +) +``` + +### Anthropic: Authentication error + +```python +import os +from anthropic import Anthropic + +api_key = os.environ.get("ANTHROPIC_API_KEY") +client = HeadroomClient( + original_client=Anthropic(api_key=api_key), + provider=AnthropicProvider(), +) +``` + +### Unknown model warnings + +```python +# For custom/fine-tuned models, specify context limit +client = HeadroomClient( + original_client=OpenAI(), + provider=OpenAIProvider(), + model_context_limits={ + "ft:gpt-4o-2024-08-06:my-org::abc123": 128000, + "my-custom-model": 32000, + }, +) +``` + +## ValidationError on Setup + +```python +result = client.validate_setup() +print(result) + +# Common issues: +# {"provider": {"ok": False, "error": "No API key"}} +# -> Set OPENAI_API_KEY or pass api_key to OpenAI() +# +# {"storage": {"ok": False, "error": "unable to open database"}} +# -> Check path permissions, use :memory: for testing +# +# {"config": {"ok": False, "error": "Invalid mode"}} +# -> Use "audit" or "optimize" only +``` + +For testing, use in-memory storage: + +```python +client = HeadroomClient( + original_client=OpenAI(), + provider=OpenAIProvider(), + store_url="sqlite:///:memory:", +) +``` + +## Debugging Techniques + +### Enable Full Logging + +```python +import logging + +# See everything +logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(name)s %(levelname)s %(message)s", +) + +# Or just Headroom logs +logging.getLogger("headroom").setLevel(logging.DEBUG) +``` + +### Use Simulation to Inspect Transforms + +```python +plan = client.chat.completions.simulate( + model="gpt-4o", + messages=messages, +) + +print(f"Tokens: {plan.tokens_before} -> {plan.tokens_after}") +print(f"Transforms: {plan.transforms_applied}") +print(f"Waste signals: {plan.waste_signals}") + +import json +print(json.dumps(plan.messages_optimized, indent=2)) +``` + +### Test Transforms Directly + +```python +from headroom import SmartCrusher, Tokenizer +from headroom.config import SmartCrusherConfig +import json + +config = SmartCrusherConfig() +crusher = SmartCrusher(config) +tokenizer = Tokenizer() + +messages = [ + { + "role": "tool", + "content": json.dumps({"items": list(range(100))}), + "tool_call_id": "1", + } +] + +result = crusher.apply(messages, tokenizer) +print(f"Tokens: {result.tokens_before} -> {result.tokens_after}") +``` + +## Getting Help + +1. Enable debug logging and check the output +2. Use `simulate()` to see what transforms would apply +3. Run `validate_setup()` for configuration issues +4. File an issue at [github.com/headroom-sdk/headroom](https://github.com/headroom-sdk/headroom/issues) with your Headroom version, Python version, provider, debug log output, and minimal reproduction code diff --git a/docs/content/docs/vercel-ai-sdk.mdx b/docs/content/docs/vercel-ai-sdk.mdx new file mode 100644 index 000000000..1817d1351 --- /dev/null +++ b/docs/content/docs/vercel-ai-sdk.mdx @@ -0,0 +1,139 @@ +--- +title: Vercel AI SDK +description: Compress LLM context with the Vercel AI SDK using middleware, withHeadroom(), or standalone compression. +--- + +Headroom integrates with the [Vercel AI SDK](https://sdk.vercel.ai) through three patterns: a one-liner wrapper, composable middleware, and standalone message compression. + +## Installation + +```bash +npm install headroom-ai ai @ai-sdk/openai +``` + + +The TypeScript SDK sends messages to a local Headroom proxy for compression. Start the proxy before using the SDK: + +```bash +pip install "headroom-ai[proxy]" +headroom proxy +``` + + +## withHeadroom() one-liner + +The simplest integration. Wraps any Vercel AI SDK language model with automatic compression: + +```ts twoslash +import { withHeadroom } from 'headroom-ai/vercel-ai'; +import { openai } from '@ai-sdk/openai'; +import { generateText } from 'ai'; + +const model = withHeadroom(openai('gpt-4o')); + +const { text } = await generateText({ + model, + messages: [ + { role: 'user', content: 'Summarize these results...' }, + ], +}); +``` + +`withHeadroom()` calls `wrapLanguageModel` + `headroomMiddleware()` under the hood. It works with any provider (`@ai-sdk/openai`, `@ai-sdk/anthropic`, `@ai-sdk/google`, etc.). + +## headroomMiddleware() for composition + +Use the middleware directly when you need to compose it with other middleware: + +```ts twoslash +// @noErrors +import { headroomMiddleware } from 'headroom-ai/vercel-ai'; +import { wrapLanguageModel } from 'ai'; +import { openai } from '@ai-sdk/openai'; + +const model = wrapLanguageModel({ + model: openai('gpt-4o'), + middleware: headroomMiddleware(), +}); +``` + +Pass options to control compression behavior: + +```ts twoslash +import { headroomMiddleware } from 'headroom-ai/vercel-ai'; + +const middleware = headroomMiddleware({ + model: 'gpt-4o', + baseUrl: 'http://localhost:8787', +}); +``` + +## compressVercelMessages() standalone + +Compress Vercel-format messages directly without wrapping a model. Useful for custom pipelines: + +```ts twoslash +import { compressVercelMessages } from 'headroom-ai/vercel-ai'; + +const result = await compressVercelMessages(messages, { + model: 'gpt-4o', +}); + +console.log(`Saved ${result.tokensSaved} tokens`); +// result.messages is in Vercel format, ready for the AI SDK +``` + +## Streaming with streamText + +Compression happens before the request. Streaming responses are unaffected: + +```ts twoslash +import { withHeadroom } from 'headroom-ai/vercel-ai'; +import { openai } from '@ai-sdk/openai'; +import { streamText } from 'ai'; + +const model = withHeadroom(openai('gpt-4o')); + +const result = streamText({ + model, + messages: longConversation, +}); + +for await (const chunk of result.textStream) { + process.stdout.write(chunk); +} +``` + +## generateObject with compressed context + +Works with structured output: + +```ts twoslash +// @noErrors +import { withHeadroom } from 'headroom-ai/vercel-ai'; +import { openai } from '@ai-sdk/openai'; +import { generateText, Output } from 'ai'; +import { z } from 'zod'; + +const model = withHeadroom(openai('gpt-4o')); + +const { output } = await generateText({ + model, + output: Output.object({ + schema: z.object({ + summary: z.string(), + severity: z.enum(['low', 'medium', 'high']), + }), + }), + messages: largeConversationHistory, +}); +``` + +## How it works + +1. Messages are converted from Vercel format to OpenAI format +2. Headroom compresses them via the proxy's `/v1/compress` endpoint +3. Compressed messages are converted back to Vercel format +4. The original model receives the smaller prompt + +All other model behavior (tool calling, structured output, streaming) is unchanged. diff --git a/docs/next.config.mjs b/docs/next.config.mjs new file mode 100644 index 000000000..821a6e23d --- /dev/null +++ b/docs/next.config.mjs @@ -0,0 +1,11 @@ +import { createMDX } from 'fumadocs-mdx/next'; + +const withMDX = createMDX(); + +/** @type {import('next').NextConfig} */ +const config = { + reactStrictMode: true, + serverExternalPackages: ['typescript', 'twoslash'], +}; + +export default withMDX(config); diff --git a/docs/package-lock.json b/docs/package-lock.json new file mode 100644 index 000000000..3f0e75ae9 --- /dev/null +++ b/docs/package-lock.json @@ -0,0 +1,5257 @@ +{ + "name": "headroom-docs", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "headroom-docs", + "version": "0.0.0", + "hasInstallScript": true, + "dependencies": { + "dotted-map": "^3.1.0", + "fumadocs-core": "16.7.10", + "fumadocs-mdx": "14.2.11", + "fumadocs-twoslash": "^3.1.3", + "fumadocs-typescript": "^4.0.3", + "fumadocs-ui": "16.7.10", + "headroom-ai": "file:../sdk/typescript", + "lucide-react": "^1.7.0", + "next": "16.2.2", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "recharts": "^3.8.1", + "tailwind-merge": "^3.5.0" + }, + "devDependencies": { + "@ai-sdk/openai": "^3.0.51", + "@anthropic-ai/sdk": "^0.82.0", + "@tailwindcss/postcss": "^4.2.2", + "@types/mdx": "^2.0.13", + "@types/node": "^25.5.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "ai": "^6.0.149", + "openai": "^6.33.0", + "postcss": "^8.5.8", + "tailwindcss": "^4.2.2", + "typescript": "^5.9.3" + } + }, + "../sdk/typescript": { + "name": "headroom-ai", + "version": "0.1.0", + "license": "Apache-2.0", + "devDependencies": { + "@ai-sdk/anthropic": "^3.0.64", + "@ai-sdk/openai": "^3.0.48", + "@ai-sdk/provider": "^1.0.0", + "@anthropic-ai/sdk": "^0.39.0", + "ai": "^6.0.0", + "dotenv": "^17.3.1", + "openai": "^4.80.0", + "tsup": "^8.0.0", + "typescript": "^5.5.0", + "vitest": "^2.0.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@ai-sdk/provider": ">=1.0.0", + "@anthropic-ai/sdk": ">=0.30.0", + "ai": ">=6.0.0", + "openai": ">=4.0.0" + }, + "peerDependenciesMeta": { + "@ai-sdk/provider": { + "optional": true + }, + "@anthropic-ai/sdk": { + "optional": true + }, + "ai": { + "optional": true + }, + "openai": { + "optional": true + } + } + }, + "node_modules/@ai-sdk/gateway": { + "version": "3.0.91", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.91.tgz", + "integrity": "sha512-J39Dh6Gyg6HjG3A7OFKnJMp3QyZ3Eex+XDiX8aFBdRwwZm3jGWaMhkCxQPH7yiQ9kRiErZwHXX/Oexx4SyGGGA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.23", + "@vercel/oidc": "3.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/openai": { + "version": "3.0.51", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-3.0.51.tgz", + "integrity": "sha512-qBgDOC+vlXwLFbZ3UoKx3T8VFyul3K39JNyW6E4XnOnzLT4Mlhb0GeDC06RvYqwGWOQFBQNLe/vegOMVtNpl5g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.23" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/provider": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.8.tgz", + "integrity": "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/provider-utils": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.23.tgz", + "integrity": "sha512-z8GlDaCmRSDlqkMF2f4/RFgWxdarvIbyuk+m6WXT1LYgsnGiXRJGTD2Z1+SDl3LqtFuRtGX1aghYvQLoHL/9pg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@standard-schema/spec": "^1.1.0", + "eventsource-parser": "^3.0.6" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.82.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.82.0.tgz", + "integrity": "sha512-xdHTjL1GlUlDugHq/I47qdOKp/ROPvuHl7ROJCgUQigbvPu7asf9KcAcU1EqdrP2LuVhEKaTs7Z+ShpZDRzHdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "license": "MIT" + }, + "node_modules/@formatjs/fast-memoize": { + "version": "3.1.1", + "license": "MIT" + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.8.2", + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "3.1.1" + } + }, + "node_modules/@fumadocs/tailwind": { + "version": "0.0.3", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.1.1" + }, + "peerDependencies": { + "tailwindcss": "^4.0.0" + }, + "peerDependenciesMeta": { + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.1", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@next/env": { + "version": "16.2.2", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.2.2", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.2.tgz", + "integrity": "sha512-7ZwSgNKJNQiwW0CKhNm9B1WS2L1Olc4B2XY0hPYCAL3epFnugMhuw5TMWzMilQ3QCZcCHoYm9NGWTHbr5REFxw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.2.tgz", + "integrity": "sha512-c3m8kBHMziMgo2fICOP/cd/5YlrxDU5YYjAJeQLyFsCqVF8xjOTH/QYG4a2u48CvvZZSj1eHQfBCbyh7kBr30Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.2.tgz", + "integrity": "sha512-VKLuscm0P/mIfzt+SDdn2+8TNNJ7f0qfEkA+az7OqQbjzKdBxAHs0UvuiVoCtbwX+dqMEL9U54b5wQ/aN3dHeg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.2.tgz", + "integrity": "sha512-kU3OPHJq6sBUjOk7wc5zJ7/lipn8yGldMoAv4z67j6ov6Xo/JvzA7L7LCsyzzsXmgLEhk3Qkpwqaq/1+XpNR3g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.2.tgz", + "integrity": "sha512-CKXRILyErMtUftp+coGcZ38ZwE/Aqq45VMCcRLr2I4OXKrgxIBDXHnBgeX/UMil0S09i2JXaDL3Q+TN8D/cKmg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.2.tgz", + "integrity": "sha512-sS/jSk5VUoShUqINJFvNjVT7JfR5ORYj/+/ZpOYbbIohv/lQfduWnGAycq2wlknbOql2xOR0DoV0s6Xfcy49+g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.2.tgz", + "integrity": "sha512-aHaKceJgdySReT7qeck5oShucxWRiiEuwCGK8HHALe6yZga8uyFpLkPgaRw3kkF04U7ROogL/suYCNt/+CuXGA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "devOptional": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@orama/orama": { + "version": "3.1.18", + "license": "Apache-2.0", + "engines": { + "node": ">= 20.0.0" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz", + "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz", + "integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/@shikijs/core": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@shikijs/primitive": "4.0.2", + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/langs": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/primitive": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/rehype": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-string": "^3.0.1", + "shiki": "4.0.2", + "unified": "^11.0.5", + "unist-util-visit": "^5.1.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/themes": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/transformers": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.0.2", + "@shikijs/types": "4.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/twoslash": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/twoslash/-/twoslash-4.0.2.tgz", + "integrity": "sha512-yHRudhirlMxOwDO6Q4OFU9hJMvUqNkY8hwtUfbaSEoG7A2cYicdO4c8fdDaDtyJ50HK7I8vTokrkIHTK3DCkLQ==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.0.2", + "@shikijs/types": "4.0.2", + "twoslash": "^0.3.6" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "typescript": ">=5.5.0" + } + }, + "node_modules/@shikijs/twoslash/node_modules/twoslash": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.3.6.tgz", + "integrity": "sha512-VuI5OKl+MaUO9UIW3rXKoPgHI3X40ZgB/j12VY6h98Ae1mCBihjPvhOPeJWlxCYcmSbmeZt5ZKkK0dsVtp+6pA==", + "license": "MIT", + "dependencies": { + "@typescript/vfs": "^1.6.2", + "twoslash-protocol": "0.3.6" + }, + "peerDependencies": { + "typescript": "^5.5.0" + } + }, + "node_modules/@shikijs/types": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.2" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-x64": "4.2.2", + "@tailwindcss/oxide-freebsd-x64": "4.2.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-x64-musl": "4.2.2", + "@tailwindcss/oxide-wasm32-wasi": "4.2.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.2", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.2.2", + "@tailwindcss/oxide": "4.2.2", + "postcss": "^8.5.6", + "tailwindcss": "4.2.2" + } + }, + "node_modules/@ts-morph/common": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.28.1.tgz", + "integrity": "sha512-W74iWf7ILp1ZKNYXY5qbddNaml7e9Sedv5lvU1V8lftlitkc9Pq1A+jlH23ltDgWYeZFFEqGCD1Ies9hqu3O+g==", + "license": "MIT", + "dependencies": { + "minimatch": "^10.0.1", + "path-browserify": "^1.0.1", + "tinyglobby": "^0.2.14" + } + }, + "node_modules/@turf/boolean-point-in-polygon": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-7.3.4.tgz", + "integrity": "sha512-v/4hfyY90Vz9cDgs2GwjQf+Lft8o7mNCLJOTz/iv8SHAIgMMX0czEoIaNVOJr7tBqPqwin1CGwsncrkf5C9n8Q==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@turf/invariant": "7.3.4", + "@types/geojson": "^7946.0.10", + "point-in-polygon-hao": "^1.1.0", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/helpers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.3.4.tgz", + "integrity": "sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/invariant": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.3.4.tgz", + "integrity": "sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.4", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "license": "MIT", + "peer": true + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.2", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.14", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "devOptional": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, + "node_modules/@typescript/vfs": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.4.tgz", + "integrity": "sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "license": "ISC" + }, + "node_modules/@vercel/oidc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.1.0.tgz", + "integrity": "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 20" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ai": { + "version": "6.0.149", + "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.149.tgz", + "integrity": "sha512-3asRb/m3ZGH7H4+VTuTgj8eQYJZ9IJUmV0ljLslY92mQp6Zj+NVn4SmFj0TBr2Y/wFBWC3xgn++47tSGOXxdbw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/gateway": "3.0.91", + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.23", + "@opentelemetry/api": "1.9.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.16", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001786", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/code-block-writer": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "license": "MIT" + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.1", + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "devOptional": true, + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dotted-map": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/dotted-map/-/dotted-map-3.1.0.tgz", + "integrity": "sha512-E0z9o5IaTf44FnWHvbyg4QQcBwXgzZJr82HJASWb1dKUCULHfnlWKRpfe5EFHTk/yaoS1sQSLMyMrL6o74/sIw==", + "license": "MIT", + "dependencies": { + "@turf/boolean-point-in-polygon": "^7.3.4", + "proj4": "^2.20.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.20.1", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-toolkit": { + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.45.1.tgz", + "integrity": "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esbuild": { + "version": "0.27.7", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.5.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/framer-motion": { + "version": "12.38.0", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.38.0", + "motion-utils": "^12.36.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fumadocs-core": { + "version": "16.7.10", + "license": "MIT", + "peer": true, + "dependencies": { + "@formatjs/intl-localematcher": "^0.8.2", + "@orama/orama": "^3.1.18", + "@shikijs/rehype": "^4.0.2", + "@shikijs/transformers": "^4.0.2", + "estree-util-value-to-estree": "^3.5.0", + "github-slugger": "^2.0.0", + "hast-util-to-estree": "^3.1.3", + "hast-util-to-jsx-runtime": "^2.3.6", + "image-size": "^2.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-markdown": "^2.1.2", + "negotiator": "^1.0.0", + "npm-to-yarn": "^3.0.1", + "path-to-regexp": "^8.4.0", + "remark": "^15.0.1", + "remark-gfm": "^4.0.1", + "remark-rehype": "^11.1.2", + "scroll-into-view-if-needed": "^3.1.0", + "shiki": "^4.0.2", + "tinyglobby": "^0.2.15", + "unified": "^11.0.5", + "unist-util-visit": "^5.1.0", + "vfile": "^6.0.3" + }, + "peerDependencies": { + "@mdx-js/mdx": "*", + "@mixedbread/sdk": "^0.46.0", + "@orama/core": "1.x.x", + "@oramacloud/client": "2.x.x", + "@tanstack/react-router": "1.x.x", + "@types/estree-jsx": "*", + "@types/hast": "*", + "@types/mdast": "*", + "@types/react": "*", + "algoliasearch": "5.x.x", + "flexsearch": "*", + "lucide-react": "*", + "next": "16.x.x", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-router": "7.x.x", + "waku": "^0.26.0 || ^0.27.0 || ^1.0.0", + "zod": "4.x.x" + }, + "peerDependenciesMeta": { + "@mdx-js/mdx": { + "optional": true + }, + "@mixedbread/sdk": { + "optional": true + }, + "@orama/core": { + "optional": true + }, + "@oramacloud/client": { + "optional": true + }, + "@tanstack/react-router": { + "optional": true + }, + "@types/estree-jsx": { + "optional": true + }, + "@types/hast": { + "optional": true + }, + "@types/mdast": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "algoliasearch": { + "optional": true + }, + "flexsearch": { + "optional": true + }, + "lucide-react": { + "optional": true + }, + "next": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-router": { + "optional": true + }, + "waku": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/fumadocs-mdx": { + "version": "14.2.11", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.1.1", + "@standard-schema/spec": "^1.1.0", + "chokidar": "^5.0.0", + "esbuild": "^0.27.3", + "estree-util-value-to-estree": "^3.5.0", + "js-yaml": "^4.1.1", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-markdown": "^2.1.2", + "picocolors": "^1.1.1", + "picomatch": "^4.0.3", + "tinyexec": "^1.0.4", + "tinyglobby": "^0.2.15", + "unified": "^11.0.5", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.1.0", + "vfile": "^6.0.3", + "zod": "^4.3.6" + }, + "bin": { + "fumadocs-mdx": "dist/bin.js" + }, + "peerDependencies": { + "@fumadocs/mdx-remote": "^1.4.0", + "@types/mdast": "*", + "@types/mdx": "*", + "@types/react": "*", + "fumadocs-core": "^15.0.0 || ^16.0.0", + "mdast-util-directive": "*", + "next": "^15.3.0 || ^16.0.0", + "react": "*", + "vite": "6.x.x || 7.x.x || 8.x.x" + }, + "peerDependenciesMeta": { + "@fumadocs/mdx-remote": { + "optional": true + }, + "@types/mdast": { + "optional": true + }, + "@types/mdx": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "mdast-util-directive": { + "optional": true + }, + "next": { + "optional": true + }, + "react": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/fumadocs-twoslash": { + "version": "3.1.15", + "resolved": "https://registry.npmjs.org/fumadocs-twoslash/-/fumadocs-twoslash-3.1.15.tgz", + "integrity": "sha512-MygtupZnfH0fKjDpI5Nb68cVMEnCpYrvWLcfWP6hJeZvyBWjCDTjN5x1PffUtsP6rHWdgpZuw8T51OnNC7f88w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-popover": "^1.1.15", + "@shikijs/twoslash": "^4.0.2", + "mdast-util-from-markdown": "^2.0.3", + "mdast-util-gfm": "^3.1.0", + "mdast-util-to-hast": "^13.2.1", + "shiki": "^4.0.2", + "tailwind-merge": "^3.5.0", + "twoslash": "^0.3.6" + }, + "peerDependencies": { + "@types/react": "*", + "fumadocs-ui": "^15.0.0 || ^16.0.0", + "react": "18.x.x || 19.x.x" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/fumadocs-twoslash/node_modules/twoslash": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.3.6.tgz", + "integrity": "sha512-VuI5OKl+MaUO9UIW3rXKoPgHI3X40ZgB/j12VY6h98Ae1mCBihjPvhOPeJWlxCYcmSbmeZt5ZKkK0dsVtp+6pA==", + "license": "MIT", + "dependencies": { + "@typescript/vfs": "^1.6.2", + "twoslash-protocol": "0.3.6" + }, + "peerDependencies": { + "typescript": "^5.5.0" + } + }, + "node_modules/fumadocs-typescript": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/fumadocs-typescript/-/fumadocs-typescript-4.0.14.tgz", + "integrity": "sha512-Jx2ldrFP2jEKUeczHuj1OCaCXNxJbVX/bseYaGA3+DY5BK0otaozfs2bJK75TfbGPF3grAZdSe+0KGP1DOTYqQ==", + "license": "MIT", + "dependencies": { + "estree-util-value-to-estree": "^3.5.0", + "hast-util-to-estree": "^3.1.3", + "hast-util-to-jsx-runtime": "^2.3.6", + "remark": "^15.0.1", + "remark-rehype": "^11.1.2", + "tinyglobby": "^0.2.15", + "ts-morph": "^27.0.2", + "unist-util-visit": "^5.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "fumadocs-core": "^15.7.0 || ^16.0.0", + "fumadocs-ui": "^15.7.0 || ^16.0.0", + "typescript": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "fumadocs-ui": { + "optional": true + } + } + }, + "node_modules/fumadocs-ui": { + "version": "16.7.10", + "license": "MIT", + "peer": true, + "dependencies": { + "@fumadocs/tailwind": "0.0.3", + "@radix-ui/react-accordion": "^1.2.12", + "@radix-ui/react-collapsible": "^1.1.12", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-direction": "^1.1.1", + "@radix-ui/react-navigation-menu": "^1.2.14", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-presence": "^1.1.5", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tabs": "^1.1.13", + "class-variance-authority": "^0.7.1", + "lucide-react": "^1.7.0", + "motion": "^12.38.0", + "next-themes": "^0.4.6", + "react-medium-image-zoom": "^5.4.1", + "react-remove-scroll": "^2.7.2", + "rehype-raw": "^7.0.0", + "scroll-into-view-if-needed": "^3.1.0", + "tailwind-merge": "^3.5.0", + "unist-util-visit": "^5.1.0" + }, + "peerDependencies": { + "@takumi-rs/image-response": "*", + "@types/mdx": "*", + "@types/react": "*", + "fumadocs-core": "16.7.10", + "next": "16.x.x", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "shiki": "*" + }, + "peerDependenciesMeta": { + "@takumi-rs/image-response": { + "optional": true + }, + "@types/mdx": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "next": { + "optional": true + }, + "shiki": { + "optional": true + } + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.1", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-string": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/headroom-ai": { + "resolved": "../sdk/typescript", + "link": true + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/image-size": { + "version": "2.0.2", + "license": "MIT", + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "license": "MIT" + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lucide-react": { + "version": "1.7.0", + "license": "ISC", + "peer": true, + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mgrs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz", + "integrity": "sha512-awNbTOqCxK1DBGjalK3xqWIstBZgN6fxsMSiXLs9/spqWkF2pAhb2rrYCFSsr1/tT7PhcDGjZndG8SWYn0byYA==", + "license": "MIT" + }, + "node_modules/micromark": { + "version": "4.0.2", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/motion": { + "version": "12.38.0", + "license": "MIT", + "dependencies": { + "framer-motion": "^12.38.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/motion-dom": { + "version": "12.38.0", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.36.0" + } + }, + "node_modules/motion-utils": { + "version": "12.36.0", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next": { + "version": "16.2.2", + "license": "MIT", + "peer": true, + "dependencies": { + "@next/env": "16.2.2", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.9.19", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.2.2", + "@next/swc-darwin-x64": "16.2.2", + "@next/swc-linux-arm64-gnu": "16.2.2", + "@next/swc-linux-arm64-musl": "16.2.2", + "@next/swc-linux-x64-gnu": "16.2.2", + "@next/swc-linux-x64-musl": "16.2.2", + "@next/swc-win32-arm64-msvc": "16.2.2", + "@next/swc-win32-x64-msvc": "16.2.2", + "sharp": "^0.34.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-themes": { + "version": "0.4.6", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/npm-to-yarn": { + "version": "3.0.1", + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/nebrelbug/npm-to-yarn?sponsor=1" + } + }, + "node_modules/oniguruma-parser": { + "version": "0.12.1", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.5", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.1", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/openai": { + "version": "6.33.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.33.0.tgz", + "integrity": "sha512-xAYN1W3YsDXJWA5F277135YfkEk6H7D3D6vWwRhJ3OEkzRgcyK8z/P5P9Gyi/wB4N8kK9kM5ZjprfvyHagKmpw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/point-in-polygon-hao": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/point-in-polygon-hao/-/point-in-polygon-hao-1.2.4.tgz", + "integrity": "sha512-x2pcvXeqhRHlNRdhLs/tgFapAbSSe86wa/eqmj1G6pWftbEs5aVRJhRGM6FYSUERKu0PjekJzMq0gsI2XyiclQ==", + "license": "MIT", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.1", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/proj4": { + "version": "2.20.8", + "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.20.8.tgz", + "integrity": "sha512-1C8sfT4xY4PAPwk0MroFBTGF4R4bzDXdmPQTGYVLsoNssrZ9odzObxS2dTeGBty8jW8KO7h16C1Hs2JP+ctfFw==", + "license": "MIT", + "dependencies": { + "mgrs": "1.0.0", + "wkt-parser": "^1.5.5" + }, + "funding": { + "url": "https://github.com/sponsors/ahocevar" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/react": { + "version": "19.2.4", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-is": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.5.tgz", + "integrity": "sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ==", + "license": "MIT", + "peer": true + }, + "node_modules/react-medium-image-zoom": { + "version": "5.4.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/rpearce" + } + ], + "license": "BSD-3-Clause", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/readdirp": { + "version": "5.0.0", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/recharts": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.8.1.tgz", + "integrity": "sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "^1.9.0 || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^10.1.1", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.1.1", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT", + "peer": true + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "license": "MIT" + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark": { + "version": "15.0.1", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.1", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "license": "MIT" + }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/shiki": { + "version": "4.0.2", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.0.2", + "@shikijs/engine-javascript": "4.0.2", + "@shikijs/engine-oniguruma": "4.0.2", + "@shikijs/langs": "4.0.2", + "@shikijs/themes": "4.0.2", + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tailwind-merge": { + "version": "3.5.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.2.2", + "devOptional": true, + "license": "MIT", + "peer": true + }, + "node_modules/tapable": { + "version": "2.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.4", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-morph": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-27.0.2.tgz", + "integrity": "sha512-fhUhgeljcrdZ+9DZND1De1029PrE+cMkIP7ooqkLRTrRLTqcki2AstsyJm0vRNbTbVCNJ0idGlbBrfqc7/nA8w==", + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.28.1", + "code-block-writer": "^13.0.3" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + }, + "node_modules/twoslash-protocol": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/twoslash-protocol/-/twoslash-protocol-0.3.6.tgz", + "integrity": "sha512-FHGsJ9Q+EsNr5bEbgG3hnbkvEBdW5STgPU824AHUjB4kw0Dn4p8tABT7Ncg1Ie6V0+mDg3Qpy41VafZXcQhWMA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "dev": true, + "license": "MIT" + }, + "node_modules/unified": { + "version": "11.0.5", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/vfile": { + "version": "6.0.3", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/wkt-parser": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.5.5.tgz", + "integrity": "sha512-/zMYi94/7D7fxcOSlVmWn6vnOMj3Gq5d1xvVjaYOS9n6h0qOJ4I7YYVxBWYcH1vq9+suhqzXkn05Yx47zQNUIA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ahocevar" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 000000000..2eded3a43 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,41 @@ +{ + "name": "headroom-docs", + "version": "0.0.0", + "private": true, + "scripts": { + "build": "next build", + "dev": "next dev", + "start": "next start", + "types:check": "fumadocs-mdx && next typegen && tsc --noEmit", + "postinstall": "fumadocs-mdx" + }, + "dependencies": { + "dotted-map": "^3.1.0", + "fumadocs-core": "16.7.10", + "fumadocs-mdx": "14.2.11", + "fumadocs-twoslash": "^3.1.3", + "fumadocs-typescript": "^4.0.3", + "fumadocs-ui": "16.7.10", + "headroom-ai": "file:../sdk/typescript", + "lucide-react": "^1.7.0", + "next": "16.2.2", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "recharts": "^3.8.1", + "tailwind-merge": "^3.5.0" + }, + "devDependencies": { + "@ai-sdk/openai": "^3.0.51", + "@anthropic-ai/sdk": "^0.82.0", + "@tailwindcss/postcss": "^4.2.2", + "@types/mdx": "^2.0.13", + "@types/node": "^25.5.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "ai": "^6.0.149", + "openai": "^6.33.0", + "postcss": "^8.5.8", + "tailwindcss": "^4.2.2", + "typescript": "^5.9.3" + } +} diff --git a/docs/postcss.config.mjs b/docs/postcss.config.mjs new file mode 100644 index 000000000..297374d80 --- /dev/null +++ b/docs/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; + +export default config; diff --git a/docs/proxy.ts b/docs/proxy.ts new file mode 100644 index 000000000..dabe3a6f0 --- /dev/null +++ b/docs/proxy.ts @@ -0,0 +1,29 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { isMarkdownPreferred, rewritePath } from 'fumadocs-core/negotiation'; +import { docsContentRoute, docsRoute } from '@/lib/shared'; + +const { rewrite: rewriteDocs } = rewritePath( + `${docsRoute}{/*path}`, + `${docsContentRoute}{/*path}/content.md`, +); +const { rewrite: rewriteSuffix } = rewritePath( + `${docsRoute}{/*path}.mdx`, + `${docsContentRoute}{/*path}/content.md`, +); + +export default function proxy(request: NextRequest) { + const result = rewriteSuffix(request.nextUrl.pathname); + if (result) { + return NextResponse.rewrite(new URL(result, request.nextUrl)); + } + + if (isMarkdownPreferred(request)) { + const result = rewriteDocs(request.nextUrl.pathname); + + if (result) { + return NextResponse.rewrite(new URL(result, request.nextUrl)); + } + } + + return NextResponse.next(); +} diff --git a/docs/source.config.ts b/docs/source.config.ts new file mode 100644 index 000000000..30e1dd63a --- /dev/null +++ b/docs/source.config.ts @@ -0,0 +1,44 @@ +import { defineConfig, defineDocs } from 'fumadocs-mdx/config'; +import { metaSchema, pageSchema } from 'fumadocs-core/source/schema'; +import { transformerTwoslash } from 'fumadocs-twoslash'; +import { rehypeCodeDefaultOptions } from 'fumadocs-core/mdx-plugins'; + +export const docs = defineDocs({ + dir: 'content/docs', + docs: { + schema: pageSchema, + postprocess: { + includeProcessedMarkdown: true, + }, + }, + meta: { + schema: metaSchema, + }, +}); + +export default defineConfig({ + mdxOptions: { + rehypeCodeOptions: { + themes: { + light: 'github-light', + dark: 'github-dark', + }, + transformers: [ + ...(rehypeCodeDefaultOptions.transformers ?? []), + transformerTwoslash({ + twoslashOptions: { + compilerOptions: { + target: 9, // ES2022 + lib: ['lib.es2022.d.ts', 'lib.dom.d.ts', 'lib.dom.iterable.d.ts'], + }, + // Documentation code snippets are illustrative — don't require full type validity + handbookOptions: { + noErrors: true, + }, + }, + }), + ], + langs: ['js', 'jsx', 'ts', 'tsx', 'python', 'bash', 'json', 'yaml', 'toml', 'css'], + }, + }, +}); diff --git a/docs/tsconfig.json b/docs/tsconfig.json new file mode 100644 index 000000000..e6be490b0 --- /dev/null +++ b/docs/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "paths": { + "@/*": ["./*"], + "collections/*": ["./.source/*"] + }, + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": ["node_modules"] +} diff --git a/docs/ARCHITECTURE.md b/wiki/ARCHITECTURE.md similarity index 100% rename from docs/ARCHITECTURE.md rename to wiki/ARCHITECTURE.md diff --git a/docs/LATENCY_BENCHMARKS.md b/wiki/LATENCY_BENCHMARKS.md similarity index 100% rename from docs/LATENCY_BENCHMARKS.md rename to wiki/LATENCY_BENCHMARKS.md diff --git a/docs/LIMITATIONS.md b/wiki/LIMITATIONS.md similarity index 100% rename from docs/LIMITATIONS.md rename to wiki/LIMITATIONS.md diff --git a/docs/agno.md b/wiki/agno.md similarity index 100% rename from docs/agno.md rename to wiki/agno.md diff --git a/docs/api.md b/wiki/api.md similarity index 100% rename from docs/api.md rename to wiki/api.md diff --git a/docs/benchmarks.md b/wiki/benchmarks.md similarity index 100% rename from docs/benchmarks.md rename to wiki/benchmarks.md diff --git a/docs/ccr.md b/wiki/ccr.md similarity index 100% rename from docs/ccr.md rename to wiki/ccr.md diff --git a/docs/cli.md b/wiki/cli.md similarity index 100% rename from docs/cli.md rename to wiki/cli.md diff --git a/docs/compression.md b/wiki/compression.md similarity index 100% rename from docs/compression.md rename to wiki/compression.md diff --git a/docs/configuration.md b/wiki/configuration.md similarity index 100% rename from docs/configuration.md rename to wiki/configuration.md diff --git a/docs/docker-install.md b/wiki/docker-install.md similarity index 100% rename from docs/docker-install.md rename to wiki/docker-install.md diff --git a/docs/errors.md b/wiki/errors.md similarity index 100% rename from docs/errors.md rename to wiki/errors.md diff --git a/docs/getting-started.md b/wiki/getting-started.md similarity index 100% rename from docs/getting-started.md rename to wiki/getting-started.md diff --git a/docs/image-compression.md b/wiki/image-compression.md similarity index 100% rename from docs/image-compression.md rename to wiki/image-compression.md diff --git a/docs/index.md b/wiki/index.md similarity index 100% rename from docs/index.md rename to wiki/index.md diff --git a/docs/integration-guide.md b/wiki/integration-guide.md similarity index 100% rename from docs/integration-guide.md rename to wiki/integration-guide.md diff --git a/docs/langchain.md b/wiki/langchain.md similarity index 100% rename from docs/langchain.md rename to wiki/langchain.md diff --git a/docs/learn.md b/wiki/learn.md similarity index 100% rename from docs/learn.md rename to wiki/learn.md diff --git a/docs/llmlingua.md b/wiki/llmlingua.md similarity index 100% rename from docs/llmlingua.md rename to wiki/llmlingua.md diff --git a/docs/macos-deployment.md b/wiki/macos-deployment.md similarity index 100% rename from docs/macos-deployment.md rename to wiki/macos-deployment.md diff --git a/docs/mcp.md b/wiki/mcp.md similarity index 100% rename from docs/mcp.md rename to wiki/mcp.md diff --git a/docs/memory.md b/wiki/memory.md similarity index 100% rename from docs/memory.md rename to wiki/memory.md diff --git a/docs/metrics.md b/wiki/metrics.md similarity index 100% rename from docs/metrics.md rename to wiki/metrics.md diff --git a/docs/overrides/.gitkeep b/wiki/overrides/.gitkeep similarity index 100% rename from docs/overrides/.gitkeep rename to wiki/overrides/.gitkeep diff --git a/docs/persistent-installs.md b/wiki/persistent-installs.md similarity index 100% rename from docs/persistent-installs.md rename to wiki/persistent-installs.md diff --git a/docs/plans/2026-04-11-persistent-installs-design.md b/wiki/plans/2026-04-11-persistent-installs-design.md similarity index 100% rename from docs/plans/2026-04-11-persistent-installs-design.md rename to wiki/plans/2026-04-11-persistent-installs-design.md diff --git a/docs/plans/dynamic-smart-crusher.md b/wiki/plans/dynamic-smart-crusher.md similarity index 100% rename from docs/plans/dynamic-smart-crusher.md rename to wiki/plans/dynamic-smart-crusher.md diff --git a/docs/proxy.md b/wiki/proxy.md similarity index 100% rename from docs/proxy.md rename to wiki/proxy.md diff --git a/docs/quickstart.md b/wiki/quickstart.md similarity index 100% rename from docs/quickstart.md rename to wiki/quickstart.md diff --git a/docs/screenshots/cache-ttl-dashboard-history.png b/wiki/screenshots/cache-ttl-dashboard-history.png similarity index 100% rename from docs/screenshots/cache-ttl-dashboard-history.png rename to wiki/screenshots/cache-ttl-dashboard-history.png diff --git a/docs/screenshots/cache-ttl-dashboard-live.png b/wiki/screenshots/cache-ttl-dashboard-live.png similarity index 100% rename from docs/screenshots/cache-ttl-dashboard-live.png rename to wiki/screenshots/cache-ttl-dashboard-live.png diff --git a/docs/sdk.md b/wiki/sdk.md similarity index 100% rename from docs/sdk.md rename to wiki/sdk.md diff --git a/docs/shared-context.md b/wiki/shared-context.md similarity index 100% rename from docs/shared-context.md rename to wiki/shared-context.md diff --git a/docs/strands.md b/wiki/strands.md similarity index 100% rename from docs/strands.md rename to wiki/strands.md diff --git a/docs/stylesheets/extra.css b/wiki/stylesheets/extra.css similarity index 100% rename from docs/stylesheets/extra.css rename to wiki/stylesheets/extra.css diff --git a/docs/text-compression.md b/wiki/text-compression.md similarity index 100% rename from docs/text-compression.md rename to wiki/text-compression.md diff --git a/docs/transforms.md b/wiki/transforms.md similarity index 100% rename from docs/transforms.md rename to wiki/transforms.md diff --git a/docs/troubleshooting.md b/wiki/troubleshooting.md similarity index 100% rename from docs/troubleshooting.md rename to wiki/troubleshooting.md diff --git a/docs/typescript-sdk.md b/wiki/typescript-sdk.md similarity index 100% rename from docs/typescript-sdk.md rename to wiki/typescript-sdk.md