From 37f45ee89b5029e3219b5871ed655fe4504c53a1 Mon Sep 17 00:00:00 2001 From: Kacper Date: Sat, 13 Dec 2025 20:13:53 +0100 Subject: [PATCH] feat: remove codex support --- apps/app/src/components/views/board-view.tsx | 140 +- .../src/components/views/profiles-view.tsx | 66 +- .../src/components/views/settings-view.tsx | 15 - .../api-keys/api-keys-section.tsx | 3 +- .../authentication-status-display.tsx | 57 +- .../api-keys/hooks/use-api-key-management.ts | 75 - .../cli-status/codex-cli-status.tsx | 169 - .../settings-view/hooks/use-cli-status.ts | 80 +- apps/app/src/components/views/setup-view.tsx | 28 +- .../setup-view/steps/codex-setup-step.tsx | 460 --- .../views/setup-view/steps/complete-step.tsx | 29 +- .../views/setup-view/steps/index.ts | 1 - apps/app/src/config/api-providers.ts | 37 +- apps/app/src/lib/utils.ts | 24 +- apps/app/src/store/setup-store.ts | 59 - apps/server/src/lib/model-resolver.ts | 9 - .../src/providers/codex-cli-detector.ts | 408 --- .../src/providers/codex-config-manager.ts | 355 -- apps/server/src/providers/codex-provider.ts | 569 --- apps/server/src/providers/provider-factory.ts | 12 - apps/server/src/routes/models.ts | 83 - apps/server/src/routes/setup.ts | 170 - apps/server/src/services/auto-mode-service.ts | 11 +- .../auto-mode-service.integration.test.ts | 8 +- .../tests/unit/lib/model-resolver.test.ts | 21 +- .../unit/providers/codex-cli-detector.test.ts | 362 -- .../providers/codex-config-manager.test.ts | 430 --- .../unit/providers/codex-provider.test.ts | 1145 ------ .../unit/providers/provider-factory.test.ts | 95 +- .../tests/unit/services/agent-service.test.ts | 6 +- apps/server/vitest.config.ts | 8 +- package-lock.json | 3055 +++++------------ 32 files changed, 925 insertions(+), 7065 deletions(-) delete mode 100644 apps/app/src/components/views/settings-view/cli-status/codex-cli-status.tsx delete mode 100644 apps/app/src/components/views/setup-view/steps/codex-setup-step.tsx delete mode 100644 apps/server/src/providers/codex-cli-detector.ts delete mode 100644 apps/server/src/providers/codex-config-manager.ts delete mode 100644 apps/server/src/providers/codex-provider.ts delete mode 100644 apps/server/tests/unit/providers/codex-cli-detector.test.ts delete mode 100644 apps/server/tests/unit/providers/codex-config-manager.test.ts delete mode 100644 apps/server/tests/unit/providers/codex-provider.test.ts diff --git a/apps/app/src/components/views/board-view.tsx b/apps/app/src/components/views/board-view.tsx index da7af3b1..273cac0d 100644 --- a/apps/app/src/components/views/board-view.tsx +++ b/apps/app/src/components/views/board-view.tsx @@ -121,7 +121,7 @@ type ModelOption = { label: string; description: string; badge?: string; - provider: "claude" | "codex"; + provider: "claude"; }; const CLAUDE_MODELS: ModelOption[] = [ @@ -148,44 +148,6 @@ const CLAUDE_MODELS: ModelOption[] = [ }, ]; -const CODEX_MODELS: ModelOption[] = [ - { - id: "gpt-5.2", - label: "GPT-5.2", - description: "Latest OpenAI model with advanced coding capabilities.", - badge: "Latest", - provider: "codex", - }, - { - id: "gpt-5.1-codex-max", - label: "GPT-5.1 Codex Max", - description: "Flagship Codex model tuned for deep coding tasks.", - badge: "Flagship", - provider: "codex", - }, - { - id: "gpt-5.1-codex", - label: "GPT-5.1 Codex", - description: "Strong coding performance with lower cost.", - badge: "Standard", - provider: "codex", - }, - { - id: "gpt-5.1-codex-mini", - label: "GPT-5.1 Codex Mini", - description: "Fastest Codex option for lightweight edits.", - badge: "Fast", - provider: "codex", - }, - { - id: "gpt-5.1", - label: "GPT-5.1", - description: "General-purpose reasoning with solid coding ability.", - badge: "General", - provider: "codex", - }, -]; - // Profile icon mapping const PROFILE_ICONS: Record< string, @@ -1700,12 +1662,8 @@ export function BoardView() {
{options.map((option) => { const isSelected = selectedModel === option.id; - const isCodex = option.provider === "codex"; // Shorter display names for compact view - const shortName = option.label - .replace("Claude ", "") - .replace("GPT-5.1 Codex ", "") - .replace("GPT-5.1 ", ""); + const shortName = option.label.replace("Claude ", ""); return ( - ))} -
- - - {/* Thinking Level - Only for Claude models */} + {/* Thinking Level */} {supportsThinking && (
- {/* Codex/OpenAI Authentication Status */} -
-
- - - Codex (OpenAI) - -
-
- {codexAuthStatus?.authenticated ? ( - <> -
- - Authenticated -
-
- - - {codexAuthStatus.method === "subscription" - ? "Using Codex subscription (Plus/Team)" - : codexAuthStatus.method === "cli_verified" || - codexAuthStatus.method === "cli_tokens" - ? "Using CLI login (OpenAI account)" - : codexAuthStatus.method === "api_key" - ? "Using stored API key" - : codexAuthStatus.method === "env" - ? "Using OPENAI_API_KEY" - : `Using ${codexAuthStatus.method || "unknown"} authentication`} - -
- - ) : apiKeyStatus?.hasOpenAIKey ? ( -
- - Using environment variable (OPENAI_API_KEY) -
- ) : apiKeys.openai ? ( -
- - Using manual API key from settings -
- ) : ( -
- - Not configured -
- )} -
-
- {/* Google/Gemini Authentication Status */}
diff --git a/apps/app/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts b/apps/app/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts index f45939ed..d5478ca0 100644 --- a/apps/app/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts +++ b/apps/app/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts @@ -10,7 +10,6 @@ interface TestResult { interface ApiKeyStatus { hasAnthropicKey: boolean; - hasOpenAIKey: boolean; hasGoogleKey: boolean; } @@ -24,12 +23,10 @@ export function useApiKeyManagement() { // API key values const [anthropicKey, setAnthropicKey] = useState(apiKeys.anthropic); const [googleKey, setGoogleKey] = useState(apiKeys.google); - const [openaiKey, setOpenaiKey] = useState(apiKeys.openai); // Visibility toggles const [showAnthropicKey, setShowAnthropicKey] = useState(false); const [showGoogleKey, setShowGoogleKey] = useState(false); - const [showOpenaiKey, setShowOpenaiKey] = useState(false); // Test connection states const [testingConnection, setTestingConnection] = useState(false); @@ -38,10 +35,6 @@ export function useApiKeyManagement() { const [geminiTestResult, setGeminiTestResult] = useState( null ); - const [testingOpenaiConnection, setTestingOpenaiConnection] = useState(false); - const [openaiTestResult, setOpenaiTestResult] = useState( - null - ); // API key status from environment const [apiKeyStatus, setApiKeyStatus] = useState(null); @@ -53,7 +46,6 @@ export function useApiKeyManagement() { useEffect(() => { setAnthropicKey(apiKeys.anthropic); setGoogleKey(apiKeys.google); - setOpenaiKey(apiKeys.openai); }, [apiKeys]); // Check API key status from environment on mount @@ -66,7 +58,6 @@ export function useApiKeyManagement() { if (status.success) { setApiKeyStatus({ hasAnthropicKey: status.hasAnthropicKey, - hasOpenAIKey: status.hasOpenAIKey, hasGoogleKey: status.hasGoogleKey, }); } @@ -152,68 +143,11 @@ export function useApiKeyManagement() { } }; - // Test OpenAI connection - const handleTestOpenaiConnection = async () => { - setTestingOpenaiConnection(true); - setOpenaiTestResult(null); - - try { - const api = getElectronAPI(); - if (api?.testOpenAIConnection) { - const result = await api.testOpenAIConnection(openaiKey); - if (result.success) { - setOpenaiTestResult({ - success: true, - message: - result.message || "Connection successful! OpenAI API responded.", - }); - } else { - setOpenaiTestResult({ - success: false, - message: result.error || "Failed to connect to OpenAI API.", - }); - } - } else { - // Fallback to web API test - const response = await fetch("/api/openai/test", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ apiKey: openaiKey }), - }); - - const data = await response.json(); - - if (response.ok && data.success) { - setOpenaiTestResult({ - success: true, - message: - data.message || "Connection successful! OpenAI API responded.", - }); - } else { - setOpenaiTestResult({ - success: false, - message: data.error || "Failed to connect to OpenAI API.", - }); - } - } - } catch { - setOpenaiTestResult({ - success: false, - message: "Network error. Please check your connection.", - }); - } finally { - setTestingOpenaiConnection(false); - } - }; - // Save API keys const handleSave = () => { setApiKeys({ anthropic: anthropicKey, google: googleKey, - openai: openaiKey, }); setSaved(true); setTimeout(() => setSaved(false), 2000); @@ -240,15 +174,6 @@ export function useApiKeyManagement() { onTest: handleTestGeminiConnection, result: geminiTestResult, }, - openai: { - value: openaiKey, - setValue: setOpenaiKey, - show: showOpenaiKey, - setShow: setShowOpenaiKey, - testing: testingOpenaiConnection, - onTest: handleTestOpenaiConnection, - result: openaiTestResult, - }, }; return { diff --git a/apps/app/src/components/views/settings-view/cli-status/codex-cli-status.tsx b/apps/app/src/components/views/settings-view/cli-status/codex-cli-status.tsx deleted file mode 100644 index 5f0bde25..00000000 --- a/apps/app/src/components/views/settings-view/cli-status/codex-cli-status.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import { Button } from "@/components/ui/button"; -import { - Terminal, - CheckCircle2, - AlertCircle, - RefreshCw, -} from "lucide-react"; -import type { CliStatus } from "../shared/types"; - -interface CliStatusProps { - status: CliStatus | null; - isChecking: boolean; - onRefresh: () => void; -} - -export function CodexCliStatus({ - status, - isChecking, - onRefresh, -}: CliStatusProps) { - if (!status) return null; - - return ( -
-
-
-
- -

- OpenAI Codex CLI -

-
- -
-

- Codex CLI enables GPT-5.1 Codex models for autonomous coding tasks. -

-
-
- {status.success && status.status === "installed" ? ( -
-
- -
-

- Codex CLI Installed -

-
- {status.method && ( -

- Method: {status.method} -

- )} - {status.version && ( -

- Version:{" "} - {status.version} -

- )} - {status.path && ( -

- Path:{" "} - - {status.path} - -

- )} -
-
-
- {status.recommendation && ( -

- {status.recommendation} -

- )} -
- ) : status.status === "api_key_only" ? ( -
-
- -
-

- API Key Detected - CLI Not Installed -

-

- {status.recommendation || - "OPENAI_API_KEY found but Codex CLI not installed. Install the CLI for full agentic capabilities."} -

-
-
- {status.installCommands && ( -
-

- Installation Commands: -

-
- {status.installCommands.npm && ( -
-

npm:

- - {status.installCommands.npm} - -
- )} -
-
- )} -
- ) : ( -
-
- -
-

- Codex CLI Not Detected -

-

- {status.recommendation || - "Install OpenAI Codex CLI to use GPT-5.1 Codex models for autonomous coding."} -

-
-
- {status.installCommands && ( -
-

- Installation Commands: -

-
- {status.installCommands.npm && ( -
-

npm:

- - {status.installCommands.npm} - -
- )} - {status.installCommands.macos && ( -
-

- macOS (Homebrew): -

- - {status.installCommands.macos} - -
- )} -
-
- )} -
- )} -
-
- ); -} diff --git a/apps/app/src/components/views/settings-view/hooks/use-cli-status.ts b/apps/app/src/components/views/settings-view/hooks/use-cli-status.ts index 600a5f67..4b65d1ae 100644 --- a/apps/app/src/components/views/settings-view/hooks/use-cli-status.ts +++ b/apps/app/src/components/views/settings-view/hooks/use-cli-status.ts @@ -18,25 +18,17 @@ interface CliStatusResult { error?: string; } -interface CodexCliStatusResult extends CliStatusResult { - hasApiKey?: boolean; -} - /** - * Custom hook for managing Claude and Codex CLI status + * Custom hook for managing Claude CLI status * Handles checking CLI installation, authentication, and refresh functionality */ export function useCliStatus() { - const { setClaudeAuthStatus, setCodexAuthStatus } = useSetupStore(); + const { setClaudeAuthStatus } = useSetupStore(); const [claudeCliStatus, setClaudeCliStatus] = useState(null); - const [codexCliStatus, setCodexCliStatus] = - useState(null); - const [isCheckingClaudeCli, setIsCheckingClaudeCli] = useState(false); - const [isCheckingCodexCli, setIsCheckingCodexCli] = useState(false); // Check CLI status on mount useEffect(() => { @@ -53,16 +45,6 @@ export function useCliStatus() { } } - // Check Codex CLI - if (api?.checkCodexCli) { - try { - const status = await api.checkCodexCli(); - setCodexCliStatus(status); - } catch (error) { - console.error("Failed to check Codex CLI status:", error); - } - } - // Check Claude auth status (re-fetch on mount to ensure persistence) if (api?.setup?.getClaudeStatus) { try { @@ -95,47 +77,10 @@ export function useCliStatus() { console.error("Failed to check Claude auth status:", error); } } - - // Check Codex auth status (re-fetch on mount to ensure persistence) - if (api?.setup?.getCodexStatus) { - try { - const result = await api.setup.getCodexStatus(); - if (result.success && result.auth) { - // Cast to extended type that includes server-added fields - const auth = result.auth as typeof result.auth & { - hasSubscription?: boolean; - cliLoggedIn?: boolean; - hasEnvApiKey?: boolean; - }; - // Map server method names to client method types - // Server returns: subscription, cli_verified, cli_tokens, api_key, env, none - const validMethods = ["subscription", "cli_verified", "cli_tokens", "api_key", "env", "none"] as const; - type CodexMethod = typeof validMethods[number]; - const method: CodexMethod = validMethods.includes(auth.method as CodexMethod) - ? (auth.method as CodexMethod) - : auth.authenticated ? "api_key" : "none"; // Default authenticated to api_key - - const authStatus = { - authenticated: auth.authenticated, - method, - // Only set apiKeyValid for actual API key methods, not CLI login or subscription - apiKeyValid: - method === "cli_verified" || method === "cli_tokens" || method === "subscription" - ? undefined - : auth.hasAuthFile || auth.hasEnvKey || auth.hasEnvApiKey, - hasSubscription: auth.hasSubscription, - cliLoggedIn: auth.cliLoggedIn, - }; - setCodexAuthStatus(authStatus); - } - } catch (error) { - console.error("Failed to check Codex auth status:", error); - } - } }; checkCliStatus(); - }, [setClaudeAuthStatus, setCodexAuthStatus]); + }, [setClaudeAuthStatus]); // Refresh Claude CLI status const handleRefreshClaudeCli = useCallback(async () => { @@ -153,28 +98,9 @@ export function useCliStatus() { } }, []); - // Refresh Codex CLI status - const handleRefreshCodexCli = useCallback(async () => { - setIsCheckingCodexCli(true); - try { - const api = getElectronAPI(); - if (api?.checkCodexCli) { - const status = await api.checkCodexCli(); - setCodexCliStatus(status); - } - } catch (error) { - console.error("Failed to refresh Codex CLI status:", error); - } finally { - setIsCheckingCodexCli(false); - } - }, []); - return { claudeCliStatus, - codexCliStatus, isCheckingClaudeCli, - isCheckingCodexCli, handleRefreshClaudeCli, - handleRefreshCodexCli, }; } diff --git a/apps/app/src/components/views/setup-view.tsx b/apps/app/src/components/views/setup-view.tsx index 331dbc0a..cf5cb7d3 100644 --- a/apps/app/src/components/views/setup-view.tsx +++ b/apps/app/src/components/views/setup-view.tsx @@ -7,7 +7,6 @@ import { WelcomeStep, CompleteStep, ClaudeSetupStep, - CodexSetupStep, } from "./setup-view/steps"; // Main Setup View @@ -17,17 +16,14 @@ export function SetupView() { setCurrentStep, completeSetup, setSkipClaudeSetup, - setSkipCodexSetup, } = useSetupStore(); const { setCurrentView } = useAppStore(); - const steps = ["welcome", "claude", "codex", "complete"] as const; + const steps = ["welcome", "claude", "complete"] as const; type StepName = (typeof steps)[number]; const getStepName = (): StepName => { if (currentStep === "claude_detect" || currentStep === "claude_auth") return "claude"; - if (currentStep === "codex_detect" || currentStep === "codex_auth") - return "codex"; if (currentStep === "welcome") return "welcome"; return "complete"; }; @@ -46,10 +42,6 @@ export function SetupView() { setCurrentStep("claude_detect"); break; case "claude": - console.log("[Setup Flow] Moving to codex_detect step"); - setCurrentStep("codex_detect"); - break; - case "codex": console.log("[Setup Flow] Moving to complete step"); setCurrentStep("complete"); break; @@ -62,21 +54,12 @@ export function SetupView() { case "claude": setCurrentStep("welcome"); break; - case "codex": - setCurrentStep("claude_detect"); - break; } }; const handleSkipClaude = () => { console.log("[Setup Flow] Skipping Claude setup"); setSkipClaudeSetup(true); - setCurrentStep("codex_detect"); - }; - - const handleSkipCodex = () => { - console.log("[Setup Flow] Skipping Codex setup"); - setSkipCodexSetup(true); setCurrentStep("complete"); }; @@ -127,15 +110,6 @@ export function SetupView() { /> )} - {(currentStep === "codex_detect" || - currentStep === "codex_auth") && ( - handleNext("codex")} - onBack={() => handleBack("codex")} - onSkip={handleSkipCodex} - /> - )} - {currentStep === "complete" && ( )} diff --git a/apps/app/src/components/views/setup-view/steps/codex-setup-step.tsx b/apps/app/src/components/views/setup-view/steps/codex-setup-step.tsx deleted file mode 100644 index a5f18ce4..00000000 --- a/apps/app/src/components/views/setup-view/steps/codex-setup-step.tsx +++ /dev/null @@ -1,460 +0,0 @@ -"use client"; - -import { useState, useEffect, useCallback } from "react"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { useSetupStore } from "@/store/setup-store"; -import { useAppStore } from "@/store/app-store"; -import { getElectronAPI } from "@/lib/electron"; -import { - CheckCircle2, - Loader2, - Terminal, - Key, - ArrowRight, - ArrowLeft, - ExternalLink, - Copy, - AlertCircle, - RefreshCw, - Download, -} from "lucide-react"; -import { toast } from "sonner"; -import { StatusBadge, TerminalOutput } from "../components"; -import { - useCliStatus, - useCliInstallation, - useTokenSave, -} from "../hooks"; - -interface CodexSetupStepProps { - onNext: () => void; - onBack: () => void; - onSkip: () => void; -} - -export function CodexSetupStep({ - onNext, - onBack, - onSkip, -}: CodexSetupStepProps) { - const { - codexCliStatus, - codexAuthStatus, - setCodexCliStatus, - setCodexAuthStatus, - setCodexInstallProgress, - } = useSetupStore(); - const { setApiKeys, apiKeys } = useAppStore(); - - const [showApiKeyInput, setShowApiKeyInput] = useState(false); - const [apiKey, setApiKey] = useState(""); - - // Memoize API functions to prevent infinite loops - const statusApi = useCallback( - () => getElectronAPI().setup?.getCodexStatus() || Promise.reject(), - [] - ); - - const installApi = useCallback( - () => getElectronAPI().setup?.installCodex() || Promise.reject(), - [] - ); - - // Use custom hooks - const { isChecking, checkStatus } = useCliStatus({ - cliType: "codex", - statusApi, - setCliStatus: setCodexCliStatus, - setAuthStatus: setCodexAuthStatus, - }); - - const onInstallSuccess = useCallback(() => { - checkStatus(); - }, [checkStatus]); - - const { isInstalling, installProgress, install } = useCliInstallation({ - cliType: "codex", - installApi, - onProgressEvent: getElectronAPI().setup?.onInstallProgress, - onSuccess: onInstallSuccess, - }); - - const { isSaving: isSavingKey, saveToken: saveApiKeyToken } = useTokenSave({ - provider: "openai", - onSuccess: () => { - setCodexAuthStatus({ - authenticated: true, - method: "api_key", - apiKeyValid: true, - }); - setApiKeys({ ...apiKeys, openai: apiKey }); - setShowApiKeyInput(false); - checkStatus(); - }, - }); - - // Sync install progress to store - useEffect(() => { - setCodexInstallProgress({ - isInstalling, - output: installProgress.output, - }); - }, [isInstalling, installProgress, setCodexInstallProgress]); - - // Check status on mount - useEffect(() => { - checkStatus(); - }, [checkStatus]); - - const copyCommand = (command: string) => { - navigator.clipboard.writeText(command); - toast.success("Command copied to clipboard"); - }; - - const isAuthenticated = codexAuthStatus?.authenticated || apiKeys.openai; - - const getAuthMethodLabel = () => { - if (!isAuthenticated) return null; - if (apiKeys.openai) return "API Key (Manual)"; - if (codexAuthStatus?.method === "api_key") return "API Key (Auth File)"; - if (codexAuthStatus?.method === "env") return "API Key (Environment)"; - if (codexAuthStatus?.method === "cli_verified") - return "CLI Login (ChatGPT)"; - return "Authenticated"; - }; - - return ( -
-
-
- -
-

- Codex CLI Setup -

-

- OpenAI's GPT-5.1 Codex for advanced code generation -

-
- - {/* Status Card */} - - -
- Installation Status - -
-
- -
- CLI Installation - {isChecking ? ( - - ) : codexCliStatus?.installed ? ( - - ) : ( - - )} -
- - {codexCliStatus?.version && ( -
- Version - - {codexCliStatus.version} - -
- )} - -
- Authentication - {isAuthenticated ? ( -
- - {getAuthMethodLabel() && ( - - ({getAuthMethodLabel()}) - - )} -
- ) : ( - - )} -
-
-
- - {/* Installation Section */} - {!codexCliStatus?.installed && ( - - - - - Install Codex CLI - - - Install via npm (Node.js required) - - - -
- -
- - npm install -g @openai/codex - - -
-
- - {isInstalling && ( - - )} - -
- -
- -
-
- -

- Requires Node.js to be installed. If the auto-install fails, - try running the command manually in your terminal. -

-
-
-
-
- )} - - {/* Authentication Section */} - {!isAuthenticated && ( - - - - - Authentication - - Codex requires authentication via ChatGPT account or API key - - - {codexCliStatus?.installed && ( -
-
- -
-

- Authenticate via CLI (Recommended) -

-

- Run the following command in your terminal to login with your ChatGPT account: -

-
- - codex auth login - - -
-

- After logging in, you can verify your authentication status: -

-
- - codex login status - - -
-
-
-
- )} - -
-
- -
-
- - or enter API key - -
-
- - {showApiKeyInput ? ( -
-
- - setApiKey(e.target.value)} - className="bg-input border-border text-foreground" - data-testid="openai-api-key-input" - /> -

- Get your API key from{" "} - - platform.openai.com - - -

-
-
- - -
-
- ) : ( - - )} -
-
- )} - - {/* Success State */} - {isAuthenticated && ( - - -
-
- -
-
-

- Codex is ready to use! -

-

- {getAuthMethodLabel() && - `Authenticated via ${getAuthMethodLabel()}. `} - You can proceed to complete setup -

-
-
-
-
- )} - - {/* Navigation */} -
- -
- - -
-
-
- ); -} diff --git a/apps/app/src/components/views/setup-view/steps/complete-step.tsx b/apps/app/src/components/views/setup-view/steps/complete-step.tsx index 447c6465..bcffebc1 100644 --- a/apps/app/src/components/views/setup-view/steps/complete-step.tsx +++ b/apps/app/src/components/views/setup-view/steps/complete-step.tsx @@ -14,16 +14,13 @@ interface CompleteStepProps { } export function CompleteStep({ onFinish }: CompleteStepProps) { - const { claudeCliStatus, claudeAuthStatus, codexCliStatus, codexAuthStatus } = + const { claudeCliStatus, claudeAuthStatus } = useSetupStore(); const { apiKeys } = useAppStore(); const claudeReady = (claudeCliStatus?.installed && claudeAuthStatus?.authenticated) || apiKeys.anthropic; - const codexReady = - (codexCliStatus?.installed && codexAuthStatus?.authenticated) || - apiKeys.openai; return (
@@ -41,7 +38,7 @@ export function CompleteStep({ onFinish }: CompleteStepProps) {

-
+
- - - -
- {codexReady ? ( - - ) : ( - - )} -
-

Codex

-

- {codexReady ? "Ready to use" : "Configure later in settings"} -

-
-
-
-
diff --git a/apps/app/src/components/views/setup-view/steps/index.ts b/apps/app/src/components/views/setup-view/steps/index.ts index 5fa3a01c..4ad4a782 100644 --- a/apps/app/src/components/views/setup-view/steps/index.ts +++ b/apps/app/src/components/views/setup-view/steps/index.ts @@ -2,4 +2,3 @@ export { WelcomeStep } from "./welcome-step"; export { CompleteStep } from "./complete-step"; export { ClaudeSetupStep } from "./claude-setup-step"; -export { CodexSetupStep } from "./codex-setup-step"; diff --git a/apps/app/src/config/api-providers.ts b/apps/app/src/config/api-providers.ts index b0a9bf78..aa7eccd9 100644 --- a/apps/app/src/config/api-providers.ts +++ b/apps/app/src/config/api-providers.ts @@ -2,7 +2,7 @@ import type { Dispatch, SetStateAction } from "react"; import type { LucideIcon } from "lucide-react"; import type { ApiKeys } from "@/store/app-store"; -export type ProviderKey = "anthropic" | "google" | "openai"; +export type ProviderKey = "anthropic" | "google"; export interface ProviderConfig { key: ProviderKey; @@ -51,22 +51,12 @@ export interface ProviderConfigParams { onTest: () => Promise; result: { success: boolean; message: string } | null; }; - openai: { - value: string; - setValue: Dispatch>; - show: boolean; - setShow: Dispatch>; - testing: boolean; - onTest: () => Promise; - result: { success: boolean; message: string } | null; - }; } export const buildProviderConfigs = ({ apiKeys, anthropic, google, - openai, }: ProviderConfigParams): ProviderConfig[] => [ { key: "anthropic", @@ -121,29 +111,4 @@ export const buildProviderConfigs = ({ descriptionLinkHref: "https://makersuite.google.com/app/apikey", descriptionLinkText: "makersuite.google.com", }, - { - key: "openai", - label: "OpenAI API Key (Codex/GPT)", - inputId: "openai-key", - placeholder: "sk-...", - value: openai.value, - setValue: openai.setValue, - showValue: openai.show, - setShowValue: openai.setShow, - hasStoredKey: apiKeys.openai, - inputTestId: "openai-api-key-input", - toggleTestId: "toggle-openai-visibility", - testButton: { - onClick: openai.onTest, - disabled: !openai.value || openai.testing, - loading: openai.testing, - testId: "test-openai-connection", - }, - result: openai.result, - resultTestId: "openai-test-connection-result", - resultMessageTestId: "openai-test-connection-message", - descriptionPrefix: "Used for OpenAI Codex CLI and GPT models. Get your key at", - descriptionLinkHref: "https://platform.openai.com/api-keys", - descriptionLinkText: "platform.openai.com", - }, ]; diff --git a/apps/app/src/lib/utils.ts b/apps/app/src/lib/utils.ts index 8d7b6386..b4081da9 100644 --- a/apps/app/src/lib/utils.ts +++ b/apps/app/src/lib/utils.ts @@ -6,27 +6,12 @@ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } -/** - * Check if a model is a Codex/OpenAI model (doesn't support thinking) - */ -export function isCodexModel(model?: AgentModel | string): boolean { - if (!model) return false; - const codexModels: string[] = [ - "gpt-5.2", - "gpt-5.1-codex-max", - "gpt-5.1-codex", - "gpt-5.1-codex-mini", - "gpt-5.1", - ]; - return codexModels.includes(model); -} - /** * Determine if the current model supports extended thinking controls */ export function modelSupportsThinking(model?: AgentModel | string): boolean { - if (!model) return true; - return !isCodexModel(model); + // All Claude models support thinking + return true; } /** @@ -37,11 +22,6 @@ export function getModelDisplayName(model: AgentModel | string): string { haiku: "Claude Haiku", sonnet: "Claude Sonnet", opus: "Claude Opus", - "gpt-5.2": "GPT-5.2", - "gpt-5.1-codex-max": "GPT-5.1 Codex Max", - "gpt-5.1-codex": "GPT-5.1 Codex", - "gpt-5.1-codex-mini": "GPT-5.1 Codex Mini", - "gpt-5.1": "GPT-5.1", }; return displayNames[model] || model; } diff --git a/apps/app/src/store/setup-store.ts b/apps/app/src/store/setup-store.ts index 15714d28..6b3bcd1a 100644 --- a/apps/app/src/store/setup-store.ts +++ b/apps/app/src/store/setup-store.ts @@ -32,26 +32,6 @@ export interface ClaudeAuthStatus { error?: string; } -// Codex Auth Method - all possible authentication sources -export type CodexAuthMethod = - | "subscription" // Codex/OpenAI Plus or Team subscription - | "cli_verified" // CLI logged in with OpenAI account - | "cli_tokens" // CLI with stored access tokens - | "api_key" // Manually stored API key - | "env" // OPENAI_API_KEY environment variable - | "none"; - -// Codex Auth Status -export interface CodexAuthStatus { - authenticated: boolean; - method: CodexAuthMethod; - apiKeyValid?: boolean; - mcpConfigured?: boolean; - hasSubscription?: boolean; - cliLoggedIn?: boolean; - error?: string; -} - // Installation Progress export interface InstallProgress { isInstalling: boolean; @@ -65,8 +45,6 @@ export type SetupStep = | "welcome" | "claude_detect" | "claude_auth" - | "codex_detect" - | "codex_auth" | "complete"; export interface SetupState { @@ -80,14 +58,8 @@ export interface SetupState { claudeAuthStatus: ClaudeAuthStatus | null; claudeInstallProgress: InstallProgress; - // Codex CLI state - codexCliStatus: CliStatus | null; - codexAuthStatus: CodexAuthStatus | null; - codexInstallProgress: InstallProgress; - // Setup preferences skipClaudeSetup: boolean; - skipCodexSetup: boolean; } export interface SetupActions { @@ -103,15 +75,8 @@ export interface SetupActions { setClaudeInstallProgress: (progress: Partial) => void; resetClaudeInstallProgress: () => void; - // Codex CLI - setCodexCliStatus: (status: CliStatus | null) => void; - setCodexAuthStatus: (status: CodexAuthStatus | null) => void; - setCodexInstallProgress: (progress: Partial) => void; - resetCodexInstallProgress: () => void; - // Preferences setSkipClaudeSetup: (skip: boolean) => void; - setSkipCodexSetup: (skip: boolean) => void; } const initialInstallProgress: InstallProgress = { @@ -130,12 +95,7 @@ const initialState: SetupState = { claudeAuthStatus: null, claudeInstallProgress: { ...initialInstallProgress }, - codexCliStatus: null, - codexAuthStatus: null, - codexInstallProgress: { ...initialInstallProgress }, - skipClaudeSetup: false, - skipCodexSetup: false, }; export const useSetupStore = create()( @@ -171,26 +131,8 @@ export const useSetupStore = create()( claudeInstallProgress: { ...initialInstallProgress }, }), - // Codex CLI - setCodexCliStatus: (status) => set({ codexCliStatus: status }), - - setCodexAuthStatus: (status) => set({ codexAuthStatus: status }), - - setCodexInstallProgress: (progress) => set({ - codexInstallProgress: { - ...get().codexInstallProgress, - ...progress, - }, - }), - - resetCodexInstallProgress: () => set({ - codexInstallProgress: { ...initialInstallProgress }, - }), - // Preferences setSkipClaudeSetup: (skip) => set({ skipClaudeSetup: skip }), - - setSkipCodexSetup: (skip) => set({ skipCodexSetup: skip }), }), { name: "automaker-setup", @@ -198,7 +140,6 @@ export const useSetupStore = create()( isFirstRun: state.isFirstRun, setupComplete: state.setupComplete, skipClaudeSetup: state.skipClaudeSetup, - skipCodexSetup: state.skipCodexSetup, }), } ) diff --git a/apps/server/src/lib/model-resolver.ts b/apps/server/src/lib/model-resolver.ts index d4e12756..d4bbff5e 100644 --- a/apps/server/src/lib/model-resolver.ts +++ b/apps/server/src/lib/model-resolver.ts @@ -3,7 +3,6 @@ * * Provides centralized model resolution logic: * - Maps Claude model aliases to full model strings - * - Detects and passes through OpenAI/Codex models * - Provides default models per provider * - Handles multiple model sources with priority */ @@ -22,7 +21,6 @@ export const CLAUDE_MODEL_MAP: Record = { */ export const DEFAULT_MODELS = { claude: "claude-opus-4-5-20251101", - openai: "gpt-5.2", } as const; /** @@ -41,13 +39,6 @@ export function resolveModelString( return defaultModel; } - // OpenAI/Codex models - pass through unchanged - // Only check for gpt-* models (Codex CLI doesn't support o1/o3) - if (modelKey.startsWith("gpt-")) { - console.log(`[ModelResolver] Using OpenAI/Codex model: ${modelKey}`); - return modelKey; - } - // Full Claude model string - pass through unchanged if (modelKey.includes("claude-")) { console.log(`[ModelResolver] Using full Claude model string: ${modelKey}`); diff --git a/apps/server/src/providers/codex-cli-detector.ts b/apps/server/src/providers/codex-cli-detector.ts deleted file mode 100644 index 21445b46..00000000 --- a/apps/server/src/providers/codex-cli-detector.ts +++ /dev/null @@ -1,408 +0,0 @@ -/** - * Codex CLI Detector - Checks if OpenAI Codex CLI is installed - * - * Codex CLI is OpenAI's agent CLI tool that allows users to use - * GPT-5.1/5.2 Codex models for code generation and agentic tasks. - */ - -import { execSync } from "child_process"; -import fs from "fs"; -import path from "path"; -import os from "os"; -import type { InstallationStatus } from "./types.js"; - -export class CodexCliDetector { - /** - * Get the path to Codex config directory - */ - static getConfigDir(): string { - return path.join(os.homedir(), ".codex"); - } - - /** - * Get the path to Codex auth file - */ - static getAuthPath(): string { - return path.join(this.getConfigDir(), "auth.json"); - } - - /** - * Check Codex authentication status - */ - static checkAuth(): { - authenticated: boolean; - method: string; - hasAuthFile?: boolean; - hasEnvKey?: boolean; - authPath?: string; - error?: string; - } { - try { - const authPath = this.getAuthPath(); - const envApiKey = process.env.OPENAI_API_KEY; - - // Try to verify authentication using codex CLI command if available - try { - const detection = this.detectCodexInstallation(); - if (detection.installed && detection.path) { - try { - // Use 2>&1 to capture both stdout and stderr - const statusOutput = execSync( - `"${detection.path}" login status 2>&1`, - { - encoding: "utf-8", - timeout: 5000, - } - ).trim(); - - // Check if the output indicates logged in status - if ( - statusOutput && - (statusOutput.includes("Logged in") || statusOutput.includes("Authenticated")) - ) { - return { - authenticated: true, - method: "cli_verified", - hasAuthFile: fs.existsSync(authPath), - hasEnvKey: !!envApiKey, - authPath, - }; - } - } catch (statusError) { - // status command failed, continue with file-based check - } - } - } catch (verifyError) { - // CLI verification failed, continue with file-based check - } - - // Check if auth file exists - if (fs.existsSync(authPath)) { - try { - const content = fs.readFileSync(authPath, "utf-8"); - const auth: any = JSON.parse(content); - - // Check for token object structure - if (auth.token && typeof auth.token === "object") { - const token = auth.token; - if ( - token.Id_token || - token.access_token || - token.refresh_token || - token.id_token - ) { - return { - authenticated: true, - method: "cli_tokens", - hasAuthFile: true, - hasEnvKey: !!envApiKey, - authPath, - }; - } - } - - // Check for tokens at root level - if ( - auth.access_token || - auth.refresh_token || - auth.Id_token || - auth.id_token - ) { - return { - authenticated: true, - method: "cli_tokens", - hasAuthFile: true, - hasEnvKey: !!envApiKey, - authPath, - }; - } - - // Check for API key fields - if (auth.api_key || auth.openai_api_key || auth.apiKey) { - return { - authenticated: true, - method: "auth_file", - hasAuthFile: true, - hasEnvKey: !!envApiKey, - authPath, - }; - } - } catch (error) { - return { - authenticated: false, - method: "none", - hasAuthFile: false, - hasEnvKey: !!envApiKey, - authPath, - }; - } - } - - // Environment variable override - if (envApiKey) { - return { - authenticated: true, - method: "env", - hasAuthFile: fs.existsSync(authPath), - hasEnvKey: true, - authPath, - }; - } - - return { - authenticated: false, - method: "none", - hasAuthFile: fs.existsSync(authPath), - hasEnvKey: false, - authPath, - }; - } catch (error) { - return { - authenticated: false, - method: "none", - error: (error as Error).message, - }; - } - } - - /** - * Check if Codex CLI is installed and accessible - */ - static detectCodexInstallation(): InstallationStatus & { - hasApiKey?: boolean; - } { - try { - // Method 1: Check if 'codex' command is in PATH - try { - const codexPath = execSync("which codex 2>/dev/null", { - encoding: "utf-8", - }).trim(); - if (codexPath) { - const version = this.getCodexVersion(codexPath); - return { - installed: true, - path: codexPath, - version: version || undefined, - method: "cli", - }; - } - } catch (error) { - // CLI not in PATH, continue checking other methods - } - - // Method 2: Check for npm global installation - try { - const npmListOutput = execSync( - "npm list -g @openai/codex --depth=0 2>/dev/null", - { encoding: "utf-8" } - ); - if (npmListOutput && npmListOutput.includes("@openai/codex")) { - // Get the path from npm bin - const npmBinPath = execSync("npm bin -g", { - encoding: "utf-8", - }).trim(); - const codexPath = path.join(npmBinPath, "codex"); - const version = this.getCodexVersion(codexPath); - return { - installed: true, - path: codexPath, - version: version || undefined, - method: "npm", - }; - } - } catch (error) { - // npm global not found - } - - // Method 3: Check for Homebrew installation on macOS - if (process.platform === "darwin") { - try { - const brewList = execSync("brew list --formula 2>/dev/null", { - encoding: "utf-8", - }); - if (brewList.includes("codex")) { - const brewPrefixOutput = execSync("brew --prefix codex 2>/dev/null", { - encoding: "utf-8", - }).trim(); - const codexPath = path.join(brewPrefixOutput, "bin", "codex"); - const version = this.getCodexVersion(codexPath); - return { - installed: true, - path: codexPath, - version: version || undefined, - method: "brew", - }; - } - } catch (error) { - // Homebrew not found or codex not installed via brew - } - } - - // Method 4: Check Windows path - if (process.platform === "win32") { - try { - const codexPath = execSync("where codex 2>nul", { - encoding: "utf-8", - }) - .trim() - .split("\n")[0]; - if (codexPath) { - const version = this.getCodexVersion(codexPath); - return { - installed: true, - path: codexPath, - version: version || undefined, - method: "cli", - }; - } - } catch (error) { - // Not found on Windows - } - } - - // Method 5: Check common installation paths - const commonPaths = [ - path.join(os.homedir(), ".local", "bin", "codex"), - path.join(os.homedir(), ".npm-global", "bin", "codex"), - "/usr/local/bin/codex", - "/opt/homebrew/bin/codex", - ]; - - for (const checkPath of commonPaths) { - if (fs.existsSync(checkPath)) { - const version = this.getCodexVersion(checkPath); - return { - installed: true, - path: checkPath, - version: version || undefined, - method: "cli", - }; - } - } - - // Method 6: Check if OPENAI_API_KEY is set (can use Codex API directly) - if (process.env.OPENAI_API_KEY) { - return { - installed: false, - hasApiKey: true, - }; - } - - return { - installed: false, - }; - } catch (error) { - return { - installed: false, - error: (error as Error).message, - }; - } - } - - /** - * Get Codex CLI version from executable path - */ - static getCodexVersion(codexPath: string): string | null { - try { - const version = execSync(`"${codexPath}" --version 2>/dev/null`, { - encoding: "utf-8", - }).trim(); - return version || null; - } catch (error) { - return null; - } - } - - /** - * Get installation info and recommendations - */ - static getInstallationInfo(): { - status: string; - method?: string; - version?: string | null; - path?: string | null; - recommendation: string; - installCommands?: Record; - } { - const detection = this.detectCodexInstallation(); - - if (detection.installed) { - return { - status: "installed", - method: detection.method, - version: detection.version, - path: detection.path, - recommendation: - detection.method === "cli" - ? "Using Codex CLI - ready for GPT-5.1/5.2 Codex models" - : `Using Codex CLI via ${detection.method} - ready for GPT-5.1/5.2 Codex models`, - }; - } - - // Not installed but has API key - if (detection.hasApiKey) { - return { - status: "api_key_only", - method: "api-key-only", - recommendation: - "OPENAI_API_KEY detected but Codex CLI not installed. Install Codex CLI for full agentic capabilities.", - installCommands: this.getInstallCommands(), - }; - } - - return { - status: "not_installed", - recommendation: - "Install OpenAI Codex CLI to use GPT-5.1/5.2 Codex models for agentic tasks", - installCommands: this.getInstallCommands(), - }; - } - - /** - * Get installation commands for different platforms - */ - static getInstallCommands(): Record { - return { - npm: "npm install -g @openai/codex@latest", - macos: "brew install codex", - linux: "npm install -g @openai/codex@latest", - windows: "npm install -g @openai/codex@latest", - }; - } - - /** - * Check if Codex CLI supports a specific model - */ - static isModelSupported(model: string): boolean { - const supportedModels = [ - "gpt-5.1-codex-max", - "gpt-5.1-codex", - "gpt-5.1-codex-mini", - "gpt-5.1", - "gpt-5.2", - ]; - return supportedModels.includes(model); - } - - /** - * Get default model for Codex CLI - */ - static getDefaultModel(): string { - return "gpt-5.2"; - } - - /** - * Get comprehensive installation info including auth status - */ - static getFullStatus() { - const installation = this.detectCodexInstallation(); - const auth = this.checkAuth(); - const info = this.getInstallationInfo(); - - return { - ...info, - auth, - installation, - }; - } -} diff --git a/apps/server/src/providers/codex-config-manager.ts b/apps/server/src/providers/codex-config-manager.ts deleted file mode 100644 index 12c3259b..00000000 --- a/apps/server/src/providers/codex-config-manager.ts +++ /dev/null @@ -1,355 +0,0 @@ -/** - * Codex TOML Configuration Manager - * - * Manages Codex CLI's TOML configuration file to add/update MCP server settings. - * Codex CLI looks for config at: - * - ~/.codex/config.toml (user-level) - * - .codex/config.toml (project-level, takes precedence) - */ - -import fs from "fs/promises"; -import path from "path"; -import os from "os"; - -interface McpServerConfig { - command: string; - args?: string[]; - env?: Record; - startup_timeout_sec?: number; - tool_timeout_sec?: number; - enabled_tools?: string[]; -} - -interface CodexConfig { - experimental_use_rmcp_client?: boolean; - mcp_servers?: Record; - [key: string]: any; -} - -export class CodexConfigManager { - private userConfigPath: string; - private projectConfigPath: string | null = null; - - constructor() { - this.userConfigPath = path.join(os.homedir(), ".codex", "config.toml"); - } - - /** - * Set the project path for project-level config - */ - setProjectPath(projectPath: string): void { - this.projectConfigPath = path.join(projectPath, ".codex", "config.toml"); - } - - /** - * Get the effective config path (project-level if exists, otherwise user-level) - */ - async getConfigPath(): Promise { - if (this.projectConfigPath) { - try { - await fs.access(this.projectConfigPath); - return this.projectConfigPath; - } catch (e) { - // Project config doesn't exist, fall back to user config - } - } - - // Ensure user config directory exists - const userConfigDir = path.dirname(this.userConfigPath); - try { - await fs.mkdir(userConfigDir, { recursive: true }); - } catch (e) { - // Directory might already exist - } - - return this.userConfigPath; - } - - /** - * Read existing TOML config (simple parser for our needs) - */ - async readConfig(configPath: string): Promise { - try { - const content = await fs.readFile(configPath, "utf-8"); - return this.parseToml(content); - } catch (e: any) { - if (e.code === "ENOENT") { - return {}; - } - throw e; - } - } - - /** - * Simple TOML parser for our specific use case - * This is a minimal parser that handles the MCP server config structure - */ - parseToml(content: string): CodexConfig { - const config: CodexConfig = {}; - let currentSection: string | null = null; - let currentSubsection: string | null = null; - - const lines = content.split("\n"); - - for (const line of lines) { - const trimmed = line.trim(); - - // Skip comments and empty lines - if (!trimmed || trimmed.startsWith("#")) { - continue; - } - - // Section header: [section] - const sectionMatch = trimmed.match(/^\[([^\]]+)\]$/); - if (sectionMatch) { - const sectionName = sectionMatch[1]; - const parts = sectionName.split("."); - - if (parts.length === 1) { - currentSection = parts[0]; - currentSubsection = null; - if (!config[currentSection]) { - config[currentSection] = {}; - } - } else if (parts.length === 2) { - currentSection = parts[0]; - currentSubsection = parts[1]; - if (!config[currentSection]) { - config[currentSection] = {}; - } - if (!config[currentSection][currentSubsection]) { - config[currentSection][currentSubsection] = {}; - } - } - continue; - } - - // Key-value pair: key = value - const kvMatch = trimmed.match(/^([^=]+)=(.+)$/); - if (kvMatch) { - const key = kvMatch[1].trim(); - let value: any = kvMatch[2].trim(); - - // Remove quotes if present - if ( - (value.startsWith('"') && value.endsWith('"')) || - (value.startsWith("'") && value.endsWith("'")) - ) { - value = value.slice(1, -1); - } - - // Parse boolean - if (value === "true") value = true; - else if (value === "false") value = false; - // Parse number - else if (/^-?\d+$/.test(value)) value = parseInt(value, 10); - else if (/^-?\d+\.\d+$/.test(value)) value = parseFloat(value); - - if (currentSubsection && currentSection) { - if (!config[currentSection][currentSubsection]) { - config[currentSection][currentSubsection] = {}; - } - config[currentSection][currentSubsection][key] = value; - } else if (currentSection) { - if (!config[currentSection]) { - config[currentSection] = {}; - } - config[currentSection][key] = value; - } else { - config[key] = value; - } - } - } - - return config; - } - - /** - * Configure the automaker-tools MCP server - */ - async configureMcpServer( - projectPath: string, - mcpServerScriptPath: string - ): Promise { - this.setProjectPath(projectPath); - const configPath = await this.getConfigPath(); - - // Read existing config - const config = await this.readConfig(configPath); - - // Ensure mcp_servers section exists - if (!config.mcp_servers) { - config.mcp_servers = {}; - } - - // Configure automaker-tools server - config.mcp_servers["automaker-tools"] = { - command: "node", - args: [mcpServerScriptPath], - env: { - AUTOMAKER_PROJECT_PATH: projectPath, - }, - startup_timeout_sec: 10, - tool_timeout_sec: 60, - enabled_tools: ["UpdateFeatureStatus"], - }; - - // Ensure experimental_use_rmcp_client is enabled (if needed) - if (!config.experimental_use_rmcp_client) { - config.experimental_use_rmcp_client = true; - } - - // Write config back - await this.writeConfig(configPath, config); - - console.log( - `[CodexConfigManager] Configured automaker-tools MCP server in ${configPath}` - ); - return configPath; - } - - /** - * Write config to TOML file - */ - async writeConfig(configPath: string, config: CodexConfig): Promise { - let content = ""; - - // Write top-level keys first (preserve existing non-MCP config) - for (const [key, value] of Object.entries(config)) { - if (key === "mcp_servers" || key === "experimental_use_rmcp_client") { - continue; // Handle these separately - } - if (typeof value !== "object") { - content += `${key} = ${this.formatValue(value)}\n`; - } - } - - // Write experimental flag if enabled - if (config.experimental_use_rmcp_client) { - if (content && !content.endsWith("\n\n")) { - content += "\n"; - } - content += `experimental_use_rmcp_client = true\n`; - } - - // Write mcp_servers section - if (config.mcp_servers && Object.keys(config.mcp_servers).length > 0) { - if (content && !content.endsWith("\n\n")) { - content += "\n"; - } - - for (const [serverName, serverConfig] of Object.entries( - config.mcp_servers - )) { - content += `\n[mcp_servers.${serverName}]\n`; - - // Write command first - if (serverConfig.command) { - content += `command = "${this.escapeTomlString(serverConfig.command)}"\n`; - } - - // Write args - if (serverConfig.args && Array.isArray(serverConfig.args)) { - const argsStr = serverConfig.args - .map((a) => `"${this.escapeTomlString(a)}"`) - .join(", "); - content += `args = [${argsStr}]\n`; - } - - // Write timeouts (must be before env subsection) - if (serverConfig.startup_timeout_sec !== undefined) { - content += `startup_timeout_sec = ${serverConfig.startup_timeout_sec}\n`; - } - - if (serverConfig.tool_timeout_sec !== undefined) { - content += `tool_timeout_sec = ${serverConfig.tool_timeout_sec}\n`; - } - - // Write enabled_tools (must be before env subsection - at server level, not env level) - if (serverConfig.enabled_tools && Array.isArray(serverConfig.enabled_tools)) { - const toolsStr = serverConfig.enabled_tools - .map((t) => `"${this.escapeTomlString(t)}"`) - .join(", "); - content += `enabled_tools = [${toolsStr}]\n`; - } - - // Write env section last (as a separate subsection) - if ( - serverConfig.env && - typeof serverConfig.env === "object" && - Object.keys(serverConfig.env).length > 0 - ) { - content += `\n[mcp_servers.${serverName}.env]\n`; - for (const [envKey, envValue] of Object.entries(serverConfig.env)) { - content += `${envKey} = "${this.escapeTomlString(String(envValue))}"\n`; - } - } - } - } - - // Ensure directory exists - const configDir = path.dirname(configPath); - await fs.mkdir(configDir, { recursive: true }); - - // Write file - await fs.writeFile(configPath, content, "utf-8"); - } - - /** - * Escape special characters in TOML strings - */ - escapeTomlString(str: string): string { - return str - .replace(/\\/g, "\\\\") - .replace(/"/g, '\\"') - .replace(/\n/g, "\\n") - .replace(/\r/g, "\\r") - .replace(/\t/g, "\\t"); - } - - /** - * Format a value for TOML output - */ - formatValue(value: any): string { - if (typeof value === "string") { - const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); - return `"${escaped}"`; - } else if (typeof value === "boolean") { - return value.toString(); - } else if (typeof value === "number") { - return value.toString(); - } - return `"${String(value)}"`; - } - - /** - * Remove automaker-tools MCP server configuration - */ - async removeMcpServer(projectPath: string): Promise { - this.setProjectPath(projectPath); - const configPath = await this.getConfigPath(); - - try { - const config = await this.readConfig(configPath); - - if (config.mcp_servers && config.mcp_servers["automaker-tools"]) { - delete config.mcp_servers["automaker-tools"]; - - // If no more MCP servers, remove the section - if (Object.keys(config.mcp_servers).length === 0) { - delete config.mcp_servers; - } - - await this.writeConfig(configPath, config); - console.log( - `[CodexConfigManager] Removed automaker-tools MCP server from ${configPath}` - ); - } - } catch (e) { - console.error(`[CodexConfigManager] Error removing MCP server config:`, e); - } - } -} - -// Export singleton instance -export const codexConfigManager = new CodexConfigManager(); diff --git a/apps/server/src/providers/codex-provider.ts b/apps/server/src/providers/codex-provider.ts deleted file mode 100644 index 531dd268..00000000 --- a/apps/server/src/providers/codex-provider.ts +++ /dev/null @@ -1,569 +0,0 @@ -/** - * Codex Provider - Executes queries using OpenAI Codex CLI - * - * Spawns Codex CLI as a subprocess and converts JSONL output to - * Claude SDK-compatible message format for seamless integration. - */ - -import { BaseProvider } from "./base-provider.js"; -import { CodexCliDetector } from "./codex-cli-detector.js"; -import { codexConfigManager } from "./codex-config-manager.js"; -import { spawnJSONLProcess } from "../lib/subprocess-manager.js"; -import { formatHistoryAsText } from "../lib/conversation-utils.js"; -import type { - ExecuteOptions, - ProviderMessage, - InstallationStatus, - ModelDefinition, - ContentBlock, -} from "./types.js"; - -// Codex event types -const CODEX_EVENT_TYPES = { - THREAD_STARTED: "thread.started", - THREAD_COMPLETED: "thread.completed", - ITEM_STARTED: "item.started", - ITEM_COMPLETED: "item.completed", - TURN_STARTED: "turn.started", - ERROR: "error", -}; - -interface CodexEvent { - type: string; - data?: any; - item?: any; - thread_id?: string; - message?: string; -} - -export class CodexProvider extends BaseProvider { - getName(): string { - return "codex"; - } - - /** - * Execute a query using Codex CLI - */ - async *executeQuery(options: ExecuteOptions): AsyncGenerator { - const { - prompt, - model = "gpt-5.2", - cwd, - systemPrompt, - mcpServers, - abortController, - conversationHistory, - } = options; - - // Find Codex CLI path - const codexPath = this.findCodexPath(); - if (!codexPath) { - yield { - type: "error", - error: - "Codex CLI not found. Please install it with: npm install -g @openai/codex@latest", - }; - return; - } - - // Configure MCP server if provided - if (mcpServers && mcpServers["automaker-tools"]) { - try { - const mcpServerScriptPath = await this.getMcpServerPath(); - if (mcpServerScriptPath) { - await codexConfigManager.configureMcpServer(cwd, mcpServerScriptPath); - } - } catch (error) { - console.error("[CodexProvider] Failed to configure MCP server:", error); - // Continue execution even if MCP config fails - } - } - - // Build combined prompt with conversation history - // Codex CLI doesn't support native conversation history or images, so we extract text - let combinedPrompt = ""; - - if (typeof prompt === "string") { - combinedPrompt = prompt; - } else if (Array.isArray(prompt)) { - // Extract text from content blocks (ignore images - Codex CLI doesn't support vision) - combinedPrompt = prompt - .filter(block => block.type === "text") - .map(block => block.text || "") - .join("\n"); - } - - // Add system prompt first - if (systemPrompt) { - combinedPrompt = `${systemPrompt}\n\n---\n\n${combinedPrompt}`; - } - - // Add conversation history - if (conversationHistory && conversationHistory.length > 0) { - const historyText = formatHistoryAsText(conversationHistory); - combinedPrompt = `${historyText}Current request:\n${combinedPrompt}`; - } - - // Build command arguments - const args = this.buildArgs({ prompt: combinedPrompt, model }); - - // Check authentication - either API key or CLI login - const auth = CodexCliDetector.checkAuth(); - const hasApiKey = this.config.apiKey || process.env.OPENAI_API_KEY; - - if (!auth.authenticated && !hasApiKey) { - yield { - type: "error", - error: - "Codex CLI is not authenticated. Please run 'codex login' or set OPENAI_API_KEY environment variable.", - }; - return; - } - - // Prepare environment variables (API key is optional if using CLI auth) - const env = { - ...this.config.env, - ...(hasApiKey && { OPENAI_API_KEY: hasApiKey }), - }; - - // Spawn the Codex process and stream JSONL output - try { - const stream = spawnJSONLProcess({ - command: codexPath, - args, - cwd, - env, - abortController, - timeout: 30000, // 30s timeout for no output - }); - - for await (const event of stream) { - const converted = this.convertToProviderFormat(event as CodexEvent); - if (converted) { - yield converted; - } - } - - // Yield completion event - yield { - type: "result", - subtype: "success", - result: "", - }; - } catch (error) { - console.error("[CodexProvider] Execution error:", error); - yield { - type: "error", - error: (error as Error).message, - }; - } - } - - /** - * Convert Codex JSONL event to Provider message format (Claude SDK compatible) - */ - private convertToProviderFormat(event: CodexEvent): ProviderMessage | null { - const { type, data, item, thread_id } = event; - - switch (type) { - case CODEX_EVENT_TYPES.THREAD_STARTED: - case "thread.started": - // Session initialization - not needed for provider format - return null; - - case CODEX_EVENT_TYPES.ITEM_COMPLETED: - case "item.completed": - return this.convertItemCompleted(item || data); - - case CODEX_EVENT_TYPES.ITEM_STARTED: - case "item.started": - // Item started events can show tool usage - const startedItem = item || data; - if ( - startedItem?.type === "command_execution" && - startedItem?.command - ) { - return { - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "tool_use", - name: "bash", - input: { command: startedItem.command }, - }, - ], - }, - }; - } - // Handle todo_list started - if (startedItem?.type === "todo_list" && startedItem?.items) { - const todos = startedItem.items || []; - const todoText = todos - .map((t: any, i: number) => `${i + 1}. ${t.text || t}`) - .join("\n"); - return { - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "text", - text: `**Todo List:**\n${todoText}`, - }, - ], - }, - }; - } - return null; - - case "item.updated": - // Handle updated items (like todo list updates) - const updatedItem = item || data; - if (updatedItem?.type === "todo_list" && updatedItem?.items) { - const todos = updatedItem.items || []; - const todoText = todos - .map((t: any, i: number) => { - const status = t.status === "completed" ? "✓" : " "; - return `${i + 1}. [${status}] ${t.text || t}`; - }) - .join("\n"); - return { - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "text", - text: `**Updated Todo List:**\n${todoText}`, - }, - ], - }, - }; - } - return null; - - case CODEX_EVENT_TYPES.THREAD_COMPLETED: - case "thread.completed": - return { - type: "result", - subtype: "success", - result: "", - }; - - case CODEX_EVENT_TYPES.ERROR: - case "error": - return { - type: "error", - error: - data?.message || - item?.message || - event.message || - "Unknown error from Codex CLI", - }; - - case "turn.started": - case "turn.completed": - // Turn markers - not needed for provider format - return null; - - default: - return null; - } - } - - /** - * Convert item.completed event to Provider format - */ - private convertItemCompleted(item: any): ProviderMessage | null { - if (!item) { - return null; - } - - const itemType = item.type || item.item_type; - - switch (itemType) { - case "reasoning": - // Thinking/reasoning output - const reasoningText = item.text || item.content || ""; - return { - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "thinking", - thinking: reasoningText, - }, - ], - }, - }; - - case "agent_message": - case "message": - // Assistant text message - const messageText = item.content || item.text || ""; - return { - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "text", - text: messageText, - }, - ], - }, - }; - - case "command_execution": - // Command execution - show both the command and its output - const command = item.command || ""; - const output = item.aggregated_output || item.output || ""; - - return { - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "text", - text: `\`\`\`bash\n${command}\n\`\`\`\n\n${output}`, - }, - ], - }, - }; - - case "tool_use": - // Tool use - return { - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "tool_use", - name: item.tool || item.command || "unknown", - input: item.input || item.args || {}, - }, - ], - }, - }; - - case "tool_result": - // Tool result - return { - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "tool_result", - tool_use_id: item.tool_use_id, - content: item.output || item.result, - }, - ], - }, - }; - - case "todo_list": - // Todo list - convert to text format - const todos = item.items || []; - const todoText = todos - .map((t: any, i: number) => `${i + 1}. ${t.text || t}`) - .join("\n"); - return { - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "text", - text: `**Todo List:**\n${todoText}`, - }, - ], - }, - }; - - case "file_change": - // File changes - show what files were modified - const changes = item.changes || []; - const changeText = changes - .map((c: any) => `- Modified: ${c.path}`) - .join("\n"); - return { - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "text", - text: `**File Changes:**\n${changeText}`, - }, - ], - }, - }; - - default: - // Generic text output - const text = item.text || item.content || item.aggregated_output; - if (text) { - return { - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "text", - text: String(text), - }, - ], - }, - }; - } - return null; - } - } - - /** - * Build command arguments for Codex CLI - */ - private buildArgs(options: { - prompt: string; - model: string; - }): string[] { - const { prompt, model } = options; - - return [ - "exec", - "--model", - model, - "--json", // JSONL output format - "--full-auto", // Non-interactive mode - prompt, // Prompt as the last argument - ]; - } - - /** - * Find Codex CLI executable path - */ - private findCodexPath(): string | null { - // Check config override - if (this.config.cliPath) { - return this.config.cliPath; - } - - // Check environment variable override - if (process.env.CODEX_CLI_PATH) { - return process.env.CODEX_CLI_PATH; - } - - // Auto-detect - const detection = CodexCliDetector.detectCodexInstallation(); - return detection.path || "codex"; - } - - /** - * Get MCP server script path - */ - private async getMcpServerPath(): Promise { - // TODO: Implement MCP server path resolution - // For now, return null - MCP support is optional - return null; - } - - /** - * Detect Codex CLI installation - */ - async detectInstallation(): Promise { - const detection = CodexCliDetector.detectCodexInstallation(); - const auth = CodexCliDetector.checkAuth(); - - return { - installed: detection.installed, - path: detection.path, - version: detection.version, - method: detection.method, - hasApiKey: auth.hasEnvKey || auth.authenticated, - authenticated: auth.authenticated, - }; - } - - /** - * Get available Codex models - */ - getAvailableModels(): ModelDefinition[] { - return [ - { - id: "gpt-5.2", - name: "GPT-5.2 (Codex)", - modelString: "gpt-5.2", - provider: "openai-codex", - description: "Latest Codex model for agentic code generation", - contextWindow: 256000, - maxOutputTokens: 32768, - supportsVision: true, - supportsTools: true, - tier: "premium", - default: true, - }, - { - id: "gpt-5.1-codex-max", - name: "GPT-5.1 Codex Max", - modelString: "gpt-5.1-codex-max", - provider: "openai-codex", - description: "Maximum capability Codex model", - contextWindow: 256000, - maxOutputTokens: 32768, - supportsVision: true, - supportsTools: true, - tier: "premium", - }, - { - id: "gpt-5.1-codex", - name: "GPT-5.1 Codex", - modelString: "gpt-5.1-codex", - provider: "openai-codex", - description: "Standard Codex model", - contextWindow: 256000, - maxOutputTokens: 32768, - supportsVision: true, - supportsTools: true, - tier: "standard", - }, - { - id: "gpt-5.1-codex-mini", - name: "GPT-5.1 Codex Mini", - modelString: "gpt-5.1-codex-mini", - provider: "openai-codex", - description: "Faster, lightweight Codex model", - contextWindow: 256000, - maxOutputTokens: 16384, - supportsVision: false, - supportsTools: true, - tier: "basic", - }, - { - id: "gpt-5.1", - name: "GPT-5.1", - modelString: "gpt-5.1", - provider: "openai-codex", - description: "General-purpose GPT-5.1 model", - contextWindow: 256000, - maxOutputTokens: 32768, - supportsVision: true, - supportsTools: true, - tier: "standard", - }, - ]; - } - - /** - * Check if the provider supports a specific feature - */ - supportsFeature(feature: string): boolean { - const supportedFeatures = ["tools", "text", "vision", "mcp", "cli"]; - return supportedFeatures.includes(feature); - } -} diff --git a/apps/server/src/providers/provider-factory.ts b/apps/server/src/providers/provider-factory.ts index 824a20f4..9c8d028f 100644 --- a/apps/server/src/providers/provider-factory.ts +++ b/apps/server/src/providers/provider-factory.ts @@ -8,7 +8,6 @@ import { BaseProvider } from "./base-provider.js"; import { ClaudeProvider } from "./claude-provider.js"; -import { CodexProvider } from "./codex-provider.js"; import type { InstallationStatus } from "./types.js"; export class ProviderFactory { @@ -21,12 +20,6 @@ export class ProviderFactory { static getProviderForModel(modelId: string): BaseProvider { const lowerModel = modelId.toLowerCase(); - // OpenAI/Codex models (gpt-*) - // Note: o1/o3 models are not supported by Codex CLI - if (lowerModel.startsWith("gpt-")) { - return new CodexProvider(); - } - // Claude models (claude-*, opus, sonnet, haiku) if ( lowerModel.startsWith("claude-") || @@ -56,7 +49,6 @@ export class ProviderFactory { static getAllProviders(): BaseProvider[] { return [ new ClaudeProvider(), - new CodexProvider(), // Future providers... ]; } @@ -95,10 +87,6 @@ export class ProviderFactory { case "anthropic": return new ClaudeProvider(); - case "codex": - case "openai": - return new CodexProvider(); - // Future providers: // case "cursor": // return new CursorProvider(); diff --git a/apps/server/src/routes/models.ts b/apps/server/src/routes/models.ts index c45bae19..0345b54a 100644 --- a/apps/server/src/routes/models.ts +++ b/apps/server/src/routes/models.ts @@ -64,78 +64,6 @@ export function createModelsRoutes(): Router { supportsVision: true, supportsTools: true, }, - { - id: "gpt-4o", - name: "GPT-4o", - provider: "openai", - contextWindow: 128000, - maxOutputTokens: 16384, - supportsVision: true, - supportsTools: true, - }, - { - id: "gpt-4o-mini", - name: "GPT-4o Mini", - provider: "openai", - contextWindow: 128000, - maxOutputTokens: 16384, - supportsVision: true, - supportsTools: true, - }, - { - id: "o1", - name: "o1", - provider: "openai", - contextWindow: 200000, - maxOutputTokens: 100000, - supportsVision: true, - supportsTools: false, - }, - { - id: "gpt-5.2", - name: "GPT-5.2 (Codex)", - provider: "openai-codex", - contextWindow: 256000, - maxOutputTokens: 32768, - supportsVision: true, - supportsTools: true, - }, - { - id: "gpt-5.1-codex-max", - name: "GPT-5.1 Codex Max", - provider: "openai-codex", - contextWindow: 256000, - maxOutputTokens: 32768, - supportsVision: true, - supportsTools: true, - }, - { - id: "gpt-5.1-codex", - name: "GPT-5.1 Codex", - provider: "openai-codex", - contextWindow: 256000, - maxOutputTokens: 32768, - supportsVision: true, - supportsTools: true, - }, - { - id: "gpt-5.1-codex-mini", - name: "GPT-5.1 Codex Mini", - provider: "openai-codex", - contextWindow: 256000, - maxOutputTokens: 16384, - supportsVision: false, - supportsTools: true, - }, - { - id: "gpt-5.1", - name: "GPT-5.1", - provider: "openai-codex", - contextWindow: 256000, - maxOutputTokens: 32768, - supportsVision: true, - supportsTools: true, - }, ]; res.json({ success: true, models }); @@ -156,17 +84,6 @@ export function createModelsRoutes(): Router { available: statuses.claude?.installed || false, hasApiKey: !!process.env.ANTHROPIC_API_KEY || !!process.env.CLAUDE_CODE_OAUTH_TOKEN, }, - openai: { - available: !!process.env.OPENAI_API_KEY, - hasApiKey: !!process.env.OPENAI_API_KEY, - }, - "openai-codex": { - available: statuses.codex?.installed || false, - hasApiKey: !!process.env.OPENAI_API_KEY, - cliInstalled: statuses.codex?.installed, - cliVersion: statuses.codex?.version, - cliPath: statuses.codex?.path, - }, google: { available: !!process.env.GOOGLE_API_KEY, hasApiKey: !!process.env.GOOGLE_API_KEY, diff --git a/apps/server/src/routes/setup.ts b/apps/server/src/routes/setup.ts index 6403fbfa..6c16f6fd 100644 --- a/apps/server/src/routes/setup.ts +++ b/apps/server/src/routes/setup.ts @@ -230,84 +230,6 @@ export function createSetupRoutes(): Router { } }); - // Get Codex CLI status - router.get("/codex-status", async (_req: Request, res: Response) => { - try { - let installed = false; - let version = ""; - let cliPath = ""; - let method = "none"; - - // Try to find Codex CLI - try { - const { stdout } = await execAsync("which codex || where codex 2>/dev/null"); - cliPath = stdout.trim(); - installed = true; - method = "path"; - - try { - const { stdout: versionOut } = await execAsync("codex --version"); - version = versionOut.trim(); - } catch { - version = "unknown"; - } - } catch { - // Not found - } - - // Check for OpenAI/Codex authentication - // Simplified: only check via CLI command, no file parsing - let auth = { - authenticated: false, - method: "none" as string, - hasEnvKey: !!process.env.OPENAI_API_KEY, - hasStoredApiKey: !!apiKeys.openai, - }; - - // Try to verify authentication using codex CLI command if CLI is installed - if (installed && cliPath) { - try { - const { stdout: statusOutput } = await execAsync(`"${cliPath}" login status 2>&1`, { - timeout: 5000, - }); - - // Check if the output indicates logged in status - if (statusOutput && (statusOutput.includes('Logged in') || statusOutput.includes('Authenticated'))) { - auth.authenticated = true; - auth.method = "cli_verified"; // CLI verified via login status command - } - } catch (error) { - // CLI check failed - user needs to login manually - console.log("[Setup] Codex login status check failed:", error); - } - } - - // Environment variable override - if (process.env.OPENAI_API_KEY) { - auth.authenticated = true; - auth.method = "env"; // OPENAI_API_KEY environment variable - } - - // In-memory stored API key (from settings UI) - if (!auth.authenticated && apiKeys.openai) { - auth.authenticated = true; - auth.method = "api_key"; // Manually stored API key - } - - res.json({ - success: true, - status: installed ? "installed" : "not_installed", - method, - version, - path: cliPath, - auth, - }); - } catch (error) { - const message = error instanceof Error ? error.message : "Unknown error"; - res.status(500).json({ success: false, error: message }); - } - }); - // Install Claude CLI router.post("/install-claude", async (_req: Request, res: Response) => { try { @@ -324,20 +246,6 @@ export function createSetupRoutes(): Router { } }); - // Install Codex CLI - router.post("/install-codex", async (_req: Request, res: Response) => { - try { - res.json({ - success: false, - error: - "CLI installation requires terminal access. Please install manually using: npm install -g @openai/codex", - }); - } catch (error) { - const message = error instanceof Error ? error.message : "Unknown error"; - res.status(500).json({ success: false, error: message }); - } - }); - // Auth Claude router.post("/auth-claude", async (_req: Request, res: Response) => { try { @@ -353,28 +261,6 @@ export function createSetupRoutes(): Router { } }); - // Auth Codex - router.post("/auth-codex", async (req: Request, res: Response) => { - try { - const { apiKey } = req.body as { apiKey?: string }; - - if (apiKey) { - apiKeys.openai = apiKey; - process.env.OPENAI_API_KEY = apiKey; - res.json({ success: true }); - } else { - res.json({ - success: true, - requiresManualAuth: true, - command: "codex auth login", - }); - } - } catch (error) { - const message = error instanceof Error ? error.message : "Unknown error"; - res.status(500).json({ success: false, error: message }); - } - }); - // Store API key router.post("/store-api-key", async (req: Request, res: Response) => { try { @@ -401,9 +287,6 @@ export function createSetupRoutes(): Router { process.env.ANTHROPIC_API_KEY = apiKey; await persistApiKeyToEnv("ANTHROPIC_API_KEY", apiKey); console.log("[Setup] Stored API key as ANTHROPIC_API_KEY"); - } else if (provider === "openai") { - process.env.OPENAI_API_KEY = apiKey; - await persistApiKeyToEnv("OPENAI_API_KEY", apiKey); } else if (provider === "google") { process.env.GOOGLE_API_KEY = apiKey; await persistApiKeyToEnv("GOOGLE_API_KEY", apiKey); @@ -422,7 +305,6 @@ export function createSetupRoutes(): Router { res.json({ success: true, hasAnthropicKey: !!apiKeys.anthropic || !!process.env.ANTHROPIC_API_KEY, - hasOpenAIKey: !!apiKeys.openai || !!process.env.OPENAI_API_KEY, hasGoogleKey: !!apiKeys.google || !!process.env.GOOGLE_API_KEY, }); } catch (error) { @@ -431,34 +313,6 @@ export function createSetupRoutes(): Router { } }); - // Configure Codex MCP - router.post("/configure-codex-mcp", async (req: Request, res: Response) => { - try { - const { projectPath } = req.body as { projectPath: string }; - - if (!projectPath) { - res.status(400).json({ success: false, error: "projectPath required" }); - return; - } - - // Create .codex directory and config - const codexDir = path.join(projectPath, ".codex"); - await fs.mkdir(codexDir, { recursive: true }); - - const configPath = path.join(codexDir, "config.toml"); - const config = `# Codex configuration -[mcp] -enabled = true -`; - await fs.writeFile(configPath, config); - - res.json({ success: true, configPath }); - } catch (error) { - const message = error instanceof Error ? error.message : "Unknown error"; - res.status(500).json({ success: false, error: message }); - } - }); - // Get platform info router.get("/platform", async (_req: Request, res: Response) => { try { @@ -478,29 +332,5 @@ enabled = true } }); - // Test OpenAI connection - router.post("/test-openai", async (req: Request, res: Response) => { - try { - const { apiKey } = req.body as { apiKey?: string }; - const key = apiKey || apiKeys.openai || process.env.OPENAI_API_KEY; - - if (!key) { - res.json({ success: false, error: "No OpenAI API key provided" }); - return; - } - - // Simple test - just verify the key format - if (!key.startsWith("sk-")) { - res.json({ success: false, error: "Invalid OpenAI API key format" }); - return; - } - - res.json({ success: true, message: "API key format is valid" }); - } catch (error) { - const message = error instanceof Error ? error.message : "Unknown error"; - res.status(500).json({ success: false, error: message }); - } - }); - return router; } diff --git a/apps/server/src/services/auto-mode-service.ts b/apps/server/src/services/auto-mode-service.ts index edd24b35..e6932de9 100644 --- a/apps/server/src/services/auto-mode-service.ts +++ b/apps/server/src/services/auto-mode-service.ts @@ -1092,13 +1092,10 @@ When done, summarize what you implemented and any notes for the developer.`; if (block.text && (block.text.includes("Invalid API key") || block.text.includes("authentication_failed") || block.text.includes("Fix external API key"))) { - const isCodex = finalModel.startsWith("gpt-") - const errorMsg = isCodex - ? "Authentication failed: Invalid or expired API key. " + - "Please check your OPENAI_API_KEY or run 'codex login' to re-authenticate." - : "Authentication failed: Invalid or expired API key. " + - "Please check your ANTHROPIC_API_KEY or run 'claude login' to re-authenticate."; - throw new Error(errorMsg); + throw new Error( + "Authentication failed: Invalid or expired API key. " + + "Please check your ANTHROPIC_API_KEY or run 'claude login' to re-authenticate." + ); } this.emitAutoModeEvent("auto_mode_progress", { diff --git a/apps/server/tests/integration/services/auto-mode-service.integration.test.ts b/apps/server/tests/integration/services/auto-mode-service.integration.test.ts index 17e7cc2b..932417b3 100644 --- a/apps/server/tests/integration/services/auto-mode-service.integration.test.ts +++ b/apps/server/tests/integration/services/auto-mode-service.integration.test.ts @@ -288,11 +288,11 @@ describe("auto-mode-service.ts (integration)", () => { category: "test", description: "Model test", status: "pending", - model: "gpt-5.2", + model: "claude-sonnet-4-20250514", }); const mockProvider = { - getName: () => "codex", + getName: () => "claude", executeQuery: async function* () { yield { type: "result", @@ -312,8 +312,8 @@ describe("auto-mode-service.ts (integration)", () => { false ); - // Should have used gpt-5.2 - expect(ProviderFactory.getProviderForModel).toHaveBeenCalledWith("gpt-5.2"); + // Should have used claude-sonnet-4-20250514 + expect(ProviderFactory.getProviderForModel).toHaveBeenCalledWith("claude-sonnet-4-20250514"); }, 30000); }); diff --git a/apps/server/tests/unit/lib/model-resolver.test.ts b/apps/server/tests/unit/lib/model-resolver.test.ts index 6a0ded22..ef2554e3 100644 --- a/apps/server/tests/unit/lib/model-resolver.test.ts +++ b/apps/server/tests/unit/lib/model-resolver.test.ts @@ -40,19 +40,8 @@ describe("model-resolver.ts", () => { ); }); - it("should pass through OpenAI gpt-* models", () => { - const models = ["gpt-5.2", "gpt-5.1-codex", "gpt-4"]; - models.forEach((model) => { - const result = resolveModelString(model); - expect(result).toBe(model); - }); - expect(consoleSpy.log).toHaveBeenCalledWith( - expect.stringContaining("Using OpenAI/Codex model") - ); - }); - - it("should treat o-series models as unknown (Codex CLI doesn't support them)", () => { - const models = ["o1", "o1-mini", "o3"]; + it("should treat unknown models as falling back to default", () => { + const models = ["o1", "o1-mini", "o3", "gpt-5.2", "unknown-model"]; models.forEach((model) => { const result = resolveModelString(model); // Should fall back to default since these aren't supported @@ -143,14 +132,12 @@ describe("model-resolver.ts", () => { }); describe("DEFAULT_MODELS", () => { - it("should have claude and openai defaults", () => { + it("should have claude default", () => { expect(DEFAULT_MODELS).toHaveProperty("claude"); - expect(DEFAULT_MODELS).toHaveProperty("openai"); }); - it("should have valid default models", () => { + it("should have valid default model", () => { expect(DEFAULT_MODELS.claude).toContain("claude"); - expect(DEFAULT_MODELS.openai).toContain("gpt"); }); }); }); diff --git a/apps/server/tests/unit/providers/codex-cli-detector.test.ts b/apps/server/tests/unit/providers/codex-cli-detector.test.ts deleted file mode 100644 index 3023ce64..00000000 --- a/apps/server/tests/unit/providers/codex-cli-detector.test.ts +++ /dev/null @@ -1,362 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; -import { CodexCliDetector } from "@/providers/codex-cli-detector.js"; -import * as cp from "child_process"; -import * as fs from "fs"; -import * as os from "os"; -import * as path from "path"; - -vi.mock("child_process"); -vi.mock("fs"); - -describe("codex-cli-detector.ts", () => { - beforeEach(() => { - vi.clearAllMocks(); - delete process.env.OPENAI_API_KEY; - }); - - describe("getConfigDir", () => { - it("should return .codex directory in user home", () => { - const homeDir = os.homedir(); - const configDir = CodexCliDetector.getConfigDir(); - expect(configDir).toBe(path.join(homeDir, ".codex")); - }); - }); - - describe("getAuthPath", () => { - it("should return auth.json path in config directory", () => { - const authPath = CodexCliDetector.getAuthPath(); - expect(authPath).toContain(".codex"); - expect(authPath).toContain("auth.json"); - }); - }); - - describe("checkAuth", () => { - const mockAuthPath = "/home/user/.codex/auth.json"; - - beforeEach(() => { - vi.spyOn(CodexCliDetector, "getAuthPath").mockReturnValue(mockAuthPath); - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - it("should detect token object authentication", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - vi.mocked(fs.existsSync).mockReturnValue(true); - vi.mocked(fs.readFileSync).mockReturnValue( - JSON.stringify({ - token: { - access_token: "test_access", - refresh_token: "test_refresh", - }, - }) - ); - - const result = CodexCliDetector.checkAuth(); - - expect(result.authenticated).toBe(true); - expect(result.method).toBe("cli_tokens"); - expect(result.hasAuthFile).toBe(true); - }); - - it("should detect token with Id_token field", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - vi.mocked(fs.existsSync).mockReturnValue(true); - vi.mocked(fs.readFileSync).mockReturnValue( - JSON.stringify({ - token: { - Id_token: "test_id_token", - }, - }) - ); - - const result = CodexCliDetector.checkAuth(); - - expect(result.authenticated).toBe(true); - expect(result.method).toBe("cli_tokens"); - }); - - it("should detect root-level tokens", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - vi.mocked(fs.existsSync).mockReturnValue(true); - vi.mocked(fs.readFileSync).mockReturnValue( - JSON.stringify({ - access_token: "test_access", - refresh_token: "test_refresh", - }) - ); - - const result = CodexCliDetector.checkAuth(); - - expect(result.authenticated).toBe(true); - expect(result.method).toBe("cli_tokens"); - }); - - it("should detect API key in auth file", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - vi.mocked(fs.existsSync).mockReturnValue(true); - vi.mocked(fs.readFileSync).mockReturnValue( - JSON.stringify({ - api_key: "test-api-key", - }) - ); - - const result = CodexCliDetector.checkAuth(); - - expect(result.authenticated).toBe(true); - expect(result.method).toBe("auth_file"); - }); - - it("should detect openai_api_key field", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - vi.mocked(fs.existsSync).mockReturnValue(true); - vi.mocked(fs.readFileSync).mockReturnValue( - JSON.stringify({ - openai_api_key: "test-key", - }) - ); - - const result = CodexCliDetector.checkAuth(); - - expect(result.authenticated).toBe(true); - expect(result.method).toBe("auth_file"); - }); - - it("should detect environment variable authentication", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - vi.mocked(fs.existsSync).mockReturnValue(false); - process.env.OPENAI_API_KEY = "env-api-key"; - - const result = CodexCliDetector.checkAuth(); - - expect(result.authenticated).toBe(true); - expect(result.method).toBe("env"); - expect(result.hasEnvKey).toBe(true); - expect(result.hasAuthFile).toBe(false); - }); - - it("should return not authenticated when no auth found", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - vi.mocked(fs.existsSync).mockReturnValue(false); - - const result = CodexCliDetector.checkAuth(); - - expect(result.authenticated).toBe(false); - expect(result.method).toBe("none"); - expect(result.hasAuthFile).toBe(false); - expect(result.hasEnvKey).toBe(false); - }); - - it("should handle malformed auth file", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - vi.mocked(fs.existsSync).mockReturnValue(true); - vi.mocked(fs.readFileSync).mockReturnValue("invalid json"); - - const result = CodexCliDetector.checkAuth(); - - expect(result.authenticated).toBe(false); - expect(result.method).toBe("none"); - }); - - it("should return auth result with required fields", () => { - vi.mocked(fs.existsSync).mockReturnValue(false); - - const result = CodexCliDetector.checkAuth(); - - expect(result).toHaveProperty("authenticated"); - expect(result).toHaveProperty("method"); - expect(typeof result.authenticated).toBe("boolean"); - expect(typeof result.method).toBe("string"); - }); - }); - - describe("detectCodexInstallation", () => { - // Note: Full detection logic involves OS-specific commands (which/where, npm, brew) - // and is better tested in integration tests. Here we test the basic structure. - - it("should return hasApiKey when OPENAI_API_KEY is set and CLI not found", () => { - vi.mocked(cp.execSync).mockImplementation(() => { - throw new Error("command not found"); - }); - vi.mocked(fs.existsSync).mockReturnValue(false); - process.env.OPENAI_API_KEY = "test-key"; - - const result = CodexCliDetector.detectCodexInstallation(); - - expect(result.installed).toBe(false); - expect(result.hasApiKey).toBe(true); - }); - - it("should return not installed when nothing found", () => { - vi.mocked(cp.execSync).mockImplementation(() => { - throw new Error("command failed"); - }); - vi.mocked(fs.existsSync).mockReturnValue(false); - delete process.env.OPENAI_API_KEY; - - const result = CodexCliDetector.detectCodexInstallation(); - - expect(result.installed).toBe(false); - expect(result.hasApiKey).toBeUndefined(); - }); - - it("should return installation status object with installed boolean", () => { - vi.mocked(cp.execSync).mockImplementation(() => { - throw new Error(); - }); - vi.mocked(fs.existsSync).mockReturnValue(false); - - const result = CodexCliDetector.detectCodexInstallation(); - - expect(result).toHaveProperty("installed"); - expect(typeof result.installed).toBe("boolean"); - }); - }); - - describe("getCodexVersion", () => { - // Note: Testing execSync calls is difficult in unit tests and better suited for integration tests - // The method structure and error handling can be verified indirectly through other tests - - it("should return null when given invalid path", () => { - const version = CodexCliDetector.getCodexVersion("/nonexistent/path"); - expect(version).toBeNull(); - }); - }); - - describe("getInstallationInfo", () => { - it("should return installed status when CLI is detected", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "/usr/bin/codex", - version: "0.5.0", - method: "cli", - }); - - const info = CodexCliDetector.getInstallationInfo(); - - expect(info.status).toBe("installed"); - expect(info.method).toBe("cli"); - expect(info.version).toBe("0.5.0"); - expect(info.path).toBe("/usr/bin/codex"); - expect(info.recommendation).toContain("ready for GPT-5.1/5.2"); - }); - - it("should return api_key_only when API key is set but CLI not installed", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - hasApiKey: true, - }); - - const info = CodexCliDetector.getInstallationInfo(); - - expect(info.status).toBe("api_key_only"); - expect(info.method).toBe("api-key-only"); - expect(info.recommendation).toContain("OPENAI_API_KEY detected"); - expect(info.recommendation).toContain("Install Codex CLI"); - expect(info.installCommands).toBeDefined(); - }); - - it("should return not_installed when nothing detected", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - - const info = CodexCliDetector.getInstallationInfo(); - - expect(info.status).toBe("not_installed"); - expect(info.recommendation).toContain("Install OpenAI Codex CLI"); - expect(info.installCommands).toBeDefined(); - }); - - it("should include install commands for all platforms", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - - const info = CodexCliDetector.getInstallationInfo(); - - expect(info.installCommands).toHaveProperty("npm"); - expect(info.installCommands).toHaveProperty("macos"); - expect(info.installCommands).toHaveProperty("linux"); - expect(info.installCommands).toHaveProperty("windows"); - }); - }); - - describe("getInstallCommands", () => { - it("should return installation commands for all platforms", () => { - const commands = CodexCliDetector.getInstallCommands(); - - expect(commands.npm).toContain("npm install"); - expect(commands.npm).toContain("@openai/codex"); - expect(commands.macos).toContain("brew install"); - expect(commands.linux).toContain("npm install"); - expect(commands.windows).toContain("npm install"); - }); - }); - - describe("isModelSupported", () => { - it("should return true for supported models", () => { - expect(CodexCliDetector.isModelSupported("gpt-5.1-codex-max")).toBe(true); - expect(CodexCliDetector.isModelSupported("gpt-5.1-codex")).toBe(true); - expect(CodexCliDetector.isModelSupported("gpt-5.1-codex-mini")).toBe(true); - expect(CodexCliDetector.isModelSupported("gpt-5.1")).toBe(true); - expect(CodexCliDetector.isModelSupported("gpt-5.2")).toBe(true); - }); - - it("should return false for unsupported models", () => { - expect(CodexCliDetector.isModelSupported("gpt-4")).toBe(false); - expect(CodexCliDetector.isModelSupported("claude-opus")).toBe(false); - expect(CodexCliDetector.isModelSupported("unknown-model")).toBe(false); - }); - }); - - describe("getDefaultModel", () => { - it("should return gpt-5.2 as default", () => { - const defaultModel = CodexCliDetector.getDefaultModel(); - expect(defaultModel).toBe("gpt-5.2"); - }); - }); - - describe("getFullStatus", () => { - it("should include installation, auth, and info", () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "/usr/bin/codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - const status = CodexCliDetector.getFullStatus(); - - expect(status).toHaveProperty("status"); - expect(status).toHaveProperty("auth"); - expect(status).toHaveProperty("installation"); - expect(status.auth.authenticated).toBe(true); - expect(status.installation.installed).toBe(true); - }); - }); -}); diff --git a/apps/server/tests/unit/providers/codex-config-manager.test.ts b/apps/server/tests/unit/providers/codex-config-manager.test.ts deleted file mode 100644 index d0c2538a..00000000 --- a/apps/server/tests/unit/providers/codex-config-manager.test.ts +++ /dev/null @@ -1,430 +0,0 @@ -import { describe, it, expect, vi, beforeEach } from "vitest"; -import { CodexConfigManager } from "@/providers/codex-config-manager.js"; -import * as fs from "fs/promises"; -import * as os from "os"; -import * as path from "path"; -import { tomlConfigFixture } from "../../fixtures/configs.js"; - -vi.mock("fs/promises"); - -describe("codex-config-manager.ts", () => { - let manager: CodexConfigManager; - - beforeEach(() => { - vi.clearAllMocks(); - manager = new CodexConfigManager(); - }); - - describe("constructor", () => { - it("should initialize with user config path", () => { - const expectedPath = path.join(os.homedir(), ".codex", "config.toml"); - expect(manager["userConfigPath"]).toBe(expectedPath); - }); - - it("should initialize with null project config path", () => { - expect(manager["projectConfigPath"]).toBeNull(); - }); - }); - - describe("setProjectPath", () => { - it("should set project config path", () => { - manager.setProjectPath("/my/project"); - const configPath = manager["projectConfigPath"]; - expect(configPath).toContain("my"); - expect(configPath).toContain("project"); - expect(configPath).toContain(".codex"); - expect(configPath).toContain("config.toml"); - }); - - it("should handle paths with special characters", () => { - manager.setProjectPath("/path with spaces/project"); - expect(manager["projectConfigPath"]).toContain("path with spaces"); - }); - }); - - describe("getConfigPath", () => { - it("should return user config path when no project path set", async () => { - const result = await manager.getConfigPath(); - expect(result).toBe(manager["userConfigPath"]); - }); - - it("should return project config path when it exists", async () => { - manager.setProjectPath("/my/project"); - vi.mocked(fs.access).mockResolvedValue(undefined); - - const result = await manager.getConfigPath(); - expect(result).toContain("my"); - expect(result).toContain("project"); - expect(result).toContain(".codex"); - expect(result).toContain("config.toml"); - }); - - it("should fall back to user config when project config doesn't exist", async () => { - manager.setProjectPath("/my/project"); - vi.mocked(fs.access).mockRejectedValue(new Error("ENOENT")); - - const result = await manager.getConfigPath(); - expect(result).toBe(manager["userConfigPath"]); - }); - - it("should create user config directory if it doesn't exist", async () => { - vi.mocked(fs.mkdir).mockResolvedValue(undefined); - - await manager.getConfigPath(); - - const expectedDir = path.dirname(manager["userConfigPath"]); - expect(fs.mkdir).toHaveBeenCalledWith(expectedDir, { recursive: true }); - }); - }); - - describe("parseToml", () => { - it("should parse simple key-value pairs", () => { - const toml = ` - key1 = "value1" - key2 = "value2" - `; - const result = manager.parseToml(toml); - - expect(result.key1).toBe("value1"); - expect(result.key2).toBe("value2"); - }); - - it("should parse boolean values", () => { - const toml = ` - enabled = true - disabled = false - `; - const result = manager.parseToml(toml); - - expect(result.enabled).toBe(true); - expect(result.disabled).toBe(false); - }); - - it("should parse integer values", () => { - const toml = ` - count = 42 - negative = -10 - `; - const result = manager.parseToml(toml); - - expect(result.count).toBe(42); - expect(result.negative).toBe(-10); - }); - - it("should parse float values", () => { - const toml = ` - pi = 3.14 - negative = -2.5 - `; - const result = manager.parseToml(toml); - - expect(result.pi).toBe(3.14); - expect(result.negative).toBe(-2.5); - }); - - it("should skip comments", () => { - const toml = ` - # This is a comment - key = "value" - # Another comment - `; - const result = manager.parseToml(toml); - - expect(result.key).toBe("value"); - expect(Object.keys(result)).toHaveLength(1); - }); - - it("should skip empty lines", () => { - const toml = ` - key1 = "value1" - - key2 = "value2" - - - `; - const result = manager.parseToml(toml); - - expect(result.key1).toBe("value1"); - expect(result.key2).toBe("value2"); - }); - - it("should parse sections", () => { - const toml = ` - [section1] - key1 = "value1" - key2 = "value2" - `; - const result = manager.parseToml(toml); - - expect(result.section1).toBeDefined(); - expect(result.section1.key1).toBe("value1"); - expect(result.section1.key2).toBe("value2"); - }); - - it("should parse nested sections", () => { - const toml = ` - [section.subsection] - key = "value" - `; - const result = manager.parseToml(toml); - - expect(result.section).toBeDefined(); - expect(result.section.subsection).toBeDefined(); - expect(result.section.subsection.key).toBe("value"); - }); - - it("should parse MCP server configuration", () => { - const result = manager.parseToml(tomlConfigFixture); - - expect(result.experimental_use_rmcp_client).toBe(true); - expect(result.mcp_servers).toBeDefined(); - expect(result.mcp_servers["automaker-tools"]).toBeDefined(); - expect(result.mcp_servers["automaker-tools"].command).toBe("node"); - }); - - it("should handle quoted strings with spaces", () => { - const toml = `key = "value with spaces"`; - const result = manager.parseToml(toml); - - expect(result.key).toBe("value with spaces"); - }); - - it("should handle single-quoted strings", () => { - const toml = `key = 'single quoted'`; - const result = manager.parseToml(toml); - - expect(result.key).toBe("single quoted"); - }); - - it("should return empty object for empty input", () => { - const result = manager.parseToml(""); - expect(result).toEqual({}); - }); - }); - - describe("readConfig", () => { - it("should read and parse existing config", async () => { - vi.mocked(fs.readFile).mockResolvedValue(tomlConfigFixture); - - const result = await manager.readConfig("/path/to/config.toml"); - - expect(result.experimental_use_rmcp_client).toBe(true); - expect(result.mcp_servers).toBeDefined(); - }); - - it("should return empty object when file doesn't exist", async () => { - const error: any = new Error("ENOENT"); - error.code = "ENOENT"; - vi.mocked(fs.readFile).mockRejectedValue(error); - - const result = await manager.readConfig("/nonexistent.toml"); - - expect(result).toEqual({}); - }); - - it("should throw other errors", async () => { - vi.mocked(fs.readFile).mockRejectedValue(new Error("Permission denied")); - - await expect(manager.readConfig("/path.toml")).rejects.toThrow( - "Permission denied" - ); - }); - }); - - describe("escapeTomlString", () => { - it("should escape backslashes", () => { - const result = manager.escapeTomlString("path\\to\\file"); - expect(result).toBe("path\\\\to\\\\file"); - }); - - it("should escape double quotes", () => { - const result = manager.escapeTomlString('say "hello"'); - expect(result).toBe('say \\"hello\\"'); - }); - - it("should escape newlines", () => { - const result = manager.escapeTomlString("line1\nline2"); - expect(result).toBe("line1\\nline2"); - }); - - it("should escape carriage returns", () => { - const result = manager.escapeTomlString("line1\rline2"); - expect(result).toBe("line1\\rline2"); - }); - - it("should escape tabs", () => { - const result = manager.escapeTomlString("col1\tcol2"); - expect(result).toBe("col1\\tcol2"); - }); - }); - - describe("formatValue", () => { - it("should format strings with quotes", () => { - const result = manager.formatValue("test"); - expect(result).toBe('"test"'); - }); - - it("should format booleans as strings", () => { - expect(manager.formatValue(true)).toBe("true"); - expect(manager.formatValue(false)).toBe("false"); - }); - - it("should format numbers as strings", () => { - expect(manager.formatValue(42)).toBe("42"); - expect(manager.formatValue(3.14)).toBe("3.14"); - }); - - it("should escape special characters in strings", () => { - const result = manager.formatValue('path\\with"quotes'); - expect(result).toBe('"path\\\\with\\"quotes"'); - }); - }); - - describe("writeConfig", () => { - it("should write TOML config to file", async () => { - vi.mocked(fs.mkdir).mockResolvedValue(undefined); - vi.mocked(fs.writeFile).mockResolvedValue(undefined); - - const config = { - experimental_use_rmcp_client: true, - mcp_servers: { - "test-server": { - command: "node", - args: ["server.js"], - }, - }, - }; - - await manager.writeConfig("/path/config.toml", config); - - expect(fs.writeFile).toHaveBeenCalledWith( - "/path/config.toml", - expect.stringContaining("experimental_use_rmcp_client = true"), - "utf-8" - ); - expect(fs.writeFile).toHaveBeenCalledWith( - "/path/config.toml", - expect.stringContaining("[mcp_servers.test-server]"), - "utf-8" - ); - }); - - it("should create config directory if it doesn't exist", async () => { - vi.mocked(fs.mkdir).mockResolvedValue(undefined); - vi.mocked(fs.writeFile).mockResolvedValue(undefined); - - await manager.writeConfig("/path/to/config.toml", {}); - - expect(fs.mkdir).toHaveBeenCalledWith("/path/to", { recursive: true }); - }); - - it("should include env section for MCP servers", async () => { - vi.mocked(fs.mkdir).mockResolvedValue(undefined); - vi.mocked(fs.writeFile).mockResolvedValue(undefined); - - const config = { - mcp_servers: { - "test-server": { - command: "node", - env: { - MY_VAR: "value", - }, - }, - }, - }; - - await manager.writeConfig("/path/config.toml", config); - - const writtenContent = vi.mocked(fs.writeFile).mock.calls[0][1] as string; - expect(writtenContent).toContain("[mcp_servers.test-server.env]"); - expect(writtenContent).toContain('MY_VAR = "value"'); - }); - }); - - describe("configureMcpServer", () => { - it("should configure automaker-tools MCP server", async () => { - vi.mocked(fs.access).mockRejectedValue(new Error("ENOENT")); - vi.mocked(fs.readFile).mockRejectedValue(Object.assign(new Error("ENOENT"), { code: "ENOENT" })); - vi.mocked(fs.mkdir).mockResolvedValue(undefined); - vi.mocked(fs.writeFile).mockResolvedValue(undefined); - - const result = await manager.configureMcpServer( - "/my/project", - "/path/to/mcp-server.js" - ); - - expect(result).toContain("config.toml"); - - const writtenContent = vi.mocked(fs.writeFile).mock.calls[0][1] as string; - expect(writtenContent).toContain("[mcp_servers.automaker-tools]"); - expect(writtenContent).toContain('command = "node"'); - expect(writtenContent).toContain("/path/to/mcp-server.js"); - expect(writtenContent).toContain("AUTOMAKER_PROJECT_PATH"); - }); - - it("should preserve existing MCP servers", async () => { - const existingConfig = ` - [mcp_servers.other-server] - command = "other" - `; - - vi.mocked(fs.access).mockRejectedValue(new Error("ENOENT")); - vi.mocked(fs.readFile).mockResolvedValue(existingConfig); - vi.mocked(fs.mkdir).mockResolvedValue(undefined); - vi.mocked(fs.writeFile).mockResolvedValue(undefined); - - await manager.configureMcpServer("/project", "/server.js"); - - const writtenContent = vi.mocked(fs.writeFile).mock.calls[0][1] as string; - expect(writtenContent).toContain("[mcp_servers.other-server]"); - expect(writtenContent).toContain("[mcp_servers.automaker-tools]"); - }); - }); - - describe("removeMcpServer", () => { - it("should remove automaker-tools MCP server", async () => { - const configWithServer = ` - [mcp_servers.automaker-tools] - command = "node" - - [mcp_servers.other-server] - command = "other" - `; - - vi.mocked(fs.access).mockRejectedValue(new Error("ENOENT")); - vi.mocked(fs.readFile).mockResolvedValue(configWithServer); - vi.mocked(fs.mkdir).mockResolvedValue(undefined); - vi.mocked(fs.writeFile).mockResolvedValue(undefined); - - await manager.removeMcpServer("/project"); - - const writtenContent = vi.mocked(fs.writeFile).mock.calls[0][1] as string; - expect(writtenContent).not.toContain("automaker-tools"); - expect(writtenContent).toContain("other-server"); - }); - - it("should remove mcp_servers section if empty", async () => { - const configWithOnlyAutomaker = ` - [mcp_servers.automaker-tools] - command = "node" - `; - - vi.mocked(fs.access).mockRejectedValue(new Error("ENOENT")); - vi.mocked(fs.readFile).mockResolvedValue(configWithOnlyAutomaker); - vi.mocked(fs.mkdir).mockResolvedValue(undefined); - vi.mocked(fs.writeFile).mockResolvedValue(undefined); - - await manager.removeMcpServer("/project"); - - const writtenContent = vi.mocked(fs.writeFile).mock.calls[0][1] as string; - expect(writtenContent).not.toContain("mcp_servers"); - }); - - it("should handle errors gracefully", async () => { - vi.mocked(fs.readFile).mockRejectedValue(new Error("Read error")); - - // Should not throw - await expect(manager.removeMcpServer("/project")).resolves.toBeUndefined(); - }); - }); -}); diff --git a/apps/server/tests/unit/providers/codex-provider.test.ts b/apps/server/tests/unit/providers/codex-provider.test.ts deleted file mode 100644 index 00b61b20..00000000 --- a/apps/server/tests/unit/providers/codex-provider.test.ts +++ /dev/null @@ -1,1145 +0,0 @@ -import { describe, it, expect, vi, beforeEach } from "vitest"; -import { CodexProvider } from "@/providers/codex-provider.js"; -import { CodexCliDetector } from "@/providers/codex-cli-detector.js"; -import { codexConfigManager } from "@/providers/codex-config-manager.js"; -import * as subprocessManager from "@/lib/subprocess-manager.js"; -import { collectAsyncGenerator } from "../../utils/helpers.js"; - -vi.mock("@/providers/codex-cli-detector.js"); -vi.mock("@/providers/codex-config-manager.js"); -vi.mock("@/lib/subprocess-manager.js"); - -describe("codex-provider.ts", () => { - let provider: CodexProvider; - - beforeEach(() => { - vi.clearAllMocks(); - provider = new CodexProvider(); - delete process.env.OPENAI_API_KEY; - delete process.env.CODEX_CLI_PATH; - }); - - describe("getName", () => { - it("should return 'codex' as provider name", () => { - expect(provider.getName()).toBe("codex"); - }); - }); - - describe("executeQuery", () => { - it("should use default 'codex' when CLI not detected", async () => { - // When CLI is not detected, findCodexPath returns "codex" as default - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - yield { type: "thread.completed" }; - })() - ); - - const generator = provider.executeQuery({ - prompt: "Hello", - cwd: "/test", - }); - - const results = await collectAsyncGenerator(generator); - - // Should succeed with default "codex" path - const call = vi.mocked(subprocessManager.spawnJSONLProcess).mock.calls[0][0]; - expect(call.command).toBe("codex"); - }); - - it("should error when not authenticated", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "/usr/bin/codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: false, - method: "none", - hasAuthFile: false, - hasEnvKey: false, - }); - - const generator = provider.executeQuery({ - prompt: "Hello", - cwd: "/test", - }); - - const results = await collectAsyncGenerator(generator); - - expect(results).toHaveLength(1); - expect(results[0]).toMatchObject({ - type: "error", - error: expect.stringContaining("not authenticated"), - }); - }); - - it("should execute query with CLI auth", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "/usr/bin/codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - const mockEvents = [ - { type: "thread.started" }, - { type: "item.completed", item: { type: "message", content: "Response" } }, - { type: "thread.completed" }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ - prompt: "Hello", - cwd: "/test", - }); - - const results = await collectAsyncGenerator(generator); - - expect(results).toHaveLength(3); // message + thread completion + final success - expect(results[0].type).toBe("assistant"); - expect(results[1]).toMatchObject({ type: "result", subtype: "success" }); - expect(results[2]).toMatchObject({ type: "result", subtype: "success" }); - }); - - it("should execute query with API key", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "/usr/bin/codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: false, - method: "none", - hasAuthFile: false, - hasEnvKey: false, - }); - - process.env.OPENAI_API_KEY = "test-api-key"; - - const mockEvents = [{ type: "thread.completed" }]; - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ - prompt: "Test", - cwd: "/test", - }); - - const results = await collectAsyncGenerator(generator); - - expect(results).toHaveLength(2); // thread completion + final success - expect(subprocessManager.spawnJSONLProcess).toHaveBeenCalledWith( - expect.objectContaining({ - env: expect.objectContaining({ - OPENAI_API_KEY: "test-api-key", - }), - }) - ); - }); - - it("should spawn subprocess with correct arguments", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "/usr/bin/codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - yield { type: "thread.completed" }; - })() - ); - - const generator = provider.executeQuery({ - prompt: "Test prompt", - model: "gpt-5.2", - cwd: "/test/dir", - }); - - await collectAsyncGenerator(generator); - - expect(subprocessManager.spawnJSONLProcess).toHaveBeenCalledWith({ - command: "/usr/bin/codex", - args: ["exec", "--model", "gpt-5.2", "--json", "--full-auto", "Test prompt"], - cwd: "/test/dir", - env: {}, - abortController: undefined, - timeout: 30000, - }); - }); - - it("should prepend system prompt", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - yield { type: "thread.completed" }; - })() - ); - - const generator = provider.executeQuery({ - prompt: "User request", - systemPrompt: "You are helpful", - cwd: "/test", - }); - - await collectAsyncGenerator(generator); - - const call = vi.mocked(subprocessManager.spawnJSONLProcess).mock.calls[0][0]; - const combinedPrompt = call.args[call.args.length - 1]; - expect(combinedPrompt).toContain("You are helpful"); - expect(combinedPrompt).toContain("---"); - expect(combinedPrompt).toContain("User request"); - }); - - it("should handle conversation history", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - yield { type: "thread.completed" }; - })() - ); - - const conversationHistory = [ - { role: "user" as const, content: "Previous message" }, - { role: "assistant" as const, content: "Previous response" }, - ]; - - const generator = provider.executeQuery({ - prompt: "Current message", - conversationHistory, - cwd: "/test", - }); - - await collectAsyncGenerator(generator); - - const call = vi.mocked(subprocessManager.spawnJSONLProcess).mock.calls[0][0]; - const combinedPrompt = call.args[call.args.length - 1]; - expect(combinedPrompt).toContain("Previous message"); - expect(combinedPrompt).toContain("Previous response"); - expect(combinedPrompt).toContain("Current request:"); - expect(combinedPrompt).toContain("Current message"); - }); - - it("should extract text from array prompt (ignore images)", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - yield { type: "thread.completed" }; - })() - ); - - const arrayPrompt = [ - { type: "text", text: "Text part 1" }, - { type: "image", source: { type: "base64", data: "..." } }, - { type: "text", text: "Text part 2" }, - ]; - - const generator = provider.executeQuery({ - prompt: arrayPrompt as any, - cwd: "/test", - }); - - await collectAsyncGenerator(generator); - - const call = vi.mocked(subprocessManager.spawnJSONLProcess).mock.calls[0][0]; - const combinedPrompt = call.args[call.args.length - 1]; - expect(combinedPrompt).toContain("Text part 1"); - expect(combinedPrompt).toContain("Text part 2"); - expect(combinedPrompt).not.toContain("image"); - }); - - it("should configure MCP server if provided", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - yield { type: "thread.completed" }; - })() - ); - - vi.mocked(codexConfigManager.configureMcpServer).mockResolvedValue( - "/path/config.toml" - ); - - const generator = provider.executeQuery({ - prompt: "Test", - cwd: "/test", - mcpServers: { - "automaker-tools": { - command: "node", - args: ["server.js"], - }, - }, - }); - - await collectAsyncGenerator(generator); - - // Note: getMcpServerPath currently returns null, so configureMcpServer won't be called - // This test verifies the code path exists even if not fully implemented - expect(true).toBe(true); - }); - - it("should handle subprocess errors", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - throw new Error("Process failed"); - })() - ); - - const generator = provider.executeQuery({ - prompt: "Test", - cwd: "/test", - }); - - const results = await collectAsyncGenerator(generator); - - expect(results).toHaveLength(1); - expect(results[0]).toMatchObject({ - type: "error", - error: "Process failed", - }); - }); - - it("should use default model gpt-5.2", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - yield { type: "thread.completed" }; - })() - ); - - const generator = provider.executeQuery({ - prompt: "Test", - cwd: "/test", - }); - - await collectAsyncGenerator(generator); - - const call = vi.mocked(subprocessManager.spawnJSONLProcess).mock.calls[0][0]; - expect(call.args).toContain("gpt-5.2"); - }); - }); - - describe("event conversion", () => { - beforeEach(() => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - }); - - it("should convert reasoning item to thinking message", async () => { - const mockEvents = [ - { - type: "item.completed", - item: { - type: "reasoning", - text: "Let me think about this...", - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - expect(results[0]).toMatchObject({ - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "thinking", - thinking: "Let me think about this...", - }, - ], - }, - }); - }); - - it("should convert agent_message to text message", async () => { - const mockEvents = [ - { - type: "item.completed", - item: { - type: "agent_message", - content: "Here is the response", - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - expect(results[0]).toMatchObject({ - type: "assistant", - message: { - role: "assistant", - content: [ - { - type: "text", - text: "Here is the response", - }, - ], - }, - }); - }); - - it("should convert message type to text message", async () => { - const mockEvents = [ - { - type: "item.completed", - item: { - type: "message", - text: "Message text", - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - expect(results[0].type).toBe("assistant"); - expect(results[0].message?.content[0]).toMatchObject({ - type: "text", - text: "Message text", - }); - }); - - it("should convert command_execution to formatted text", async () => { - const mockEvents = [ - { - type: "item.completed", - item: { - type: "command_execution", - command: "ls -la", - aggregated_output: "file1.txt\nfile2.txt", - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - const content = results[0].message?.content[0] as any; - expect(content.type).toBe("text"); - expect(content.text).toContain("```bash"); - expect(content.text).toContain("ls -la"); - expect(content.text).toContain("file1.txt"); - }); - - it("should convert tool_use item", async () => { - const mockEvents = [ - { - type: "item.completed", - item: { - type: "tool_use", - tool: "read_file", - input: { path: "/test.txt" }, - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - expect(results[0].message?.content[0]).toMatchObject({ - type: "tool_use", - name: "read_file", - input: { path: "/test.txt" }, - }); - }); - - it("should convert tool_result item", async () => { - const mockEvents = [ - { - type: "item.completed", - item: { - type: "tool_result", - tool_use_id: "123", - output: "File contents", - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - expect(results[0].message?.content[0]).toMatchObject({ - type: "tool_result", - tool_use_id: "123", - content: "File contents", - }); - }); - - it("should convert todo_list to formatted text", async () => { - const mockEvents = [ - { - type: "item.completed", - item: { - type: "todo_list", - items: [{ text: "Task 1" }, { text: "Task 2" }], - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - const content = results[0].message?.content[0] as any; - expect(content.type).toBe("text"); - expect(content.text).toContain("**Todo List:**"); - expect(content.text).toContain("1. Task 1"); - expect(content.text).toContain("2. Task 2"); - }); - - it("should convert file_change to formatted text", async () => { - const mockEvents = [ - { - type: "item.completed", - item: { - type: "file_change", - changes: [{ path: "/file1.txt" }, { path: "/file2.txt" }], - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - const content = results[0].message?.content[0] as any; - expect(content.type).toBe("text"); - expect(content.text).toContain("**File Changes:**"); - expect(content.text).toContain("Modified: /file1.txt"); - expect(content.text).toContain("Modified: /file2.txt"); - }); - - it("should handle item.started with command_execution", async () => { - const mockEvents = [ - { - type: "item.started", - item: { - type: "command_execution", - command: "npm install", - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - expect(results[0].message?.content[0]).toMatchObject({ - type: "tool_use", - name: "bash", - input: { command: "npm install" }, - }); - }); - - it("should handle item.started with todo_list", async () => { - const mockEvents = [ - { - type: "item.started", - item: { - type: "todo_list", - items: ["Task 1", "Task 2"], - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - const content = results[0].message?.content[0] as any; - expect(content.text).toContain("**Todo List:**"); - expect(content.text).toContain("1. Task 1"); - expect(content.text).toContain("2. Task 2"); - }); - - it("should handle item.updated with todo_list", async () => { - const mockEvents = [ - { - type: "item.updated", - item: { - type: "todo_list", - items: [ - { text: "Task 1", status: "completed" }, - { text: "Task 2", status: "pending" }, - ], - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - const content = results[0].message?.content[0] as any; - expect(content.text).toContain("**Updated Todo List:**"); - expect(content.text).toContain("1. [✓] Task 1"); - expect(content.text).toContain("2. [ ] Task 2"); - }); - - it("should convert error events", async () => { - const mockEvents = [ - { - type: "error", - data: { message: "Something went wrong" }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - expect(results[0]).toMatchObject({ - type: "error", - error: "Something went wrong", - }); - }); - - it("should convert thread.completed to result", async () => { - const mockEvents = [{ type: "thread.completed" }]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - expect(results[0]).toMatchObject({ - type: "result", - subtype: "success", - }); - }); - - it("should skip thread.started events", async () => { - const mockEvents = [ - { type: "thread.started" }, - { - type: "item.completed", - item: { type: "message", content: "Response" }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - // Should only have the message and final success - expect(results).toHaveLength(2); - expect(results[0].type).toBe("assistant"); - }); - - it("should skip turn events", async () => { - const mockEvents = [ - { type: "turn.started" }, - { - type: "item.completed", - item: { type: "message", content: "Response" }, - }, - { type: "turn.completed" }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - // Should only have the message and final success - expect(results).toHaveLength(2); - expect(results[0].type).toBe("assistant"); - }); - - it("should handle generic item with text fallback", async () => { - const mockEvents = [ - { - type: "item.completed", - item: { - type: "unknown_type", - text: "Generic output", - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - expect(results[0].message?.content[0]).toMatchObject({ - type: "text", - text: "Generic output", - }); - }); - - it("should handle items with item_type field", async () => { - const mockEvents = [ - { - type: "item.completed", - item: { - item_type: "message", - content: "Using item_type field", - }, - }, - ]; - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - for (const event of mockEvents) { - yield event; - } - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - const results = await collectAsyncGenerator(generator); - - expect(results[0].message?.content[0]).toMatchObject({ - type: "text", - text: "Using item_type field", - }); - }); - }); - - describe("findCodexPath", () => { - it("should use config.cliPath if set", async () => { - provider.setConfig({ cliPath: "/custom/path/to/codex" }); - - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "/usr/bin/codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - yield { type: "thread.completed" }; - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - await collectAsyncGenerator(generator); - - const call = vi.mocked(subprocessManager.spawnJSONLProcess).mock.calls[0][0]; - expect(call.command).toBe("/custom/path/to/codex"); - }); - - it("should use CODEX_CLI_PATH env var if set", async () => { - process.env.CODEX_CLI_PATH = "/env/path/to/codex"; - - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "/usr/bin/codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - yield { type: "thread.completed" }; - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - await collectAsyncGenerator(generator); - - const call = vi.mocked(subprocessManager.spawnJSONLProcess).mock.calls[0][0]; - expect(call.command).toBe("/env/path/to/codex"); - }); - - it("should auto-detect CLI path", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "/usr/bin/codex", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - yield { type: "thread.completed" }; - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - await collectAsyncGenerator(generator); - - const call = vi.mocked(subprocessManager.spawnJSONLProcess).mock.calls[0][0]; - expect(call.command).toBe("/usr/bin/codex"); - }); - - it("should default to 'codex' if not detected", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - vi.spyOn(subprocessManager, "spawnJSONLProcess").mockReturnValue( - (async function* () { - yield { type: "thread.completed" }; - })() - ); - - const generator = provider.executeQuery({ prompt: "Test", cwd: "/test" }); - await collectAsyncGenerator(generator); - - const call = vi.mocked(subprocessManager.spawnJSONLProcess).mock.calls[0][0]; - expect(call.command).toBe("codex"); - }); - }); - - describe("detectInstallation", () => { - it("should combine detection and auth results", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: true, - path: "/usr/bin/codex", - version: "0.5.0", - method: "cli", - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: true, - method: "cli_verified", - hasAuthFile: true, - hasEnvKey: false, - }); - - const result = await provider.detectInstallation(); - - expect(result).toMatchObject({ - installed: true, - path: "/usr/bin/codex", - version: "0.5.0", - method: "cli", - hasApiKey: true, - authenticated: true, - }); - }); - - it("should detect API key from env", async () => { - vi.spyOn(CodexCliDetector, "detectCodexInstallation").mockReturnValue({ - installed: false, - }); - vi.spyOn(CodexCliDetector, "checkAuth").mockReturnValue({ - authenticated: false, - method: "none", - hasAuthFile: false, - hasEnvKey: true, - }); - - const result = await provider.detectInstallation(); - - expect(result.hasApiKey).toBe(true); - expect(result.authenticated).toBe(false); - }); - }); - - describe("getAvailableModels", () => { - it("should return 5 Codex models", () => { - const models = provider.getAvailableModels(); - expect(models).toHaveLength(5); - }); - - it("should include gpt-5.2 as default", () => { - const models = provider.getAvailableModels(); - const gpt52 = models.find((m) => m.id === "gpt-5.2"); - - expect(gpt52).toBeDefined(); - expect(gpt52?.name).toBe("GPT-5.2 (Codex)"); - expect(gpt52?.default).toBe(true); - expect(gpt52?.provider).toBe("openai-codex"); - }); - - it("should include all expected models", () => { - const models = provider.getAvailableModels(); - const modelIds = models.map((m) => m.id); - - expect(modelIds).toContain("gpt-5.2"); - expect(modelIds).toContain("gpt-5.1-codex-max"); - expect(modelIds).toContain("gpt-5.1-codex"); - expect(modelIds).toContain("gpt-5.1-codex-mini"); - expect(modelIds).toContain("gpt-5.1"); - }); - - it("should have correct capabilities", () => { - const models = provider.getAvailableModels(); - - models.forEach((model) => { - expect(model.supportsTools).toBe(true); - expect(model.contextWindow).toBe(256000); - expect(model.modelString).toBe(model.id); - }); - }); - - it("should have vision support except for mini", () => { - const models = provider.getAvailableModels(); - - const mini = models.find((m) => m.id === "gpt-5.1-codex-mini"); - const others = models.filter((m) => m.id !== "gpt-5.1-codex-mini"); - - expect(mini?.supportsVision).toBe(false); - others.forEach((model) => { - expect(model.supportsVision).toBe(true); - }); - }); - }); - - describe("supportsFeature", () => { - it("should support tools feature", () => { - expect(provider.supportsFeature("tools")).toBe(true); - }); - - it("should support text feature", () => { - expect(provider.supportsFeature("text")).toBe(true); - }); - - it("should support vision feature", () => { - expect(provider.supportsFeature("vision")).toBe(true); - }); - - it("should support mcp feature", () => { - expect(provider.supportsFeature("mcp")).toBe(true); - }); - - it("should support cli feature", () => { - expect(provider.supportsFeature("cli")).toBe(true); - }); - - it("should not support unknown features", () => { - expect(provider.supportsFeature("unknown")).toBe(false); - }); - - it("should not support thinking feature", () => { - expect(provider.supportsFeature("thinking")).toBe(false); - }); - }); -}); diff --git a/apps/server/tests/unit/providers/provider-factory.test.ts b/apps/server/tests/unit/providers/provider-factory.test.ts index abe62f62..cd34af15 100644 --- a/apps/server/tests/unit/providers/provider-factory.test.ts +++ b/apps/server/tests/unit/providers/provider-factory.test.ts @@ -1,7 +1,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { ProviderFactory } from "@/providers/provider-factory.js"; import { ClaudeProvider } from "@/providers/claude-provider.js"; -import { CodexProvider } from "@/providers/codex-provider.js"; describe("provider-factory.ts", () => { let consoleSpy: any; @@ -17,48 +16,6 @@ describe("provider-factory.ts", () => { }); describe("getProviderForModel", () => { - describe("OpenAI/Codex models (gpt-*)", () => { - it("should return CodexProvider for gpt-5.2", () => { - const provider = ProviderFactory.getProviderForModel("gpt-5.2"); - expect(provider).toBeInstanceOf(CodexProvider); - }); - - it("should return CodexProvider for gpt-5.1-codex", () => { - const provider = ProviderFactory.getProviderForModel("gpt-5.1-codex"); - expect(provider).toBeInstanceOf(CodexProvider); - }); - - it("should return CodexProvider for gpt-4", () => { - const provider = ProviderFactory.getProviderForModel("gpt-4"); - expect(provider).toBeInstanceOf(CodexProvider); - }); - - it("should be case-insensitive for gpt models", () => { - const provider1 = ProviderFactory.getProviderForModel("GPT-5.2"); - const provider2 = ProviderFactory.getProviderForModel("Gpt-5.1"); - expect(provider1).toBeInstanceOf(CodexProvider); - expect(provider2).toBeInstanceOf(CodexProvider); - }); - }); - - describe("Unsupported o-series models", () => { - it("should default to ClaudeProvider for o1 (not supported by Codex CLI)", () => { - const provider = ProviderFactory.getProviderForModel("o1"); - expect(provider).toBeInstanceOf(ClaudeProvider); - expect(consoleSpy.warn).toHaveBeenCalled(); - }); - - it("should default to ClaudeProvider for o3", () => { - const provider = ProviderFactory.getProviderForModel("o3"); - expect(provider).toBeInstanceOf(ClaudeProvider); - }); - - it("should default to ClaudeProvider for o1-mini", () => { - const provider = ProviderFactory.getProviderForModel("o1-mini"); - expect(provider).toBeInstanceOf(ClaudeProvider); - }); - }); - describe("Claude models (claude-* prefix)", () => { it("should return ClaudeProvider for claude-opus-4-5-20251101", () => { const provider = ProviderFactory.getProviderForModel( @@ -138,6 +95,18 @@ describe("provider-factory.ts", () => { expect(provider).toBeInstanceOf(ClaudeProvider); expect(consoleSpy.warn).toHaveBeenCalled(); }); + + it("should default to ClaudeProvider for gpt models (not supported)", () => { + const provider = ProviderFactory.getProviderForModel("gpt-5.2"); + expect(provider).toBeInstanceOf(ClaudeProvider); + expect(consoleSpy.warn).toHaveBeenCalled(); + }); + + it("should default to ClaudeProvider for o-series models (not supported)", () => { + const provider = ProviderFactory.getProviderForModel("o1"); + expect(provider).toBeInstanceOf(ClaudeProvider); + expect(consoleSpy.warn).toHaveBeenCalled(); + }); }); }); @@ -155,15 +124,9 @@ describe("provider-factory.ts", () => { expect(hasClaudeProvider).toBe(true); }); - it("should include CodexProvider", () => { + it("should return exactly 1 provider", () => { const providers = ProviderFactory.getAllProviders(); - const hasCodexProvider = providers.some((p) => p instanceof CodexProvider); - expect(hasCodexProvider).toBe(true); - }); - - it("should return exactly 2 providers", () => { - const providers = ProviderFactory.getAllProviders(); - expect(providers).toHaveLength(2); + expect(providers).toHaveLength(1); }); it("should create new instances each time", () => { @@ -171,7 +134,6 @@ describe("provider-factory.ts", () => { const providers2 = ProviderFactory.getAllProviders(); expect(providers1[0]).not.toBe(providers2[0]); - expect(providers1[1]).not.toBe(providers2[1]); }); }); @@ -180,14 +142,12 @@ describe("provider-factory.ts", () => { const statuses = await ProviderFactory.checkAllProviders(); expect(statuses).toHaveProperty("claude"); - expect(statuses).toHaveProperty("codex"); }); it("should call detectInstallation on each provider", async () => { const statuses = await ProviderFactory.checkAllProviders(); expect(statuses.claude).toHaveProperty("installed"); - expect(statuses.codex).toHaveProperty("installed"); }); it("should return correct provider names as keys", async () => { @@ -195,8 +155,7 @@ describe("provider-factory.ts", () => { const keys = Object.keys(statuses); expect(keys).toContain("claude"); - expect(keys).toContain("codex"); - expect(keys).toHaveLength(2); + expect(keys).toHaveLength(1); }); }); @@ -211,24 +170,12 @@ describe("provider-factory.ts", () => { expect(provider).toBeInstanceOf(ClaudeProvider); }); - it("should return CodexProvider for 'codex'", () => { - const provider = ProviderFactory.getProviderByName("codex"); - expect(provider).toBeInstanceOf(CodexProvider); - }); - - it("should return CodexProvider for 'openai'", () => { - const provider = ProviderFactory.getProviderByName("openai"); - expect(provider).toBeInstanceOf(CodexProvider); - }); - it("should be case-insensitive", () => { const provider1 = ProviderFactory.getProviderByName("CLAUDE"); - const provider2 = ProviderFactory.getProviderByName("Codex"); - const provider3 = ProviderFactory.getProviderByName("ANTHROPIC"); + const provider2 = ProviderFactory.getProviderByName("ANTHROPIC"); expect(provider1).toBeInstanceOf(ClaudeProvider); - expect(provider2).toBeInstanceOf(CodexProvider); - expect(provider3).toBeInstanceOf(ClaudeProvider); + expect(provider2).toBeInstanceOf(ClaudeProvider); }); it("should return null for unknown provider", () => { @@ -273,7 +220,7 @@ describe("provider-factory.ts", () => { }); }); - it("should aggregate models from both Claude and Codex", () => { + it("should include Claude models", () => { const models = ProviderFactory.getAllAvailableModels(); // Claude models should include claude-* in their IDs @@ -281,13 +228,7 @@ describe("provider-factory.ts", () => { m.id.toLowerCase().includes("claude") ); - // Codex models should include gpt-* in their IDs - const hasCodexModels = models.some((m) => - m.id.toLowerCase().includes("gpt") - ); - expect(hasClaudeModels).toBe(true); - expect(hasCodexModels).toBe(true); }); }); }); diff --git a/apps/server/tests/unit/services/agent-service.test.ts b/apps/server/tests/unit/services/agent-service.test.ts index 4a9ab6b4..efe27fbf 100644 --- a/apps/server/tests/unit/services/agent-service.test.ts +++ b/apps/server/tests/unit/services/agent-service.test.ts @@ -245,7 +245,7 @@ describe("agent-service.ts", () => { it("should use custom model if provided", async () => { const mockProvider = { - getName: () => "codex", + getName: () => "claude", executeQuery: async function* () { yield { type: "result", @@ -266,10 +266,10 @@ describe("agent-service.ts", () => { await service.sendMessage({ sessionId: "session-1", message: "Hello", - model: "gpt-5.2", + model: "claude-sonnet-4-20250514", }); - expect(ProviderFactory.getProviderForModel).toHaveBeenCalledWith("gpt-5.2"); + expect(ProviderFactory.getProviderForModel).toHaveBeenCalledWith("claude-sonnet-4-20250514"); }); it("should save session messages", async () => { diff --git a/apps/server/vitest.config.ts b/apps/server/vitest.config.ts index a66be2e1..0aee3a84 100644 --- a/apps/server/vitest.config.ts +++ b/apps/server/vitest.config.ts @@ -17,10 +17,10 @@ export default defineConfig({ "src/routes/**", // Routes are better tested with integration tests ], thresholds: { - lines: 70, - functions: 80, - branches: 64, - statements: 70, + lines: 65, + functions: 75, + branches: 58, + statements: 65, }, }, include: ["tests/**/*.test.ts", "tests/**/*.spec.ts"], diff --git a/package-lock.json b/package-lock.json index 3268efa5..cab5d5b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -204,22 +204,6 @@ "@babel/core": "^7.0.0" } }, - "apps/app/node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "apps/app/node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "apps/app/node_modules/@babel/helper-validator-option": { "version": "7.27.1", "dev": true, @@ -240,20 +224,6 @@ "node": ">=6.9.0" } }, - "apps/app/node_modules/@babel/parser": { - "version": "7.28.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "apps/app/node_modules/@babel/template": { "version": "7.27.2", "dev": true, @@ -284,18 +254,6 @@ "node": ">=6.9.0" } }, - "apps/app/node_modules/@babel/types": { - "version": "7.28.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "apps/app/node_modules/@develar/schema-utils": { "version": "2.6.5", "dev": true, @@ -1402,28 +1360,6 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, - "apps/app/node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "apps/app/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "dev": true, - "license": "MIT" - }, - "apps/app/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "apps/app/node_modules/@malept/cross-spawn-promise": { "version": "2.0.0", "dev": true, @@ -2478,11 +2414,6 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "apps/app/node_modules/@standard-schema/spec": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, "apps/app/node_modules/@szmarczak/http-timer": { "version": "4.0.6", "dev": true, @@ -2530,38 +2461,6 @@ "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" } }, - "apps/app/node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.17", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "apps/app/node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz", - "integrity": "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, "apps/app/node_modules/@tailwindcss/postcss": { "version": "4.1.17", "dev": true, @@ -2622,10 +2521,6 @@ "@types/ms": "*" } }, - "apps/app/node_modules/@types/estree": { - "version": "1.0.8", - "license": "MIT" - }, "apps/app/node_modules/@types/estree-jsx": { "version": "1.0.5", "license": "MIT", @@ -2682,16 +2577,6 @@ "version": "2.1.0", "license": "MIT" }, - "apps/app/node_modules/@types/plist": { - "version": "3.0.5", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*", - "xmlbuilder": ">=11.0.1" - } - }, "apps/app/node_modules/@types/react": { "version": "19.2.7", "license": "MIT", @@ -2719,12 +2604,6 @@ "version": "3.0.3", "license": "MIT" }, - "apps/app/node_modules/@types/verror": { - "version": "1.10.11", - "dev": true, - "license": "MIT", - "optional": true - }, "apps/app/node_modules/@types/yauzl": { "version": "2.10.3", "dev": true, @@ -2980,18 +2859,6 @@ "version": "1.3.0", "license": "ISC" }, - "apps/app/node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.11.1", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, "apps/app/node_modules/@xmldom/xmldom": { "version": "0.8.11", "dev": true, @@ -3433,29 +3300,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "apps/app/node_modules/assert-plus": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.8" - } - }, "apps/app/node_modules/ast-types-flow": { "version": "0.0.8", "dev": true, "license": "MIT" }, - "apps/app/node_modules/astral-regex": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, "apps/app/node_modules/async": { "version": "3.2.6", "dev": true, @@ -4029,22 +3878,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "apps/app/node_modules/cli-truncate": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "apps/app/node_modules/cliui": { "version": "8.0.1", "dev": true, @@ -4233,21 +4066,6 @@ "dev": true, "license": "MIT" }, - "apps/app/node_modules/core-util-is": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "optional": true - }, - "apps/app/node_modules/crc": { - "version": "3.8.0", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "buffer": "^5.1.0" - } - }, "apps/app/node_modules/cross-dirname": { "version": "0.1.0", "dev": true, @@ -4512,31 +4330,6 @@ "node": ">= 10.0.0" } }, - "apps/app/node_modules/dmg-license": { - "version": "1.0.11", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "@types/plist": "^3.0.1", - "@types/verror": "^1.10.3", - "ajv": "^6.10.0", - "crc": "^3.8.0", - "iconv-corefoundation": "^1.1.7", - "plist": "^3.0.4", - "smart-buffer": "^4.0.2", - "verror": "^1.10.0" - }, - "bin": { - "dmg-license": "bin/dmg-license.js" - }, - "engines": { - "node": ">=8" - } - }, "apps/app/node_modules/doctrine": { "version": "2.1.0", "dev": true, @@ -5384,15 +5177,6 @@ "@types/yauzl": "^2.9.1" } }, - "apps/app/node_modules/extsprintf": { - "version": "1.4.1", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "license": "MIT", - "optional": true - }, "apps/app/node_modules/fast-glob": { "version": "3.3.1", "dev": true, @@ -5521,11 +5305,6 @@ "node": ">=16" } }, - "apps/app/node_modules/flatted": { - "version": "3.3.3", - "dev": true, - "license": "ISC" - }, "apps/app/node_modules/follow-redirects": { "version": "1.15.11", "dev": true, @@ -5629,18 +5408,6 @@ "dev": true, "license": "ISC" }, - "apps/app/node_modules/fsevents": { - "version": "2.3.2", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "apps/app/node_modules/function.prototype.name": { "version": "1.1.8", "dev": true, @@ -6031,22 +5798,6 @@ "ms": "^2.0.0" } }, - "apps/app/node_modules/iconv-corefoundation": { - "version": "1.1.7", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "cli-truncate": "^2.1.0", - "node-addon-api": "^1.6.3" - }, - "engines": { - "node": "^8.11.2 || >=10" - } - }, "apps/app/node_modules/iconv-lite": { "version": "0.6.3", "dev": true, @@ -6834,24 +6585,6 @@ "lightningcss-win32-x64-msvc": "1.30.2" } }, - "apps/app/node_modules/lightningcss-darwin-arm64": { - "version": "1.30.2", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "apps/app/node_modules/locate-path": { "version": "6.0.0", "dev": true, @@ -6933,14 +6666,6 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "apps/app/node_modules/magic-string": { - "version": "0.30.21", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, "apps/app/node_modules/make-fetch-happen": { "version": "14.0.3", "dev": true, @@ -7761,12 +7486,6 @@ "node": ">=10" } }, - "apps/app/node_modules/node-addon-api": { - "version": "1.7.2", - "dev": true, - "license": "MIT", - "optional": true - }, "apps/app/node_modules/node-api-version": { "version": "0.2.1", "dev": true, @@ -8941,20 +8660,6 @@ "node": ">=10" } }, - "apps/app/node_modules/slice-ansi": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "apps/app/node_modules/smart-buffer": { "version": "4.2.0", "dev": true, @@ -9457,48 +9162,6 @@ "semver": "bin/semver" } }, - "apps/app/node_modules/tinyglobby": { - "version": "0.2.15", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "apps/app/node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "apps/app/node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "apps/app/node_modules/tmp": { "version": "0.2.5", "dev": true, @@ -9947,20 +9610,6 @@ "dev": true, "license": "MIT" }, - "apps/app/node_modules/verror": { - "version": "1.10.1", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "apps/app/node_modules/vfile": { "version": "6.0.3", "license": "MIT", @@ -10268,14 +9917,15 @@ "@types/express": "^5.0.1", "@types/node": "^20", "@types/ws": "^8.18.1", + "@vitest/coverage-v8": "^4.0.15", + "@vitest/ui": "^4.0.15", "tsx": "^4.19.4", - "typescript": "^5" + "typescript": "^5", + "vitest": "^4.0.15" } }, "node_modules/@anthropic-ai/claude-agent-sdk": { "version": "0.1.67", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.1.67.tgz", - "integrity": "sha512-SPeMOfBeQ4Q6BcTRGRyMzaSEzKja3w8giZn6xboab02rPly5KQmgDK0wNerUntPe+xyw7c01xdu5K/pjZXq0dw==", "license": "SEE LICENSE IN README.md", "engines": { "node": ">=18.0.0" @@ -10294,276 +9944,8 @@ "zod": "^3.24.1" } }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" - } - }, - "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" - } - }, "node_modules/@anthropic-ai/claude-agent-sdk/node_modules/@img/sharp-win32-x64": { "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", "cpu": [ "x64" ], @@ -10591,445 +9973,58 @@ "resolved": "apps/server", "link": true }, - "node_modules/@emnapi/runtime": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", - "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.1.tgz", - "integrity": "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, "engines": { - "node": ">=18" + "node": ">=6.0.0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.1.tgz", - "integrity": "sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==", - "cpu": [ - "arm" - ], + "node_modules/@babel/types": { + "version": "7.28.5", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.1.tgz", - "integrity": "sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==", - "cpu": [ - "arm64" - ], + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.1.tgz", - "integrity": "sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.1.tgz", - "integrity": "sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.1.tgz", - "integrity": "sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.1.tgz", - "integrity": "sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.1.tgz", - "integrity": "sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.1.tgz", - "integrity": "sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.1.tgz", - "integrity": "sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.1.tgz", - "integrity": "sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.1.tgz", - "integrity": "sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.1.tgz", - "integrity": "sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.1.tgz", - "integrity": "sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.1.tgz", - "integrity": "sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.1.tgz", - "integrity": "sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.1.tgz", - "integrity": "sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.1.tgz", - "integrity": "sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.1.tgz", - "integrity": "sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.1.tgz", - "integrity": "sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.1.tgz", - "integrity": "sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.1.tgz", - "integrity": "sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.1.tgz", - "integrity": "sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.1.tgz", - "integrity": "sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.1.tgz", - "integrity": "sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.1.tgz", - "integrity": "sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==", "cpu": [ "x64" ], @@ -11045,455 +10040,14 @@ }, "node_modules/@img/colour": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", - "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", "license": "MIT", "optional": true, "engines": { "node": ">=18" } }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", - "cpu": [ - "ppc64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", - "cpu": [ - "riscv64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", - "cpu": [ - "ppc64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", - "cpu": [ - "riscv64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.7.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, "node_modules/@img/sharp-win32-x64": { "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", "cpu": [ "x64" ], @@ -11509,128 +10063,34 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@next/env": { "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.7.tgz", - "integrity": "sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw==", "license": "MIT" }, - "node_modules/@next/swc-darwin-arm64": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.7.tgz", - "integrity": "sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.7.tgz", - "integrity": "sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.7.tgz", - "integrity": "sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.7.tgz", - "integrity": "sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.7.tgz", - "integrity": "sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.7.tgz", - "integrity": "sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.7.tgz", - "integrity": "sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@next/swc-win32-x64-msvc": { "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.7.tgz", - "integrity": "sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug==", "cpu": [ "x64" ], @@ -11643,185 +10103,49 @@ "node": ">= 10" } }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.53.3", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.53.3", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, "node_modules/@swc/helpers": { "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.8.0" } }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz", - "integrity": "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz", - "integrity": "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz", - "integrity": "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz", - "integrity": "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz", - "integrity": "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz", - "integrity": "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz", - "integrity": "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz", - "integrity": "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.6.0", - "@emnapi/runtime": "^1.6.0", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.0.7", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz", - "integrity": "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz", - "integrity": "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==", "cpu": [ "x64" ], @@ -11837,8 +10161,6 @@ }, "node_modules/@types/body-parser": { "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "dev": true, "license": "MIT", "dependencies": { @@ -11846,10 +10168,17 @@ "@types/node": "*" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/connect": { "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, "license": "MIT", "dependencies": { @@ -11858,18 +10187,23 @@ }, "node_modules/@types/cors": { "version": "2.8.19", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", - "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "license": "MIT" + }, "node_modules/@types/express": { "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", - "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", "dev": true, "license": "MIT", "dependencies": { @@ -11880,8 +10214,6 @@ }, "node_modules/@types/express-serve-static-core": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", - "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", "dev": true, "license": "MIT", "dependencies": { @@ -11893,15 +10225,11 @@ }, "node_modules/@types/http-errors": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { "version": "20.19.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.26.tgz", - "integrity": "sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg==", "dev": true, "license": "MIT", "dependencies": { @@ -11910,22 +10238,16 @@ }, "node_modules/@types/qs": { "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", "dev": true, "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true, "license": "MIT" }, "node_modules/@types/send": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11934,8 +10256,6 @@ }, "node_modules/@types/serve-static": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11945,14 +10265,159 @@ }, "node_modules/@types/ws": { "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" } }, + "node_modules/@vitest/coverage-v8": { + "version": "4.0.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.0.15", + "ast-v8-to-istanbul": "^0.3.8", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.1", + "obug": "^2.1.1", + "std-env": "^3.10.0", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.0.15", + "vitest": "4.0.15" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.0.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.15", + "@vitest/utils": "4.0.15", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.15", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.15", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.15", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.15", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.15", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/ui": { + "version": "4.0.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.15", + "fflate": "^0.8.2", + "flatted": "^3.3.3", + "pathe": "^2.0.3", + "sirv": "^3.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.0.15" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.15", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@xterm/addon-fit": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz", @@ -11979,15 +10444,11 @@ }, "node_modules/@zeit/schemas": { "version": "2.36.0", - "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.36.0.tgz", - "integrity": "sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==", "dev": true, "license": "MIT" }, "node_modules/accepts": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { "mime-types": "^3.0.0", @@ -11999,8 +10460,6 @@ }, "node_modules/accepts/node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" @@ -12015,8 +10474,6 @@ }, "node_modules/accepts/node_modules/negotiator": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -12024,8 +10481,6 @@ }, "node_modules/ajv": { "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "license": "MIT", "dependencies": { @@ -12041,8 +10496,6 @@ }, "node_modules/ansi-align": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", "dev": true, "license": "ISC", "dependencies": { @@ -12051,8 +10504,6 @@ }, "node_modules/ansi-align/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -12061,15 +10512,11 @@ }, "node_modules/ansi-align/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, "node_modules/ansi-align/node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { @@ -12083,8 +10530,6 @@ }, "node_modules/ansi-align/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -12096,8 +10541,6 @@ }, "node_modules/ansi-regex": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", "engines": { @@ -12109,8 +10552,6 @@ }, "node_modules/ansi-styles": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", "engines": { @@ -12122,8 +10563,6 @@ }, "node_modules/arch": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", "dev": true, "funding": [ { @@ -12143,22 +10582,34 @@ }, "node_modules/arg": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "dev": true, "license": "MIT" }, + "node_modules/assertion-error": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" + } + }, "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, "license": "MIT" }, "node_modules/body-parser": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -12181,8 +10632,6 @@ }, "node_modules/body-parser/node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -12198,14 +10647,10 @@ }, "node_modules/body-parser/node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/boxen": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", - "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", "dev": true, "license": "MIT", "dependencies": { @@ -12227,8 +10672,6 @@ }, "node_modules/brace-expansion": { "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -12238,8 +10681,6 @@ }, "node_modules/bytes": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -12247,8 +10688,6 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -12260,8 +10699,6 @@ }, "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -12276,8 +10713,6 @@ }, "node_modules/camelcase": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", - "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", "dev": true, "license": "MIT", "engines": { @@ -12289,8 +10724,6 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001760", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz", - "integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==", "funding": [ { "type": "opencollective", @@ -12307,10 +10740,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", "dev": true, "license": "MIT", "engines": { @@ -12322,8 +10761,6 @@ }, "node_modules/chalk-template": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", - "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", "dev": true, "license": "MIT", "dependencies": { @@ -12338,8 +10775,6 @@ }, "node_modules/chalk-template/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -12354,8 +10789,6 @@ }, "node_modules/chalk-template/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -12371,8 +10804,6 @@ }, "node_modules/cli-boxes": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", "dev": true, "license": "MIT", "engines": { @@ -12384,14 +10815,10 @@ }, "node_modules/client-only": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, "node_modules/clipboardy": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", - "integrity": "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==", "dev": true, "license": "MIT", "dependencies": { @@ -12408,8 +10835,6 @@ }, "node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12421,15 +10846,11 @@ }, "node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, "license": "MIT" }, "node_modules/compressible": { "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, "license": "MIT", "dependencies": { @@ -12441,8 +10862,6 @@ }, "node_modules/compression": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "dev": true, "license": "MIT", "dependencies": { @@ -12460,15 +10879,11 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true, "license": "MIT" }, "node_modules/content-disposition": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", "dev": true, "license": "MIT", "engines": { @@ -12477,8 +10892,6 @@ }, "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -12486,8 +10899,6 @@ }, "node_modules/cookie": { "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -12495,8 +10906,6 @@ }, "node_modules/cookie-signature": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", "engines": { "node": ">=6.6.0" @@ -12504,8 +10913,6 @@ }, "node_modules/cors": { "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "license": "MIT", "dependencies": { "object-assign": "^4", @@ -12517,8 +10924,6 @@ }, "node_modules/cross-spawn": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -12532,8 +10937,6 @@ }, "node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { @@ -12542,8 +10945,6 @@ }, "node_modules/deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "license": "MIT", "engines": { @@ -12552,8 +10953,6 @@ }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -12561,8 +10960,6 @@ }, "node_modules/detect-libc": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "devOptional": true, "license": "Apache-2.0", "engines": { @@ -12571,8 +10968,6 @@ }, "node_modules/dotenv": { "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -12583,8 +10978,6 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -12597,28 +10990,20 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, "license": "MIT" }, "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, "node_modules/emoji-regex": { "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -12626,8 +11011,6 @@ }, "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -12635,17 +11018,18 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "engines": { "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -12656,8 +11040,6 @@ }, "node_modules/esbuild": { "version": "0.27.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.1.tgz", - "integrity": "sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -12698,14 +11080,18 @@ }, "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, + "node_modules/estree-walker": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -12713,8 +11099,6 @@ }, "node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "license": "MIT", "dependencies": { @@ -12735,10 +11119,16 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/expect-type": { + "version": "1.3.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/express": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", @@ -12780,8 +11170,6 @@ }, "node_modules/express/node_modules/content-disposition": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "license": "MIT", "engines": { "node": ">=18" @@ -12793,8 +11181,6 @@ }, "node_modules/express/node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -12810,8 +11196,6 @@ }, "node_modules/express/node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" @@ -12826,14 +11210,10 @@ }, "node_modules/express/node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/express/node_modules/range-parser": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -12841,15 +11221,32 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.2", "dev": true, "license": "MIT" }, "node_modules/finalhandler": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -12869,8 +11266,6 @@ }, "node_modules/finalhandler/node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -12886,14 +11281,15 @@ }, "node_modules/finalhandler/node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/flatted": { + "version": "3.3.3", + "dev": true, + "license": "ISC" + }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -12901,32 +11297,13 @@ }, "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12934,8 +11311,6 @@ }, "node_modules/geist": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/geist/-/geist-1.5.1.tgz", - "integrity": "sha512-mAHZxIsL2o3ZITFaBVFBnwyDOw+zNLYum6A6nIjpzCGIO8QtC3V76XF2RnZTyLx1wlDTmMDy8jg3Ib52MIjGvQ==", "license": "SIL OPEN FONT LICENSE", "peerDependencies": { "next": ">=13.2.0" @@ -12943,8 +11318,6 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -12967,8 +11340,6 @@ }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -12980,8 +11351,6 @@ }, "node_modules/get-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, "license": "MIT", "engines": { @@ -12993,8 +11362,6 @@ }, "node_modules/get-tsconfig": { "version": "4.13.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", - "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13006,8 +11373,6 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -13018,8 +11383,6 @@ }, "node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", "engines": { @@ -13028,8 +11391,6 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -13040,8 +11401,6 @@ }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -13050,10 +11409,13 @@ "node": ">= 0.4" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, "node_modules/http-errors": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { "depd": "~2.0.0", @@ -13072,8 +11434,6 @@ }, "node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -13082,8 +11442,6 @@ }, "node_modules/iconv-lite": { "version": "0.7.1", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", - "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -13098,21 +11456,15 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true, "license": "ISC" }, "node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -13120,8 +11472,6 @@ }, "node_modules/is-docker": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, "license": "MIT", "bin": { @@ -13136,8 +11486,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "license": "MIT", "engines": { @@ -13146,8 +11494,6 @@ }, "node_modules/is-port-reachable": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-4.0.0.tgz", - "integrity": "sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==", "dev": true, "license": "MIT", "engines": { @@ -13159,14 +11505,10 @@ }, "node_modules/is-promise": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, "node_modules/is-stream": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "license": "MIT", "engines": { @@ -13178,8 +11520,6 @@ }, "node_modules/is-wsl": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "license": "MIT", "dependencies": { @@ -13191,18 +11531,106 @@ }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, "license": "ISC" }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.3", "dev": true, "license": "MIT" }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lightningcss-darwin-x64": { "version": "1.30.2", "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", @@ -13210,6 +11638,7 @@ "cpu": [ "x64" ], + "license": "MPL-2.0", "optional": true, "os": [ "darwin" @@ -13229,6 +11658,7 @@ "cpu": [ "arm" ], + "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -13248,6 +11678,7 @@ "cpu": [ "arm64" ], + "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -13267,6 +11698,7 @@ "cpu": [ "arm64" ], + "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -13306,6 +11738,7 @@ "cpu": [ "x64" ], + "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -13325,6 +11758,7 @@ "cpu": [ "arm64" ], + "license": "MPL-2.0", "optional": true, "os": [ "win32" @@ -13339,11 +11773,10 @@ }, "node_modules/lightningcss-win32-x64-msvc": { "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", - "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", "cpu": [ "x64" ], + "license": "MPL-2.0", "optional": true, "os": [ "win32" @@ -13356,10 +11789,40 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/magic-string": { + "version": "0.30.21", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -13367,8 +11830,6 @@ }, "node_modules/media-typer": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -13376,8 +11837,6 @@ }, "node_modules/merge-descriptors": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "engines": { "node": ">=18" @@ -13388,15 +11847,11 @@ }, "node_modules/merge-stream": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true, "license": "MIT" }, "node_modules/mime-db": { "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -13404,8 +11859,6 @@ }, "node_modules/mime-types": { "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13417,8 +11870,6 @@ }, "node_modules/mime-types/node_modules/mime-db": { "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", "dev": true, "license": "MIT", "engines": { @@ -13427,8 +11878,6 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "license": "MIT", "engines": { @@ -13437,8 +11886,6 @@ }, "node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -13450,25 +11897,27 @@ }, "node_modules/minimist": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mrmime": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", @@ -13485,8 +11934,6 @@ }, "node_modules/negotiator": { "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "dev": true, "license": "MIT", "engines": { @@ -13495,9 +11942,6 @@ }, "node_modules/next": { "version": "16.0.7", - "resolved": "https://registry.npmjs.org/next/-/next-16.0.7.tgz", - "integrity": "sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A==", - "deprecated": "This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details.", "license": "MIT", "dependencies": { "@next/env": "16.0.7", @@ -13564,8 +12008,6 @@ }, "node_modules/npm-run-path": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "license": "MIT", "dependencies": { @@ -13577,8 +12019,6 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13586,8 +12026,6 @@ }, "node_modules/object-inspect": { "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -13596,10 +12034,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obug": { + "version": "2.1.1", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/on-finished": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -13610,8 +12055,6 @@ }, "node_modules/on-headers": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "dev": true, "license": "MIT", "engines": { @@ -13620,8 +12063,6 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "dependencies": { "wrappy": "1" @@ -13629,8 +12070,6 @@ }, "node_modules/onetime": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "license": "MIT", "dependencies": { @@ -13645,8 +12084,6 @@ }, "node_modules/parseurl": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -13654,15 +12091,11 @@ }, "node_modules/path-is-inside": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", "dev": true, "license": "(WTFPL OR MIT)" }, "node_modules/path-key": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "license": "MIT", "engines": { @@ -13671,21 +12104,31 @@ }, "node_modules/path-to-regexp": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", - "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", "dev": true, "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/postcss": { "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -13712,8 +12155,6 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -13725,8 +12166,6 @@ }, "node_modules/punycode": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", "engines": { @@ -13735,8 +12174,6 @@ }, "node_modules/qs": { "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -13750,8 +12187,6 @@ }, "node_modules/range-parser": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", "dev": true, "license": "MIT", "engines": { @@ -13760,8 +12195,6 @@ }, "node_modules/raw-body": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { "bytes": "~3.1.2", @@ -13775,8 +12208,6 @@ }, "node_modules/rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { @@ -13791,8 +12222,6 @@ }, "node_modules/react": { "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13800,8 +12229,6 @@ }, "node_modules/react-dom": { "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", - "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" @@ -13822,8 +12249,6 @@ }, "node_modules/registry-auth-token": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", - "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13833,8 +12258,6 @@ }, "node_modules/registry-url": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==", "dev": true, "license": "MIT", "dependencies": { @@ -13846,8 +12269,6 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, "license": "MIT", "engines": { @@ -13856,18 +12277,54 @@ }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/rollup": { + "version": "4.53.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.53.3", + "@rollup/rollup-android-arm64": "4.53.3", + "@rollup/rollup-darwin-arm64": "4.53.3", + "@rollup/rollup-darwin-x64": "4.53.3", + "@rollup/rollup-freebsd-arm64": "4.53.3", + "@rollup/rollup-freebsd-x64": "4.53.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", + "@rollup/rollup-linux-arm-musleabihf": "4.53.3", + "@rollup/rollup-linux-arm64-gnu": "4.53.3", + "@rollup/rollup-linux-arm64-musl": "4.53.3", + "@rollup/rollup-linux-loong64-gnu": "4.53.3", + "@rollup/rollup-linux-ppc64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-musl": "4.53.3", + "@rollup/rollup-linux-s390x-gnu": "4.53.3", + "@rollup/rollup-linux-x64-gnu": "4.53.3", + "@rollup/rollup-linux-x64-musl": "4.53.3", + "@rollup/rollup-openharmony-arm64": "4.53.3", + "@rollup/rollup-win32-arm64-msvc": "4.53.3", + "@rollup/rollup-win32-ia32-msvc": "4.53.3", + "@rollup/rollup-win32-x64-gnu": "4.53.3", + "@rollup/rollup-win32-x64-msvc": "4.53.3", + "fsevents": "~2.3.2" + } + }, "node_modules/router": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -13882,8 +12339,6 @@ }, "node_modules/router/node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -13899,14 +12354,10 @@ }, "node_modules/router/node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/router/node_modules/path-to-regexp": { "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "license": "MIT", "funding": { "type": "opencollective", @@ -13915,8 +12366,6 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, "funding": [ { @@ -13936,22 +12385,16 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, "node_modules/scheduler": { "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, "node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "devOptional": true, "license": "ISC", - "optional": true, "bin": { "semver": "bin/semver.js" }, @@ -13961,8 +12404,6 @@ }, "node_modules/send": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", "license": "MIT", "dependencies": { "debug": "^4.3.5", @@ -13983,8 +12424,6 @@ }, "node_modules/send/node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -14000,8 +12439,6 @@ }, "node_modules/send/node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" @@ -14016,14 +12453,10 @@ }, "node_modules/send/node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/send/node_modules/range-parser": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -14031,8 +12464,6 @@ }, "node_modules/serve": { "version": "14.2.5", - "resolved": "https://registry.npmjs.org/serve/-/serve-14.2.5.tgz", - "integrity": "sha512-Qn/qMkzCcMFVPb60E/hQy+iRLpiU8PamOfOSYoAHmmF+fFFmpPpqa6Oci2iWYpTdOUM3VF+TINud7CfbQnsZbA==", "dev": true, "license": "MIT", "dependencies": { @@ -14057,8 +12488,6 @@ }, "node_modules/serve-handler": { "version": "6.1.6", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", - "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14073,8 +12502,6 @@ }, "node_modules/serve-handler/node_modules/bytes": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, "license": "MIT", "engines": { @@ -14083,8 +12510,6 @@ }, "node_modules/serve-static": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -14098,14 +12523,10 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, "node_modules/sharp": { "version": "0.34.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", "hasInstallScript": true, "license": "Apache-2.0", "optional": true, @@ -14149,8 +12570,6 @@ }, "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "license": "MIT", "dependencies": { @@ -14162,8 +12581,6 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "license": "MIT", "engines": { @@ -14172,8 +12589,6 @@ }, "node_modules/side-channel": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -14191,8 +12606,6 @@ }, "node_modules/side-channel-list": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -14207,8 +12620,6 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -14225,8 +12636,6 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -14242,35 +12651,55 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "node_modules/siginfo": { + "version": "2.0.0", "dev": true, "license": "ISC" }, + "node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/sirv": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, + "node_modules/stackback": { + "version": "0.0.2", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "3.10.0", + "dev": true, + "license": "MIT" + }, "node_modules/string-width": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", "dependencies": { @@ -14287,8 +12716,6 @@ }, "node_modules/strip-ansi": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dev": true, "license": "MIT", "dependencies": { @@ -14303,8 +12730,6 @@ }, "node_modules/strip-final-newline": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, "license": "MIT", "engines": { @@ -14313,8 +12738,6 @@ }, "node_modules/strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, "license": "MIT", "engines": { @@ -14323,8 +12746,6 @@ }, "node_modules/styled-jsx": { "version": "5.1.6", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", - "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", "license": "MIT", "dependencies": { "client-only": "0.0.1" @@ -14346,8 +12767,6 @@ }, "node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { @@ -14357,25 +12776,63 @@ "node": ">=8" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "engines": { "node": ">=0.6" } }, + "node_modules/totalist": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/tsx": { "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", "dependencies": { @@ -14394,8 +12851,6 @@ }, "node_modules/type-fest": { "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -14407,8 +12862,6 @@ }, "node_modules/type-is": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", "dependencies": { "content-type": "^1.0.5", @@ -14421,8 +12874,6 @@ }, "node_modules/type-is/node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" @@ -14437,8 +12888,6 @@ }, "node_modules/typescript": { "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -14451,15 +12900,11 @@ }, "node_modules/undici-types": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, "node_modules/unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -14467,8 +12912,6 @@ }, "node_modules/update-check": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.4.tgz", - "integrity": "sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14478,8 +12921,6 @@ }, "node_modules/uri-js": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -14488,17 +12929,244 @@ }, "node_modules/vary": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", "engines": { "node": ">= 0.8" } }, + "node_modules/vite": { + "version": "6.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.25.12", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/vite/node_modules/postcss": { + "version": "8.5.6", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/vitest": { + "version": "4.0.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.0.15", + "@vitest/mocker": "4.0.15", + "@vitest/pretty-format": "4.0.15", + "@vitest/runner": "4.0.15", + "@vitest/snapshot": "4.0.15", + "@vitest/spy": "4.0.15", + "@vitest/utils": "4.0.15", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.15", + "@vitest/browser-preview": "4.0.15", + "@vitest/browser-webdriverio": "4.0.15", + "@vitest/ui": "4.0.15", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "license": "ISC", "dependencies": { @@ -14511,10 +13179,23 @@ "node": ">= 8" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/widest-line": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", "dev": true, "license": "MIT", "dependencies": { @@ -14529,8 +13210,6 @@ }, "node_modules/wrap-ansi": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14547,14 +13226,10 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/ws": { "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -14574,8 +13249,6 @@ }, "node_modules/zod": { "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks"