diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 201f19f0..60ad9244 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -13,11 +13,11 @@ name: "CodeQL Advanced"
on:
push:
- branches: [ "b/devcontainer-setup" ]
+ branches: ["b/devcontainer-setup"]
pull_request:
- branches: [ "b/devcontainer-setup" ]
+ branches: ["b/devcontainer-setup"]
schedule:
- - cron: '16 2 * * 6'
+ - cron: "16 2 * * 6"
jobs:
analyze:
@@ -43,8 +43,8 @@ jobs:
fail-fast: false
matrix:
include:
- - language: javascript-typescript
- build-mode: none
+ - language: javascript-typescript
+ build-mode: none
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
@@ -54,46 +54,46 @@ jobs:
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- - name: Checkout repository
- uses: actions/checkout@v4
+ - name: Checkout repository
+ uses: actions/checkout@v4
- # Add any setup steps before running the `github/codeql-action/init` action.
- # This includes steps like installing compilers or runtimes (`actions/setup-node`
- # or others). This is typically only required for manual builds.
- # - name: Setup runtime (example)
- # uses: actions/setup-example@v1
+ # Add any setup steps before running the `github/codeql-action/init` action.
+ # This includes steps like installing compilers or runtimes (`actions/setup-node`
+ # or others). This is typically only required for manual builds.
+ # - name: Setup runtime (example)
+ # uses: actions/setup-example@v1
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v4
- with:
- languages: ${{ matrix.language }}
- build-mode: ${{ matrix.build-mode }}
- # If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
- # Prefix the list here with "+" to use these queries and those in the config file.
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v4
+ with:
+ languages: ${{ matrix.language }}
+ build-mode: ${{ matrix.build-mode }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
- # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
- # queries: security-extended,security-and-quality
+ # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+ # queries: security-extended,security-and-quality
- # If the analyze step fails for one of the languages you are analyzing with
- # "We were unable to automatically build your code", modify the matrix above
- # to set the build mode to "manual" for that language. Then modify this step
- # to build your code.
- # ℹ️ Command-line programs to run using the OS shell.
- # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- - name: Run manual build steps
- if: matrix.build-mode == 'manual'
- shell: bash
- run: |
- echo 'If you are using a "manual" build mode for one or more of the' \
- 'languages you are analyzing, replace this with the commands to build' \
- 'your code, for example:'
- echo ' make bootstrap'
- echo ' make release'
- exit 1
+ # If the analyze step fails for one of the languages you are analyzing with
+ # "We were unable to automatically build your code", modify the matrix above
+ # to set the build mode to "manual" for that language. Then modify this step
+ # to build your code.
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+ - name: Run manual build steps
+ if: matrix.build-mode == 'manual'
+ shell: bash
+ run: |
+ echo 'If you are using a "manual" build mode for one or more of the' \
+ 'languages you are analyzing, replace this with the commands to build' \
+ 'your code, for example:'
+ echo ' make bootstrap'
+ echo ' make release'
+ exit 1
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v4
- with:
- category: "/language:${{matrix.language}}"
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v4
+ with:
+ category: "/language:${{matrix.language}}"
diff --git a/.gitig b/.gitig
new file mode 100644
index 00000000..b9f40a7b
--- /dev/null
+++ b/.gitig
@@ -0,0 +1 @@
+ore
diff --git a/apps/web/app/get-started/get-started-flow.tsx b/apps/web/app/get-started/get-started-flow.tsx
index f5354e6f..e55c6c2d 100644
--- a/apps/web/app/get-started/get-started-flow.tsx
+++ b/apps/web/app/get-started/get-started-flow.tsx
@@ -4,7 +4,8 @@ import { useCallback, useState } from "react";
import Image from "next/image";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
-import { Check, Github, Loader2 } from "lucide-react";
+import { Check, Loader2, Icon } from "lucide-react";
+import { github } from "@lucide/lab";
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import { useSession } from "@/hooks/use-session";
@@ -304,9 +305,9 @@ function GitHubConnectStep({
className="size-8 rounded-full bg-zinc-800"
/>
) : (
-
-
-
+
+
+
)}
@@ -345,7 +346,7 @@ function GitHubConnectStep({
className="gap-2 border-zinc-700 bg-transparent text-zinc-300 hover:bg-white/5 hover:text-white"
>
-
+
Install GitHub App
@@ -376,7 +377,7 @@ function GitHubConnectStep({
{isLinking ? (
) : (
-
+
)}
{forceReconnect ? "Reconnect GitHub" : "Connect GitHub"}
diff --git a/apps/web/app/terms-of-service/page.tsx b/apps/web/app/terms-of-service/page.tsx
new file mode 100644
index 00000000..67fc494b
--- /dev/null
+++ b/apps/web/app/terms-of-service/page.tsx
@@ -0,0 +1,11 @@
+export default function TermsOfServicePage() {
+ return (
+
+
Terms of Service
+
+ By using bl1nk-note, you agree to these Terms of Service. This is a
+ placeholder page. Please update with your actual Terms of Service.
+
+
+ );
+}
diff --git a/apps/web/components/ai-elements/code-block.tsx b/apps/web/components/ai-elements/code-block.tsx
new file mode 100644
index 00000000..ccef52c3
--- /dev/null
+++ b/apps/web/components/ai-elements/code-block.tsx
@@ -0,0 +1,563 @@
+"use client";
+
+import { Button } from "@/components/ui/button";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+import { cn } from "@/lib/utils";
+import { CheckIcon, CopyIcon } from "lucide-react";
+import type { ComponentProps, CSSProperties, HTMLAttributes } from "react";
+import {
+ createContext,
+ memo,
+ useCallback,
+ useContext,
+ useEffect,
+ useMemo,
+ useRef,
+ useState,
+} from "react";
+import type {
+ BundledLanguage,
+ BundledTheme,
+ HighlighterGeneric,
+ ThemedToken,
+} from "shiki";
+import { createHighlighter } from "shiki";
+
+// Shiki uses bitflags for font styles: 1=italic, 2=bold, 4=underline
+// oxlint-disable-next-line eslint(no-bitwise)
+const isItalic = (fontStyle: number | undefined) => fontStyle && fontStyle & 1;
+// oxlint-disable-next-line eslint(no-bitwise)
+const isBold = (fontStyle: number | undefined) => fontStyle && fontStyle & 2;
+const isUnderline = (fontStyle: number | undefined) =>
+ // oxlint-disable-next-line eslint(no-bitwise)
+ fontStyle && fontStyle & 4;
+
+// Transform tokens to include pre-computed keys to avoid noArrayIndexKey lint
+interface KeyedToken {
+ token: ThemedToken;
+ key: string;
+}
+interface KeyedLine {
+ tokens: KeyedToken[];
+ key: string;
+}
+
+const addKeysToTokens = (lines: ThemedToken[][]): KeyedLine[] =>
+ lines.map((line, lineIdx) => ({
+ key: `line-${lineIdx}`,
+ tokens: line.map((token, tokenIdx) => ({
+ key: `line-${lineIdx}-${tokenIdx}`,
+ token,
+ })),
+ }));
+
+// Token rendering component
+const TokenSpan = ({ token }: { token: ThemedToken }) => (
+
+ {token.content}
+
+);
+
+// Line number styles using CSS counters
+const lineNumberClasses = cn(
+ "block",
+ "before:content-[counter(line)]",
+ "before:inline-block",
+ "before:[counter-increment:line]",
+ "before:w-8",
+ "before:mr-4",
+ "before:text-right",
+ "before:text-muted-foreground/50",
+ "before:font-mono",
+ "before:select-none",
+);
+
+// Line rendering component
+const LineSpan = ({
+ keyedLine,
+ showLineNumbers,
+}: {
+ keyedLine: KeyedLine;
+ showLineNumbers: boolean;
+}) => (
+
+ {keyedLine.tokens.length === 0
+ ? "\n"
+ : keyedLine.tokens.map(({ token, key }) => (
+
+ ))}
+
+);
+
+// Types
+type CodeBlockProps = HTMLAttributes
& {
+ code: string;
+ language: BundledLanguage;
+ showLineNumbers?: boolean;
+};
+
+interface TokenizedCode {
+ tokens: ThemedToken[][];
+ fg: string;
+ bg: string;
+}
+
+interface CodeBlockContextType {
+ code: string;
+}
+
+// Context
+const CodeBlockContext = createContext({
+ code: "",
+});
+
+// Highlighter cache (singleton per language)
+const highlighterCache = new Map<
+ string,
+ Promise>
+>();
+
+// Token cache
+const tokensCache = new Map();
+
+// Subscribers for async token updates
+const subscribers = new Map void>>();
+
+const getTokensCacheKey = (code: string, language: BundledLanguage) => {
+ const start = code.slice(0, 100);
+ const end = code.length > 100 ? code.slice(-100) : "";
+ return `${language}:${code.length}:${start}:${end}`;
+};
+
+const getHighlighter = (
+ language: BundledLanguage,
+): Promise> => {
+ const cached = highlighterCache.get(language);
+ if (cached) {
+ return cached;
+ }
+
+ const highlighterPromise = createHighlighter({
+ langs: [language],
+ themes: ["github-light", "github-dark"],
+ });
+
+ highlighterCache.set(language, highlighterPromise);
+ return highlighterPromise;
+};
+
+// Create raw tokens for immediate display while highlighting loads
+const createRawTokens = (code: string): TokenizedCode => ({
+ bg: "transparent",
+ fg: "inherit",
+ tokens: code.split("\n").map((line) =>
+ line === ""
+ ? []
+ : [
+ {
+ color: "inherit",
+ content: line,
+ } as ThemedToken,
+ ],
+ ),
+});
+
+// Synchronous highlight with callback for async results
+export const highlightCode = (
+ code: string,
+ language: BundledLanguage,
+ // oxlint-disable-next-line eslint-plugin-promise(prefer-await-to-callbacks)
+ callback?: (result: TokenizedCode) => void,
+): TokenizedCode | null => {
+ const tokensCacheKey = getTokensCacheKey(code, language);
+
+ // Return cached result if available
+ const cached = tokensCache.get(tokensCacheKey);
+ if (cached) {
+ return cached;
+ }
+
+ // Subscribe callback if provided
+ if (callback) {
+ if (!subscribers.has(tokensCacheKey)) {
+ subscribers.set(tokensCacheKey, new Set());
+ }
+ subscribers.get(tokensCacheKey)?.add(callback);
+ }
+
+ // Start highlighting in background - fire-and-forget async pattern
+ getHighlighter(language)
+ // oxlint-disable-next-line eslint-plugin-promise(prefer-await-to-then)
+ .then((highlighter) => {
+ const availableLangs = highlighter.getLoadedLanguages();
+ const langToUse = availableLangs.includes(language) ? language : "text";
+
+ const result = highlighter.codeToTokens(code, {
+ lang: langToUse,
+ themes: {
+ dark: "github-dark",
+ light: "github-light",
+ },
+ });
+
+ const tokenized: TokenizedCode = {
+ bg: result.bg ?? "transparent",
+ fg: result.fg ?? "inherit",
+ tokens: result.tokens,
+ };
+
+ // Cache the result
+ tokensCache.set(tokensCacheKey, tokenized);
+
+ // Notify all subscribers
+ const subs = subscribers.get(tokensCacheKey);
+ if (subs) {
+ for (const sub of subs) {
+ sub(tokenized);
+ }
+ subscribers.delete(tokensCacheKey);
+ }
+ })
+ // oxlint-disable-next-line eslint-plugin-promise(prefer-await-to-then), eslint-plugin-promise(prefer-await-to-callbacks)
+ .catch((error) => {
+ console.error("Failed to highlight code:", error);
+ subscribers.delete(tokensCacheKey);
+ });
+
+ return null;
+};
+
+const CodeBlockBody = memo(
+ ({
+ tokenized,
+ showLineNumbers,
+ className,
+ }: {
+ tokenized: TokenizedCode;
+ showLineNumbers: boolean;
+ className?: string;
+ }) => {
+ const preStyle = useMemo(
+ () => ({
+ backgroundColor: tokenized.bg,
+ color: tokenized.fg,
+ }),
+ [tokenized.bg, tokenized.fg],
+ );
+
+ const keyedLines = useMemo(
+ () => addKeysToTokens(tokenized.tokens),
+ [tokenized.tokens],
+ );
+
+ return (
+
+
+ {keyedLines.map((keyedLine) => (
+
+ ))}
+
+
+ );
+ },
+ (prevProps, nextProps) =>
+ prevProps.tokenized === nextProps.tokenized &&
+ prevProps.showLineNumbers === nextProps.showLineNumbers &&
+ prevProps.className === nextProps.className,
+);
+
+CodeBlockBody.displayName = "CodeBlockBody";
+
+export const CodeBlockContainer = ({
+ className,
+ language,
+ style,
+ ...props
+}: HTMLAttributes & { language: string }) => (
+
+);
+
+export const CodeBlockHeader = ({
+ children,
+ className,
+ ...props
+}: HTMLAttributes) => (
+
+ {children}
+
+);
+
+export const CodeBlockTitle = ({
+ children,
+ className,
+ ...props
+}: HTMLAttributes) => (
+
+ {children}
+
+);
+
+export const CodeBlockFilename = ({
+ children,
+ className,
+ ...props
+}: HTMLAttributes) => (
+
+ {children}
+
+);
+
+export const CodeBlockActions = ({
+ children,
+ className,
+ ...props
+}: HTMLAttributes) => (
+
+ {children}
+
+);
+
+export const CodeBlockContent = ({
+ code,
+ language,
+ showLineNumbers = false,
+}: {
+ code: string;
+ language: BundledLanguage;
+ showLineNumbers?: boolean;
+}) => {
+ // Memoized raw tokens for immediate display
+ const rawTokens = useMemo(() => createRawTokens(code), [code]);
+
+ // Synchronous cache lookup — avoids setState in effect for cached results
+ const syncTokens = useMemo(
+ () => highlightCode(code, language) ?? rawTokens,
+ [code, language, rawTokens],
+ );
+
+ // Async highlighting result (populated after shiki loads)
+ const [asyncTokens, setAsyncTokens] = useState(null);
+ const asyncKeyRef = useRef({ code, language });
+
+ // Invalidate stale async tokens synchronously during render
+ if (
+ asyncKeyRef.current.code !== code ||
+ asyncKeyRef.current.language !== language
+ ) {
+ asyncKeyRef.current = { code, language };
+ setAsyncTokens(null);
+ }
+
+ useEffect(() => {
+ let cancelled = false;
+
+ highlightCode(code, language, (result) => {
+ if (!cancelled) {
+ setAsyncTokens(result);
+ }
+ });
+
+ return () => {
+ cancelled = true;
+ };
+ }, [code, language]);
+
+ const tokenized = asyncTokens ?? syncTokens;
+
+ return (
+
+
+
+ );
+};
+
+export const CodeBlock = ({
+ code,
+ language,
+ showLineNumbers = false,
+ className,
+ children,
+ ...props
+}: CodeBlockProps) => {
+ const contextValue = useMemo(() => ({ code }), [code]);
+
+ return (
+
+
+ {children}
+
+
+
+ );
+};
+
+export type CodeBlockCopyButtonProps = ComponentProps & {
+ onCopy?: () => void;
+ onError?: (error: Error) => void;
+ timeout?: number;
+};
+
+export const CodeBlockCopyButton = ({
+ onCopy,
+ onError,
+ timeout = 2000,
+ children,
+ className,
+ ...props
+}: CodeBlockCopyButtonProps) => {
+ const [isCopied, setIsCopied] = useState(false);
+ const timeoutRef = useRef(0);
+ const { code } = useContext(CodeBlockContext);
+
+ const copyToClipboard = useCallback(async () => {
+ if (typeof window === "undefined" || !navigator?.clipboard?.writeText) {
+ onError?.(new Error("Clipboard API not available"));
+ return;
+ }
+
+ try {
+ if (!isCopied) {
+ await navigator.clipboard.writeText(code);
+ setIsCopied(true);
+ onCopy?.();
+ timeoutRef.current = window.setTimeout(
+ () => setIsCopied(false),
+ timeout,
+ );
+ }
+ } catch (error) {
+ onError?.(error as Error);
+ }
+ }, [code, onCopy, onError, timeout, isCopied]);
+
+ useEffect(
+ () => () => {
+ window.clearTimeout(timeoutRef.current);
+ },
+ [],
+ );
+
+ const Icon = isCopied ? CheckIcon : CopyIcon;
+
+ return (
+
+ {children ?? }
+
+ );
+};
+
+export type CodeBlockLanguageSelectorProps = ComponentProps;
+
+export const CodeBlockLanguageSelector = (
+ props: CodeBlockLanguageSelectorProps,
+) => ;
+
+export type CodeBlockLanguageSelectorTriggerProps = ComponentProps<
+ typeof SelectTrigger
+>;
+
+export const CodeBlockLanguageSelectorTrigger = ({
+ className,
+ ...props
+}: CodeBlockLanguageSelectorTriggerProps) => (
+
+);
+
+export type CodeBlockLanguageSelectorValueProps = ComponentProps<
+ typeof SelectValue
+>;
+
+export const CodeBlockLanguageSelectorValue = (
+ props: CodeBlockLanguageSelectorValueProps,
+) => ;
+
+export type CodeBlockLanguageSelectorContentProps = ComponentProps<
+ typeof SelectContent
+>;
+
+export const CodeBlockLanguageSelectorContent = ({
+ align = "end",
+ ...props
+}: CodeBlockLanguageSelectorContentProps) => (
+
+);
+
+export type CodeBlockLanguageSelectorItemProps = ComponentProps<
+ typeof SelectItem
+>;
+
+export const CodeBlockLanguageSelectorItem = (
+ props: CodeBlockLanguageSelectorItemProps,
+) => ;
diff --git a/apps/web/components/ui/button.tsx b/apps/web/components/ui/button.tsx
index 46b3a48c..4d38506c 100644
--- a/apps/web/components/ui/button.tsx
+++ b/apps/web/components/ui/button.tsx
@@ -1,19 +1,19 @@
-import * as React from "react";
-import { Slot } from "@radix-ui/react-slot";
-import { cva, type VariantProps } from "class-variance-authority";
+import * as React from "react"
+import { cva, type VariantProps } from "class-variance-authority"
+import { Slot } from "radix-ui"
-import { cn } from "@/lib/utils";
+import { cn } from "@/lib/utils"
const buttonVariants = cva(
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
+ "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
- "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
+ "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
outline:
- "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
+ "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost:
@@ -22,9 +22,11 @@ const buttonVariants = cva(
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",
- sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
+ sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
icon: "size-9",
+ "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
"icon-sm": "size-8",
"icon-lg": "size-10",
},
@@ -33,8 +35,8 @@ const buttonVariants = cva(
variant: "default",
size: "default",
},
- },
-);
+ }
+)
function Button({
className,
@@ -44,9 +46,9 @@ function Button({
...props
}: React.ComponentProps<"button"> &
VariantProps & {
- asChild?: boolean;
+ asChild?: boolean
}) {
- const Comp = asChild ? Slot : "button";
+ const Comp = asChild ? Slot.Root : "button"
return (
- );
+ )
}
-export { Button, buttonVariants };
+export { Button, buttonVariants }
diff --git a/apps/web/components/ui/select.tsx b/apps/web/components/ui/select.tsx
index c3f080d4..c0dc7120 100644
--- a/apps/web/components/ui/select.tsx
+++ b/apps/web/components/ui/select.tsx
@@ -1,27 +1,27 @@
-"use client";
+"use client"
-import * as React from "react";
-import * as SelectPrimitive from "@radix-ui/react-select";
-import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
+import * as React from "react"
+import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
+import { Select as SelectPrimitive } from "radix-ui"
-import { cn } from "@/lib/utils";
+import { cn } from "@/lib/utils"
function Select({
...props
}: React.ComponentProps) {
- return ;
+ return
}
function SelectGroup({
...props
}: React.ComponentProps) {
- return ;
+ return
}
function SelectValue({
...props
}: React.ComponentProps) {
- return ;
+ return
}
function SelectTrigger({
@@ -30,15 +30,15 @@ function SelectTrigger({
children,
...props
}: React.ComponentProps & {
- size?: "sm" | "default";
+ size?: "sm" | "default"
}) {
return (
@@ -47,7 +47,7 @@ function SelectTrigger({
- );
+ )
}
function SelectContent({
@@ -62,10 +62,10 @@ function SelectContent({
{children}
@@ -84,7 +84,7 @@ function SelectContent({
- );
+ )
}
function SelectLabel({
@@ -94,10 +94,10 @@ function SelectLabel({
return (
- );
+ )
}
function SelectItem({
@@ -109,8 +109,8 @@ function SelectItem({
@@ -124,7 +124,7 @@ function SelectItem({
{children}
- );
+ )
}
function SelectSeparator({
@@ -134,10 +134,10 @@ function SelectSeparator({
return (
- );
+ )
}
function SelectScrollUpButton({
@@ -149,13 +149,13 @@ function SelectScrollUpButton({
data-slot="select-scroll-up-button"
className={cn(
"flex cursor-default items-center justify-center py-1",
- className,
+ className
)}
{...props}
>
- );
+ )
}
function SelectScrollDownButton({
@@ -167,13 +167,13 @@ function SelectScrollDownButton({
data-slot="select-scroll-down-button"
className={cn(
"flex cursor-default items-center justify-center py-1",
- className,
+ className
)}
{...props}
>
- );
+ )
}
export {
@@ -187,4 +187,4 @@ export {
SelectSeparator,
SelectTrigger,
SelectValue,
-};
+}
diff --git a/apps/web/git b/apps/web/git
new file mode 100644
index 00000000..e69de29b
diff --git a/apps/web/package.json b/apps/web/package.json
index 390dbaed..c5eb0098 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -49,14 +49,17 @@
"drizzle-orm": "^0.45.1",
"ioredis": "^5.9.2",
"jose": "^6.1.3",
- "lucide-react": "^0.562.0",
+ "lucide-react": "^1.11.0",
+ "@lucide/lab": "^0.1.2",
"nanoid": "^5.1.6",
"next": "16.2.3",
"postgres": "^3.4.8",
+ "radix-ui": "^1.4.3",
"react": "19.2.3",
"react-day-picker": "^9.14.0",
"react-dom": "19.2.3",
"server-only": "^0.0.1",
+ "shiki": "^4.0.2",
"sonner": "^2.0.7",
"streamdown": "^2.5.0",
"swr": "^2.3.8",
diff --git a/bun.lock b/bun.lock
index c3cd439b..3289e4d3 100644
--- a/bun.lock
+++ b/bun.lock
@@ -4,7 +4,11 @@
"workspaces": {
"": {
"name": "open-agents",
+ "dependencies": {
+ "@vercel/analytics": "^2.0.1",
+ },
"devDependencies": {
+ "@shelve/cli": "^5.0.1",
"oxfmt": "^0.43.0",
"oxlint": "1.57.0",
"turbo": "^2.5.4",
@@ -18,6 +22,7 @@
"dependencies": {
"@ai-sdk/elevenlabs": "^2.0.29",
"@ai-sdk/react": "catalog:",
+ "@lucide/lab": "^0.1.2",
"@octokit/auth-app": "^8.2.0",
"@octokit/rest": "^22.0.1",
"@open-agents/agent": "workspace:*",
@@ -50,14 +55,16 @@
"drizzle-orm": "^0.45.1",
"ioredis": "^5.9.2",
"jose": "^6.1.3",
- "lucide-react": "^0.562.0",
+ "lucide-react": "^1.11.0",
"nanoid": "^5.1.6",
"next": "16.2.3",
"postgres": "^3.4.8",
+ "radix-ui": "^1.4.3",
"react": "19.2.3",
"react-day-picker": "^9.14.0",
"react-dom": "19.2.3",
"server-only": "^0.0.1",
+ "shiki": "^4.0.2",
"sonner": "^2.0.7",
"streamdown": "^2.5.0",
"swr": "^2.3.8",
@@ -169,6 +176,8 @@
"@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="],
+ "@antfu/ni": ["@antfu/ni@30.1.0", "", { "dependencies": { "fzf": "^0.5.2", "package-manager-detector": "^1.6.0", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15" }, "bin": { "ni": "bin/ni.mjs", "nci": "bin/nci.mjs", "nr": "bin/nr.mjs", "nup": "bin/nup.mjs", "nd": "bin/nd.mjs", "nlx": "bin/nlx.mjs", "na": "bin/na.mjs", "nun": "bin/nun.mjs" } }, "sha512-3VuAbPjgY52rQNn4wABaXMhBU2Oq91uy6L8nX49eJ35OLI68CyckGU+HZxcaHix4ymuGM2nFL1D6sLpgODK5xw=="],
+
"@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
"@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="],
@@ -331,6 +340,8 @@
"@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="],
+ "@gar/promise-retry": ["@gar/promise-retry@1.0.3", "", {}, "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA=="],
+
"@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="],
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
@@ -401,10 +412,38 @@
"@keyv/serialize": ["@keyv/serialize@1.1.1", "", {}, "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA=="],
+ "@lucide/lab": ["@lucide/lab@0.1.2", "", {}, "sha512-VprF2BJa7ZuTGOhUd5cf8tHJXyL63wdxcGieAiVVoR9hO0YmPsnZO0AGqDiX2/br+/MC6n8BoJcmPilltOXIJA=="],
+
"@lukeed/csprng": ["@lukeed/csprng@1.1.0", "", {}, "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA=="],
"@mermaid-js/parser": ["@mermaid-js/parser@1.1.0", "", { "dependencies": { "langium": "^4.0.0" } }, "sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw=="],
+ "@napi-rs/keyring": ["@napi-rs/keyring@1.2.0", "", { "optionalDependencies": { "@napi-rs/keyring-darwin-arm64": "1.2.0", "@napi-rs/keyring-darwin-x64": "1.2.0", "@napi-rs/keyring-freebsd-x64": "1.2.0", "@napi-rs/keyring-linux-arm-gnueabihf": "1.2.0", "@napi-rs/keyring-linux-arm64-gnu": "1.2.0", "@napi-rs/keyring-linux-arm64-musl": "1.2.0", "@napi-rs/keyring-linux-riscv64-gnu": "1.2.0", "@napi-rs/keyring-linux-x64-gnu": "1.2.0", "@napi-rs/keyring-linux-x64-musl": "1.2.0", "@napi-rs/keyring-win32-arm64-msvc": "1.2.0", "@napi-rs/keyring-win32-ia32-msvc": "1.2.0", "@napi-rs/keyring-win32-x64-msvc": "1.2.0" } }, "sha512-d0d4Oyxm+v980PEq1ZH2PmS6cvpMIRc17eYpiU47KgW+lzxklMu6+HOEOPmxrpnF/XQZ0+Q78I2mgMhbIIo/dg=="],
+
+ "@napi-rs/keyring-darwin-arm64": ["@napi-rs/keyring-darwin-arm64@1.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-CA83rDeyONDADO25JLZsh3eHY8yTEtm/RS6ecPsY+1v+dSawzT9GywBMu2r6uOp1IEhQs/xAfxgybGAFr17lSA=="],
+
+ "@napi-rs/keyring-darwin-x64": ["@napi-rs/keyring-darwin-x64@1.2.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-dBHjtKRCj4ByfnfqIKIJLo3wueQNJhLRyuxtX/rR4K/XtcS7VLlRD01XXizjpre54vpmObj63w+ZpHG+mGM8uA=="],
+
+ "@napi-rs/keyring-freebsd-x64": ["@napi-rs/keyring-freebsd-x64@1.2.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-DPZFr11pNJSnaoh0dzSUNF+T6ORhy3CkzUT3uGixbA71cAOPJ24iG8e8QrLOkuC/StWrAku3gBnth2XMWOcR3Q=="],
+
+ "@napi-rs/keyring-linux-arm-gnueabihf": ["@napi-rs/keyring-linux-arm-gnueabihf@1.2.0", "", { "os": "linux", "cpu": "arm" }, "sha512-8xv6DyEMlvRdqJzp4F39RLUmmTQsLcGYYv/3eIfZNZN1O5257tHxTrFYqAsny659rJJK2EKeSa7PhrSibQqRWQ=="],
+
+ "@napi-rs/keyring-linux-arm64-gnu": ["@napi-rs/keyring-linux-arm64-gnu@1.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Pu2V6Py+PBt7inryEecirl+t+ti8bhZphjP+W68iVaXHUxLdWmkgL9KI1VkbRHbx5k8K5Tew9OP218YfmVguIA=="],
+
+ "@napi-rs/keyring-linux-arm64-musl": ["@napi-rs/keyring-linux-arm64-musl@1.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-8TDymrpC4P1a9iDEaegT7RnrkmrJN5eNZh3Im3UEV5PPYGtrb82CRxsuFohthCWQW81O483u1bu+25+XA4nKUw=="],
+
+ "@napi-rs/keyring-linux-riscv64-gnu": ["@napi-rs/keyring-linux-riscv64-gnu@1.2.0", "", { "os": "linux", "cpu": "none" }, "sha512-awsB5XI1MYL7fwfjMDGmKOWvNgJEO7mM7iVEMS0fO39f0kVJnOSjlu7RHcXAF0LOx+0VfF3oxbWqJmZbvRCRHw=="],
+
+ "@napi-rs/keyring-linux-x64-gnu": ["@napi-rs/keyring-linux-x64-gnu@1.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8E+7z4tbxSJXxIBqA+vfB1CGajpCDRyTyqXkBig5NtASrv4YXcntSo96Iah2QDR5zD3dSTsmbqJudcj9rKKuHQ=="],
+
+ "@napi-rs/keyring-linux-x64-musl": ["@napi-rs/keyring-linux-x64-musl@1.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8RZ8yVEnmWr/3BxKgBSzmgntI7lNEsY7xouNfOsQkuVAiCNmxzJwETspzK3PQ2FHtDxgz5vHQDEBVGMyM4hUHA=="],
+
+ "@napi-rs/keyring-win32-arm64-msvc": ["@napi-rs/keyring-win32-arm64-msvc@1.2.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-AoqaDZpQ6KPE19VBLpxyORcp+yWmHI9Xs9Oo0PJ4mfHma4nFSLVdhAubJCxdlNptHe5va7ghGCHj3L9Akiv4cQ=="],
+
+ "@napi-rs/keyring-win32-ia32-msvc": ["@napi-rs/keyring-win32-ia32-msvc@1.2.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-EYL+EEI6bCsYi3LfwcQdnX3P/R76ENKNn+3PmpGheBsUFLuh0gQuP7aMVHM4rTw6UVe+L3vCLZSptq/oeacz0A=="],
+
+ "@napi-rs/keyring-win32-x64-msvc": ["@napi-rs/keyring-win32-x64-msvc@1.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-xFlx/TsmqmCwNU9v+AVnEJgoEAlBYgzFF5Ihz1rMpPAt4qQWWkMd4sCyM1gMJ1A/GnRqRegDiQpwaxGUHFtFbA=="],
+
"@napi-rs/nice": ["@napi-rs/nice@1.1.1", "", { "optionalDependencies": { "@napi-rs/nice-android-arm-eabi": "1.1.1", "@napi-rs/nice-android-arm64": "1.1.1", "@napi-rs/nice-darwin-arm64": "1.1.1", "@napi-rs/nice-darwin-x64": "1.1.1", "@napi-rs/nice-freebsd-x64": "1.1.1", "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", "@napi-rs/nice-linux-arm64-gnu": "1.1.1", "@napi-rs/nice-linux-arm64-musl": "1.1.1", "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", "@napi-rs/nice-linux-s390x-gnu": "1.1.1", "@napi-rs/nice-linux-x64-gnu": "1.1.1", "@napi-rs/nice-linux-x64-musl": "1.1.1", "@napi-rs/nice-openharmony-arm64": "1.1.1", "@napi-rs/nice-win32-arm64-msvc": "1.1.1", "@napi-rs/nice-win32-ia32-msvc": "1.1.1", "@napi-rs/nice-win32-x64-msvc": "1.1.1" } }, "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw=="],
"@napi-rs/nice-android-arm-eabi": ["@napi-rs/nice-android-arm-eabi@1.1.1", "", { "os": "android", "cpu": "arm" }, "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw=="],
@@ -467,6 +506,12 @@
"@noble/hashes": ["@noble/hashes@2.2.0", "", {}, "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg=="],
+ "@npmcli/agent": ["@npmcli/agent@4.0.0", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^11.2.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA=="],
+
+ "@npmcli/fs": ["@npmcli/fs@5.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og=="],
+
+ "@npmcli/redact": ["@npmcli/redact@4.0.0", "", {}, "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q=="],
+
"@nuxt/kit": ["@nuxt/kit@4.4.2", "", { "dependencies": { "c12": "^3.3.3", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.8", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "mlly": "^1.8.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^3.0.0", "scule": "^1.3.0", "semver": "^7.7.4", "tinyglobby": "^0.2.15", "ufo": "^1.6.3", "unctx": "^2.5.0", "untyped": "^2.0.0" } }, "sha512-5+IPRNX2CjkBhuWUwz0hBuLqiaJPRoKzQ+SvcdrQDbAyE+VDeFt74VpSFr5/R0ujrK4b+XnSHUJWdS72w6hsog=="],
"@nuxt/opencollective": ["@nuxt/opencollective@0.4.1", "", { "dependencies": { "consola": "^3.2.3" }, "bin": { "opencollective": "bin/opencollective.js" } }, "sha512-GXD3wy50qYbxCJ652bDrDzgMr3NFEkIS374+IgFQKkCvk9yiYcLvX2XDYr7UyQxf4wK0e+yqDYRubZ0DtOxnmQ=="],
@@ -617,16 +662,30 @@
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
+ "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.7", "", { "dependencies": { "@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-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="],
+
+ "@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-alert-dialog": ["@radix-ui/react-alert-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-dialog": "1.1.15", "@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-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="],
+
"@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-aspect-ratio": ["@radix-ui/react-aspect-ratio@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-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="],
+
"@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.11", "", { "dependencies": { "@radix-ui/react-context": "1.1.3", "@radix-ui/react-primitive": "2.1.4", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@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-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q=="],
+ "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "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-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "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-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="],
+
+ "@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.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw=="],
+ "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-menu": "2.1.16", "@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-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="],
+
"@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=="],
@@ -639,12 +698,24 @@
"@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-form": ["@radix-ui/react-form@0.1.8", "", { "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-label": "2.1.7", "@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-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="],
+
+ "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@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-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-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-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="],
+
"@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-label": ["@radix-ui/react-label@2.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "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-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A=="],
"@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "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-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-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "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-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="],
+ "@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.16", "", { "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-menu": "2.1.16", "@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-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA=="],
+
+ "@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-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.8", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@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-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0", "@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-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="],
+
+ "@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.3", "", { "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-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0" }, "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-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="],
+
"@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=="],
@@ -655,6 +726,10 @@
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "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-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
+ "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@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-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="],
+
+ "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "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-direction": "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", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "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-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="],
+
"@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=="],
@@ -663,12 +738,22 @@
"@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "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-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g=="],
+ "@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@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-primitive": "2.1.3", "@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-use-size": "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-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="],
+
"@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-switch": ["@radix-ui/react-switch@1.2.6", "", { "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-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "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-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="],
"@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-toast": ["@radix-ui/react-toast@1.2.15", "", { "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-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@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-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-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="],
+
+ "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@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-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="],
+
+ "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@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-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="],
+
+ "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-toggle-group": "1.1.11" }, "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-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="],
+
"@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "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-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", "@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-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="],
"@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=="],
@@ -695,19 +780,23 @@
"@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="],
- "@shikijs/core": ["@shikijs/core@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA=="],
+ "@shelve/cli": ["@shelve/cli@5.0.1", "", { "dependencies": { "@antfu/ni": "^30.0.0", "@clack/prompts": "^1.2.0", "@napi-rs/keyring": "^1.1.7", "c12": "3.3.4", "citty": "^0.2.2", "consola": "^3.4.2", "defu": "^6.1.7", "dotenv": "^17.4.2", "npm-registry-fetch": "19.1.1", "nypm": "0.6.5", "ofetch": "1.5.1", "pkg-types": "2.3.0", "rc9": "^3.0.1", "semver": "7.7.4", "std-env": "^4.1.0", "tinyexec": "^1.1.1", "tinyglobby": "0.2.16", "tree-kill": "^1.2.2" }, "bin": { "shelve": "dist/index.mjs", "shelve-cli": "dist/index.mjs" } }, "sha512-1BS2JvJ+Prp+aAllpstx8nYqEVGHc4OKNdyD6g6fp0m/hHGrdVTCru7GTwk9ypVOKrj6M0m+zVEIr3sazVnB/g=="],
+
+ "@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@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA=="],
+ "@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@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g=="],
+ "@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@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg=="],
+ "@shikijs/langs": ["@shikijs/langs@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg=="],
- "@shikijs/themes": ["@shikijs/themes@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA=="],
+ "@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/themes": ["@shikijs/themes@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA=="],
"@shikijs/transformers": ["@shikijs/transformers@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/types": "3.23.0" } }, "sha512-F9msZVxdF+krQNSdQ4V+Ja5QemeAoTQ2jxt7nJCwhDsdF1JWS3KxIQXA3lQbyKwS3J61oHRUSv4jYWv3CkaKTQ=="],
- "@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="],
+ "@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=="],
@@ -969,7 +1058,7 @@
"@upsetjs/venn.js": ["@upsetjs/venn.js@2.0.0", "", { "optionalDependencies": { "d3-selection": "^3.0.0", "d3-transition": "^3.0.1" } }, "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw=="],
- "@vercel/analytics": ["@vercel/analytics@1.6.1", "", { "peerDependencies": { "@remix-run/react": "^2", "@sveltejs/kit": "^1 || ^2", "next": ">= 13", "react": "^18 || ^19 || ^19.0.0-rc", "svelte": ">= 4", "vue": "^3", "vue-router": "^4" }, "optionalPeers": ["@remix-run/react", "@sveltejs/kit", "next", "react", "svelte", "vue", "vue-router"] }, "sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg=="],
+ "@vercel/analytics": ["@vercel/analytics@2.0.1", "", { "peerDependencies": { "@remix-run/react": "^2", "@sveltejs/kit": "^1 || ^2", "next": ">= 13", "nuxt": ">= 3", "react": "^18 || ^19 || ^19.0.0-rc", "svelte": ">= 4", "vue": "^3", "vue-router": "^4" }, "optionalPeers": ["@remix-run/react", "@sveltejs/kit", "next", "nuxt", "react", "svelte", "vue", "vue-router"] }, "sha512-MTQG6V9qQrt1tsDeF+2Uoo5aPjqbVPys1xvnIftXSJYG2SrwXRHnqEvVoYID7BTruDz4lCd2Z7rM1BdkUehk2g=="],
"@vercel/cli-auth": ["@vercel/cli-auth@0.0.1", "", { "dependencies": { "async-listen": "3.0.0", "open": "8.4.0", "xdg-app-paths": "5", "zod": "4.1.11" } }, "sha512-CnqiuMlZ4pjs2LCPYiR6aLKPPd3Xb8SBI1Y7eotXKgpx6qgrGNY+E7EIyUt5ErGHJGIrCZyGG5WEo4bHtVmz2Q=="],
@@ -1045,6 +1134,8 @@
"acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
+ "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
+
"ai": ["ai@6.0.168", "", { "dependencies": { "@ai-sdk/gateway": "3.0.104", "@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-2HqCJuO+1V2aV7vfYs5LFEUfxbkGX+5oa54q/gCCTL7KLTdbxcCu5D7TdLA5kwsrs3Szgjah9q6D9tpjHM3hUQ=="],
"ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="],
@@ -1123,6 +1214,8 @@
"c12": ["c12@3.3.4", "", { "dependencies": { "chokidar": "^5.0.0", "confbox": "^0.2.4", "defu": "^6.1.6", "dotenv": "^17.3.1", "exsolve": "^1.0.8", "giget": "^3.2.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.1.0", "pkg-types": "^2.3.0", "rc9": "^3.0.1" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA=="],
+ "cacache": ["cacache@20.0.4", "", { "dependencies": { "@npmcli/fs": "^5.0.0", "fs-minipass": "^3.0.0", "glob": "^13.0.0", "lru-cache": "^11.1.0", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^13.0.0" } }, "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA=="],
+
"cacheable-lookup": ["cacheable-lookup@7.0.0", "", {}, "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w=="],
"cacheable-request": ["cacheable-request@13.0.18", "", { "dependencies": { "@types/http-cache-semantics": "^4.0.4", "get-stream": "^9.0.1", "http-cache-semantics": "^4.2.0", "keyv": "^5.5.5", "mimic-response": "^4.0.0", "normalize-url": "^8.1.1", "responselike": "^4.0.2" } }, "sha512-rFWadDRKJs3s2eYdXlGggnBZKG7MTblkFBB0YllFds+UYnfogDp2wcR6JN97FhRkHTvq59n2vhNoHNZn29dh/Q=="],
@@ -1155,7 +1248,7 @@
"chevrotain-allstar": ["chevrotain-allstar@0.4.1", "", { "dependencies": { "lodash-es": "^4.17.21" }, "peerDependencies": { "chevrotain": "^12.0.0" } }, "sha512-PvVJm3oGqrveUVW2Vt/eZGeiAIsJszYweUcYwcskg9e+IubNYKKD+rHHem7A6XVO22eDAL+inxNIGAzZ/VIWlA=="],
- "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
+ "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"citty": ["citty@0.2.2", "", {}, "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w=="],
@@ -1429,12 +1522,16 @@
"fs-extra": ["fs-extra@11.3.4", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA=="],
+ "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="],
+
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
"function-timeout": ["function-timeout@1.0.2", "", {}, "sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA=="],
+ "fzf": ["fzf@0.5.2", "", {}, "sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q=="],
+
"get-east-asian-width": ["get-east-asian-width@1.5.0", "", {}, "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA=="],
"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=="],
@@ -1489,6 +1586,8 @@
"hono": ["hono@4.12.14", "", {}, "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w=="],
+ "hosted-git-info": ["hosted-git-info@9.0.2", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg=="],
+
"html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
"html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="],
@@ -1497,11 +1596,15 @@
"http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
+ "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
+
"http2-wrapper": ["http2-wrapper@2.2.1", "", { "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.2.0" } }, "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ=="],
+ "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
+
"human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="],
- "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
+ "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
@@ -1519,6 +1622,8 @@
"ioredis": ["ioredis@5.10.1", "", { "dependencies": { "@ioredis/commands": "1.5.1", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA=="],
+ "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
+
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
"is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
@@ -1567,6 +1672,8 @@
"jsonlines": ["jsonlines@0.1.1", "", {}, "sha512-ekDrAGso79Cvf+dtm+mL8OBI2bmAOt3gssYs833De/C9NmIpWDWyUO4zPgB5x2/OhY366dkhgfPMYfwZF7yOZA=="],
+ "jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="],
+
"katex": ["katex@0.16.45", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA=="],
"keyv": ["keyv@5.6.0", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw=="],
@@ -1631,12 +1738,14 @@
"lru_map": ["lru_map@0.4.1", "", {}, "sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg=="],
- "lucide-react": ["lucide-react@0.562.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw=="],
+ "lucide-react": ["lucide-react@1.11.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-UOhjdztXCgdBReRcIhsvz2siIBogfv/lhJEIViCpLt924dO+GDms9T7DNoucI23s6kEPpe988m5N0D2ajnzb2g=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
"make-asynchronous": ["make-asynchronous@1.1.0", "", { "dependencies": { "p-event": "^6.0.0", "type-fest": "^4.6.0", "web-worker": "^1.5.0" } }, "sha512-ayF7iT+44LXdxJLTrTd3TLQpFDDvPCBxXxbv+pMUSuHA5Q8zyAfwkRP6aHHwNVFBUFWtxAHqwNJxF8vMZLAbVg=="],
+ "make-fetch-happen": ["make-fetch-happen@15.0.5", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/agent": "^4.0.0", "@npmcli/redact": "^4.0.0", "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^6.0.0", "ssri": "^13.0.0" } }, "sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg=="],
+
"markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="],
"marked": ["marked@17.0.6", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA=="],
@@ -1755,6 +1864,18 @@
"minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
+ "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="],
+
+ "minipass-fetch": ["minipass-fetch@5.0.2", "", { "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^2.0.0", "minizlib": "^3.0.1" }, "optionalDependencies": { "iconv-lite": "^0.7.2" } }, "sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ=="],
+
+ "minipass-flush": ["minipass-flush@1.0.7", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA=="],
+
+ "minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="],
+
+ "minipass-sized": ["minipass-sized@2.0.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA=="],
+
+ "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="],
+
"mixpart": ["mixpart@0.0.4", "", {}, "sha512-RAoaOSXnMLrfUfmFbNynRYjeMru/bhgAYRy/GQVI8gmRq7vm9V9c2gGVYnYoQ008X6YTmRIu5b0397U7vb0bIA=="],
"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=="],
@@ -1765,20 +1886,28 @@
"nanostores": ["nanostores@1.3.0", "", {}, "sha512-XPUa/jz+P1oJvN9VBxw4L9MtdFfaH3DAryqPssqhb2kXjmb9npz0dly6rCsgFWOPr4Yg9mTfM3MDZgZZ+7A3lA=="],
- "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
+ "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
"next": ["next@16.2.3", "", { "dependencies": { "@next/env": "16.2.3", "@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.3", "@next/swc-darwin-x64": "16.2.3", "@next/swc-linux-arm64-gnu": "16.2.3", "@next/swc-linux-arm64-musl": "16.2.3", "@next/swc-linux-x64-gnu": "16.2.3", "@next/swc-linux-x64-musl": "16.2.3", "@next/swc-win32-arm64-msvc": "16.2.3", "@next/swc-win32-x64-msvc": "16.2.3", "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-9V3zV4oZFza3PVev5/poB9g0dEafVcgNyQ8eTRop8GvxZjV2G15FC5ARuG1eFD42QgeYkzJBJzHghNP8Ad9xtA=="],
+ "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
+
"node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.1.1", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-test": "build-test.js", "node-gyp-build-optional-packages-optional": "optional.js" } }, "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw=="],
"normalize-url": ["normalize-url@8.1.1", "", {}, "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ=="],
+ "npm-package-arg": ["npm-package-arg@13.0.2", "", { "dependencies": { "hosted-git-info": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^7.0.0" } }, "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA=="],
+
+ "npm-registry-fetch": ["npm-registry-fetch@19.1.1", "", { "dependencies": { "@npmcli/redact": "^4.0.0", "jsonparse": "^1.3.1", "make-fetch-happen": "^15.0.0", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minizlib": "^3.0.1", "npm-package-arg": "^13.0.0", "proc-log": "^6.0.0" } }, "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw=="],
+
"npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="],
"nypm": ["nypm@0.6.5", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ=="],
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
+ "ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="],
+
"ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
@@ -1807,6 +1936,8 @@
"p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="],
+ "p-map": ["p-map@7.0.4", "", {}, "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ=="],
+
"p-timeout": ["p-timeout@6.1.4", "", {}, "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg=="],
"package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="],
@@ -1855,6 +1986,8 @@
"pretty-ms": ["pretty-ms@9.3.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ=="],
+ "proc-log": ["proc-log@6.1.0", "", {}, "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ=="],
+
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
@@ -1863,6 +1996,8 @@
"quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="],
+ "radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.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-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@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-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "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-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="],
+
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
"raw-body": ["raw-body@2.5.3", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" } }, "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA=="],
@@ -1881,7 +2016,7 @@
"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@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
+ "readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"redis-errors": ["redis-errors@1.2.0", "", {}, "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w=="],
@@ -1967,7 +2102,7 @@
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
- "shiki": ["shiki@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/engine-javascript": "3.23.0", "@shikijs/engine-oniguruma": "3.23.0", "@shikijs/langs": "3.23.0", "@shikijs/themes": "3.23.0", "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA=="],
+ "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=="],
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
@@ -1983,6 +2118,12 @@
"slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
+ "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
+
+ "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="],
+
+ "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="],
+
"sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="],
"sort-keys": ["sort-keys@1.1.2", "", { "dependencies": { "is-plain-obj": "^1.0.0" } }, "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg=="],
@@ -1997,10 +2138,14 @@
"space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],
+ "ssri": ["ssri@13.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ=="],
+
"standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="],
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
+ "std-env": ["std-env@4.1.0", "", {}, "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ=="],
+
"stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="],
"streamdown": ["streamdown@2.5.0", "", { "dependencies": { "clsx": "^2.1.1", "hast-util-to-jsx-runtime": "^2.3.6", "html-url-attributes": "^3.0.1", "marked": "^17.0.1", "mermaid": "^11.12.2", "rehype-harden": "^1.1.8", "rehype-raw": "^7.0.0", "rehype-sanitize": "^6.0.0", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remend": "1.3.0", "tailwind-merge": "^3.4.0", "unified": "^11.0.5", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-/tTnURfIOxZK/pqJAxsfCvETG/XCJHoWnk3jq9xLcuz6CSpnjjuxSRBTTL4PKGhxiZQf0lqPxGhImdpwcZ2XwA=="],
@@ -2057,7 +2202,7 @@
"tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="],
- "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
+ "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="],
"tinypool": ["tinypool@2.1.0", "", {}, "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw=="],
@@ -2067,6 +2212,8 @@
"token-types": ["token-types@6.1.2", "", { "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww=="],
+ "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=="],
@@ -2141,6 +2288,8 @@
"uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],
+ "validate-npm-package-name": ["validate-npm-package-name@7.0.2", "", {}, "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A=="],
+
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
"vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="],
@@ -2191,6 +2340,8 @@
"xdg-portable": ["xdg-portable@7.3.0", "", { "dependencies": { "os-paths": "^4.0.1" } }, "sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw=="],
+ "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
+
"yauzl": ["yauzl@3.3.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "pend": "~1.2.0" } }, "sha512-PtGEvEP30p7sbIBJKUBjUnqgTVOyMURc4dLo9iNyAJnNIEz9pm88cCXF21w94Kg3k6RXkeZh5DHOGS0qEONvNQ=="],
"yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="],
@@ -2209,16 +2360,46 @@
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
+ "@nuxt/kit/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
+
+ "@oclif/core/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
+
"@oslojs/jwt/@oslojs/encoding": ["@oslojs/encoding@0.4.1", "", {}, "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q=="],
+ "@pierre/diffs/shiki": ["shiki@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/engine-javascript": "3.23.0", "@shikijs/engine-oniguruma": "3.23.0", "@shikijs/langs": "3.23.0", "@shikijs/themes": "3.23.0", "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA=="],
+
+ "@radix-ui/react-accordion/@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-accordion/@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-alert-dialog/@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-alert-dialog/@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-alert-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-arrow/@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-aspect-ratio/@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-checkbox/@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-checkbox/@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-collapsible/@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-collapsible/@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-collection/@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-collection/@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-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-context-menu/@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-context-menu/@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-dialog/@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-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=="],
@@ -2233,12 +2414,38 @@
"@radix-ui/react-focus-scope/@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-form/@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-form/@radix-ui/react-label": ["@radix-ui/react-label@2.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-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="],
+
+ "@radix-ui/react-form/@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-hover-card/@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-hover-card/@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-menu/@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-menu/@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-menu/@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-menubar/@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-menubar/@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-navigation-menu/@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-navigation-menu/@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-one-time-password-field/@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-one-time-password-field/@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-password-toggle-field/@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-password-toggle-field/@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-popover/@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-popover/@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=="],
@@ -2251,6 +2458,14 @@
"@radix-ui/react-portal/@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-progress/@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-progress/@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-radio-group/@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-radio-group/@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-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-roving-focus/@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=="],
@@ -2265,6 +2480,10 @@
"@radix-ui/react-select/@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-slider/@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-slider/@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-switch/@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-switch/@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=="],
@@ -2273,6 +2492,22 @@
"@radix-ui/react-tabs/@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-toast/@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-toast/@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-toggle/@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-toggle-group/@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-toggle-group/@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-toolbar/@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-toolbar/@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-toolbar/@radix-ui/react-separator": ["@radix-ui/react-separator@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-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
+
"@radix-ui/react-tooltip/@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-tooltip/@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=="],
@@ -2281,10 +2516,18 @@
"@radix-ui/react-visually-hidden/@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=="],
+ "@shikijs/transformers/@shikijs/core": ["@shikijs/core@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA=="],
+
+ "@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="],
+
+ "@streamdown/code/shiki": ["shiki@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/engine-javascript": "3.23.0", "@shikijs/engine-oniguruma": "3.23.0", "@shikijs/langs": "3.23.0", "@shikijs/themes": "3.23.0", "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA=="],
+
"@swc/cli/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="],
"@swc/cli/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
+ "@swc/cli/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
+
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
@@ -2311,10 +2554,16 @@
"@workflow/builders/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=="],
+ "@workflow/builders/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
+
+ "@workflow/cli/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
+
"@workflow/cli/enhanced-resolve": ["enhanced-resolve@5.19.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg=="],
"@workflow/cli/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=="],
+ "@workflow/cli/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
+
"@workflow/core/@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
"@workflow/core/nanoid": ["nanoid@5.1.6", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg=="],
@@ -2331,6 +2580,8 @@
"@xhmikosr/downloader/content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="],
+ "accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
+
"ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="],
"binary-version/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
@@ -2345,14 +2596,14 @@
"boxen/wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],
- "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
-
"cmdk/@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=="],
"cytoscape-fcose/cose-base": ["cose-base@2.2.0", "", { "dependencies": { "layout-base": "^2.0.0" } }, "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g=="],
"d3-dsv/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="],
+ "d3-dsv/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
+
"d3-sankey/d3-array": ["d3-array@2.12.1", "", { "dependencies": { "internmap": "^1.0.0" } }, "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ=="],
"d3-sankey/d3-shape": ["d3-shape@1.3.7", "", { "dependencies": { "d3-path": "1" } }, "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw=="],
@@ -2375,6 +2626,10 @@
"mermaid/marked": ["marked@16.4.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="],
+ "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
+
+ "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
+
"mlly/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=="],
"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=="],
@@ -2389,6 +2644,18 @@
"postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
+ "radix-ui/@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@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-is-hydrated": "0.1.0", "@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-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="],
+
+ "radix-ui/@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/@radix-ui/react-label": ["@radix-ui/react-label@2.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-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="],
+
+ "radix-ui/@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/@radix-ui/react-separator": ["@radix-ui/react-separator@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-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
+
+ "radix-ui/@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=="],
+
"raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
"seek-bzip/commander": ["commander@6.2.1", "", {}, "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="],
@@ -2417,6 +2684,8 @@
"web/@types/node": ["@types/node@20.19.39", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw=="],
+ "web/@vercel/analytics": ["@vercel/analytics@1.6.1", "", { "peerDependencies": { "@remix-run/react": "^2", "@sveltejs/kit": "^1 || ^2", "next": ">= 13", "react": "^18 || ^19 || ^19.0.0-rc", "svelte": ">= 4", "vue": "^3", "vue-router": "^4" }, "optionalPeers": ["@remix-run/react", "@sveltejs/kit", "next", "react", "svelte", "vue", "vue-router"] }, "sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg=="],
+
"wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"wsl-utils/is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="],
@@ -2469,28 +2738,88 @@
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
+ "@pierre/diffs/shiki/@shikijs/core": ["@shikijs/core@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA=="],
+
+ "@pierre/diffs/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA=="],
+
+ "@pierre/diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g=="],
+
+ "@pierre/diffs/shiki/@shikijs/langs": ["@shikijs/langs@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg=="],
+
+ "@pierre/diffs/shiki/@shikijs/themes": ["@shikijs/themes@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA=="],
+
+ "@pierre/diffs/shiki/@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="],
+
+ "@radix-ui/react-accordion/@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=="],
+
"@radix-ui/react-arrow/@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=="],
+ "@radix-ui/react-aspect-ratio/@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=="],
+
+ "@radix-ui/react-checkbox/@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=="],
+
+ "@radix-ui/react-collapsible/@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=="],
+
+ "@radix-ui/react-context-menu/@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=="],
+
"@radix-ui/react-dismissable-layer/@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=="],
"@radix-ui/react-dropdown-menu/@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=="],
"@radix-ui/react-focus-scope/@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=="],
+ "@radix-ui/react-form/@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=="],
+
+ "@radix-ui/react-hover-card/@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=="],
+
+ "@radix-ui/react-menubar/@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=="],
+
+ "@radix-ui/react-navigation-menu/@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=="],
+
+ "@radix-ui/react-one-time-password-field/@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=="],
+
+ "@radix-ui/react-password-toggle-field/@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=="],
+
"@radix-ui/react-popper/@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=="],
"@radix-ui/react-portal/@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=="],
+ "@radix-ui/react-progress/@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=="],
+
+ "@radix-ui/react-radio-group/@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=="],
+
"@radix-ui/react-roving-focus/@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=="],
"@radix-ui/react-scroll-area/@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=="],
+ "@radix-ui/react-slider/@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=="],
+
"@radix-ui/react-switch/@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=="],
"@radix-ui/react-tabs/@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=="],
+ "@radix-ui/react-toast/@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=="],
+
+ "@radix-ui/react-toggle-group/@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=="],
+
+ "@radix-ui/react-toggle/@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=="],
+
+ "@radix-ui/react-toolbar/@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=="],
+
"@radix-ui/react-visually-hidden/@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=="],
+ "@streamdown/code/shiki/@shikijs/core": ["@shikijs/core@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA=="],
+
+ "@streamdown/code/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA=="],
+
+ "@streamdown/code/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g=="],
+
+ "@streamdown/code/shiki/@shikijs/langs": ["@shikijs/langs@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg=="],
+
+ "@streamdown/code/shiki/@shikijs/themes": ["@shikijs/themes@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA=="],
+
+ "@streamdown/code/shiki/@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="],
+
"@swc/cli/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="],
"@vercel/cli-auth/open/define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="],
@@ -2547,6 +2876,8 @@
"@workflow/builders/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="],
+ "@workflow/cli/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
+
"@workflow/cli/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="],
"@workflow/cli/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="],
@@ -2617,8 +2948,6 @@
"boxen/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
- "c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
-
"cmdk/@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=="],
"cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="],
diff --git a/package.json b/package.json
index 6e2d771c..55ee6a15 100644
--- a/package.json
+++ b/package.json
@@ -24,9 +24,14 @@
"fix": "ultracite fix",
"ci": "bun run check && bun run typecheck && bun run test:isolated && bun run --cwd apps/web db:check",
"test:isolated": "bun run scripts/test-isolated.ts",
- "test:verbose": "bun test --reporter=junit --reporter-outfile /dev/stdout"
+ "test:verbose": "bun test --reporter=junit --reporter-outfile /dev/stdout",
+ "clean:workspace": "bash scripts/clean-workspace.sh"
+ },
+ "dependencies": {
+ "@vercel/analytics": "^2.0.1"
},
"devDependencies": {
+ "@shelve/cli": "^5.0.1",
"oxfmt": "^0.43.0",
"oxlint": "1.57.0",
"turbo": "^2.5.4",
diff --git a/packages/agent/kilo/client.ts b/packages/agent/kilo/client.ts
new file mode 100644
index 00000000..b4ef3b05
--- /dev/null
+++ b/packages/agent/kilo/client.ts
@@ -0,0 +1,169 @@
+export type ChatCompletionRequest = {
+ model: string;
+ messages: Message[];
+ stream?: boolean;
+ max_tokens?: number;
+ temperature?: number;
+ top_p?: number;
+ stop?: string | string[];
+ frequency_penalty?: number;
+ presence_penalty?: number;
+ tools?: Tool[];
+ tool_choice?: ToolChoice;
+ response_format?: ResponseFormat;
+ user?: string;
+ seed?: number;
+};
+
+export type Message =
+ | { role: "system"; content: string }
+ | { role: "user"; content: string | ContentPart[] }
+ | { role: "assistant"; content: string | null; tool_calls?: ToolCall[] }
+ | { role: "tool"; content: string; tool_call_id: string };
+
+export type ContentPart =
+ | { type: "text"; text: string }
+ | { type: "image_url"; image_url: { url: string; detail?: string } };
+
+export type Tool = {
+ type: "function";
+ function: {
+ name: string;
+ description?: string;
+ parameters: object;
+ };
+};
+
+export type ToolChoice =
+ | "none"
+ | "auto"
+ | "required"
+ | { type: "function"; function: { name: string } };
+
+export type ResponseFormat = {
+ type: "text" | "json_object";
+};
+
+export type ToolCall = {
+ id: string;
+ type: "function";
+ function: {
+ name: string;
+ arguments: string;
+ };
+};
+
+export type ChatCompletionResponse = {
+ id: string;
+ object: "chat.completion";
+ created: number;
+ model: string;
+ choices: Array<{
+ index: number;
+ message: {
+ role: "assistant";
+ content: string | null;
+ tool_calls?: ToolCall[];
+ };
+ finish_reason: "stop" | "length" | "tool_calls" | "content_filter";
+ }>;
+ usage: {
+ prompt_tokens: number;
+ completion_tokens: number;
+ total_tokens: number;
+ };
+};
+
+export type FIMRequest = {
+ model: string;
+ prompt: string;
+ suffix?: string;
+ max_tokens?: number;
+ temperature?: number;
+ stop?: string[];
+ stream?: boolean;
+};
+
+export type Model = {
+ id: string;
+ object: "model";
+ created: number;
+ owned_by: string;
+ name: string;
+ context_length: number;
+ pricing: {
+ prompt: string;
+ completion: string;
+ };
+};
+
+export class KiloClient {
+ private apiKey: string;
+ private baseUrl = "https://api.kilo.ai";
+
+ constructor(apiKey?: string) {
+ this.apiKey = apiKey || process.env.KILO_API_KEY || "";
+ if (!this.apiKey) {
+ throw new Error(
+ "Kilo API key is required. Set KILO_API_KEY environment variable.",
+ );
+ }
+ }
+
+ private async request(path: string, options?: RequestInit): Promise {
+ const response = await fetch(`${this.baseUrl}${path}`, {
+ ...options,
+ headers: {
+ Authorization: `Bearer ${this.apiKey}`,
+ "Content-Type": "application/json",
+ ...options?.headers,
+ },
+ });
+
+ if (!response.ok) {
+ let errorData: unknown;
+ try {
+ errorData = await response.json();
+ } catch {
+ throw new Error(
+ `Kilo API Error ${response.status}: ${response.statusText}`,
+ { cause: e },
+ );
+ }
+ throw new Error(
+ `Kilo API Error ${response.status}: ${
+ errorData?.error?.message || response.statusText
+ }`,
+ );
+ }
+
+ return response.json() as Promise;
+ }
+
+ async chatCompletions(
+ body: ChatCompletionRequest,
+ ): Promise {
+ return this.request(
+ "/api/gateway/chat/completions",
+ {
+ method: "POST",
+ body: JSON.stringify(body),
+ },
+ );
+ }
+
+ async fimCompletions(body: FIMRequest): Promise {
+ return this.request("/api/fim/completions", {
+ method: "POST",
+ body: JSON.stringify(body),
+ });
+ }
+
+ async listModels(): Promise<{ data: Model[] }> {
+ return this.request<{ data: Model[] }>("/api/gateway/models");
+ }
+
+ async listProviders(): Promise {
+ return this.request("/api/gateway/providers");
+ }
+}
diff --git a/packages/agent/open-agent.ts b/packages/agent/open-agent.ts
index ceb7d151..ef4aa2b0 100644
--- a/packages/agent/open-agent.ts
+++ b/packages/agent/open-agent.ts
@@ -19,6 +19,7 @@ import {
readFileTool,
skillTool,
taskTool,
+ delegateTaskTool,
todoWriteTool,
webFetchTool,
writeFileTool,
@@ -71,6 +72,7 @@ const tools = {
glob: globTool(),
bash: bashTool(),
task: taskTool,
+ delegate_task: delegateTaskTool,
ask_user_question: askUserQuestionTool,
skill: skillTool,
web_fetch: webFetchTool,
diff --git a/packages/agent/tools/delegate.ts b/packages/agent/tools/delegate.ts
new file mode 100644
index 00000000..af81f402
--- /dev/null
+++ b/packages/agent/tools/delegate.ts
@@ -0,0 +1,186 @@
+import {
+ type LanguageModelUsage,
+ type ModelMessage,
+ tool,
+ type UIToolInvocation,
+} from "ai";
+import { z } from "zod";
+import {
+ buildSubagentSummaryLines,
+ SUBAGENT_REGISTRY,
+ SUBAGENT_TYPES,
+} from "../subagents/registry";
+import { sumLanguageModelUsage } from "../usage";
+import { getSandboxContext, getSubagentModel } from "./utils";
+
+const subagentTypeSchema = z.enum(SUBAGENT_TYPES);
+const subagentSummaryLines = buildSubagentSummaryLines();
+
+const delegateTaskSchema = z.object({
+ subagentType: subagentTypeSchema.describe(
+ `Subagent to launch. Available options:\n${subagentSummaryLines}`,
+ ),
+ task: z
+ .string()
+ .describe("Short description of the task (displayed to user)"),
+ instructions: z.string().describe(
+ `Detailed instructions for the subagent. Include:
+- Goal and deliverables
+- Step-by-step procedure
+- Constraints and patterns to follow
+- How to verify the work`,
+ ),
+});
+
+export const delegateTaskOutputSchema = z.object({
+ results: z.array(
+ z.object({
+ task: z.string(),
+ modelId: z.string().optional(),
+ toolCallCount: z.number(),
+ final: z.custom().optional(),
+ usage: z.custom().optional(),
+ }),
+ ),
+ totalToolCallCount: z.number().int().nonnegative().optional(),
+ startedAt: z.number().int().nonnegative().optional(),
+});
+
+export type DelegateTaskToolOutput = z.infer;
+
+export const delegateTaskTool = tool({
+ needsApproval: false,
+ description: `Spawn multiple subagents to work on tasks in isolated contexts simultaneously.
+Each subagent gets its own workspace context. Only the final summary is returned.
+
+AVAILABLE SUBAGENTS:
+${subagentSummaryLines}
+
+WHEN TO USE delegate_task:
+- Parallel independent workstreams (e.g. researching different topics simultaneously)
+- Reasoning-heavy subtasks that can be separated and executed concurrently
+
+WHEN NOT TO USE (use existing tools instead):
+- Single sequential task -> just use the 'task' tool directly
+- Tasks needing your direct interaction or memory -> do it yourself
+- Simple, single-file or single-change edits -> do it yourself
+
+HOW TO USE:
+- Provide an array of 'tasks'. All run concurrently and results are returned together.
+- Choose the appropriate subagentType for each task.
+- Be explicit and concrete - subagents cannot ask clarifying questions.`,
+ inputSchema: z.object({
+ tasks: z
+ .array(delegateTaskSchema)
+ .min(1)
+ .max(5)
+ .describe("Tasks to run in parallel. Each gets its own subagent."),
+ }),
+ outputSchema: delegateTaskOutputSchema,
+ execute: async function* ({ tasks }, { experimental_context, abortSignal }) {
+ const sandboxContext = getSandboxContext(
+ experimental_context,
+ "delegateTask",
+ );
+ const model = getSubagentModel(experimental_context, "delegateTask");
+ const subagentModelId = typeof model === "string" ? model : model.modelId;
+ const startedAt = Date.now();
+
+ // Initialize state
+ const taskStates = tasks.map((t) => ({
+ task: t.task,
+ modelId: subagentModelId,
+ toolCallCount: 0,
+ usage: undefined as LanguageModelUsage | undefined,
+ final: undefined as ModelMessage[] | undefined,
+ }));
+
+ yield {
+ results: taskStates,
+ totalToolCallCount: 0,
+ startedAt,
+ };
+
+ const runTask = async (taskInput: (typeof tasks)[0], index: number) => {
+ const state = taskStates[index];
+ if (!state) return;
+ const subagent = SUBAGENT_REGISTRY[taskInput.subagentType].agent;
+ const result = await subagent.stream({
+ prompt:
+ "Complete this task and provide a summary of what you accomplished.",
+ options: {
+ task: taskInput.task,
+ instructions: taskInput.instructions,
+ sandbox: sandboxContext.sandbox,
+ model,
+ },
+ abortSignal,
+ });
+
+ for await (const part of result.fullStream) {
+ if (part.type === "tool-call") {
+ state.toolCallCount += 1;
+ } else if (part.type === "finish-step") {
+ state.usage = sumLanguageModelUsage(state.usage, part.usage);
+ }
+ }
+
+ const response = await result.response;
+ const finalUsage = state.usage ?? (await result.usage);
+
+ state.final = response.messages;
+ state.usage = finalUsage;
+
+ return state;
+ };
+
+ // Run all tasks in parallel
+ const promises = tasks.map((t, i) => runTask(t, i));
+ await Promise.all(promises);
+
+ const totalToolCallCount = taskStates.reduce(
+ (acc, t) => acc + t.toolCallCount,
+ 0,
+ );
+
+ yield {
+ results: taskStates,
+ totalToolCallCount,
+ startedAt,
+ };
+ },
+ toModelOutput: ({ output: { results } }) => {
+ if (!results || results.length === 0) {
+ return { type: "text", value: "All tasks completed." };
+ }
+
+ const summaries = results.map((result, i) => {
+ const messages = result.final;
+ let contentValue = "Task completed without detailed summary.";
+
+ if (messages) {
+ const lastAssistantMessage = messages.findLast(
+ (p) => p.role === "assistant",
+ );
+ const content = lastAssistantMessage?.content;
+
+ if (content) {
+ if (typeof content === "string") {
+ contentValue = content;
+ } else {
+ const lastTextPart = content.findLast((p) => p.type === "text");
+ if (lastTextPart) {
+ contentValue = lastTextPart.text;
+ }
+ }
+ }
+ }
+
+ return `=== Result for Task ${i + 1}: ${result.task} ===\n${contentValue}`;
+ });
+
+ return { type: "text", value: summaries.join("\n\n") };
+ },
+});
+
+export type DelegateTaskToolUIPart = UIToolInvocation;
diff --git a/packages/agent/tools/github.ts b/packages/agent/tools/github.ts
new file mode 100644
index 00000000..e0ceb7eb
--- /dev/null
+++ b/packages/agent/tools/github.ts
@@ -0,0 +1,129 @@
+import { tool } from "ai";
+import { z } from "zod";
+import { getSandbox, shellEscape } from "./utils";
+
+// หมดเวลาในการดำเนินการคำสั่ง git และ gh
+export const TIMEOUT_MS = 60_000;
+
+export const commitAndPrTool = tool({
+ description: `Commit all current changes, push to a new branch, and create a Pull Request using the GitHub CLI.
+
+WHEN TO USE:
+- When you have completed a task and want to submit your code for review.
+- When the user explicitly asks you to commit and create a PR.
+
+USAGE:
+- Automatically stages all changes (git add -A)
+- Creates a new branch
+- Commits the changes
+- Pushes the branch to origin
+- Uses the 'gh' CLI to create the PR`,
+ inputSchema: z.object({
+ branchName: z
+ .string()
+ .describe("The name of the new branch to create and push"),
+ commitMessage: z.string().describe("The commit message"),
+ prTitle: z.string().describe("The title of the pull request"),
+ prBody: z
+ .string()
+ .optional()
+ .describe("The body/description of the pull request"),
+ }),
+ needsApproval: () => true,
+ execute: async (
+ { branchName, commitMessage, prTitle, prBody },
+ { experimental_context, abortSignal },
+ ) => {
+ const sandbox = await getSandbox(experimental_context, "commitAndPr");
+ const cwd = sandbox.workingDirectory;
+
+ try {
+ // 1. Create and checkout new branch
+ const branchRes = await sandbox.exec(
+ `git checkout -b ${shellEscape(branchName)}`,
+ cwd,
+ TIMEOUT_MS,
+ { signal: abortSignal },
+ );
+
+ if (
+ !branchRes.success &&
+ !branchRes.stderr.includes("already exists") &&
+ !branchRes.stderr.includes("already a branch")
+ ) {
+ return {
+ success: false,
+ error: `Failed to create branch: ${branchRes.stderr}`,
+ };
+ }
+
+ // 2. Stage all changes
+ await sandbox.exec("git add -A", cwd, TIMEOUT_MS, {
+ signal: abortSignal,
+ });
+
+ // 3. Commit changes
+ const commitRes = await sandbox.exec(
+ `git commit -m ${shellEscape(commitMessage)}`,
+ cwd,
+ TIMEOUT_MS,
+ { signal: abortSignal },
+ );
+
+ if (
+ !commitRes.success &&
+ !commitRes.stdout.includes("nothing to commit") &&
+ !commitRes.stderr.includes("nothing to commit")
+ ) {
+ return {
+ success: false,
+ error: `Failed to commit: ${commitRes.stdout} ${commitRes.stderr}`,
+ };
+ }
+
+ // 4. Push branch
+ const pushRes = await sandbox.exec(
+ `git push -u origin ${shellEscape(branchName)}`,
+ cwd,
+ TIMEOUT_MS,
+ { signal: abortSignal },
+ );
+
+ if (!pushRes.success) {
+ return {
+ success: false,
+ error: `Failed to push: ${pushRes.stdout} ${pushRes.stderr}`,
+ };
+ }
+
+ // 5. Create PR via gh cli
+ const bodyArg = prBody ? `--body ${shellEscape(prBody)}` : '--body ""';
+ const prRes = await sandbox.exec(
+ `gh pr create --title ${shellEscape(prTitle)} ${bodyArg}`,
+ cwd,
+ TIMEOUT_MS,
+ { signal: abortSignal },
+ );
+
+ if (prRes.success) {
+ return {
+ success: true,
+ message: "Successfully committed, pushed, and created PR.",
+ prUrl: prRes.stdout.trim(),
+ };
+ } else {
+ return {
+ success: true,
+ message: `Successfully committed and pushed to branch ${branchName}. Note: Could not create PR automatically via gh CLI. Please create it manually.`,
+ errorDetails: prRes.stderr,
+ };
+ }
+ } catch (error) {
+ const message = error instanceof Error ? error.message : String(error);
+ return {
+ success: false,
+ error: `Error during commit and PR process: ${message}`,
+ };
+ }
+ },
+});
diff --git a/packages/agent/tools/index.ts b/packages/agent/tools/index.ts
index bd81875f..c92fbc2e 100644
--- a/packages/agent/tools/index.ts
+++ b/packages/agent/tools/index.ts
@@ -10,6 +10,11 @@ export {
type TaskToolOutput,
type TaskToolUIPart,
} from "./task";
+export {
+ delegateTaskTool,
+ type DelegateTaskToolOutput,
+ type DelegateTaskToolUIPart,
+} from "./delegate";
export {
askUserQuestionTool,
type AskUserQuestionToolUIPart,
@@ -17,3 +22,4 @@ export {
} from "./ask-user-question";
export { skillTool, type SkillToolInput } from "./skill";
export { webFetchTool } from "./fetch";
+export { commitAndPrTool } from "./github";
diff --git a/packages/agent/tools/kilo.test.ts b/packages/agent/tools/kilo.test.ts
new file mode 100644
index 00000000..86d8fec1
--- /dev/null
+++ b/packages/agent/tools/kilo.test.ts
@@ -0,0 +1,214 @@
+import { describe, test, expect, mock, beforeEach, afterEach } from "bun:test";
+
+// Mock node-fetch
+const fetchMock = mock(async (unusedUrl: string, unusedOptions: RequestInit) => {
+ return new Response(
+ JSON.stringify({ jsonrpc: "2.0", result: { success: true }, id: 1 }),
+ {
+ status: 200,
+ headers: { "Content-Type": "application/json" },
+ },
+ );
+});
+
+mock.module("node-fetch", () => ({
+ __esModule: true,
+ default: fetchMock,
+}));
+
+// Mock process.env
+const originalEnv = process.env;
+beforeEach(() => {
+ process.env = { ...originalEnv };
+});
+afterEach(() => {
+ process.env = originalEnv;
+});
+
+// Now import the class to be tested
+const { Context7Client } = await import("./kilo");
+
+describe("Context7Client", () => {
+ beforeEach(() => {
+ fetchMock.mockClear();
+ });
+
+ describe("constructor", () => {
+ test("should use provided API key", () => {
+ const client = new Context7Client("test-api-key");
+ expect(client).toBeDefined();
+ });
+
+ test("should use environment variable if no key provided", () => {
+ process.env.CONTEXT7_API_KEY = "env-api-key";
+ const client = new Context7Client();
+ expect(client).toBeDefined();
+ });
+
+ test("should throw error if no API key available", () => {
+ delete process.env.CONTEXT7_API_KEY;
+ expect(() => new Context7Client()).toThrow(
+ "Context7 API key is required. Provide it as parameter or set CONTEXT7_API_KEY environment variable.",
+ );
+ });
+ });
+
+ describe("call method", () => {
+ let client: Context7Client;
+
+ beforeEach(() => {
+ process.env.CONTEXT7_API_KEY = "test-api-key";
+ client = new Context7Client();
+ });
+
+ test("should make POST request with correct headers and payload", async () => {
+ await client.call("test.method", { param: "value" });
+
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ const [url, options] = fetchMock.mock.calls[0];
+
+ expect(url).toBe("https://mcp.context7.com/mcp");
+ expect(options?.method).toBe("POST");
+ expect(options?.headers).toEqual({
+ CONTEXT7_API_KEY: "test-api-key",
+ "Content-Type": "application/json",
+ });
+
+ const body = JSON.parse(options?.body as string);
+ expect(body).toEqual({
+ jsonrpc: "2.0",
+ method: "test.method",
+ id: 1,
+ params: { param: "value" },
+ });
+ });
+
+ test("should increment request ID for multiple calls", async () => {
+ await client.call("method1");
+ await client.call("method2");
+ await client.call("method3");
+
+ expect(fetchMock).toHaveBeenCalledTimes(3);
+
+ const bodies = fetchMock.mock.calls.map(([unusedUrl, options]) =>
+ JSON.parse((options as RequestInit)?.body as string),
+ );
+
+ expect(bodies[0].id).toBe(1);
+ expect(bodies[1].id).toBe(2);
+ expect(bodies[2].id).toBe(3);
+ });
+
+ test("should handle empty params", async () => {
+ await client.call("test.method");
+
+ const [unusedUrl, options] = fetchMock.mock.calls[0];
+ const body = JSON.parse((options as RequestInit)?.body as string);
+ expect(body.params).toEqual({});
+ });
+
+ test("should return parsed JSON response", async () => {
+ const mockResponse = {
+ jsonrpc: "2.0",
+ result: { tools: ["tool1", "tool2"] },
+ id: 1,
+ };
+ fetchMock.mockResolvedValueOnce(
+ new Response(JSON.stringify(mockResponse)),
+ );
+
+ const result = await client.call("tools/list");
+ expect(result).toEqual(mockResponse);
+ });
+
+ test("should handle error responses", async () => {
+ const errorResponse = {
+ jsonrpc: "2.0",
+ error: { code: -32601, message: "Method not found" },
+ id: 1,
+ };
+ fetchMock.mockResolvedValueOnce(
+ new Response(JSON.stringify(errorResponse)),
+ );
+
+ const result = await client.call("invalid.method");
+ expect(result).toEqual(errorResponse);
+ });
+
+ test("should throw on HTTP errors", async () => {
+ fetchMock.mockResolvedValueOnce(
+ new Response("Forbidden", { status: 403 }),
+ );
+
+ await expect(client.call("tools/list")).rejects.toThrow(
+ "Context7 API call failed with status 403: Forbidden",
+ );
+ });
+
+ test("should handle network errors", async () => {
+ fetchMock.mockRejectedValueOnce(new Error("Network timeout"));
+
+ await expect(client.call("tools/list")).rejects.toThrow(
+ "Network timeout",
+ );
+ });
+
+ test("should handle malformed JSON response", async () => {
+ fetchMock.mockResolvedValueOnce(
+ new Response("invalid json", {
+ status: 200,
+ headers: { "Content-Type": "application/json" },
+ }),
+ );
+
+ await expect(client.call("tools/list")).rejects.toThrow();
+ });
+ });
+
+ describe("integration scenarios", () => {
+ let client: Context7Client;
+
+ beforeEach(() => {
+ process.env.CONTEXT7_API_KEY = "test-api-key";
+ client = new Context7Client();
+ });
+
+ test("should handle tools/list call", async () => {
+ const mockResponse = {
+ jsonrpc: "2.0",
+ result: {
+ tools: [
+ { name: "query-docs", description: "Query documentation" },
+ { name: "resolve-library-id", description: "Resolve library ID" },
+ ],
+ },
+ id: 1,
+ };
+ fetchMock.mockResolvedValueOnce(
+ new Response(JSON.stringify(mockResponse)),
+ );
+
+ const result = await client.call("tools/list");
+ expect(result.result.tools).toHaveLength(2);
+ expect(result.result.tools[0].name).toBe("query-docs");
+ });
+
+ test("should handle query-docs call with complex params", async () => {
+ const params = {
+ libraryId: "/reactjs/react.dev",
+ query: "how to use useState hook",
+ };
+
+ await client.call("tools/call", {
+ name: "query-docs",
+ arguments: params,
+ });
+
+ const [unusedUrl, options] = fetchMock.mock.calls[0];
+ const body = JSON.parse((options as RequestInit)?.body as string);
+
+ expect(body.params.name).toBe("query-docs");
+ expect(body.params.arguments.libraryId).toBe("/reactjs/react.dev");
+ });
+ });
+});
diff --git a/packages/agent/tools/kilo.ts b/packages/agent/tools/kilo.ts
new file mode 100644
index 00000000..36a73857
--- /dev/null
+++ b/packages/agent/tools/kilo.ts
@@ -0,0 +1,55 @@
+import fetch from "node-fetch";
+
+class Context7Client {
+ private url: string = "https://mcp.context7.com/mcp";
+ private headers: Record;
+ private id: number = 1;
+
+ constructor(apiKey?: string) {
+ const key = apiKey || process.env.CONTEXT7_API_KEY;
+ if (!key) {
+ throw new Error(
+ "Context7 API key is required. Provide it as parameter or set CONTEXT7_API_KEY environment variable.",
+ );
+ }
+ this.headers = {
+ CONTEXT7_API_KEY: key,
+ "Content-Type": "application/json",
+ };
+ }
+
+ async call(
+ method: string,
+ params: Record = {},
+ ): Promise {
+ const payload = {
+ jsonrpc: "2.0",
+ method,
+ id: this.id,
+ params,
+ };
+ this.id++;
+
+ const response = await fetch(this.url, {
+ method: "POST",
+ headers: this.headers,
+ body: JSON.stringify(payload),
+ });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+ throw new Error(
+ `Context7 API call failed with status ${response.status}: ${errorText}`,
+ );
+ }
+
+ return await response.json();
+ }
+}
+
+// Usage example
+// const client = new Context7Client(); // uses env var
+// const client = new Context7Client('your_api_key_here'); // explicit key
+// client.call('tools/list').then(result => console.log(result));
+
+export { Context7Client };
diff --git a/packages/agent/tools/lsp.test.ts b/packages/agent/tools/lsp.test.ts
new file mode 100644
index 00000000..afb4c302
--- /dev/null
+++ b/packages/agent/tools/lsp.test.ts
@@ -0,0 +1,447 @@
+import { describe, test, expect, mock, beforeEach } from "bun:test";
+
+// Mock LSP dependencies
+const mockLspClientManager = {
+ runWithClientLease: mock(async (filePath: string, fn: unknown) => {
+ const mockClient = {
+ hover: mock(async () => ({
+ contents: [{ kind: "markdown", value: "Test hover content" }],
+ range: {
+ start: { line: 0, character: 0 },
+ end: { line: 0, character: 10 },
+ },
+ })),
+ definition: mock(async () => [
+ {
+ uri: "file:///test/file.ts",
+ range: {
+ start: { line: 5, character: 0 },
+ end: { line: 5, character: 15 },
+ },
+ },
+ ]),
+ references: mock(async () => [
+ {
+ uri: "file:///test/file.ts",
+ range: {
+ start: { line: 10, character: 0 },
+ end: { line: 10, character: 10 },
+ },
+ },
+ ]),
+ documentSymbols: mock(async () => [
+ {
+ name: "testFunction",
+ kind: 12, // Function
+ range: {
+ start: { line: 5, character: 0 },
+ end: { line: 5, character: 20 },
+ },
+ selectionRange: {
+ start: { line: 5, character: 9 },
+ end: { line: 5, character: 21 },
+ },
+ },
+ ]),
+ workspaceSymbols: mock(async () => [
+ {
+ name: "TestClass",
+ kind: 5, // Class
+ location: {
+ uri: "file:///test/class.ts",
+ range: {
+ start: { line: 1, character: 0 },
+ end: { line: 1, character: 10 },
+ },
+ },
+ },
+ ]),
+ openDocument: mock(async () => {}),
+ waitForDiagnostics: mock(async () => {}),
+ getDiagnostics: mock(() => [
+ {
+ range: {
+ start: { line: 1, character: 5 },
+ end: { line: 1, character: 10 },
+ },
+ severity: 1,
+ message: "Test error",
+ source: "test",
+ },
+ ]),
+ prepareRename: mock(async () => ({
+ start: { line: 1, character: 0 },
+ end: { line: 1, character: 5 },
+ })),
+ rename: mock(async () => ({
+ changes: {
+ "file:///test/file.ts": [
+ {
+ range: {
+ start: { line: 1, character: 0 },
+ end: { line: 1, character: 5 },
+ },
+ newText: "newName",
+ },
+ ],
+ },
+ })),
+ codeActions: mock(async () => [
+ {
+ title: "Extract function",
+ kind: "refactor.extract",
+ edit: {
+ changes: {
+ "file:///test/file.ts": [
+ {
+ range: {
+ start: { line: 2, character: 0 },
+ end: { line: 4, character: 0 },
+ },
+ newText: "extractedFunction() {\n // code\n}",
+ },
+ ],
+ },
+ },
+ },
+ ]),
+ supportsPullDiagnostics: false,
+ };
+ return await fn(mockClient);
+ }),
+};
+
+const mockGetAllServers = mock(() => [
+ {
+ name: "typescript",
+ command: "tsserver",
+ extensions: [".ts", ".tsx"],
+ installed: true,
+ },
+ {
+ name: "python",
+ command: "pylsp",
+ extensions: [".py"],
+ installed: false,
+ installHint: "pip install python-lsp-server",
+ },
+]);
+
+const mockGetServerForFile = mock((filePath: string) => {
+ if (filePath.endsWith(".ts")) {
+ return {
+ name: "typescript",
+ command: "tsserver",
+ extensions: [".ts", ".tsx"],
+ installed: true,
+ };
+ }
+ return null;
+});
+
+const mockFormatHover = mock(
+ (_hover: unknown) => "Formatted hover: Test hover content",
+);
+const mockFormatLocations = mock(
+ (_locations: unknown) => "Found 1 location(s)",
+);
+const mockFormatDocumentSymbols = mock(
+ (_symbols: unknown) => "1 symbol(s) found",
+);
+const mockFormatWorkspaceSymbols = mock(
+ (_symbols: unknown) => "Found 1 symbol(s)",
+);
+const mockFormatDiagnostics = mock(
+ (_diagnostics: unknown) => "Found 1 diagnostic(s)",
+);
+const mockFormatCodeActions = mock(
+ (_actions: unknown) => "Found 1 code action(s)",
+);
+const mockFormatWorkspaceEdit = mock(
+ (_edit: unknown) => "Workspace edit applied",
+);
+const mockCountEdits = mock(() => ({ files: 1, edits: 1 }));
+
+mock.module("./lsp/index.js", () => ({
+ lspClientManager: mockLspClientManager,
+ getAllServers: mockGetAllServers,
+ getServerForFile: mockGetServerForFile,
+ formatHover: mockFormatHover,
+ formatLocations: mockFormatLocations,
+ formatDocumentSymbols: mockFormatDocumentSymbols,
+ formatWorkspaceSymbols: mockFormatWorkspaceSymbols,
+ formatDiagnostics: mockFormatDiagnostics,
+ formatCodeActions: mockFormatCodeActions,
+ formatWorkspaceEdit: mockFormatWorkspaceEdit,
+ countEdits: mockCountEdits,
+}));
+
+mock.module("./diagnostics/index.js", () => ({
+ runDirectoryDiagnostics: mock(async () => ({
+ strategy: "tsc",
+ summary: "2 errors, 1 warning",
+ diagnostics: "Error: test error\nWarning: test warning",
+ })),
+}));
+
+// Import after mocking
+const { lspTools } = await import("./lsp");
+
+describe("LSP Tools", () => {
+ beforeEach(() => {
+ // Reset all mocks
+ mockLspClientManager.runWithClientLease.mockClear();
+ mockGetAllServers.mockClear();
+ mockGetServerForFile.mockClear();
+ Object.values({
+ mockFormatHover,
+ mockFormatLocations,
+ mockFormatDocumentSymbols,
+ mockFormatWorkspaceSymbols,
+ mockFormatDiagnostics,
+ mockFormatCodeActions,
+ mockFormatWorkspaceEdit,
+ mockCountEdits,
+ }).forEach((mock) => mock.mockClear());
+ });
+
+ test("should export lspTools array with expected tools", () => {
+ expect(Array.isArray(lspTools)).toBe(true);
+ expect(lspTools.length).toBe(12); // All LSP tools
+
+ const toolNames = lspTools.map((t) => t.name);
+ expect(toolNames).toEqual([
+ "lsp_hover",
+ "lsp_goto_definition",
+ "lsp_find_references",
+ "lsp_document_symbols",
+ "lsp_workspace_symbols",
+ "lsp_diagnostics",
+ "lsp_diagnostics_directory",
+ "lsp_servers",
+ "lsp_prepare_rename",
+ "lsp_rename",
+ "lsp_code_actions",
+ "lsp_code_action_resolve",
+ ]);
+ });
+
+ test("each tool should have required properties with correct types", () => {
+ for (const tool of lspTools) {
+ expect(tool).toHaveProperty("name");
+ expect(tool).toHaveProperty("description");
+ expect(tool).toHaveProperty("schema");
+ expect(tool).toHaveProperty("handler");
+
+ expect(typeof tool.name).toBe("string");
+ expect(typeof tool.description).toBe("string");
+ expect(typeof tool.handler).toBe("function");
+
+ // Schema should be an object with properties
+ expect(typeof tool.schema).toBe("object");
+ }
+ });
+
+ describe("lsp_hover tool", () => {
+ test("should call LSP hover and format result", async () => {
+ const result = await lspTools[0].handler({
+ file: "test.ts",
+ line: 1,
+ character: 5,
+ });
+
+ expect(mockLspClientManager.runWithClientLease).toHaveBeenCalledWith(
+ "test.ts",
+ expect.any(Function),
+ );
+ expect(mockFormatHover).toHaveBeenCalled();
+ expect(result.content[0].text).toBe(
+ "Formatted hover: Test hover content",
+ );
+ });
+ });
+
+ describe("lsp_goto_definition tool", () => {
+ test("should find definition locations", async () => {
+ const result = await lspTools[1].handler({
+ file: "test.ts",
+ line: 1,
+ character: 5,
+ });
+
+ expect(mockFormatLocations).toHaveBeenCalledWith([
+ {
+ uri: "file:///test/file.ts",
+ range: {
+ start: { line: 5, character: 0 },
+ end: { line: 5, character: 15 },
+ },
+ },
+ ]);
+ expect(result.content[0].text).toBe("Found 1 location(s)");
+ });
+ });
+
+ describe("lsp_find_references tool", () => {
+ test("should find references with includeDeclaration true", async () => {
+ const result = await lspTools[2].handler({
+ file: "test.ts",
+ line: 1,
+ character: 5,
+ includeDeclaration: true,
+ });
+
+ expect(result.content[0].text).toBe(
+ "Found 1 reference(s):\n\nFound 1 location(s)",
+ );
+ });
+
+ test("should handle no references found", async () => {
+ mockLspClientManager.runWithClientLease.mockImplementationOnce(
+ async (filePath, fn) => {
+ const mockClient = {
+ references: mock(async () => []),
+ };
+ return await fn(mockClient);
+ },
+ );
+
+ const result = await lspTools[2].handler({
+ file: "test.ts",
+ line: 1,
+ character: 5,
+ });
+
+ expect(result.content[0].text).toBe("No references found");
+ });
+ });
+
+ describe("lsp_document_symbols tool", () => {
+ test("should get document symbols", async () => {
+ const result = await lspTools[3].handler({
+ file: "test.ts",
+ });
+
+ expect(mockFormatDocumentSymbols).toHaveBeenCalled();
+ expect(result.content[0].text).toBe("1 symbol(s) found");
+ });
+ });
+
+ describe("lsp_workspace_symbols tool", () => {
+ test("should search workspace symbols", async () => {
+ const result = await lspTools[4].handler({
+ query: "TestClass",
+ file: "test.ts",
+ });
+
+ expect(result.content[0].text).toBe(
+ 'Found 1 symbol(s) matching "TestClass":\n\nFound 1 symbol(s)',
+ );
+ });
+
+ test("should handle no symbols found", async () => {
+ mockLspClientManager.runWithClientLease.mockImplementationOnce(
+ async (filePath, fn) => {
+ const mockClient = {
+ workspaceSymbols: mock(async () => []),
+ };
+ return await fn(mockClient);
+ },
+ );
+
+ const result = await lspTools[4].handler({
+ query: "UnknownSymbol",
+ file: "test.ts",
+ });
+
+ expect(result.content[0].text).toBe(
+ "No symbols found matching: UnknownSymbol",
+ );
+ });
+ });
+
+ describe("lsp_diagnostics tool", () => {
+ test("should get diagnostics with severity filter", async () => {
+ const result = await lspTools[5].handler({
+ file: "test.ts",
+ severity: "error",
+ });
+
+ expect(result.content[0].text).toContain("Found 1 diagnostic(s)");
+ });
+ });
+
+ describe("lsp_servers tool", () => {
+ test("should list all language servers", async () => {
+ const result = await lspTools[7].handler({});
+
+ expect(mockGetAllServers).toHaveBeenCalled();
+ expect(result.content[0].text).toContain("Language Server Status");
+ expect(result.content[0].text).toContain("typescript");
+ expect(result.content[0].text).toContain("python");
+ });
+ });
+
+ describe("lsp_rename tool", () => {
+ test("should perform rename and show edit summary", async () => {
+ const result = await lspTools[9].handler({
+ file: "test.ts",
+ line: 1,
+ character: 5,
+ newName: "newFunctionName",
+ });
+
+ expect(mockCountEdits).toHaveBeenCalled();
+ expect(result.content[0].text).toContain(
+ 'Rename to "newFunctionName" would affect 1 file(s) with 1 edit(s)',
+ );
+ });
+ });
+
+ describe("lsp_code_actions tool", () => {
+ test("should get code actions for selection", async () => {
+ const result = await lspTools[10].handler({
+ file: "test.ts",
+ startLine: 1,
+ startCharacter: 0,
+ endLine: 3,
+ endCharacter: 10,
+ });
+
+ expect(mockFormatCodeActions).toHaveBeenCalled();
+ expect(result.content[0].text).toBe("Found 1 code action(s)");
+ });
+ });
+
+ describe("error handling", () => {
+ test("should handle unsupported file type", async () => {
+ mockGetServerForFile.mockReturnValueOnce(null);
+
+ const result = await lspTools[0].handler({
+ file: "test.unknown",
+ line: 1,
+ character: 5,
+ });
+
+ expect(result.isError).toBe(true);
+ expect(result.content[0].text).toContain("No language server available");
+ });
+
+ test("should handle LSP client errors", async () => {
+ mockLspClientManager.runWithClientLease.mockRejectedValueOnce(
+ new Error("LSP connection failed"),
+ );
+
+ const result = await lspTools[0].handler({
+ file: "test.ts",
+ line: 1,
+ character: 5,
+ });
+
+ expect(result.isError).toBe(true);
+ expect(result.content[0].text).toBe(
+ "Error in hover: LSP connection failed",
+ );
+ });
+ });
+});
diff --git a/packages/agent/tools/lsp.ts b/packages/agent/tools/lsp.ts
new file mode 100644
index 00000000..e3d10fed
--- /dev/null
+++ b/packages/agent/tools/lsp.ts
@@ -0,0 +1,624 @@
+/**
+ * LSP (Language Server Protocol) Tools
+ *
+ * Provides IDE-like capabilities to agents via real LSP server integration:
+ * - Hover information
+ * - Go to definition
+ * - Find references
+ * - Document/workspace symbols
+ * - Diagnostics
+ * - Rename
+ * - Code actions
+ */
+
+import { z } from "zod";
+import {
+ lspClientManager,
+ getAllServers,
+ getServerForFile,
+ formatHover,
+ formatLocations,
+ formatDocumentSymbols,
+ formatWorkspaceSymbols,
+ formatDiagnostics,
+ formatCodeActions,
+ formatWorkspaceEdit,
+ countEdits,
+} from "./lsp/index";
+import { runDirectoryDiagnostics } from "./diagnostics/index";
+import { ToolDefinition } from "./types";
+
+/**
+ * Helper to handle LSP errors gracefully.
+ * Uses runWithClientLease to protect the client from idle eviction
+ * while the operation is in flight.
+ */
+async function withLspClient(
+ filePath: string,
+ operation: string,
+ fn: (
+ client: NonNullable<
+ Awaited>
+ >,
+ ) => Promise,
+): Promise<{ isError?: true; content: Array<{ type: "text"; text: string }> }> {
+ try {
+ // Pre-check: is there a server for this file type?
+ const serverConfig = getServerForFile(filePath);
+ if (!serverConfig) {
+ return {
+ isError: true as const,
+ content: [
+ {
+ type: "text" as const,
+ text: `No language server available for file type: ${filePath}\n\nUse lsp_servers tool to see available language servers.`,
+ },
+ ],
+ };
+ }
+
+ const result = await lspClientManager.runWithClientLease(
+ filePath,
+ async (client) => {
+ return fn(client);
+ },
+ );
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: String(result),
+ },
+ ],
+ };
+ } catch (error) {
+ const message = error instanceof Error ? error.message : String(error);
+ // Surface install hints for missing servers
+ if (message.includes("not found")) {
+ return {
+ isError: true as const,
+ content: [
+ {
+ type: "text" as const,
+ text: `${message}`,
+ },
+ ],
+ };
+ }
+ return {
+ isError: true as const,
+ content: [
+ {
+ type: "text" as const,
+ text: `Error in ${operation}: ${message}`,
+ },
+ ],
+ };
+ }
+}
+
+/**
+ * LSP Hover Tool - Get type information and documentation at a position
+ */
+export const lspHoverTool: ToolDefinition<{
+ file: z.ZodString;
+ line: z.ZodNumber;
+ character: z.ZodNumber;
+}> = {
+ name: "lsp_hover",
+ description:
+ "Get type information, documentation, and signature at a specific position in a file. Useful for understanding what a symbol represents.",
+ schema: {
+ file: z.string().describe("Path to the source file"),
+ line: z.number().int().min(1).describe("Line number (1-indexed)"),
+ character: z
+ .number()
+ .int()
+ .min(0)
+ .describe("Character position in the line (0-indexed)"),
+ },
+ handler: async (args) => {
+ const { file, line, character } = args;
+ return withLspClient(file, "hover", async (client) => {
+ const hover = await client!.hover(file, line - 1, character);
+ return formatHover(hover);
+ });
+ },
+};
+
+/**
+ * LSP Go to Definition Tool - Jump to where a symbol is defined
+ */
+export const lspGotoDefinitionTool: ToolDefinition<{
+ file: z.ZodString;
+ line: z.ZodNumber;
+ character: z.ZodNumber;
+}> = {
+ name: "lsp_goto_definition",
+ description:
+ "Find the definition location of a symbol (function, variable, class, etc.). Returns the file path and position where the symbol is defined.",
+ schema: {
+ file: z.string().describe("Path to the source file"),
+ line: z.number().int().min(1).describe("Line number (1-indexed)"),
+ character: z
+ .number()
+ .int()
+ .min(0)
+ .describe("Character position in the line (0-indexed)"),
+ },
+ handler: async (args) => {
+ const { file, line, character } = args;
+ return withLspClient(file, "goto definition", async (client) => {
+ const locations = await client!.definition(file, line - 1, character);
+ return formatLocations(locations);
+ });
+ },
+};
+
+/**
+ * LSP Find References Tool - Find all usages of a symbol
+ */
+export const lspFindReferencesTool: ToolDefinition<{
+ file: z.ZodString;
+ line: z.ZodNumber;
+ character: z.ZodNumber;
+ includeDeclaration: z.ZodOptional;
+}> = {
+ name: "lsp_find_references",
+ description:
+ "Find all references to a symbol across the codebase. Useful for understanding usage patterns and impact of changes.",
+ schema: {
+ file: z.string().describe("Path to the source file"),
+ line: z.number().int().min(1).describe("Line number (1-indexed)"),
+ character: z
+ .number()
+ .int()
+ .min(0)
+ .describe("Character position in the line (0-indexed)"),
+ includeDeclaration: z
+ .boolean()
+ .optional()
+ .describe("Include the declaration in results (default: true)"),
+ },
+ handler: async (args) => {
+ const { file, line, character, includeDeclaration = true } = args;
+ return withLspClient(file, "find references", async (client) => {
+ const locations = await client!.references(
+ file,
+ line - 1,
+ character,
+ includeDeclaration,
+ );
+ if (!locations || locations.length === 0) {
+ return "No references found";
+ }
+ return `Found ${locations.length} reference(s):\n\n${formatLocations(locations)}`;
+ });
+ },
+};
+
+/**
+ * LSP Document Symbols Tool - Get outline of all symbols in a file
+ */
+export const lspDocumentSymbolsTool: ToolDefinition<{
+ file: z.ZodString;
+}> = {
+ name: "lsp_document_symbols",
+ description:
+ "Get a hierarchical outline of all symbols in a file (functions, classes, variables, etc.). Useful for understanding file structure.",
+ schema: {
+ file: z.string().describe("Path to the source file"),
+ },
+ handler: async (args) => {
+ const { file } = args;
+ return withLspClient(file, "document symbols", async (client) => {
+ const symbols = await client!.documentSymbols(file);
+ return formatDocumentSymbols(symbols);
+ });
+ },
+};
+
+/**
+ * LSP Workspace Symbols Tool - Search symbols across workspace
+ */
+export const lspWorkspaceSymbolsTool: ToolDefinition<{
+ query: z.ZodString;
+ file: z.ZodString;
+}> = {
+ name: "lsp_workspace_symbols",
+ description:
+ "Search for symbols (functions, classes, etc.) across the entire workspace by name. Useful for finding definitions without knowing the exact file.",
+ schema: {
+ query: z.string().describe("Symbol name or pattern to search"),
+ file: z
+ .string()
+ .describe(
+ "Any file in the workspace (used to determine which language server to use)",
+ ),
+ },
+ handler: async (args) => {
+ const { query, file } = args;
+ return withLspClient(file, "workspace symbols", async (client) => {
+ const symbols = await client!.workspaceSymbols(query);
+ if (!symbols || symbols.length === 0) {
+ return `No symbols found matching: ${query}`;
+ }
+ return `Found ${symbols.length} symbol(s) matching "${query}":\n\n${formatWorkspaceSymbols(symbols)}`;
+ });
+ },
+};
+
+/**
+ * LSP Diagnostics Tool - Get errors, warnings, and hints
+ */
+export const lspDiagnosticsTool: ToolDefinition<{
+ file: z.ZodString;
+ severity: z.ZodOptional>;
+}> = {
+ name: "lsp_diagnostics",
+ description:
+ "Get language server diagnostics (errors, warnings, hints) for a file. Useful for finding issues without running the compiler.",
+ schema: {
+ file: z.string().describe("Path to the source file"),
+ severity: z
+ .enum(["error", "warning", "info", "hint"])
+ .optional()
+ .describe("Filter by severity level"),
+ },
+ handler: async (args) => {
+ const { file, severity } = args;
+ return withLspClient(file, "diagnostics", async (client) => {
+ await client!.openDocument(file);
+
+ let diagnostics;
+ if (client!.supportsPullDiagnostics) {
+ diagnostics = await client!.pullDiagnostics(file);
+ } else {
+ await client!.waitForDiagnostics(file, 30_000);
+ diagnostics = client!.getDiagnostics(file);
+ }
+
+ if (severity) {
+ const severityMap: Record = {
+ error: 1,
+ warning: 2,
+ info: 3,
+ hint: 4,
+ };
+ const severityNum = severityMap[severity];
+ diagnostics = diagnostics.filter((d) => d.severity === severityNum);
+ }
+
+ if (diagnostics.length === 0) {
+ return severity
+ ? `No ${severity} diagnostics in ${file}`
+ : `No diagnostics in ${file}`;
+ }
+
+ return `Found ${diagnostics.length} diagnostic(s):\n\n${formatDiagnostics(diagnostics, file)}`;
+ });
+ },
+};
+
+/**
+ * LSP Servers Tool - List available language servers
+ */
+export const lspServersTool: ToolDefinition> = {
+ name: "lsp_servers",
+ description:
+ "List all known language servers and their installation status. Shows which servers are available and how to install missing ones.",
+ schema: {},
+ handler: async () => {
+ const servers = getAllServers();
+
+ const installed = servers.filter((s) => s.installed);
+ const notInstalled = servers.filter((s) => !s.installed);
+
+ let text = "## Language Server Status\n\n";
+
+ if (installed.length > 0) {
+ text += "### Installed:\n";
+ for (const server of installed) {
+ text += `- ${server.name} (${server.command})\n`;
+ text += ` Extensions: ${server.extensions.join(", ")}\n`;
+ }
+ text += "\n";
+ }
+
+ if (notInstalled.length > 0) {
+ text += "### Not Installed:\n";
+ for (const server of notInstalled) {
+ text += `- ${server.name} (${server.command})\n`;
+ text += ` Extensions: ${server.extensions.join(", ")}\n`;
+ text += ` Install: ${server.installHint}\n`;
+ }
+ }
+
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text,
+ },
+ ],
+ };
+ },
+};
+
+/**
+ * LSP Prepare Rename Tool - Check if rename is valid
+ */
+export const lspPrepareRenameTool: ToolDefinition<{
+ file: z.ZodString;
+ line: z.ZodNumber;
+ character: z.ZodNumber;
+}> = {
+ name: "lsp_prepare_rename",
+ description:
+ "Check if a symbol at the given position can be renamed. Returns the range of the symbol if rename is possible.",
+ schema: {
+ file: z.string().describe("Path to the source file"),
+ line: z.number().int().min(1).describe("Line number (1-indexed)"),
+ character: z
+ .number()
+ .int()
+ .min(0)
+ .describe("Character position in the line (0-indexed)"),
+ },
+ handler: async (args) => {
+ const { file, line, character } = args;
+ return withLspClient(file, "prepare rename", async (client) => {
+ const range = await client!.prepareRename(file, line - 1, character);
+ if (!range) {
+ return "Cannot rename symbol at this position";
+ }
+ return `Rename possible. Symbol range: line ${range.start.line + 1}, col ${range.start.character + 1} to line ${range.end.line + 1}, col ${range.end.character + 1}`;
+ });
+ },
+};
+
+/**
+ * LSP Rename Tool - Rename a symbol across all files
+ */
+export const lspRenameTool: ToolDefinition<{
+ file: z.ZodString;
+ line: z.ZodNumber;
+ character: z.ZodNumber;
+ newName: z.ZodString;
+}> = {
+ name: "lsp_rename",
+ description:
+ "Rename a symbol (variable, function, class, etc.) across all files in the project. Returns the list of edits that would be made. Does NOT apply the changes automatically.",
+ schema: {
+ file: z.string().describe("Path to the source file"),
+ line: z.number().int().min(1).describe("Line number (1-indexed)"),
+ character: z
+ .number()
+ .int()
+ .min(0)
+ .describe("Character position in the line (0-indexed)"),
+ newName: z.string().min(1).describe("New name for the symbol"),
+ },
+ handler: async (args) => {
+ const { file, line, character, newName } = args;
+ return withLspClient(file, "rename", async (client) => {
+ const edit = await client!.rename(file, line - 1, character, newName);
+ if (!edit) {
+ return "Rename failed or no edits returned";
+ }
+
+ const { files, edits } = countEdits(edit);
+ return `Rename to "${newName}" would affect ${files} file(s) with ${edits} edit(s):\n\n${formatWorkspaceEdit(edit)}\n\nNote: Use the Edit tool to apply these changes.`;
+ });
+ },
+};
+
+/**
+ * LSP Code Actions Tool - Get available refactoring and quick-fix actions
+ */
+export const lspCodeActionsTool: ToolDefinition<{
+ file: z.ZodString;
+ startLine: z.ZodNumber;
+ startCharacter: z.ZodNumber;
+ endLine: z.ZodNumber;
+ endCharacter: z.ZodNumber;
+}> = {
+ name: "lsp_code_actions",
+ description:
+ "Get available code actions (refactorings, quick fixes) for a selection. Returns a list of possible actions that can be applied.",
+ schema: {
+ file: z.string().describe("Path to the source file"),
+ startLine: z
+ .number()
+ .int()
+ .min(1)
+ .describe("Start line of selection (1-indexed)"),
+ startCharacter: z
+ .number()
+ .int()
+ .min(0)
+ .describe("Start character of selection (0-indexed)"),
+ endLine: z
+ .number()
+ .int()
+ .min(1)
+ .describe("End line of selection (1-indexed)"),
+ endCharacter: z
+ .number()
+ .int()
+ .min(0)
+ .describe("End character of selection (0-indexed)"),
+ },
+ handler: async (args) => {
+ const { file, startLine, startCharacter, endLine, endCharacter } = args;
+ return withLspClient(file, "code actions", async (client) => {
+ const range = {
+ start: { line: startLine - 1, character: startCharacter },
+ end: { line: endLine - 1, character: endCharacter },
+ };
+ const actions = await client!.codeActions(file, range);
+ return formatCodeActions(actions);
+ });
+ },
+};
+
+/**
+ * LSP Code Action Resolve Tool - Get details of a code action
+ */
+export const lspCodeActionResolveTool: ToolDefinition<{
+ file: z.ZodString;
+ startLine: z.ZodNumber;
+ startCharacter: z.ZodNumber;
+ endLine: z.ZodNumber;
+ endCharacter: z.ZodNumber;
+ actionIndex: z.ZodNumber;
+}> = {
+ name: "lsp_code_action_resolve",
+ description:
+ "Get the full edit details for a specific code action. Use after lsp_code_actions to see what changes an action would make.",
+ schema: {
+ file: z.string().describe("Path to the source file"),
+ startLine: z
+ .number()
+ .int()
+ .min(1)
+ .describe("Start line of selection (1-indexed)"),
+ startCharacter: z
+ .number()
+ .int()
+ .min(0)
+ .describe("Start character of selection (0-indexed)"),
+ endLine: z
+ .number()
+ .int()
+ .min(1)
+ .describe("End line of selection (1-indexed)"),
+ endCharacter: z
+ .number()
+ .int()
+ .min(0)
+ .describe("End character of selection (0-indexed)"),
+ actionIndex: z
+ .number()
+ .int()
+ .min(1)
+ .describe(
+ "Index of the action (1-indexed, from lsp_code_actions output)",
+ ),
+ },
+ handler: async (args) => {
+ const {
+ file,
+ startLine,
+ startCharacter,
+ endLine,
+ endCharacter,
+ actionIndex,
+ } = args;
+ return withLspClient(file, "code action resolve", async (client) => {
+ const range = {
+ start: { line: startLine - 1, character: startCharacter },
+ end: { line: endLine - 1, character: endCharacter },
+ };
+ const actions = await client!.codeActions(file, range);
+
+ if (!actions || actions.length === 0) {
+ return "No code actions available";
+ }
+
+ if (actionIndex < 1 || actionIndex > actions.length) {
+ return `Invalid action index. Available actions: 1-${actions.length}`;
+ }
+
+ const action = actions[actionIndex - 1];
+
+ let result = `Action: ${action.title}\n`;
+ if (action.kind) result += `Kind: ${action.kind}\n`;
+ if (action.isPreferred) result += `(Preferred)\n`;
+
+ if (action.edit) {
+ result += `\nEdits:\n${formatWorkspaceEdit(action.edit)}`;
+ }
+
+ if (action.command) {
+ result += `\nCommand: ${action.command.title} (${action.command.command})`;
+ }
+
+ return result;
+ });
+ },
+};
+
+/**
+ * LSP Diagnostics Directory Tool - Get project-level diagnostics
+ */
+export const lspDiagnosticsDirectoryTool: ToolDefinition<{
+ directory: z.ZodString;
+ strategy: z.ZodOptional>;
+}> = {
+ name: "lsp_diagnostics_directory",
+ description:
+ "Run project-level diagnostics on a directory using tsc --noEmit (preferred) or LSP iteration (fallback). Useful for checking the entire codebase for errors.",
+ schema: {
+ directory: z.string().describe("Project directory to check"),
+ strategy: z
+ .enum(["tsc", "lsp", "auto"])
+ .optional()
+ .describe(
+ 'Strategy to use: "tsc" (TypeScript compiler), "lsp" (Language Server iteration), or "auto" (default: auto-detect)',
+ ),
+ },
+ handler: async (args) => {
+ const { directory, strategy = "auto" } = args;
+ try {
+ const result = await runDirectoryDiagnostics(directory, strategy);
+
+ let output = `## Directory Diagnostics\n\n`;
+ output += `Strategy: ${result.strategy}\n`;
+ output += `Summary: ${result.summary}\n\n`;
+
+ if (result.errorCount > 0 || result.warningCount > 0) {
+ output += `### Diagnostics\n\n${result.diagnostics}`;
+ } else {
+ output += result.diagnostics;
+ }
+
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: output,
+ },
+ ],
+ };
+ } catch (error) {
+ return {
+ isError: true as const,
+ content: [
+ {
+ type: "text" as const,
+ text: `Error running directory diagnostics: ${error instanceof Error ? error.message : String(error)}`,
+ },
+ ],
+ };
+ }
+ },
+};
+
+/**
+ * Get all LSP tool definitions
+ */
+export const lspTools = [
+ lspHoverTool,
+ lspGotoDefinitionTool,
+ lspFindReferencesTool,
+ lspDocumentSymbolsTool,
+ lspWorkspaceSymbolsTool,
+ lspDiagnosticsTool,
+ lspDiagnosticsDirectoryTool,
+ lspServersTool,
+ lspPrepareRenameTool,
+ lspRenameTool,
+ lspCodeActionsTool,
+ lspCodeActionResolveTool,
+];
diff --git a/packages/agent/tools/notepad.test.ts b/packages/agent/tools/notepad.test.ts
new file mode 100644
index 00000000..adb67f1f
--- /dev/null
+++ b/packages/agent/tools/notepad.test.ts
@@ -0,0 +1,416 @@
+import { describe, test, expect, mock, beforeEach, afterEach } from "bun:test";
+import { mkdtemp, rm } from "node:fs/promises";
+import { tmpdir } from "node:os";
+import path from "node:path";
+
+// Mock notepad hooks
+const mockGetPriorityContext = mock(() => "Priority context content");
+const mockGetWorkingMemory = mock(
+ () => "Working memory entries\n- Entry 1\n- Entry 2",
+);
+const mockGetManualSection = mock(() => "Manual section content");
+const mockSetPriorityContext = mock(() => ({ success: true }));
+const mockAddWorkingMemoryEntry = mock(() => true);
+const mockAddManualEntry = mock(() => true);
+const mockPruneOldEntries = mock(() => ({ pruned: 2, remaining: 5 }));
+const mockGetNotepadStats = mock(() => ({
+ exists: true,
+ totalSize: 1024,
+ prioritySize: 256,
+ workingMemoryEntries: 3,
+ oldestEntry: "2024-01-01",
+}));
+const mockFormatFullNotepad = mock(
+ () =>
+ "## Priority Context\nContent\n\n## Working Memory\nEntries\n\n## MANUAL\nManual content",
+);
+const mockDEFAULT_CONFIG = { workingMemoryDays: 7 };
+
+mock.module("../hooks/notepad/index.js", () => ({
+ getPriorityContext: mockGetPriorityContext,
+ getWorkingMemory: mockGetWorkingMemory,
+ getManualSection: mockGetManualSection,
+ setPriorityContext: mockSetPriorityContext,
+ addWorkingMemoryEntry: mockAddWorkingMemoryEntry,
+ addManualEntry: mockAddManualEntry,
+ pruneOldEntries: mockPruneOldEntries,
+ getNotepadStats: mockGetNotepadStats,
+ formatFullNotepad: mockFormatFullNotepad,
+ DEFAULT_CONFIG: mockDEFAULT_CONFIG,
+}));
+
+// Mock worktree paths
+const mockGetWorktreeNotepadPath = mock((root: string) =>
+ path.join(root, ".omc", "notepad.md"),
+);
+const mockEnsureOmcDir = mock(() => {});
+const mockValidateWorkingDirectory = mock((wd?: string) => wd || "/test/root");
+
+mock.module("../lib/worktree-paths.js", () => ({
+ getWorktreeNotepadPath: mockGetWorktreeNotepadPath,
+ ensureOmcDir: mockEnsureOmcDir,
+ validateWorkingDirectory: mockValidateWorkingDirectory,
+}));
+
+// Import after mocking
+const { notepadTools } = await import("./notepad");
+
+describe("Notepad Tools", () => {
+ let testRoot: string;
+
+ beforeEach(async () => {
+ testRoot = await mkdtemp(path.join(tmpdir(), "notepad-test-"));
+
+ // Reset all mocks
+ Object.values({
+ mockGetPriorityContext,
+ mockGetWorkingMemory,
+ mockGetManualSection,
+ mockSetPriorityContext,
+ mockAddWorkingMemoryEntry,
+ mockAddManualEntry,
+ mockPruneOldEntries,
+ mockGetNotepadStats,
+ mockFormatFullNotepad,
+ mockGetWorktreeNotepadPath,
+ mockEnsureOmcDir,
+ mockValidateWorkingDirectory,
+ }).forEach((mock) => mock.mockClear());
+ });
+
+ afterEach(async () => {
+ try {
+ await rm(testRoot, { recursive: true, force: true });
+ } catch {
+ // Ignore cleanup errors
+ }
+ });
+
+ test("should export notepadTools array with 6 tools", () => {
+ expect(Array.isArray(notepadTools)).toBe(true);
+ expect(notepadTools.length).toBe(6);
+
+ const toolNames = notepadTools.map((t) => t.name);
+ expect(toolNames).toEqual([
+ "notepad_read",
+ "notepad_write_priority",
+ "notepad_write_working",
+ "notepad_write_manual",
+ "notepad_prune",
+ "notepad_stats",
+ ]);
+ });
+
+ test("each tool should have required properties with correct types", () => {
+ for (const tool of notepadTools) {
+ expect(tool).toHaveProperty("name");
+ expect(tool).toHaveProperty("description");
+ expect(tool).toHaveProperty("schema");
+ expect(tool).toHaveProperty("handler");
+
+ expect(typeof tool.name).toBe("string");
+ expect(typeof tool.description).toBe("string");
+ expect(typeof tool.handler).toBe("function");
+ expect(typeof tool.schema).toBe("object");
+ }
+ });
+
+ describe("notepad_read tool", () => {
+ test('should read full notepad when section is "all"', async () => {
+ const result = await notepadTools[0].handler({
+ section: "all",
+ workingDirectory: testRoot,
+ });
+
+ expect(mockValidateWorkingDirectory).toHaveBeenCalledWith(testRoot);
+ expect(mockFormatFullNotepad).toHaveBeenCalledWith(testRoot);
+ expect(result.content[0].text).toContain("## Notepad");
+ expect(result.content[0].text).toContain("Path:");
+ });
+
+ test("should read priority section", async () => {
+ const result = await notepadTools[0].handler({
+ section: "priority",
+ workingDirectory: testRoot,
+ });
+
+ expect(mockGetPriorityContext).toHaveBeenCalledWith(testRoot);
+ expect(result.content[0].text).toBe(
+ "## Priority Context\n\nPriority context content",
+ );
+ });
+
+ test("should read working memory section", async () => {
+ const result = await notepadTools[0].handler({
+ section: "working",
+ workingDirectory: testRoot,
+ });
+
+ expect(mockGetWorkingMemory).toHaveBeenCalledWith(testRoot);
+ expect(result.content[0].text).toBe(
+ "## Working Memory\n\nWorking memory entries\n- Entry 1\n- Entry 2",
+ );
+ });
+
+ test("should read manual section", async () => {
+ const result = await notepadTools[0].handler({
+ section: "manual",
+ workingDirectory: testRoot,
+ });
+
+ expect(mockGetManualSection).toHaveBeenCalledWith(testRoot);
+ expect(result.content[0].text).toBe(
+ "## MANUAL\n\nManual section content",
+ );
+ });
+
+ test("should handle empty sections", async () => {
+ mockGetPriorityContext.mockReturnValueOnce(null);
+
+ const result = await notepadTools[0].handler({
+ section: "priority",
+ workingDirectory: testRoot,
+ });
+
+ expect(result.content[0].text).toBe(
+ "## Priority Context\n\n(Empty or notepad does not exist)",
+ );
+ });
+
+ test("should handle missing notepad", async () => {
+ mockFormatFullNotepad.mockReturnValueOnce(null);
+
+ const result = await notepadTools[0].handler({
+ section: "all",
+ workingDirectory: testRoot,
+ });
+
+ expect(result.content[0].text).toBe(
+ "Notepad does not exist. Use notepad_write_* tools to create it.",
+ );
+ });
+
+ test("should use default working directory", async () => {
+ const _result = await notepadTools[0].handler({
+ section: "all",
+ });
+
+ expect(mockValidateWorkingDirectory).toHaveBeenCalledWith(undefined);
+ });
+ });
+
+ describe("notepad_write_priority tool", () => {
+ test("should write priority context successfully", async () => {
+ const result = await notepadTools[1].handler({
+ content: "New priority content",
+ workingDirectory: testRoot,
+ });
+
+ expect(mockValidateWorkingDirectory).toHaveBeenCalledWith(testRoot);
+ expect(mockEnsureOmcDir).toHaveBeenCalled();
+ expect(mockSetPriorityContext).toHaveBeenCalledWith(
+ testRoot,
+ "New priority content",
+ );
+ expect(result.content[0].text).toBe(
+ "Successfully wrote to Priority Context (20 chars)",
+ );
+ });
+
+ test("should handle write failure", async () => {
+ mockSetPriorityContext.mockReturnValueOnce({ success: false });
+
+ const result = await notepadTools[1].handler({
+ content: "Content",
+ workingDirectory: testRoot,
+ });
+
+ expect(result.content[0].text).toBe(
+ "Failed to write to Priority Context. Check file permissions.",
+ );
+ });
+
+ test("should show warning on long content", async () => {
+ mockSetPriorityContext.mockReturnValueOnce({
+ success: true,
+ warning: "Content exceeds recommended length",
+ });
+
+ const result = await notepadTools[1].handler({
+ content: "Very long content that exceeds limits",
+ workingDirectory: testRoot,
+ });
+
+ expect(result.content[0].text).toContain(
+ "**Warning:** Content exceeds recommended length",
+ );
+ });
+
+ test("should accept content up to max length", async () => {
+ const maxContent = "x".repeat(2000);
+
+ const result = await notepadTools[1].handler({
+ content: maxContent,
+ workingDirectory: testRoot,
+ });
+
+ expect(result.content[0].text).toContain("Successfully wrote");
+ });
+ });
+
+ describe("notepad_write_working tool", () => {
+ test("should add working memory entry successfully", async () => {
+ const result = await notepadTools[2].handler({
+ content: "New working memory entry",
+ workingDirectory: testRoot,
+ });
+
+ expect(mockAddWorkingMemoryEntry).toHaveBeenCalledWith(
+ testRoot,
+ "New working memory entry",
+ );
+ expect(result.content[0].text).toBe(
+ "Successfully added entry to Working Memory (24 chars)",
+ );
+ });
+
+ test("should handle add failure", async () => {
+ mockAddWorkingMemoryEntry.mockReturnValueOnce(false);
+
+ const result = await notepadTools[2].handler({
+ content: "Content",
+ workingDirectory: testRoot,
+ });
+
+ expect(result.content[0].text).toBe(
+ "Failed to add entry to Working Memory. Check file permissions.",
+ );
+ });
+ });
+
+ describe("notepad_write_manual tool", () => {
+ test("should add manual entry successfully", async () => {
+ const result = await notepadTools[3].handler({
+ content: "New manual entry",
+ workingDirectory: testRoot,
+ });
+
+ expect(mockAddManualEntry).toHaveBeenCalledWith(
+ testRoot,
+ "New manual entry",
+ );
+ expect(result.content[0].text).toBe(
+ "Successfully added entry to MANUAL section (16 chars)",
+ );
+ });
+
+ test("should handle add failure", async () => {
+ mockAddManualEntry.mockReturnValueOnce(false);
+
+ const result = await notepadTools[3].handler({
+ content: "Content",
+ workingDirectory: testRoot,
+ });
+
+ expect(result.content[0].text).toBe(
+ "Failed to add entry to MANUAL section. Check file permissions.",
+ );
+ });
+ });
+
+ describe("notepad_prune tool", () => {
+ test("should prune entries with default days", async () => {
+ const result = await notepadTools[4].handler({
+ workingDirectory: testRoot,
+ });
+
+ expect(mockPruneOldEntries).toHaveBeenCalledWith(testRoot, 7);
+ expect(result.content[0].text).toBe(
+ "## Prune Results\n\n- Pruned: 2 entries\n- Remaining: 5 entries\n- Threshold: 7 days",
+ );
+ });
+
+ test("should prune entries with custom days", async () => {
+ const result = await notepadTools[4].handler({
+ daysOld: 14,
+ workingDirectory: testRoot,
+ });
+
+ expect(mockPruneOldEntries).toHaveBeenCalledWith(testRoot, 14);
+ expect(result.content[0].text).toContain("Threshold: 14 days");
+ });
+ });
+
+ describe("notepad_stats tool", () => {
+ test("should get notepad statistics", async () => {
+ const result = await notepadTools[5].handler({
+ workingDirectory: testRoot,
+ });
+
+ expect(mockGetNotepadStats).toHaveBeenCalledWith(testRoot);
+ expect(result.content[0].text).toContain("## Notepad Statistics");
+ expect(result.content[0].text).toContain("**Total Size:** 1024 bytes");
+ expect(result.content[0].text).toContain("**Working Memory Entries:** 3");
+ expect(result.content[0].text).toContain("Path:");
+ });
+
+ test("should handle non-existent notepad", async () => {
+ mockGetNotepadStats.mockReturnValueOnce({ exists: false });
+
+ const result = await notepadTools[5].handler({
+ workingDirectory: testRoot,
+ });
+
+ expect(result.content[0].text).toBe(
+ "## Notepad Statistics\n\nNotepad does not exist yet.",
+ );
+ });
+ });
+
+ describe("error handling", () => {
+ test("should handle validation errors", async () => {
+ mockValidateWorkingDirectory.mockImplementationOnce(() => {
+ throw new Error("Invalid working directory");
+ });
+
+ const result = await notepadTools[0].handler({
+ section: "all",
+ workingDirectory: "/invalid/path",
+ });
+
+ expect(result.content[0].text).toBe(
+ "Error reading notepad: Invalid working directory",
+ );
+ });
+
+ test("should handle hook errors", async () => {
+ mockGetPriorityContext.mockImplementationOnce(() => {
+ throw new Error("File system error");
+ });
+
+ const result = await notepadTools[0].handler({
+ section: "priority",
+ workingDirectory: testRoot,
+ });
+
+ expect(result.content[0].text).toBe(
+ "Error reading notepad: File system error",
+ );
+ });
+ });
+
+ describe("schema validation", () => {
+ test("notepad_write_priority should have content schema", () => {
+ expect(notepadTools[1].schema).toHaveProperty("content");
+ });
+
+ test("write tools should have content schema", () => {
+ expect(notepadTools[2].schema).toHaveProperty("content");
+ expect(notepadTools[3].schema).toHaveProperty("content");
+ });
+
+ test("notepad_prune should have daysOld schema", () => {
+ expect(notepadTools[4].schema).toHaveProperty("daysOld");
+ });
+ });
+});
diff --git a/packages/agent/tools/notepad.ts b/packages/agent/tools/notepad.ts
new file mode 100644
index 00000000..e00cfa7d
--- /dev/null
+++ b/packages/agent/tools/notepad.ts
@@ -0,0 +1,454 @@
+/**
+ * Notepad MCP Tools
+ *
+ * Provides tools for reading and writing notepad sections
+ * (Priority Context, Working Memory, MANUAL).
+ */
+
+import { z } from "zod";
+import {
+ getWorktreeNotepadPath,
+ ensureOmcDir,
+ validateWorkingDirectory,
+} from "../lib/worktree-paths";
+import {
+ getPriorityContext,
+ getWorkingMemory,
+ getManualSection,
+ setPriorityContext,
+ addWorkingMemoryEntry,
+ addManualEntry,
+ pruneOldEntries,
+ getNotepadStats,
+ formatFullNotepad,
+ DEFAULT_CONFIG,
+} from "../hooks/notepad/index";
+import { ToolDefinition } from "./types.js";
+
+const SECTION_NAMES: [string, ...string[]] = [
+ "all",
+ "priority",
+ "working",
+ "manual",
+];
+
+// ============================================================================
+// notepad_read - Read notepad content
+// ============================================================================
+
+export const notepadReadTool: ToolDefinition<{
+ section: z.ZodOptional>;
+ workingDirectory: z.ZodOptional;
+}> = {
+ name: "notepad_read",
+ description:
+ "Read the notepad content. Can read the full notepad or a specific section (priority, working, manual).",
+ schema: {
+ section: z
+ .enum(SECTION_NAMES)
+ .optional()
+ .describe(
+ 'Section to read: "all" (default), "priority", "working", or "manual"',
+ ),
+ workingDirectory: z
+ .string()
+ .optional()
+ .describe("Working directory (defaults to cwd)"),
+ },
+ handler: async (args) => {
+ const { section = "all", workingDirectory } = args;
+
+ try {
+ const root = validateWorkingDirectory(workingDirectory);
+
+ if (section === "all") {
+ const content = formatFullNotepad(root);
+ if (!content) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: "Notepad does not exist. Use notepad_write_* tools to create it.",
+ },
+ ],
+ };
+ }
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `## Notepad\n\nPath: ${getWorktreeNotepadPath(root)}\n\n${content}`,
+ },
+ ],
+ };
+ }
+
+ let sectionContent: string | null = null;
+ let sectionTitle = "";
+
+ switch (section) {
+ case "priority":
+ sectionContent = getPriorityContext(root);
+ sectionTitle = "Priority Context";
+ break;
+ case "working":
+ sectionContent = getWorkingMemory(root);
+ sectionTitle = "Working Memory";
+ break;
+ case "manual":
+ sectionContent = getManualSection(root);
+ sectionTitle = "MANUAL";
+ break;
+ }
+
+ if (!sectionContent) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `## ${sectionTitle}\n\n(Empty or notepad does not exist)`,
+ },
+ ],
+ };
+ }
+
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `## ${sectionTitle}\n\n${sectionContent}`,
+ },
+ ],
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `Error reading notepad: ${error instanceof Error ? error.message : String(error)}`,
+ },
+ ],
+ };
+ }
+ },
+};
+
+// ============================================================================
+// notepad_write_priority - Write to Priority Context
+// ============================================================================
+
+export const notepadWritePriorityTool: ToolDefinition<{
+ content: z.ZodString;
+ workingDirectory: z.ZodOptional;
+}> = {
+ name: "notepad_write_priority",
+ description:
+ "Write to the Priority Context section. This REPLACES the existing content. Keep under 500 chars - this is always loaded at session start.",
+ schema: {
+ content: z
+ .string()
+ .max(2000)
+ .describe("Content to write (recommend under 500 chars)"),
+ workingDirectory: z
+ .string()
+ .optional()
+ .describe("Working directory (defaults to cwd)"),
+ },
+ handler: async (args) => {
+ const { content, workingDirectory } = args;
+
+ try {
+ const root = validateWorkingDirectory(workingDirectory);
+
+ // Ensure .omc directory exists
+ ensureOmcDir("", root);
+
+ const result = setPriorityContext(root, content);
+
+ if (!result.success) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: "Failed to write to Priority Context. Check file permissions.",
+ },
+ ],
+ };
+ }
+
+ let response = `Successfully wrote to Priority Context (${content.length} chars)`;
+ if (result.warning) {
+ response += `\n\n**Warning:** ${result.warning}`;
+ }
+
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: response,
+ },
+ ],
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `Error writing to Priority Context: ${error instanceof Error ? error.message : String(error)}`,
+ },
+ ],
+ };
+ }
+ },
+};
+
+// ============================================================================
+// notepad_write_working - Add to Working Memory
+// ============================================================================
+
+export const notepadWriteWorkingTool: ToolDefinition<{
+ content: z.ZodString;
+ workingDirectory: z.ZodOptional;
+}> = {
+ name: "notepad_write_working",
+ description:
+ "Add an entry to Working Memory section. Entries are timestamped and auto-pruned after 7 days.",
+ schema: {
+ content: z.string().max(4000).describe("Content to add as a new entry"),
+ workingDirectory: z
+ .string()
+ .optional()
+ .describe("Working directory (defaults to cwd)"),
+ },
+ handler: async (args) => {
+ const { content, workingDirectory } = args;
+
+ try {
+ const root = validateWorkingDirectory(workingDirectory);
+
+ // Ensure .omc directory exists
+ ensureOmcDir("", root);
+
+ const success = addWorkingMemoryEntry(root, content);
+
+ if (!success) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: "Failed to add entry to Working Memory. Check file permissions.",
+ },
+ ],
+ };
+ }
+
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `Successfully added entry to Working Memory (${content.length} chars)`,
+ },
+ ],
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `Error writing to Working Memory: ${error instanceof Error ? error.message : String(error)}`,
+ },
+ ],
+ };
+ }
+ },
+};
+
+// ============================================================================
+// notepad_write_manual - Add to MANUAL section
+// ============================================================================
+
+export const notepadWriteManualTool: ToolDefinition<{
+ content: z.ZodString;
+ workingDirectory: z.ZodOptional;
+}> = {
+ name: "notepad_write_manual",
+ description:
+ "Add an entry to the MANUAL section. Content in this section is never auto-pruned.",
+ schema: {
+ content: z.string().max(4000).describe("Content to add as a new entry"),
+ workingDirectory: z
+ .string()
+ .optional()
+ .describe("Working directory (defaults to cwd)"),
+ },
+ handler: async (args) => {
+ const { content, workingDirectory } = args;
+
+ try {
+ const root = validateWorkingDirectory(workingDirectory);
+
+ // Ensure .omc directory exists
+ ensureOmcDir("", root);
+
+ const success = addManualEntry(root, content);
+
+ if (!success) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: "Failed to add entry to MANUAL section. Check file permissions.",
+ },
+ ],
+ };
+ }
+
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `Successfully added entry to MANUAL section (${content.length} chars)`,
+ },
+ ],
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `Error writing to MANUAL: ${error instanceof Error ? error.message : String(error)}`,
+ },
+ ],
+ };
+ }
+ },
+};
+
+// ============================================================================
+// notepad_prune - Prune old Working Memory entries
+// ============================================================================
+
+export const notepadPruneTool: ToolDefinition<{
+ daysOld: z.ZodOptional;
+ workingDirectory: z.ZodOptional;
+}> = {
+ name: "notepad_prune",
+ description:
+ "Prune Working Memory entries older than N days (default: 7 days).",
+ schema: {
+ daysOld: z
+ .number()
+ .int()
+ .min(1)
+ .max(365)
+ .optional()
+ .describe("Remove entries older than this many days (default: 7)"),
+ workingDirectory: z
+ .string()
+ .optional()
+ .describe("Working directory (defaults to cwd)"),
+ },
+ handler: async (args) => {
+ const { daysOld = DEFAULT_CONFIG.workingMemoryDays, workingDirectory } =
+ args;
+
+ try {
+ const root = validateWorkingDirectory(workingDirectory);
+ const result = pruneOldEntries(root, daysOld);
+
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `## Prune Results\n\n- Pruned: ${result.pruned} entries\n- Remaining: ${result.remaining} entries\n- Threshold: ${daysOld} days`,
+ },
+ ],
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `Error pruning notepad: ${error instanceof Error ? error.message : String(error)}`,
+ },
+ ],
+ };
+ }
+ },
+};
+
+// ============================================================================
+// notepad_stats - Get notepad statistics
+// ============================================================================
+
+export const notepadStatsTool: ToolDefinition<{
+ workingDirectory: z.ZodOptional;
+}> = {
+ name: "notepad_stats",
+ description:
+ "Get statistics about the notepad (size, entry count, oldest entry).",
+ schema: {
+ workingDirectory: z
+ .string()
+ .optional()
+ .describe("Working directory (defaults to cwd)"),
+ },
+ handler: async (args) => {
+ const { workingDirectory } = args;
+
+ try {
+ const root = validateWorkingDirectory(workingDirectory);
+ const stats = getNotepadStats(root);
+
+ if (!stats.exists) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: "## Notepad Statistics\n\nNotepad does not exist yet.",
+ },
+ ],
+ };
+ }
+
+ const lines = [
+ "## Notepad Statistics\n",
+ `- **Total Size:** ${stats.totalSize} bytes`,
+ `- **Priority Context Size:** ${stats.prioritySize} bytes`,
+ `- **Working Memory Entries:** ${stats.workingMemoryEntries}`,
+ `- **Oldest Entry:** ${stats.oldestEntry || "None"}`,
+ `- **Path:** ${getWorktreeNotepadPath(root)}`,
+ ];
+
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: lines.join("\n"),
+ },
+ ],
+ };
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: "text" as const,
+ text: `Error getting notepad stats: ${error instanceof Error ? error.message : String(error)}`,
+ },
+ ],
+ };
+ }
+ },
+};
+
+/**
+ * All notepad tools for registration
+ */
+export const notepadTools = [
+ notepadReadTool,
+ notepadWritePriorityTool,
+ notepadWriteWorkingTool,
+ notepadWriteManualTool,
+ notepadPruneTool,
+ notepadStatsTool,
+];
diff --git a/packages/agent/tools/tools.test.ts b/packages/agent/tools/tools.test.ts
index 81468248..813d0ea6 100644
--- a/packages/agent/tools/tools.test.ts
+++ b/packages/agent/tools/tools.test.ts
@@ -1,6 +1,15 @@
-import { afterEach, describe, expect, mock, test } from "bun:test";
+import {
+ afterEach,
+ beforeEach,
+ describe,
+ expect,
+ mock,
+ type Mock,
+ test,
+} from "bun:test";
import { mkdir, mkdtemp, readFile, stat, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
+
import path from "node:path";
import type { ToolNeedsApprovalFunction } from "./utils";
@@ -72,6 +81,7 @@ const { grepTool } = await import("./grep");
const { readFileTool } = await import("./read");
const { skillTool } = await import("./skill");
const { taskTool } = await import("./task");
+const { commitAndPrTool, TIMEOUT_MS } = await import("./github");
const { todoWriteTool } = await import("./todo");
const { editFileTool, writeFileTool } = await import("./write");
const { buildSystemPrompt } = await import("../system-prompt");
@@ -457,6 +467,237 @@ describe("tools execute behavior", () => {
expect(allowedBuildCommand).toBe(false);
});
+ describe("commitAndPrTool", () => {
+ // ทดสอบเครื่องมือ commit และสร้าง PR
+ let mockSandboxExec: Mock;
+ let mockSandbox: {
+ workingDirectory: string;
+ exec: Mock;
+ };
+
+ beforeEach(() => {
+ mockSandboxExec = mock(async (command: string) => {
+ if (command.startsWith("git checkout -b")) {
+ return { success: true, exitCode: 0, stdout: "", stderr: "" };
+ }
+ if (command === "git add -A") {
+ return { success: true, exitCode: 0, stdout: "", stderr: "" };
+ }
+ if (command.startsWith("git commit -m")) {
+ return { success: true, exitCode: 0, stdout: "", stderr: "" };
+ }
+ if (command.startsWith("git push -u origin")) {
+ return { success: true, exitCode: 0, stdout: "", stderr: "" };
+ }
+ if (command.startsWith("gh pr create")) {
+ return {
+ success: true,
+ exitCode: 0,
+ stdout: "https://github.com/test/repo/pull/1",
+ stderr: "",
+ };
+ }
+ return {
+ success: false,
+ exitCode: 1,
+ stdout: "",
+ stderr: `Unknown command: ${command}`,
+ };
+ });
+
+ mockSandbox = {
+ workingDirectory: "/repo",
+ exec: mockSandboxExec,
+ readFile: mock(
+ async () =>
+ "---\nname: review\ndescription: review code\n---\nRun review with $ARGUMENTS",
+ ),
+ };
+
+ // Mock getSandbox to return our controlled mockSandbox
+ mock.module("./utils", () => ({
+ getSandbox: mock(async () => mockSandbox),
+ }));
+ });
+
+ function createCommitAndPrContext() {
+ return {
+ sandbox: {
+ state: { type: "vercel" as const, sandboxId: "mock-sandbox-id" },
+ workingDirectory: mockSandbox.workingDirectory,
+ },
+ approval: {},
+ model: "test-model",
+ };
+ }
+
+ test("should successfully commit, push, and create a PR", async () => {
+ const args = {
+ needsApproval: true,
+ branchName: "feature/test-branch",
+ commitMessage: "feat: add new feature",
+ prTitle: "feat: Add new feature",
+ prBody: "This PR adds a new feature.",
+ };
+
+ const result = await commitAndPrTool.execute?.(
+ args,
+ executionOptions(createCommitAndPrContext()),
+ );
+
+ expect(result).toEqual({
+ success: true,
+ message: "Successfully committed, pushed, and created PR.",
+ prUrl: "https://github.com/test/repo/pull/1",
+ });
+
+ expect(mockSandboxExec).toHaveBeenCalledTimes(5);
+ expect(mockSandboxExec).toHaveBeenCalledWith(
+ `git checkout -b 'feature/test-branch'`,
+ mockSandbox.workingDirectory,
+ TIMEOUT_MS,
+ expect.any(Object),
+ );
+ expect(mockSandboxExec).toHaveBeenCalledWith(
+ "git add -A",
+ mockSandbox.workingDirectory,
+ TIMEOUT_MS,
+ expect.any(Object),
+ );
+ expect(mockSandboxExec).toHaveBeenCalledWith(
+ `git commit -m 'feat: add new feature'`,
+ mockSandbox.workingDirectory,
+ TIMEOUT_MS,
+ expect.any(Object),
+ );
+ expect(mockSandboxExec).toHaveBeenCalledWith(
+ `git push -u origin 'feature/test-branch'`,
+ mockSandbox.workingDirectory,
+ TIMEOUT_MS,
+ expect.any(Object),
+ );
+ expect(mockSandboxExec).toHaveBeenCalledWith(
+ `gh pr create --title 'feat: Add new feature' --body 'This PR adds a new feature.'`,
+ mockSandbox.workingDirectory,
+ TIMEOUT_MS,
+ expect.any(Object),
+ );
+ });
+
+ test("should return error if git commit fails for a non-'nothing to commit' reason", async () => {
+ mockSandbox.exec.mockImplementation(async (command: string) => {
+ if (command.startsWith("git commit -m")) {
+ return {
+ success: false,
+ exitCode: 1,
+ stdout: "Commit failed",
+ stderr: "Pre-commit hook failed",
+ };
+ }
+ return { success: true, exitCode: 0, stdout: "", stderr: "" }; // Other commands succeed
+ });
+
+ const args = {
+ needsApproval: true,
+ branchName: "b",
+ commitMessage: "c",
+ prTitle: "p",
+ prBody: "pb",
+ };
+ const result = await commitAndPrTool.execute?.(
+ args,
+ executionOptions(createCommitAndPrContext()),
+ );
+
+ expect(result).toEqual({
+ success: false,
+ error: "Failed to commit: Commit failed Pre-commit hook failed",
+ });
+ });
+
+ test("should return error if git push fails", async () => {
+ mockSandbox.exec.mockImplementation(async (command: string) => {
+ if (command.startsWith("git push -u origin")) {
+ return {
+ success: false,
+ exitCode: 1,
+ stdout: "Push failed",
+ stderr: "Authentication required",
+ };
+ }
+ return { success: true, exitCode: 0, stdout: "", stderr: "" }; // Other commands succeed
+ });
+
+ const args = {
+ needsApproval: true,
+ branchName: "b",
+ commitMessage: "c",
+ prTitle: "p",
+ prBody: "pb",
+ };
+ const result = await commitAndPrTool.execute?.(
+ args,
+ executionOptions(createCommitAndPrContext()),
+ );
+
+ expect(result).toEqual({
+ success: false,
+ error: "Failed to push: Push failed Authentication required",
+ });
+ });
+
+ test("should report partial success if PR creation fails", async () => {
+ mockSandbox.exec.mockImplementation(async (command: string) => {
+ if (command.startsWith("gh pr create")) {
+ return {
+ success: false,
+ exitCode: 1,
+ stdout: "",
+ stderr: "PR creation failed: Missing required fields",
+ };
+ }
+ return { success: true, exitCode: 0, stdout: "", stderr: "" }; // Other commands succeed
+ });
+
+ const args = {
+ needsApproval: true,
+ branchName: "b",
+ commitMessage: "c",
+ prTitle: "p",
+ prBody: "pb",
+ };
+ const result = await commitAndPrTool.execute?.(
+ args,
+ executionOptions(createCommitAndPrContext()),
+ );
+
+ expect(result).toEqual({
+ success: true,
+ message:
+ "Successfully committed and pushed to branch b. Note: Could not create PR automatically via gh CLI. Please create it manually.",
+ errorDetails: "PR creation failed: Missing required fields",
+ });
+ });
+
+ test("needsApproval should always return true", async () => {
+ const args = {
+ needsApproval: true,
+ branchName: "feature/test-branch",
+ commitMessage: "feat: add new feature",
+ prTitle: "feat: Add new feature",
+ prBody: "This PR adds a new feature.",
+ };
+
+ const approvalResult = await getNeedsApprovalResult(
+ commitAndPrTool.needsApproval,
+ args,
+ createCommitAndPrContext(),
+ );
+
+ expect(approvalResult).toBe(true);
+ });
+ });
+
afterEach(() => {
sandboxRegistry.clear();
});
@@ -479,6 +720,10 @@ describe("tools execute behavior", () => {
},
};
+ mock.module("./utils", () => ({
+ getSandbox: mock(async () => sandbox),
+ }));
+
const context = createContext(sandbox);
const result = await webFetchTool.execute?.(
@@ -542,6 +787,10 @@ describe("tools execute behavior", () => {
"---\nname: review\ndescription: review code\n---\nRun review with $ARGUMENTS",
};
+ mock.module("./utils", () => ({
+ getSandbox: mock(async () => sandbox),
+ }));
+
const result = await skillTool.execute?.(
{ skill: "Review", args: "--quick" },
executionOptions({
@@ -675,3 +924,177 @@ describe("tools execute behavior", () => {
});
});
});
+
+test("askUserQuestionTool formats structured answers", () => {
+ const answerOutput = askUserQuestionTool.toModelOutput?.({
+ toolCallId: "tool-call-1",
+ input: { questions: [] },
+ output: {
+ answers: {
+ "Which package manager?": "bun",
+ "Which checks?": ["typecheck", "test"],
+ },
+ },
+ });
+
+ expect(answerOutput).toEqual({
+ type: "text",
+ value:
+ 'User has answered your questions: "Which package manager?"="bun", "Which checks?"="typecheck, test". You can now continue with the user\'s answers in mind.',
+ });
+
+ const declinedOutput = askUserQuestionTool.toModelOutput?.({
+ toolCallId: "tool-call-1",
+ input: { questions: [] },
+ output: { declined: true },
+ });
+
+ expect(declinedOutput).toEqual({
+ type: "text",
+ value:
+ "User declined to answer questions. You should continue without this information or ask in a different way.",
+ });
+});
+
+test("skillTool loads skill content and substitutes arguments", async () => {
+ const sandbox = {
+ workingDirectory: "/repo",
+ readFile: async () =>
+ "---\nname: review\ndescription: review code\n---\nRun review with $ARGUMENTS",
+ };
+
+ mock.module("./utils", () => ({
+ getSandbox: mock(async () => sandbox),
+ }));
+
+ const result = await skillTool.execute?.(
+ { skill: "Review", args: "--quick" },
+ executionOptions({
+ ...createContext(sandbox),
+ skills: [
+ {
+ name: "review",
+ description: "Review code changes",
+ path: "/repo/.skills/review",
+ filename: "SKILL.md",
+ options: {},
+ },
+ ],
+ }),
+ );
+
+ expect(result).toEqual({
+ success: true,
+ skillName: "Review",
+ skillPath: "/repo/.skills/review",
+ content: "Skill directory: /repo/.skills/review\n\nRun review with --quick",
+ });
+});
+
+test("skillTool returns helpful errors for missing or disabled skills", async () => {
+ const sandbox = {
+ workingDirectory: "/repo",
+ readFile: async () => "skill-body",
+ };
+
+ const missingResult = await skillTool.execute?.(
+ { skill: "unknown" },
+ executionOptions({ ...createContext(sandbox), skills: [] }),
+ );
+
+ expect(missingResult).toEqual({
+ success: false,
+ error: "Skill 'unknown' not found. Available skills: none",
+ });
+
+ const disabledResult = await skillTool.execute?.(
+ { skill: "commit" },
+ executionOptions({
+ ...createContext(sandbox),
+ skills: [
+ {
+ name: "commit",
+ description: "Create a commit",
+ path: "/repo/.skills/commit",
+ filename: "SKILL.md",
+ options: { disableModelInvocation: true },
+ },
+ ],
+ }),
+ );
+
+ expect(disabledResult).toEqual({
+ success: false,
+ error:
+ "Skill 'commit' cannot be invoked by the model (disable-model-invocation is set)",
+ });
+});
+
+test("taskTool exposes both subagent types without approval gates", async () => {
+ const explorerNeedsApproval = await getNeedsApprovalResult(
+ taskTool.needsApproval,
+ {
+ subagentType: "explorer",
+ task: "Find usages",
+ instructions: "Search for helper usage",
+ },
+ {
+ sandbox: { workingDirectory: "/repo" },
+ model: "test-model",
+ approval: {},
+ },
+ );
+ expect(explorerNeedsApproval).toBe(false);
+
+ const executorNeedsApproval = await getNeedsApprovalResult(
+ taskTool.needsApproval,
+ {
+ subagentType: "executor",
+ task: "Apply changes",
+ instructions: "Update files",
+ },
+ {
+ sandbox: { workingDirectory: "/repo" },
+ model: "test-model",
+ approval: {},
+ },
+ );
+ expect(executorNeedsApproval).toBe(false);
+});
+
+test("taskTool description lists subagents from the shared registry", () => {
+ expect(taskTool.description).toContain(
+ "`explorer` - Use for read-only codebase exploration, tracing behavior, and answering questions without changing files",
+ );
+ expect(taskTool.description).toContain(
+ "`executor` - Use for well-scoped implementation work, including edits, scaffolding, refactors, and other file changes",
+ );
+ expect(taskTool.description).toContain("up to 100 tool steps");
+});
+
+test("buildSystemPrompt lists subagents from the shared registry", () => {
+ const prompt = buildSystemPrompt({});
+
+ expect(prompt).toContain("Available subagents:");
+ expect(prompt).toContain(
+ "`explorer` - Use for read-only codebase exploration, tracing behavior, and answering questions without changing files",
+ );
+ expect(prompt).toContain(
+ "`executor` - Use for well-scoped implementation work, including edits, scaffolding, refactors, and other file changes",
+ );
+});
+
+test("todoWriteTool returns updated todo list metadata", async () => {
+ const todos = [
+ { id: "1", content: "Write tests", status: "in_progress" as const },
+ { id: "2", content: "Run checks", status: "pending" as const },
+ ];
+
+ const result = await todoWriteTool.execute?.({ todos }, executionOptions());
+
+ expect(result).toEqual({
+ success: true,
+ message: "Updated task list with 2 items",
+ todos,
+ });
+});
diff --git a/packages/mcp/context.ts b/packages/mcp/context.ts
new file mode 100644
index 00000000..fcae6d10
--- /dev/null
+++ b/packages/mcp/context.ts
@@ -0,0 +1,9 @@
+export const context7 = {
+ type: "remote" as const,
+ url: "https://mcp.context7.com/mcp",
+ enabled: true,
+ headers: process.env.CONTEXT7_API_KEY
+ ? { Authorization: `Bearer ${process.env.CONTEXT7_API_KEY}` }
+ : undefined,
+ oauth: false as const,
+};
diff --git a/packages/prompt/bot.ts b/packages/prompt/bot.ts
new file mode 100644
index 00000000..c23a1a3e
--- /dev/null
+++ b/packages/prompt/bot.ts
@@ -0,0 +1,131 @@
+import type { AgentConfigData, ThreadContext } from "../types";
+import type { AgentConfig } from "../router/schema";
+import {
+ applyAgentConfig,
+ applyComplexity,
+ applyTemporalContext,
+} from "./shared";
+
+export const BOT_SYSTEM_PROMPT = `You are a documentation assistant with bash access to a sandbox containing docs (markdown, JSON, YAML).
+{{TEMPORAL_CONTEXT}}
+
+## Critical Rule
+ALWAYS search AND read the relevant documentation before responding. NEVER just list files — actually read them and provide a concrete, actionable answer.
+
+## Fast Search Strategy
+
+ALWAYS prefer \`bash_batch\` over sequential \`bash\` calls. Combine search and read in the same batch.
+
+| Task | Command |
+|------|---------|
+| Find files by content | \`grep -rl "keyword" docs/ --include="*.md" | head -5\` |
+| Multi-keyword search | \`grep -rlE "term1|term2" docs/ --include="*.md" | head -5\` |
+| Find files by name | \`find docs/ -name "*routing*" -name "*.md"\` |
+| Read file (partial) | \`head -100 docs/path/file.md\` |
+| Read file (full) | \`cat docs/path/file.md\` |
+| Search with context | \`grep -n -C3 "keyword" docs/path/file.md\` |
+
+### Batch-first principle
+
+Use \`bash_batch\` to combine search AND read in a single call:
+\`\`\`
+bash_batch: [
+ "grep -rl \\"keyword\\" docs/source1/ --include=\\"*.md\\" | head -5",
+ "grep -rl \\"keyword\\" docs/source2/ --include=\\"*.md\\" | head -5",
+ "head -100 docs/source1/getting-started/index.md"
+]
+\`\`\`
+
+Use \`| head -N\` on all search output. Use \`grep -rlE "term1|term2"\` for multi-keyword search.
+1–2 batched calls beats 5 sequential ones.
+
+**ALWAYS provide a text answer.** If you run out of relevant search results, answer with what you have. Never end on a tool call without a final response.
+
+## Good vs Bad
+
+**Good** — 1-2 calls:
+1. \`bash_batch\`: grep across likely dirs + read obvious files in one call
+2. \`bash_batch\`: read remaining files from grep results
+
+**Bad** — 5+ calls:
+1. \`find docs/ -maxdepth 2 -type d\`
+2. \`grep -rl "keyword" docs/source1/\`
+3. \`grep -rl "keyword" docs/source2/\`
+4. \`cat docs/source1/file1.md\`
+5. \`cat docs/source2/file2.md\`
+
+## Web Search
+
+You have access to a \`search_web\` tool for finding information NOT in the sandbox.
+
+**Use search_web when:**
+- The sandbox search yields no relevant results
+- Questions about current events, release dates, or recent changes
+- Third-party libraries or services not covered in the sandbox
+
+**Do NOT use search_web when:**
+- The question is answerable from sandbox documentation (always search sandbox FIRST)
+
+**Priority:** sandbox docs (bash_batch) → web search → general knowledge
+
+## Response Style
+
+- Be concise and helpful
+- **Contextualize your answer to the user's question.** If they ask about a feature in a specific framework, show that framework's config — not the underlying library's config. Adapt code examples to the framework they're asking about.
+- When a topic spans multiple sources, **cross-reference both** — search the specific source AND related docs.
+- Include code examples from the documentation
+- Try to give a direct answer`;
+
+export function buildBotSystemPrompt(
+ context?: ThreadContext,
+ agentConfig?: AgentConfig,
+ savoirConfig?: AgentConfigData | null,
+): string {
+ let prompt: string = applyTemporalContext(BOT_SYSTEM_PROMPT);
+
+ if (savoirConfig) {
+ prompt = applyAgentConfig(prompt, savoirConfig);
+ }
+
+ if (agentConfig) {
+ prompt = applyComplexity(prompt, agentConfig);
+ }
+
+ if (context) {
+ const ref = context.number ? `#${context.number}` : "Thread";
+ prompt += `\n\n${ref}: "${context.title}" in ${context.source} (${context.platform})`;
+ }
+
+ return prompt;
+}
+
+export function buildBotUserMessage(
+ question: string,
+ context?: ThreadContext,
+): string {
+ const cleanQuestion = question.replace(/@[\w-]+(\[bot\])?/gi, "").trim();
+ const parts: string[] = [];
+
+ if (context) {
+ if (context.body) {
+ parts.push(`**Description:**\n${context.body.slice(0, 1000)}`);
+ }
+
+ if (context.previousComments?.length) {
+ const relevant = context.previousComments
+ .filter((c) => !c.isBot)
+ .slice(-2)
+ .map((c) => `@${c.author}: ${c.body.slice(0, 200)}`);
+
+ if (relevant.length) {
+ parts.push(`**Previous comments:**\n${relevant.join("\n")}`);
+ }
+ }
+ }
+
+ parts.push(
+ `**Question:**\n${cleanQuestion || context?.title || "How can I help?"}`,
+ );
+
+ return parts.join("\n\n");
+}
diff --git a/packages/sandbox/vercel/sandbox.ts b/packages/sandbox/vercel/sandbox.ts
index a3469286..c018ef0c 100644
--- a/packages/sandbox/vercel/sandbox.ts
+++ b/packages/sandbox/vercel/sandbox.ts
@@ -111,15 +111,22 @@ function buildAuthenticatedGitHubUrl(
repoUrl: string,
token: string,
): string | null {
+ // Match GitHub URL patterns to avoid REDOS vulnerability
+ // Matches: github.com/:owner/:repo or github.com/:owner/:repo.git
const githubUrlMatch = repoUrl.match(
- /github\.com[/:]([^/]+)\/([^/]+?)(?:\.git)?$/,
+ /^.*?github\.com[/:]([^/]+?)\/([^/]+?)(?:\.git)?$/,
);
-
if (!githubUrlMatch) {
return null;
}
const [, owner, repo] = githubUrlMatch;
+
+ // Validate that owner and repo are non-empty
+ if (!owner || !repo) {
+ return null;
+ }
+
return `https://x-access-token:${token}@github.com/${owner}/${repo}.git`;
}
diff --git a/renovate.json b/renovate.json
index cbc6661c..1ccd67a8 100644
--- a/renovate.json
+++ b/renovate.json
@@ -26,7 +26,12 @@
},
{
"description": "Group React and React DOM — must stay in sync",
- "matchPackageNames": ["react", "react-dom", "@types/react", "@types/react-dom"],
+ "matchPackageNames": [
+ "react",
+ "react-dom",
+ "@types/react",
+ "@types/react-dom"
+ ],
"groupName": "React",
"automerge": false
},
diff --git a/scripts/clean-workspace.sh b/scripts/clean-workspace.sh
new file mode 100755
index 00000000..80e8e28f
--- /dev/null
+++ b/scripts/clean-workspace.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+set -euo pipefail
+
+echo "🧹 Starting workspace cleanup to free up disk space..."
+
+# Go to project root (assuming script is in scripts/)
+cd "$(dirname "$0")/.." || { echo "❌ Failed to cd to repo root"; exit 1; }
+
+# Refuse to run outside a git checkout to avoid accidental wipes.
+if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
+ echo "❌ Not inside a git working tree; aborting."
+ exit 1
+fi
+
+echo "🗑️ Removing all node_modules directories..."
+# find and remove all node_modules safely
+find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
+
+echo "🗑️ Cleaning Bun cache (~/.bun/install/cache)..."
+if [ -d "$HOME/.bun/install/cache" ]; then
+ rm -rf "$HOME/.bun/install/cache"/*
+fi
+
+echo "🗑️ Cleaning npm cache..."
+npm cache clean --force 2>/dev/null
+
+echo "🗑️ Cleaning temporary turbo and Next.js build caches..."
+find . -name ".turbo" -type d -prune -exec rm -rf '{}' +
+find . -name ".next" -type d -prune -exec rm -rf '{}' +
+
+echo "✅ Cleanup complete! Disk space has been reclaimed."
+echo "💡 Remember to run 'bun install' when you come back to start coding again."